From 38d0c098d0b8f52cd2c8ae16eff3fcf5396d4c4f Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Tue, 8 Nov 2022 11:59:27 +0100 Subject: [PATCH 01/19] in progress --- solidjs-tailwind/src/services/api.js | 25 +++++++++++++++++++ .../src/services/queries/all-repos.js | 0 2 files changed, 25 insertions(+) create mode 100644 solidjs-tailwind/src/services/api.js create mode 100644 solidjs-tailwind/src/services/queries/all-repos.js diff --git a/solidjs-tailwind/src/services/api.js b/solidjs-tailwind/src/services/api.js new file mode 100644 index 000000000..bd3699910 --- /dev/null +++ b/solidjs-tailwind/src/services/api.js @@ -0,0 +1,25 @@ +const FetchApi = ({url, query, variables, headersOptions}) => { + return new Promise((resolve, reject) => { + fetch(url, { + method: "POST", + headers: { + ...headersOptions, + Accept: 'application/vnd.github+json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + query, + variables + }) + }) + .then((res) => res.json()) + .then((result) => { + resolve(result); + }) + .catch((error) => { + reject(error); + }); + }); +}; + +export default FetchApi; diff --git a/solidjs-tailwind/src/services/queries/all-repos.js b/solidjs-tailwind/src/services/queries/all-repos.js new file mode 100644 index 000000000..e69de29bb From e2d8555cb7a2352197526704289cc6b3898e762e Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Tue, 8 Nov 2022 15:41:14 +0100 Subject: [PATCH 02/19] chore: get all repos api --- solidjs-tailwind/src/services/api.js | 10 ++-- .../src/services/queries/all-repos.js | 55 +++++++++++++++++++ solidjs-tailwind/src/services/user-repos.js | 50 +++++++++++++++++ 3 files changed, 110 insertions(+), 5 deletions(-) create mode 100644 solidjs-tailwind/src/services/user-repos.js diff --git a/solidjs-tailwind/src/services/api.js b/solidjs-tailwind/src/services/api.js index bd3699910..f625fae29 100644 --- a/solidjs-tailwind/src/services/api.js +++ b/solidjs-tailwind/src/services/api.js @@ -1,7 +1,7 @@ -const FetchApi = ({url, query, variables, headersOptions}) => { +const FetchApi = ({ url, query, variables, headersOptions }) => { return new Promise((resolve, reject) => { fetch(url, { - method: "POST", + method: 'POST', headers: { ...headersOptions, Accept: 'application/vnd.github+json', @@ -9,10 +9,10 @@ const FetchApi = ({url, query, variables, headersOptions}) => { }, body: JSON.stringify({ query, - variables - }) + variables, + }), }) - .then((res) => res.json()) + .then((res) => res.json()) .then((result) => { resolve(result); }) diff --git a/solidjs-tailwind/src/services/queries/all-repos.js b/solidjs-tailwind/src/services/queries/all-repos.js index e69de29bb..697509912 100644 --- a/solidjs-tailwind/src/services/queries/all-repos.js +++ b/solidjs-tailwind/src/services/queries/all-repos.js @@ -0,0 +1,55 @@ +export const USER_REPOS_QUERY = ` + query UserRepos( + $username: String! + $afterCursor: String + $beforeCursor: String + $orderBy: RepositoryOrder + $first: Int + $last: Int + ) { + owner: user(login: $username) { + repositories( + first: $first + last: $last + after: $afterCursor + before: $beforeCursor + orderBy: $orderBy + ownerAffiliations: [OWNER] + ) { + nodes { + id + name + description + stargazerCount + forkCount + isArchived + isFork + primaryLanguage { + id + color + name + } + languages(first: 10, orderBy: { direction: ASC, field: SIZE }) { + nodes { + color + name + id + } + } + isPrivate + visibility + updatedAt + owner { + login + } + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } + } +`; diff --git a/solidjs-tailwind/src/services/user-repos.js b/solidjs-tailwind/src/services/user-repos.js new file mode 100644 index 000000000..03a66f3b2 --- /dev/null +++ b/solidjs-tailwind/src/services/user-repos.js @@ -0,0 +1,50 @@ +import FetchApi from "./api"; +import { USER_REPOS_QUERY } from "./queries/all-repos"; + +const getUserRepos = async ({ + url +}) => { + const data = { + url, + query: USER_REPOS_QUERY, + variable: null, + headersOptions: { + authorization: `Bearer tokenvalue`, + } + } + const resp = await FetchApi(data); + const nodes = resp?.owner?.repositories?.nodes; + const pageInfo = resp?.owner?.repositories?.pageInfo; + + if (!nodes) { + return undefined; + } + const repos = nodes?.reduce((acc, repo) => { + return repo + ? [ + ...acc, + { + id: repo.id, + name: repo.name, + description: repo.description, + stargazerCount: repo.stargazerCount, + forkCount: repo.forkCount, + primaryLanguage: { + name: repo.primaryLanguage?.name, + color: repo.primaryLanguage?.color, + }, + visibility: repo.visibility, + updatedAt: repo.updatedAt, + owner: repo.owner, + }, + ] + : acc; + }, []); + + return { + pageInfo, + repos + }; +}; + +export default getUserRepos; From 01f3cbe9fc60f5943a30416497d63084f45efbd4 Mon Sep 17 00:00:00 2001 From: Linda Thompson Date: Thu, 3 Nov 2022 17:06:30 -0500 Subject: [PATCH 03/19] [Angular - NgRx - SCSS] 440: state & service refactor (#527) * setup: get branch caught up and ready for work * feat: refactored repository service and test * feat: refactor of user service and test * feat: updated user service spec * feat: created dashboard store files; updated global state files; renamed RepoState and updated all calls * attempt to fix issues with service updates; some refactoring and adjusting so app compiles * feat: added auth user data to auth state; updated nav component to use auth state * feat: adjusted auth call; fixed user call so home page loads * moved some user logic; still having reload issues and repo view issues * feat: got app working again! cleaned out console logs * rebased and fixed most files * fix broken tests * removed unused code * fix: fix pr comments and most tests * fix: fixed final broken unit test * fix: updated test; removed unused code in user effect; new user mapping file * add todo for refactor improvements; update authUser effect to use different rxjs operation Co-authored-by: LindaT --- angular-ngrx-scss/package-lock.json | 2162 +++++++++++------ angular-ngrx-scss/src/app/app.module.ts | 8 +- .../src/app/auth/auth.component.ts | 4 +- angular-ngrx-scss/src/app/auth/auth.module.ts | 10 +- .../file-explorer-blob.component.spec.ts | 6 +- .../file-explorer-container.component.spec.ts | 12 + .../file-explorer.component.html | 4 +- .../file-explorer.component.spec.ts | 6 +- .../file-explorer/file-explorer.component.ts | 4 +- .../src/app/home/home.component.ts | 19 +- .../home/nav-bar/nav-bar.component.spec.ts | 4 +- .../src/app/home/nav-bar/nav-bar.component.ts | 10 +- .../profile-about.component.html | 6 +- .../pull-requests.component.spec.ts | 6 +- .../repo-heading/repo-heading.component.ts | 4 +- .../repo-navigation.component.ts | 4 +- .../services/repository.service.spec.ts | 136 +- .../repository/services/repository.service.ts | 309 ++- .../src/app/state/app.reducer.ts | 6 +- angular-ngrx-scss/src/app/state/app.state.ts | 8 +- .../src/app/state/auth/auth.actions.ts | 19 +- .../src/app/state/auth/auth.effects.spec.ts | 14 +- .../src/app/state/auth/auth.effects.ts | 62 +- .../src/app/state/auth/auth.reducer.ts | 17 + .../src/app/state/auth/auth.selectors.ts | 17 +- .../src/app/state/auth/auth.state.ts | 7 + .../src/app/state/profile/index.ts | 5 + .../src/app/state/profile/profile.effects.ts | 52 +- .../src/app/state/profile/profile.state.ts | 23 +- .../state/repository/repository.actions.ts | 4 +- .../repository/repository.effects.spec.ts | 245 +- .../state/repository/repository.effects.ts | 74 +- .../state/repository/repository.reducer.ts | 11 +- .../state/repository/repository.selectors.ts | 15 +- .../app/state/repository/repository.state.ts | 9 +- .../src/app/state/user/user.actions.ts | 5 +- .../src/app/state/user/user.effects.spec.ts | 151 +- .../src/app/state/user/user.effects.ts | 31 +- .../src/app/state/user/user.mappings.ts | 49 + .../src/app/state/user/user.reducer.ts | 2 +- .../src/app/state/user/user.state.ts | 2 +- .../app/user/services/user.service.spec.ts | 259 +- .../src/app/user/services/user.service.ts | 226 +- 43 files changed, 2657 insertions(+), 1370 deletions(-) create mode 100644 angular-ngrx-scss/src/app/state/profile/index.ts create mode 100644 angular-ngrx-scss/src/app/state/user/user.mappings.ts diff --git a/angular-ngrx-scss/package-lock.json b/angular-ngrx-scss/package-lock.json index ed512645c..7c1a5a8c8 100644 --- a/angular-ngrx-scss/package-lock.json +++ b/angular-ngrx-scss/package-lock.json @@ -61,13 +61,13 @@ } }, "node_modules/@ampproject/remapping": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-1.1.1.tgz", - "integrity": "sha512-YVAcA4DKLOj296CF5SrQ8cYiMRiUGc2sqFpLxsDGWE34suHqhGP/5yMsDHKsrh8hs8I5TiRVXNwKPWQpX3iGjw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "sourcemap-codec": "1.4.8" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -107,15 +107,15 @@ "dev": true }, "node_modules/@angular-devkit/build-angular": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.2.1.tgz", - "integrity": "sha512-bK1fXqtE/By9cybmVp7oFbCKoI6y9AlZO3k/k7AsyMgLtKL1YYLPN93Tq6L99W+zFI9+8V7x5bjuXWiexA63DA==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.9.tgz", + "integrity": "sha512-1LqcMizeabx3yOkx3tptCSAoEhG6nO6hPgI/B3EJ07G/ZcoxunMWSeN3P3zT10dZMEHhcxl+8cSStSXaXj9hfA==", "dev": true, "dependencies": { - "@ampproject/remapping": "1.1.1", - "@angular-devkit/architect": "0.1302.1", - "@angular-devkit/build-webpack": "0.1302.1", - "@angular-devkit/core": "13.2.1", + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1303.9", + "@angular-devkit/build-webpack": "0.1303.9", + "@angular-devkit/core": "13.3.9", "@babel/core": "7.16.12", "@babel/generator": "7.16.8", "@babel/helper-annotate-as-pure": "7.16.7", @@ -126,9 +126,9 @@ "@babel/runtime": "7.16.7", "@babel/template": "7.16.7", "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.2.1", + "@ngtools/webpack": "13.3.9", "ansi-colors": "4.1.1", - "babel-loader": "8.2.3", + "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.9.1", "cacache": "15.3.0", @@ -137,7 +137,7 @@ "core-js": "3.20.3", "critters": "0.0.16", "css-loader": "6.5.1", - "esbuild-wasm": "0.14.14", + "esbuild-wasm": "0.14.22", "glob": "7.2.0", "https-proxy-agent": "5.0.0", "inquirer": "8.2.0", @@ -145,10 +145,10 @@ "karma-source-map-support": "1.4.0", "less": "4.1.2", "less-loader": "10.2.0", - "license-webpack-plugin": "4.0.0", + "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.0", "mini-css-extract-plugin": "2.5.3", - "minimatch": "3.0.4", + "minimatch": "3.0.5", "open": "8.4.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", @@ -160,18 +160,18 @@ "regenerator-runtime": "0.13.9", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.49.0", + "sass": "1.49.9", "sass-loader": "12.4.0", "semver": "7.3.5", "source-map-loader": "3.0.1", "source-map-support": "0.5.21", "stylus": "0.56.0", "stylus-loader": "6.2.0", - "terser": "5.10.0", + "terser": "5.14.2", "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.3.1", - "webpack": "5.67.0", + "webpack": "5.70.0", "webpack-dev-middleware": "5.3.0", "webpack-dev-server": "4.7.3", "webpack-merge": "5.8.0", @@ -183,17 +183,17 @@ "yarn": ">= 1.13.0" }, "optionalDependencies": { - "esbuild": "0.14.14" + "esbuild": "0.14.22" }, "peerDependencies": { - "@angular/compiler-cli": "^13.0.0", - "@angular/localize": "^13.0.0", - "@angular/service-worker": "^13.0.0", + "@angular/compiler-cli": "^13.0.0 || ^13.3.0-rc.0", + "@angular/localize": "^13.0.0 || ^13.3.0-rc.0", + "@angular/service-worker": "^13.0.0 || ^13.3.0-rc.0", "karma": "^6.3.0", "ng-packagr": "^13.0.0", "protractor": "^7.0.0", "tailwindcss": "^2.0.0 || ^3.0.0", - "typescript": ">=4.4.3 <4.6" + "typescript": ">=4.4.3 <4.7" }, "peerDependenciesMeta": { "@angular/localize": { @@ -217,12 +217,12 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/architect": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.1.tgz", - "integrity": "sha512-h5LA1VTmWKLLzYvnLPqwdyLI9l43FVIUflvmDf6s2ScTrVf3Bb7B4KkCBDdNa8FxnBitfFqKJBf6RGcKjjeDcw==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.9.tgz", + "integrity": "sha512-RMHqCGDxbLqT+250A0a8vagsoTdqGjAxjhrvTeq7PJmClI7uJ/uA1Fs18+t85toIqVKn2hovdY9sNf42nBDD2Q==", "dev": true, "dependencies": { - "@angular-devkit/core": "13.2.1", + "@angular-devkit/core": "13.3.9", "rxjs": "6.6.7" }, "engines": { @@ -232,9 +232,9 @@ } }, "node_modules/@angular-devkit/build-angular/node_modules/@angular-devkit/core": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.1.tgz", - "integrity": "sha512-yR+FJq/RfthPmK0LtPIjj6mZLzLGMQ137yyOljsRgHoFhLxtluz9FdjyAk+61rP0LxH3FCt4qRWa9jd7+oBJxw==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.9.tgz", + "integrity": "sha512-XqCuIWyoqIsLABjV3GQL/+EiBCt3xVPPtNp3Mg4gjBsDLW7PEnvbb81yGkiZQmIsq4EIyQC/6fQa3VdjsCshGg==", "dev": true, "dependencies": { "ajv": "8.9.0", @@ -311,12 +311,12 @@ "dev": true }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1302.1.tgz", - "integrity": "sha512-MYWGqXK42ksnhArLjycPfwxGh7fsR87LRL4yV3e2EfGl07s7mAnohnRhyAs8o8lxRHQU4+yBs9JnMWRcqqqp2A==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.9.tgz", + "integrity": "sha512-CdYXvAN1xAik8FyfdF1B8Nt1B/1aBvkZr65AUVFOmP6wuVzcdn78BMZmZD42srYbV2449sWi5Vyo/j0a/lfJww==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1302.1", + "@angular-devkit/architect": "0.1303.9", "rxjs": "6.6.7" }, "engines": { @@ -330,12 +330,12 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/architect": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.1.tgz", - "integrity": "sha512-h5LA1VTmWKLLzYvnLPqwdyLI9l43FVIUflvmDf6s2ScTrVf3Bb7B4KkCBDdNa8FxnBitfFqKJBf6RGcKjjeDcw==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.9.tgz", + "integrity": "sha512-RMHqCGDxbLqT+250A0a8vagsoTdqGjAxjhrvTeq7PJmClI7uJ/uA1Fs18+t85toIqVKn2hovdY9sNf42nBDD2Q==", "dev": true, "dependencies": { - "@angular-devkit/core": "13.2.1", + "@angular-devkit/core": "13.3.9", "rxjs": "6.6.7" }, "engines": { @@ -345,9 +345,9 @@ } }, "node_modules/@angular-devkit/build-webpack/node_modules/@angular-devkit/core": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.1.tgz", - "integrity": "sha512-yR+FJq/RfthPmK0LtPIjj6mZLzLGMQ137yyOljsRgHoFhLxtluz9FdjyAk+61rP0LxH3FCt4qRWa9jd7+oBJxw==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.9.tgz", + "integrity": "sha512-XqCuIWyoqIsLABjV3GQL/+EiBCt3xVPPtNp3Mg4gjBsDLW7PEnvbb81yGkiZQmIsq4EIyQC/6fQa3VdjsCshGg==", "dev": true, "dependencies": { "ajv": "8.9.0", @@ -2452,6 +2452,15 @@ "node": ">=6.9.0" } }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/@csstools/postcss-cascade-layers": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.5.tgz", @@ -2851,13 +2860,75 @@ "node": ">=8" } }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.3.tgz", - "integrity": "sha512-fuIOnc81C5iRNevb/XPiM8Khp9bVjreydRQ37rt0C/dY0PAW1DRvEM3WrKX/5rStS5lbgwS0FCgqSndh9tvK5w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true, "engines": { - "node": ">=10.0.0" + "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.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "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/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@ngrx/effects": { @@ -2904,9 +2975,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.2.1.tgz", - "integrity": "sha512-NugLJfzp0EFX2Pdbr94bsktE/qniUE6mEgmv3ZkmimPBBHhAd1M73XBx8lesjLh7D3SRecHCjD5yyygF8gNO0g==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.9.tgz", + "integrity": "sha512-wmgOI5sogAuilwBZJqCHVMjm2uhDxjdSmNLFx7eznwGDa6LjvjuATqCv2dVlftq0Y/5oZFVrg5NpyHt5kfZ8Cg==", "dev": true, "engines": { "node": "^12.20.0 || ^14.15.0 || >=16.10.0", @@ -2915,7 +2986,7 @@ }, "peerDependencies": { "@angular/compiler-cli": "^13.0.0", - "typescript": ">=4.4.3 <4.6", + "typescript": ">=4.4.3 <4.7", "webpack": "^5.30.0" } }, @@ -3661,9 +3732,9 @@ } }, "node_modules/@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "node_modules/@types/express": { @@ -3679,9 +3750,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "dev": true, "dependencies": { "@types/node": "*", @@ -3690,9 +3761,9 @@ } }, "node_modules/@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", "dev": true, "dependencies": { "@types/node": "*" @@ -3717,9 +3788,9 @@ "dev": true }, "node_modules/@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "node_modules/@types/node": { @@ -3768,9 +3839,9 @@ } }, "node_modules/@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, "node_modules/@types/serve-index": { @@ -3783,12 +3854,12 @@ } }, "node_modules/@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dev": true, "dependencies": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -3802,9 +3873,9 @@ } }, "node_modules/@types/ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "dev": true, "dependencies": { "@types/node": "*" @@ -4182,27 +4253,18 @@ "dev": true }, "node_modules/accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "dependencies": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" + "mime-types": "~2.1.34", + "negotiator": "0.6.3" }, "engines": { "node": ">= 0.6" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/acorn": { "version": "8.7.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", @@ -4474,13 +4536,10 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" - } + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true }, "node_modules/at-least-node": { "version": "1.0.0", @@ -4543,13 +4602,13 @@ "dev": true }, "node_modules/babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "dependencies": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" }, @@ -4561,30 +4620,18 @@ "webpack": ">=2" } }, - "node_modules/babel-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, "node_modules/babel-loader/node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "dependencies": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "json5": "^2.1.2" }, "engines": { - "node": ">=4.0.0" + "node": ">=8.9.0" } }, "node_modules/babel-plugin-dynamic-import-node": { @@ -4698,7 +4745,7 @@ "node_modules/batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "node_modules/big.js": { @@ -4731,24 +4778,27 @@ } }, "node_modules/body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "dev": true, "dependencies": { - "bytes": "3.1.1", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "engines": { - "node": ">= 0.8" + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" } }, "node_modules/body-parser/node_modules/debug": { @@ -4760,16 +4810,37 @@ "ms": "2.0.0" } }, + "node_modules/body-parser/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/bonjour": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", "dev": true, "dependencies": { "array-flatten": "^2.1.0", @@ -4891,9 +4962,9 @@ "dev": true }, "node_modules/bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "engines": { "node": ">= 0.8" @@ -5159,9 +5230,9 @@ } }, "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, "node_modules/colors": { @@ -5224,7 +5295,7 @@ "node_modules/compression/node_modules/bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true, "engines": { "node": ">= 0.8" @@ -5242,7 +5313,7 @@ "node_modules/compression/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/concat-map": { @@ -5358,7 +5429,7 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, "node_modules/copy-anything": { @@ -5895,9 +5966,9 @@ } }, "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dev": true, "dependencies": { "globby": "^11.0.1", @@ -5979,10 +6050,14 @@ } }, "node_modules/destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", - "dev": true + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "dev": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } }, "node_modules/detect-node": { "version": "2.1.0", @@ -6011,7 +6086,7 @@ "node_modules/dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", "dev": true }, "node_modules/dns-packet": { @@ -6027,7 +6102,7 @@ "node_modules/dns-txt": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", "dev": true, "dependencies": { "buffer-indexof": "^1.0.0" @@ -6119,12 +6194,12 @@ "dev": true }, "node_modules/ejs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", "dev": true, "dependencies": { - "jake": "^10.6.1" + "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" @@ -6220,9 +6295,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.4", @@ -6303,34 +6378,38 @@ "dev": true }, "node_modules/esbuild": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.14.tgz", - "integrity": "sha512-aiK4ddv+uui0k52OqSHu4xxu+SzOim7Rlz4i25pMEiC8rlnGU0HJ9r+ZMfdWL5bzifg+nhnn7x4NSWTeehYblg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", + "integrity": "sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA==", "dev": true, "hasInstallScript": true, "optional": true, "bin": { "esbuild": "bin/esbuild" }, + "engines": { + "node": ">=12" + }, "optionalDependencies": { - "esbuild-android-arm64": "0.14.14", - "esbuild-darwin-64": "0.14.14", - "esbuild-darwin-arm64": "0.14.14", - "esbuild-freebsd-64": "0.14.14", - "esbuild-freebsd-arm64": "0.14.14", - "esbuild-linux-32": "0.14.14", - "esbuild-linux-64": "0.14.14", - "esbuild-linux-arm": "0.14.14", - "esbuild-linux-arm64": "0.14.14", - "esbuild-linux-mips64le": "0.14.14", - "esbuild-linux-ppc64le": "0.14.14", - "esbuild-linux-s390x": "0.14.14", - "esbuild-netbsd-64": "0.14.14", - "esbuild-openbsd-64": "0.14.14", - "esbuild-sunos-64": "0.14.14", - "esbuild-windows-32": "0.14.14", - "esbuild-windows-64": "0.14.14", - "esbuild-windows-arm64": "0.14.14" + "esbuild-android-arm64": "0.14.22", + "esbuild-darwin-64": "0.14.22", + "esbuild-darwin-arm64": "0.14.22", + "esbuild-freebsd-64": "0.14.22", + "esbuild-freebsd-arm64": "0.14.22", + "esbuild-linux-32": "0.14.22", + "esbuild-linux-64": "0.14.22", + "esbuild-linux-arm": "0.14.22", + "esbuild-linux-arm64": "0.14.22", + "esbuild-linux-mips64le": "0.14.22", + "esbuild-linux-ppc64le": "0.14.22", + "esbuild-linux-riscv64": "0.14.22", + "esbuild-linux-s390x": "0.14.22", + "esbuild-netbsd-64": "0.14.22", + "esbuild-openbsd-64": "0.14.22", + "esbuild-sunos-64": "0.14.22", + "esbuild-windows-32": "0.14.22", + "esbuild-windows-64": "0.14.22", + "esbuild-windows-arm64": "0.14.22" } }, "node_modules/esbuild-android-64": { @@ -6350,9 +6429,9 @@ } }, "node_modules/esbuild-android-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.14.tgz", - "integrity": "sha512-be/Uw6DdpQiPfula1J4bdmA+wtZ6T3BRCZsDMFB5X+k0Gp8TIh9UvmAcqvKNnbRAafSaXG3jPCeXxDKqnc8hFQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz", + "integrity": "sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ==", "cpu": [ "arm64" ], @@ -6360,12 +6439,15 @@ "optional": true, "os": [ "android" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-darwin-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.14.tgz", - "integrity": "sha512-BEexYmjWafcISK8cT6O98E3TfcLuZL8DKuubry6G54n2+bD4GkoRD6HYUOnCkfl2p7jodA+s4369IjSFSWjtHg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz", + "integrity": "sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw==", "cpu": [ "x64" ], @@ -6373,12 +6455,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-darwin-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.14.tgz", - "integrity": "sha512-tnBKm41pDOB1GtZ8q/w26gZlLLRzVmP8fdsduYjvM+yFD7E2DLG4KbPAqFMWm4Md9B+DitBglP57FY7AznxbTg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz", + "integrity": "sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw==", "cpu": [ "arm64" ], @@ -6386,12 +6471,15 @@ "optional": true, "os": [ "darwin" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-freebsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.14.tgz", - "integrity": "sha512-Q9Rx6sgArOHalQtNwAaIzJ6dnQ8A+I7f/RsQsdkS3JrdzmnlFo8JEVofTmwVQLoIop7OKUqIVOGP4PoQcwfVMA==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz", + "integrity": "sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A==", "cpu": [ "x64" ], @@ -6399,12 +6487,15 @@ "optional": true, "os": [ "freebsd" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-freebsd-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.14.tgz", - "integrity": "sha512-TJvq0OpLM7BkTczlyPIphcvnwrQwQDG1HqxzoYePWn26SMUAlt6wrLnEvxdbXAvNvDLVzG83kA+JimjK7aRNBA==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz", + "integrity": "sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ==", "cpu": [ "arm64" ], @@ -6412,12 +6503,15 @@ "optional": true, "os": [ "freebsd" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-32": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.14.tgz", - "integrity": "sha512-h/CrK9Baimt5VRbu8gqibWV7e1P9l+mkanQgyOgv0Ng3jHT1NVFC9e6rb1zbDdaJVmuhWX5xVliUA5bDDCcJeg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz", + "integrity": "sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg==", "cpu": [ "ia32" ], @@ -6425,12 +6519,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.14.tgz", - "integrity": "sha512-IC+wAiIg/egp5OhQp4W44D9PcBOH1b621iRn1OXmlLzij9a/6BGr9NMIL4CRwz4j2kp3WNZu5sT473tYdynOuQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz", + "integrity": "sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg==", "cpu": [ "x64" ], @@ -6438,12 +6535,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-arm": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.14.tgz", - "integrity": "sha512-gxpOaHOPwp7zSmcKYsHrtxabScMqaTzfSQioAMUaB047YiMuDBzqVcKBG8OuESrYkGrL9DDljXr/mQNg7pbdaQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz", + "integrity": "sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g==", "cpu": [ "arm" ], @@ -6451,12 +6551,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.14.tgz", - "integrity": "sha512-6QVul3RI4M5/VxVIRF/I5F+7BaxzR3DfNGoqEVSCZqUbgzHExPn+LXr5ly1C7af2Kw4AHpo+wDqx8A4ziP9avw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz", + "integrity": "sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A==", "cpu": [ "arm64" ], @@ -6464,12 +6567,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-mips64le": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.14.tgz", - "integrity": "sha512-4Jl5/+xoINKbA4cesH3f4R+q0vltAztZ6Jm8YycS8lNhN1pgZJBDxWfI6HUMIAdkKlIpR1PIkA9aXQgZ8sxFAg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz", + "integrity": "sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ==", "cpu": [ "mips64el" ], @@ -6477,12 +6583,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-ppc64le": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.14.tgz", - "integrity": "sha512-BitW37GxeebKxqYNl4SVuSdnIJAzH830Lr6Mkq3pBHXtzQay0vK+IeOR/Ele1GtNVJ+/f8wYM53tcThkv5SC5w==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz", + "integrity": "sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng==", "cpu": [ "ppc64" ], @@ -6490,7 +6599,10 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-linux-riscv64": { "version": "0.14.49", @@ -6509,9 +6621,9 @@ } }, "node_modules/esbuild-linux-s390x": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.14.tgz", - "integrity": "sha512-vLj6p76HOZG3wfuTr5MyO3qW5iu8YdhUNxuY+tx846rPo7GcKtYSPMusQjeVEfZlJpSYoR+yrNBBxq+qVF9zrw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz", + "integrity": "sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw==", "cpu": [ "s390x" ], @@ -6519,12 +6631,15 @@ "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-netbsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.14.tgz", - "integrity": "sha512-fn8looXPQhpVqUyCBWUuPjesH+yGIyfbIQrLKG05rr1Kgm3rZD/gaYrd3Wpmf5syVZx70pKZPvdHp8OTA+y7cQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz", + "integrity": "sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA==", "cpu": [ "x64" ], @@ -6532,12 +6647,15 @@ "optional": true, "os": [ "netbsd" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-openbsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.14.tgz", - "integrity": "sha512-HdAnJ399pPff3SKbd8g+P4o5znseni5u5n5rJ6Z7ouqOdgbOwHe2ofZbMow17WMdNtz1IyOZk2Wo9Ve6/lZ4Rg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz", + "integrity": "sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA==", "cpu": [ "x64" ], @@ -6545,12 +6663,15 @@ "optional": true, "os": [ "openbsd" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-sunos-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.14.tgz", - "integrity": "sha512-bmDHa99ulsGnYlh/xjBEfxoGuC8CEG5OWvlgD+pF7bKKiVTbtxqVCvOGEZeoDXB+ja6AvHIbPxrEE32J+m5nqQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz", + "integrity": "sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g==", "cpu": [ "x64" ], @@ -6558,24 +6679,27 @@ "optional": true, "os": [ "sunos" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-wasm": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.14.tgz", - "integrity": "sha512-qTjK4MWnYtQHCMGg2qDUqeFYXfVvYq5qJkQTIsOV4VZCknoYePVaDTG9ygEB9Ct0kc0DWs7IrS6Ja+GjY62Kzw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.22.tgz", + "integrity": "sha512-FOSAM29GN1fWusw0oLMv6JYhoheDIh5+atC72TkJKfIUMID6yISlicoQSd9gsNSFsNBvABvtE2jR4JB1j4FkFw==", "dev": true, "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=8" + "node": ">=12" } }, "node_modules/esbuild-windows-32": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.14.tgz", - "integrity": "sha512-6tVooQcxJCNenPp5GHZBs/RLu31q4B+BuF4MEoRxswT+Eq2JGF0ZWDRQwNKB8QVIo3t6Svc5wNGez+CwKNQjBg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz", + "integrity": "sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg==", "cpu": [ "ia32" ], @@ -6583,12 +6707,15 @@ "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-windows-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.14.tgz", - "integrity": "sha512-kl3BdPXh0/RD/dad41dtzj2itMUR4C6nQbXQCyYHHo4zoUoeIXhpCrSl7BAW1nv5EFL8stT1V+TQVXGZca5A2A==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz", + "integrity": "sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw==", "cpu": [ "x64" ], @@ -6596,12 +6723,15 @@ "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=12" + } }, "node_modules/esbuild-windows-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.14.tgz", - "integrity": "sha512-dCm1wTOm6HIisLanmybvRKvaXZZo4yEVrHh1dY0v582GThXJOzuXGja1HIQgV09RpSHYRL3m4KoUBL00l6SWEg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz", + "integrity": "sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg==", "cpu": [ "arm64" ], @@ -6609,7 +6739,26 @@ "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/esbuild/node_modules/esbuild-linux-riscv64": { + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz", + "integrity": "sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } }, "node_modules/escalade": { "version": "3.1.1", @@ -7048,7 +7197,7 @@ "node_modules/etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "engines": { "node": ">= 0.6" @@ -7099,38 +7248,39 @@ } }, "node_modules/express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "dev": true, "dependencies": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.1", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.1", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.6", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -7142,9 +7292,18 @@ "node_modules/express/node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", "dev": true }, + "node_modules/express/node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -7154,12 +7313,51 @@ "ms": "2.0.0" } }, + "node_modules/express/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/express/node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -7180,6 +7378,15 @@ } ] }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -7312,12 +7519,33 @@ } }, "node_modules/filelist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, "dependencies": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" } }, "node_modules/fill-range": { @@ -7415,9 +7643,9 @@ "dev": true }, "node_modules/follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "dev": true, "funding": [ { @@ -7471,7 +7699,7 @@ "node_modules/fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true, "engines": { "node": ">= 0.6" @@ -7541,6 +7769,15 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gauge": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", @@ -7779,7 +8016,7 @@ "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "dependencies": { "inherits": "^2.0.1", @@ -7813,9 +8050,9 @@ } }, "node_modules/html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "dev": true }, "node_modules/html-escaper": { @@ -7833,29 +8070,47 @@ "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true }, "node_modules/http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "dependencies": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" }, "engines": { - "node": ">= 0.6" + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, "node_modules/http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "node_modules/http-proxy": { @@ -7887,9 +8142,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.2.tgz", - "integrity": "sha512-XtmDN5w+vdFTBZaYhdJAbMqn0DP/EhkUaAeo963mojwpKMMbw6nivtFKw07D7DDOH745L5k0VL0P8KRYNEVF/g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, "dependencies": { "@types/http-proxy": "^1.17.8", @@ -7903,6 +8158,11 @@ }, "peerDependencies": { "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } } }, "node_modules/https-proxy-agent": { @@ -8464,7 +8724,7 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "node_modules/isbinaryfile": { @@ -8600,13 +8860,13 @@ } }, "node_modules/jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "dev": true, "dependencies": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, @@ -8614,15 +8874,79 @@ "jake": "bin/cli.js" }, "engines": { - "node": "*" + "node": ">=10" } }, - "node_modules/jake/node_modules/async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "node_modules/jake/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/jake/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/jake/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/jake/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/jake/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/jake/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/jasmine-core": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.10.1.tgz", @@ -8765,15 +9089,15 @@ ] }, "node_modules/karma": { - "version": "6.3.12", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.12.tgz", - "integrity": "sha512-qwIG+oB2YmHx4hjvYSRMNzL3YWAJ9baHaLAxiP7biFNkfpwYTUTtPck0joFpucalNLzMr+7z/FX1uY/kl8DV9A==", + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", "dev": true, "dependencies": { + "@colors/colors": "1.5.0", "body-parser": "^1.19.0", "braces": "^3.0.2", "chokidar": "^3.5.1", - "colors": "1.4.0", "connect": "^3.7.0", "di": "^0.0.1", "dom-serialize": "^2.2.1", @@ -8782,13 +9106,14 @@ "http-proxy": "^1.18.1", "isbinaryfile": "^4.0.8", "lodash": "^4.17.21", - "log4js": "^6.3.0", + "log4js": "^6.4.1", "mime": "^2.5.2", "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", @@ -8898,6 +9223,18 @@ "karma": ">=0.12" } }, + "node_modules/karma/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -9081,9 +9418,9 @@ } }, "node_modules/license-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-b9iMrROrw2fTOJBZ57h0xJfT5/1Cxg4ucYbtpWoukv4Awb2TFPfDDFVHNM8w6SYQpVfB13a5tQJxgGamqwrsyw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, "dependencies": { "webpack-sources": "^3.0.0" @@ -9346,12 +9683,12 @@ } }, "node_modules/memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", "dev": true, "dependencies": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" }, "engines": { "node": ">= 4.0.0" @@ -9360,7 +9697,7 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "dev": true }, "node_modules/merge-stream": { @@ -9381,7 +9718,7 @@ "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true, "engines": { "node": ">= 0.6" @@ -9487,9 +9824,9 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, "dependencies": { "brace-expansion": "^1.1.7" @@ -9499,9 +9836,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "node_modules/minipass": { @@ -9638,7 +9975,7 @@ "node_modules/multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", "dev": true }, "node_modules/mute-stream": { @@ -10277,9 +10614,9 @@ } }, "node_modules/node-fetch": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", - "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", "dev": true, "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -10295,9 +10632,9 @@ } }, "node_modules/node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true, "engines": { "node": ">= 6.13.0" @@ -10540,6 +10877,15 @@ "node": ">=0.10.0" } }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", @@ -10813,12 +11159,12 @@ } }, "node_modules/p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, "dependencies": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" }, "engines": { @@ -11000,7 +11346,7 @@ "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "dev": true }, "node_modules/path-type": { @@ -11079,6 +11425,15 @@ "node": ">= 0.12.0" } }, + "node_modules/portfinder/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, "node_modules/portfinder/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -11089,12 +11444,12 @@ } }, "node_modules/portfinder/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "dependencies": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" @@ -11899,10 +12254,13 @@ } }, "node_modules/qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", "dev": true, + "dependencies": { + "side-channel": "^1.0.4" + }, "engines": { "node": ">=0.6" }, @@ -11949,13 +12307,13 @@ } }, "node_modules/raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dev": true, "dependencies": { - "bytes": "3.1.1", - "http-errors": "1.8.1", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" }, @@ -12057,13 +12415,14 @@ "dev": true }, "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -12361,9 +12720,9 @@ "dev": true }, "node_modules/sass": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", - "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -12374,7 +12733,7 @@ "sass": "sass.js" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.0.0" } }, "node_modules/sass-loader": { @@ -12469,16 +12828,16 @@ "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "node_modules/selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", "dev": true, "dependencies": { - "node-forge": "^1.2.0" + "node-forge": "^1" }, "engines": { "node": ">=10" @@ -12500,24 +12859,24 @@ } }, "node_modules/send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "dependencies": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "engines": { "node": ">= 0.8.0" @@ -12535,9 +12894,18 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/send/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -12547,15 +12915,36 @@ "mime": "cli.js" }, "engines": { - "node": ">=4" + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true, + "engines": { + "node": ">= 0.8" } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "node_modules/serialize-javascript": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", @@ -12568,7 +12957,7 @@ "node_modules/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "dependencies": { "accepts": "~1.3.4", @@ -12595,7 +12984,7 @@ "node_modules/serve-index/node_modules/http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "dependencies": { "depd": "~1.1.2", @@ -12610,13 +12999,13 @@ "node_modules/serve-index/node_modules/inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "node_modules/serve-index/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "node_modules/serve-index/node_modules/setprototypeof": { @@ -12626,15 +13015,15 @@ "dev": true }, "node_modules/serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" }, "engines": { "node": ">= 0.8.0" @@ -12685,6 +13074,20 @@ "node": ">=8" } }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -13113,13 +13516,14 @@ } }, "node_modules/terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "dependencies": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" }, "bin": { @@ -13127,14 +13531,6 @@ }, "engines": { "node": ">=10" - }, - "peerDependencies": { - "acorn": "^8.5.0" - }, - "peerDependenciesMeta": { - "acorn": { - "optional": true - } } }, "node_modules/terser-webpack-plugin": { @@ -13622,13 +14018,13 @@ } }, "node_modules/webpack": { - "version": "5.67.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", - "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", "dev": true, "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -13636,7 +14032,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", + "enhanced-resolve": "^5.9.2", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -14106,13 +14502,13 @@ }, "dependencies": { "@ampproject/remapping": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-1.1.1.tgz", - "integrity": "sha512-YVAcA4DKLOj296CF5SrQ8cYiMRiUGc2sqFpLxsDGWE34suHqhGP/5yMsDHKsrh8hs8I5TiRVXNwKPWQpX3iGjw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", "dev": true, "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "sourcemap-codec": "1.4.8" + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" } }, "@angular-devkit/architect": { @@ -14143,15 +14539,15 @@ } }, "@angular-devkit/build-angular": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.2.1.tgz", - "integrity": "sha512-bK1fXqtE/By9cybmVp7oFbCKoI6y9AlZO3k/k7AsyMgLtKL1YYLPN93Tq6L99W+zFI9+8V7x5bjuXWiexA63DA==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-13.3.9.tgz", + "integrity": "sha512-1LqcMizeabx3yOkx3tptCSAoEhG6nO6hPgI/B3EJ07G/ZcoxunMWSeN3P3zT10dZMEHhcxl+8cSStSXaXj9hfA==", "dev": true, "requires": { - "@ampproject/remapping": "1.1.1", - "@angular-devkit/architect": "0.1302.1", - "@angular-devkit/build-webpack": "0.1302.1", - "@angular-devkit/core": "13.2.1", + "@ampproject/remapping": "2.2.0", + "@angular-devkit/architect": "0.1303.9", + "@angular-devkit/build-webpack": "0.1303.9", + "@angular-devkit/core": "13.3.9", "@babel/core": "7.16.12", "@babel/generator": "7.16.8", "@babel/helper-annotate-as-pure": "7.16.7", @@ -14162,9 +14558,9 @@ "@babel/runtime": "7.16.7", "@babel/template": "7.16.7", "@discoveryjs/json-ext": "0.5.6", - "@ngtools/webpack": "13.2.1", + "@ngtools/webpack": "13.3.9", "ansi-colors": "4.1.1", - "babel-loader": "8.2.3", + "babel-loader": "8.2.5", "babel-plugin-istanbul": "6.1.1", "browserslist": "^4.9.1", "cacache": "15.3.0", @@ -14173,8 +14569,8 @@ "core-js": "3.20.3", "critters": "0.0.16", "css-loader": "6.5.1", - "esbuild": "0.14.14", - "esbuild-wasm": "0.14.14", + "esbuild": "0.14.22", + "esbuild-wasm": "0.14.22", "glob": "7.2.0", "https-proxy-agent": "5.0.0", "inquirer": "8.2.0", @@ -14182,10 +14578,10 @@ "karma-source-map-support": "1.4.0", "less": "4.1.2", "less-loader": "10.2.0", - "license-webpack-plugin": "4.0.0", + "license-webpack-plugin": "4.0.2", "loader-utils": "3.2.0", "mini-css-extract-plugin": "2.5.3", - "minimatch": "3.0.4", + "minimatch": "3.0.5", "open": "8.4.0", "ora": "5.4.1", "parse5-html-rewriting-stream": "6.0.1", @@ -14197,18 +14593,18 @@ "regenerator-runtime": "0.13.9", "resolve-url-loader": "5.0.0", "rxjs": "6.6.7", - "sass": "1.49.0", + "sass": "1.49.9", "sass-loader": "12.4.0", "semver": "7.3.5", "source-map-loader": "3.0.1", "source-map-support": "0.5.21", "stylus": "0.56.0", "stylus-loader": "6.2.0", - "terser": "5.10.0", + "terser": "5.14.2", "text-table": "0.2.0", "tree-kill": "1.2.2", "tslib": "2.3.1", - "webpack": "5.67.0", + "webpack": "5.70.0", "webpack-dev-middleware": "5.3.0", "webpack-dev-server": "4.7.3", "webpack-merge": "5.8.0", @@ -14216,19 +14612,19 @@ }, "dependencies": { "@angular-devkit/architect": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.1.tgz", - "integrity": "sha512-h5LA1VTmWKLLzYvnLPqwdyLI9l43FVIUflvmDf6s2ScTrVf3Bb7B4KkCBDdNa8FxnBitfFqKJBf6RGcKjjeDcw==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.9.tgz", + "integrity": "sha512-RMHqCGDxbLqT+250A0a8vagsoTdqGjAxjhrvTeq7PJmClI7uJ/uA1Fs18+t85toIqVKn2hovdY9sNf42nBDD2Q==", "dev": true, "requires": { - "@angular-devkit/core": "13.2.1", + "@angular-devkit/core": "13.3.9", "rxjs": "6.6.7" } }, "@angular-devkit/core": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.1.tgz", - "integrity": "sha512-yR+FJq/RfthPmK0LtPIjj6mZLzLGMQ137yyOljsRgHoFhLxtluz9FdjyAk+61rP0LxH3FCt4qRWa9jd7+oBJxw==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.9.tgz", + "integrity": "sha512-XqCuIWyoqIsLABjV3GQL/+EiBCt3xVPPtNp3Mg4gjBsDLW7PEnvbb81yGkiZQmIsq4EIyQC/6fQa3VdjsCshGg==", "dev": true, "requires": { "ajv": "8.9.0", @@ -14282,29 +14678,29 @@ } }, "@angular-devkit/build-webpack": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1302.1.tgz", - "integrity": "sha512-MYWGqXK42ksnhArLjycPfwxGh7fsR87LRL4yV3e2EfGl07s7mAnohnRhyAs8o8lxRHQU4+yBs9JnMWRcqqqp2A==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1303.9.tgz", + "integrity": "sha512-CdYXvAN1xAik8FyfdF1B8Nt1B/1aBvkZr65AUVFOmP6wuVzcdn78BMZmZD42srYbV2449sWi5Vyo/j0a/lfJww==", "dev": true, "requires": { - "@angular-devkit/architect": "0.1302.1", + "@angular-devkit/architect": "0.1303.9", "rxjs": "6.6.7" }, "dependencies": { "@angular-devkit/architect": { - "version": "0.1302.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1302.1.tgz", - "integrity": "sha512-h5LA1VTmWKLLzYvnLPqwdyLI9l43FVIUflvmDf6s2ScTrVf3Bb7B4KkCBDdNa8FxnBitfFqKJBf6RGcKjjeDcw==", + "version": "0.1303.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1303.9.tgz", + "integrity": "sha512-RMHqCGDxbLqT+250A0a8vagsoTdqGjAxjhrvTeq7PJmClI7uJ/uA1Fs18+t85toIqVKn2hovdY9sNf42nBDD2Q==", "dev": true, "requires": { - "@angular-devkit/core": "13.2.1", + "@angular-devkit/core": "13.3.9", "rxjs": "6.6.7" } }, "@angular-devkit/core": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.2.1.tgz", - "integrity": "sha512-yR+FJq/RfthPmK0LtPIjj6mZLzLGMQ137yyOljsRgHoFhLxtluz9FdjyAk+61rP0LxH3FCt4qRWa9jd7+oBJxw==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-13.3.9.tgz", + "integrity": "sha512-XqCuIWyoqIsLABjV3GQL/+EiBCt3xVPPtNp3Mg4gjBsDLW7PEnvbb81yGkiZQmIsq4EIyQC/6fQa3VdjsCshGg==", "dev": true, "requires": { "ajv": "8.9.0", @@ -15767,6 +16163,12 @@ "to-fast-properties": "^2.0.0" } }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true + }, "@csstools/postcss-cascade-layers": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/@csstools/postcss-cascade-layers/-/postcss-cascade-layers-1.0.5.tgz", @@ -16006,12 +16408,67 @@ "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@jridgewell/resolve-uri": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.3.tgz", - "integrity": "sha512-fuIOnc81C5iRNevb/XPiM8Khp9bVjreydRQ37rt0C/dY0PAW1DRvEM3WrKX/5rStS5lbgwS0FCgqSndh9tvK5w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@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 + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", "dev": true }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@ngrx/effects": { "version": "13.0.2", "resolved": "https://registry.npmjs.org/@ngrx/effects/-/effects-13.0.2.tgz", @@ -16043,9 +16500,9 @@ } }, "@ngtools/webpack": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.2.1.tgz", - "integrity": "sha512-NugLJfzp0EFX2Pdbr94bsktE/qniUE6mEgmv3ZkmimPBBHhAd1M73XBx8lesjLh7D3SRecHCjD5yyygF8gNO0g==", + "version": "13.3.9", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-13.3.9.tgz", + "integrity": "sha512-wmgOI5sogAuilwBZJqCHVMjm2uhDxjdSmNLFx7eznwGDa6LjvjuATqCv2dVlftq0Y/5oZFVrg5NpyHt5kfZ8Cg==", "dev": true, "requires": {} }, @@ -16648,9 +17105,9 @@ } }, "@types/estree": { - "version": "0.0.50", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz", - "integrity": "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, "@types/express": { @@ -16666,9 +17123,9 @@ } }, "@types/express-serve-static-core": { - "version": "4.17.28", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", - "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "version": "4.17.30", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz", + "integrity": "sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ==", "dev": true, "requires": { "@types/node": "*", @@ -16677,9 +17134,9 @@ } }, "@types/http-proxy": { - "version": "1.17.8", - "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", - "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "version": "1.17.9", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.9.tgz", + "integrity": "sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==", "dev": true, "requires": { "@types/node": "*" @@ -16704,9 +17161,9 @@ "dev": true }, "@types/mime": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", - "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, "@types/node": { @@ -16755,9 +17212,9 @@ } }, "@types/retry": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", - "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", "dev": true }, "@types/serve-index": { @@ -16770,12 +17227,12 @@ } }, "@types/serve-static": { - "version": "1.13.10", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz", - "integrity": "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", "dev": true, "requires": { - "@types/mime": "^1", + "@types/mime": "*", "@types/node": "*" } }, @@ -16789,9 +17246,9 @@ } }, "@types/ws": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", - "integrity": "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.3.tgz", + "integrity": "sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==", "dev": true, "requires": { "@types/node": "*" @@ -17085,21 +17542,13 @@ "dev": true }, "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - }, - "dependencies": { - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", - "dev": true - } + "mime-types": "~2.1.34", + "negotiator": "0.6.3" } }, "acorn": { @@ -17299,13 +17748,10 @@ "dev": true }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true }, "at-least-node": { "version": "1.0.0", @@ -17340,35 +17786,26 @@ "dev": true }, "babel-loader": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", - "integrity": "sha512-n4Zeta8NC3QAsuyiizu0GkmRcQ6clkV9WFUnUf1iXP//IeSKbWjofW3UHyZVwlOB4y039YQKefawyTn64Zwbuw==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", + "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", "dev": true, "requires": { "find-cache-dir": "^3.3.1", - "loader-utils": "^1.4.0", + "loader-utils": "^2.0.0", "make-dir": "^3.1.0", "schema-utils": "^2.6.5" }, "dependencies": { - "json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - } - }, "loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "requires": { "big.js": "^5.2.2", "emojis-list": "^3.0.0", - "json5": "^1.0.1" + "json5": "^2.1.2" } } } @@ -17454,7 +17891,7 @@ "batch": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==", "dev": true }, "big.js": { @@ -17481,21 +17918,23 @@ } }, "body-parser": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz", - "integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.0.tgz", + "integrity": "sha512-DfJ+q6EPcGKZD1QWUjSpqp+Q7bDQTsQIF4zfUAtZ6qk+H/3/QRhg9CEp39ss+/T2vw0+HaidC0ecJj/DRLIaKg==", "dev": true, "requires": { - "bytes": "3.1.1", + "bytes": "3.1.2", "content-type": "~1.0.4", "debug": "2.6.9", - "depd": "~1.1.2", - "http-errors": "1.8.1", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", - "on-finished": "~2.3.0", - "qs": "6.9.6", - "raw-body": "2.4.2", - "type-is": "~1.6.18" + "on-finished": "2.4.1", + "qs": "6.10.3", + "raw-body": "2.5.1", + "type-is": "~1.6.18", + "unpipe": "1.0.0" }, "dependencies": { "debug": { @@ -17507,18 +17946,33 @@ "ms": "2.0.0" } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } } } }, "bonjour": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", + "integrity": "sha512-RaVTblr+OnEli0r/ud8InrU7D+G0y6aJhlxaLa6Pwty4+xoxboF1BsUI45tujvRpbj9dQVoglChqonGAsjEBYg==", "dev": true, "requires": { "array-flatten": "^2.1.0", @@ -17601,9 +18055,9 @@ "dev": true }, "bytes": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz", - "integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true }, "cacache": { @@ -17795,9 +18249,9 @@ "dev": true }, "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", + "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", "dev": true }, "colors": { @@ -17851,7 +18305,7 @@ "bytes": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", - "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", "dev": true }, "debug": { @@ -17866,7 +18320,7 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } @@ -17959,7 +18413,7 @@ "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, "copy-anything": { @@ -18344,9 +18798,9 @@ } }, "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/del/-/del-6.1.1.tgz", + "integrity": "sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==", "dev": true, "requires": { "globby": "^11.0.1", @@ -18406,9 +18860,9 @@ "dev": true }, "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true }, "detect-node": { @@ -18435,7 +18889,7 @@ "dns-equal": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=", + "integrity": "sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==", "dev": true }, "dns-packet": { @@ -18451,7 +18905,7 @@ "dns-txt": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", + "integrity": "sha512-Ix5PrWjphuSoUXV/Zv5gaFHjnaJtb02F2+Si3Ht9dyJ87+Z/lMmy+dpNHtTGraNK958ndXq2i+GLkWsWHcKaBQ==", "dev": true, "requires": { "buffer-indexof": "^1.0.0" @@ -18522,12 +18976,12 @@ "dev": true }, "ejs": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz", - "integrity": "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw==", + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.8.tgz", + "integrity": "sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==", "dev": true, "requires": { - "jake": "^10.6.1" + "jake": "^10.8.5" } }, "electron-to-chromium": { @@ -18604,9 +19058,9 @@ } }, "enhanced-resolve": { - "version": "5.8.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", - "integrity": "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.10.0.tgz", + "integrity": "sha512-T0yTFjdpldGY8PmuXXR0PyQ1ufZpEGiHVrp7zHKB7jdR4qlmZHhONVM5AQOAWXuF/w3dnHbEQVrNptJgt7F+cQ==", "dev": true, "requires": { "graceful-fs": "^4.2.4", @@ -18672,30 +19126,40 @@ "dev": true }, "esbuild": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.14.tgz", - "integrity": "sha512-aiK4ddv+uui0k52OqSHu4xxu+SzOim7Rlz4i25pMEiC8rlnGU0HJ9r+ZMfdWL5bzifg+nhnn7x4NSWTeehYblg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.14.22.tgz", + "integrity": "sha512-CjFCFGgYtbFOPrwZNJf7wsuzesx8kqwAffOlbYcFDLFuUtP8xloK1GH+Ai13Qr0RZQf9tE7LMTHJ2iVGJ1SKZA==", "dev": true, "optional": true, "requires": { - "esbuild-android-arm64": "0.14.14", - "esbuild-darwin-64": "0.14.14", - "esbuild-darwin-arm64": "0.14.14", - "esbuild-freebsd-64": "0.14.14", - "esbuild-freebsd-arm64": "0.14.14", - "esbuild-linux-32": "0.14.14", - "esbuild-linux-64": "0.14.14", - "esbuild-linux-arm": "0.14.14", - "esbuild-linux-arm64": "0.14.14", - "esbuild-linux-mips64le": "0.14.14", - "esbuild-linux-ppc64le": "0.14.14", - "esbuild-linux-s390x": "0.14.14", - "esbuild-netbsd-64": "0.14.14", - "esbuild-openbsd-64": "0.14.14", - "esbuild-sunos-64": "0.14.14", - "esbuild-windows-32": "0.14.14", - "esbuild-windows-64": "0.14.14", - "esbuild-windows-arm64": "0.14.14" + "esbuild-android-arm64": "0.14.22", + "esbuild-darwin-64": "0.14.22", + "esbuild-darwin-arm64": "0.14.22", + "esbuild-freebsd-64": "0.14.22", + "esbuild-freebsd-arm64": "0.14.22", + "esbuild-linux-32": "0.14.22", + "esbuild-linux-64": "0.14.22", + "esbuild-linux-arm": "0.14.22", + "esbuild-linux-arm64": "0.14.22", + "esbuild-linux-mips64le": "0.14.22", + "esbuild-linux-ppc64le": "0.14.22", + "esbuild-linux-riscv64": "0.14.22", + "esbuild-linux-s390x": "0.14.22", + "esbuild-netbsd-64": "0.14.22", + "esbuild-openbsd-64": "0.14.22", + "esbuild-sunos-64": "0.14.22", + "esbuild-windows-32": "0.14.22", + "esbuild-windows-64": "0.14.22", + "esbuild-windows-arm64": "0.14.22" + }, + "dependencies": { + "esbuild-linux-riscv64": { + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.22.tgz", + "integrity": "sha512-AyJHipZKe88sc+tp5layovquw5cvz45QXw5SaDgAq2M911wLHiCvDtf/07oDx8eweCyzYzG5Y39Ih568amMTCQ==", + "dev": true, + "optional": true + } } }, "esbuild-android-64": { @@ -18706,79 +19170,79 @@ "optional": true }, "esbuild-android-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.14.tgz", - "integrity": "sha512-be/Uw6DdpQiPfula1J4bdmA+wtZ6T3BRCZsDMFB5X+k0Gp8TIh9UvmAcqvKNnbRAafSaXG3jPCeXxDKqnc8hFQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.14.22.tgz", + "integrity": "sha512-k1Uu4uC4UOFgrnTj2zuj75EswFSEBK+H6lT70/DdS4mTAOfs2ECv2I9ZYvr3w0WL0T4YItzJdK7fPNxcPw6YmQ==", "dev": true, "optional": true }, "esbuild-darwin-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.14.tgz", - "integrity": "sha512-BEexYmjWafcISK8cT6O98E3TfcLuZL8DKuubry6G54n2+bD4GkoRD6HYUOnCkfl2p7jodA+s4369IjSFSWjtHg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.14.22.tgz", + "integrity": "sha512-d8Ceuo6Vw6HM3fW218FB6jTY6O3r2WNcTAU0SGsBkXZ3k8SDoRLd3Nrc//EqzdgYnzDNMNtrWegK2Qsss4THhw==", "dev": true, "optional": true }, "esbuild-darwin-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.14.tgz", - "integrity": "sha512-tnBKm41pDOB1GtZ8q/w26gZlLLRzVmP8fdsduYjvM+yFD7E2DLG4KbPAqFMWm4Md9B+DitBglP57FY7AznxbTg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.22.tgz", + "integrity": "sha512-YAt9Tj3SkIUkswuzHxkaNlT9+sg0xvzDvE75LlBo4DI++ogSgSmKNR6B4eUhU5EUUepVXcXdRIdqMq9ppeRqfw==", "dev": true, "optional": true }, "esbuild-freebsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.14.tgz", - "integrity": "sha512-Q9Rx6sgArOHalQtNwAaIzJ6dnQ8A+I7f/RsQsdkS3JrdzmnlFo8JEVofTmwVQLoIop7OKUqIVOGP4PoQcwfVMA==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.22.tgz", + "integrity": "sha512-ek1HUv7fkXMy87Qm2G4IRohN+Qux4IcnrDBPZGXNN33KAL0pEJJzdTv0hB/42+DCYWylSrSKxk3KUXfqXOoH4A==", "dev": true, "optional": true }, "esbuild-freebsd-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.14.tgz", - "integrity": "sha512-TJvq0OpLM7BkTczlyPIphcvnwrQwQDG1HqxzoYePWn26SMUAlt6wrLnEvxdbXAvNvDLVzG83kA+JimjK7aRNBA==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.22.tgz", + "integrity": "sha512-zPh9SzjRvr9FwsouNYTqgqFlsMIW07O8mNXulGeQx6O5ApgGUBZBgtzSlBQXkHi18WjrosYfsvp5nzOKiWzkjQ==", "dev": true, "optional": true }, "esbuild-linux-32": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.14.tgz", - "integrity": "sha512-h/CrK9Baimt5VRbu8gqibWV7e1P9l+mkanQgyOgv0Ng3jHT1NVFC9e6rb1zbDdaJVmuhWX5xVliUA5bDDCcJeg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.14.22.tgz", + "integrity": "sha512-SnpveoE4nzjb9t2hqCIzzTWBM0RzcCINDMBB67H6OXIuDa4KqFqaIgmTchNA9pJKOVLVIKd5FYxNiJStli21qg==", "dev": true, "optional": true }, "esbuild-linux-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.14.tgz", - "integrity": "sha512-IC+wAiIg/egp5OhQp4W44D9PcBOH1b621iRn1OXmlLzij9a/6BGr9NMIL4CRwz4j2kp3WNZu5sT473tYdynOuQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.14.22.tgz", + "integrity": "sha512-Zcl9Wg7gKhOWWNqAjygyqzB+fJa19glgl2JG7GtuxHyL1uEnWlpSMytTLMqtfbmRykIHdab797IOZeKwk5g0zg==", "dev": true, "optional": true }, "esbuild-linux-arm": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.14.tgz", - "integrity": "sha512-gxpOaHOPwp7zSmcKYsHrtxabScMqaTzfSQioAMUaB047YiMuDBzqVcKBG8OuESrYkGrL9DDljXr/mQNg7pbdaQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.14.22.tgz", + "integrity": "sha512-soPDdbpt/C0XvOOK45p4EFt8HbH5g+0uHs5nUKjHVExfgR7du734kEkXR/mE5zmjrlymk5AA79I0VIvj90WZ4g==", "dev": true, "optional": true }, "esbuild-linux-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.14.tgz", - "integrity": "sha512-6QVul3RI4M5/VxVIRF/I5F+7BaxzR3DfNGoqEVSCZqUbgzHExPn+LXr5ly1C7af2Kw4AHpo+wDqx8A4ziP9avw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.22.tgz", + "integrity": "sha512-8q/FRBJtV5IHnQChO3LHh/Jf7KLrxJ/RCTGdBvlVZhBde+dk3/qS9fFsUy+rs3dEi49aAsyVitTwlKw1SUFm+A==", "dev": true, "optional": true }, "esbuild-linux-mips64le": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.14.tgz", - "integrity": "sha512-4Jl5/+xoINKbA4cesH3f4R+q0vltAztZ6Jm8YycS8lNhN1pgZJBDxWfI6HUMIAdkKlIpR1PIkA9aXQgZ8sxFAg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.22.tgz", + "integrity": "sha512-SiNDfuRXhGh1JQLLA9JPprBgPVFOsGuQ0yDfSPTNxztmVJd8W2mX++c4FfLpAwxuJe183mLuKf7qKCHQs5ZnBQ==", "dev": true, "optional": true }, "esbuild-linux-ppc64le": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.14.tgz", - "integrity": "sha512-BitW37GxeebKxqYNl4SVuSdnIJAzH830Lr6Mkq3pBHXtzQay0vK+IeOR/Ele1GtNVJ+/f8wYM53tcThkv5SC5w==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.22.tgz", + "integrity": "sha512-6t/GI9I+3o1EFm2AyN9+TsjdgWCpg2nwniEhjm2qJWtJyJ5VzTXGUU3alCO3evopu8G0hN2Bu1Jhz2YmZD0kng==", "dev": true, "optional": true }, @@ -18790,57 +19254,57 @@ "optional": true }, "esbuild-linux-s390x": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.14.tgz", - "integrity": "sha512-vLj6p76HOZG3wfuTr5MyO3qW5iu8YdhUNxuY+tx846rPo7GcKtYSPMusQjeVEfZlJpSYoR+yrNBBxq+qVF9zrw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.22.tgz", + "integrity": "sha512-Sz1NjZewTIXSblQDZWEFZYjOK6p8tV6hrshYdXZ0NHTjWE+lwxpOpWeElUGtEmiPcMT71FiuA9ODplqzzSxkzw==", "dev": true, "optional": true }, "esbuild-netbsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.14.tgz", - "integrity": "sha512-fn8looXPQhpVqUyCBWUuPjesH+yGIyfbIQrLKG05rr1Kgm3rZD/gaYrd3Wpmf5syVZx70pKZPvdHp8OTA+y7cQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.22.tgz", + "integrity": "sha512-TBbCtx+k32xydImsHxvFgsOCuFqCTGIxhzRNbgSL1Z2CKhzxwT92kQMhxort9N/fZM2CkRCPPs5wzQSamtzEHA==", "dev": true, "optional": true }, "esbuild-openbsd-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.14.tgz", - "integrity": "sha512-HdAnJ399pPff3SKbd8g+P4o5znseni5u5n5rJ6Z7ouqOdgbOwHe2ofZbMow17WMdNtz1IyOZk2Wo9Ve6/lZ4Rg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.22.tgz", + "integrity": "sha512-vK912As725haT313ANZZZN+0EysEEQXWC/+YE4rQvOQzLuxAQc2tjbzlAFREx3C8+uMuZj/q7E5gyVB7TzpcTA==", "dev": true, "optional": true }, "esbuild-sunos-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.14.tgz", - "integrity": "sha512-bmDHa99ulsGnYlh/xjBEfxoGuC8CEG5OWvlgD+pF7bKKiVTbtxqVCvOGEZeoDXB+ja6AvHIbPxrEE32J+m5nqQ==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.14.22.tgz", + "integrity": "sha512-/mbJdXTW7MTcsPhtfDsDyPEOju9EOABvCjeUU2OJ7fWpX/Em/H3WYDa86tzLUbcVg++BScQDzqV/7RYw5XNY0g==", "dev": true, "optional": true }, "esbuild-wasm": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.14.tgz", - "integrity": "sha512-qTjK4MWnYtQHCMGg2qDUqeFYXfVvYq5qJkQTIsOV4VZCknoYePVaDTG9ygEB9Ct0kc0DWs7IrS6Ja+GjY62Kzw==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.14.22.tgz", + "integrity": "sha512-FOSAM29GN1fWusw0oLMv6JYhoheDIh5+atC72TkJKfIUMID6yISlicoQSd9gsNSFsNBvABvtE2jR4JB1j4FkFw==", "dev": true }, "esbuild-windows-32": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.14.tgz", - "integrity": "sha512-6tVooQcxJCNenPp5GHZBs/RLu31q4B+BuF4MEoRxswT+Eq2JGF0ZWDRQwNKB8QVIo3t6Svc5wNGez+CwKNQjBg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.14.22.tgz", + "integrity": "sha512-1vRIkuvPTjeSVK3diVrnMLSbkuE36jxA+8zGLUOrT4bb7E/JZvDRhvtbWXWaveUc/7LbhaNFhHNvfPuSw2QOQg==", "dev": true, "optional": true }, "esbuild-windows-64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.14.tgz", - "integrity": "sha512-kl3BdPXh0/RD/dad41dtzj2itMUR4C6nQbXQCyYHHo4zoUoeIXhpCrSl7BAW1nv5EFL8stT1V+TQVXGZca5A2A==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.14.22.tgz", + "integrity": "sha512-AxjIDcOmx17vr31C5hp20HIwz1MymtMjKqX4qL6whPj0dT9lwxPexmLj6G1CpR3vFhui6m75EnBEe4QL82SYqw==", "dev": true, "optional": true }, "esbuild-windows-arm64": { - "version": "0.14.14", - "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.14.tgz", - "integrity": "sha512-dCm1wTOm6HIisLanmybvRKvaXZZo4yEVrHh1dY0v582GThXJOzuXGja1HIQgV09RpSHYRL3m4KoUBL00l6SWEg==", + "version": "0.14.22", + "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.22.tgz", + "integrity": "sha512-5wvQ+39tHmRhNpu2Fx04l7QfeK3mQ9tKzDqqGR8n/4WUxsFxnVLfDRBGirIfk4AfWlxk60kqirlODPoT5LqMUg==", "dev": true, "optional": true }, @@ -19156,7 +19620,7 @@ "etag": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true }, "eventemitter-asyncresource": { @@ -19195,38 +19659,39 @@ } }, "express": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.17.2.tgz", - "integrity": "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg==", + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.1.tgz", + "integrity": "sha512-zZBcOX9TfehHQhtupq57OF8lFZ3UZi08Y97dwFCkD8p9d/d2Y3M+ykKcwaMDEL+4qyUolgBDX6AblpR3fL212Q==", "dev": true, "requires": { - "accepts": "~1.3.7", + "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.19.1", + "body-parser": "1.20.0", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.4.1", + "cookie": "0.5.0", "cookie-signature": "1.0.6", "debug": "2.6.9", - "depd": "~1.1.2", + "depd": "2.0.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.1.2", + "finalhandler": "1.2.0", "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.1", "methods": "~1.1.2", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "parseurl": "~1.3.3", "path-to-regexp": "0.1.7", "proxy-addr": "~2.0.7", - "qs": "6.9.6", + "qs": "6.10.3", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.17.2", - "serve-static": "1.14.2", + "send": "0.18.0", + "serve-static": "1.15.0", "setprototypeof": "1.2.0", - "statuses": "~1.5.0", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -19235,7 +19700,13 @@ "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "dev": true }, "debug": { @@ -19247,17 +19718,53 @@ "ms": "2.0.0" } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + } + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true } } }, @@ -19362,12 +19869,32 @@ } }, "filelist": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz", - "integrity": "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", + "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", "dev": true, "requires": { - "minimatch": "^3.0.4" + "minimatch": "^5.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } } }, "fill-range": { @@ -19449,9 +19976,9 @@ "dev": true }, "follow-redirects": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.7.tgz", - "integrity": "sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", "dev": true }, "formdata-polyfill": { @@ -19478,7 +20005,7 @@ "fresh": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", "dev": true }, "fs-extra": { @@ -19532,6 +20059,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, "gauge": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.0.tgz", @@ -19710,7 +20243,7 @@ "hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", "dev": true, "requires": { "inherits": "^2.0.1", @@ -19746,9 +20279,9 @@ } }, "html-entities": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz", - "integrity": "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", + "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==", "dev": true }, "html-escaper": { @@ -19766,26 +20299,40 @@ "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", "dev": true }, "http-errors": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", - "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "requires": { - "depd": "~1.1.2", + "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", - "statuses": ">= 1.5.0 < 2", + "statuses": "2.0.1", "toidentifier": "1.0.1" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true + } } }, "http-parser-js": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz", - "integrity": "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA==", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, "http-proxy": { @@ -19811,9 +20358,9 @@ } }, "http-proxy-middleware": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.2.tgz", - "integrity": "sha512-XtmDN5w+vdFTBZaYhdJAbMqn0DP/EhkUaAeo963mojwpKMMbw6nivtFKw07D7DDOH745L5k0VL0P8KRYNEVF/g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", "dev": true, "requires": { "@types/http-proxy": "^1.17.8", @@ -20220,7 +20767,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "isbinaryfile": { @@ -20326,22 +20873,65 @@ } }, "jake": { - "version": "10.8.2", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz", - "integrity": "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A==", + "version": "10.8.5", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.5.tgz", + "integrity": "sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==", "dev": true, "requires": { - "async": "0.9.x", - "chalk": "^2.4.2", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.1", "minimatch": "^3.0.4" }, "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=", + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "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 + }, + "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, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -20457,15 +21047,15 @@ "dev": true }, "karma": { - "version": "6.3.12", - "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.12.tgz", - "integrity": "sha512-qwIG+oB2YmHx4hjvYSRMNzL3YWAJ9baHaLAxiP7biFNkfpwYTUTtPck0joFpucalNLzMr+7z/FX1uY/kl8DV9A==", + "version": "6.3.20", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.20.tgz", + "integrity": "sha512-HRNQhMuKOwKpjYlWiJP0DUrJOh+QjaI/DTaD8b9rEm4Il3tJ8MijutVZH4ts10LuUFst/CedwTS6vieCN8yTSw==", "dev": true, "requires": { + "@colors/colors": "1.5.0", "body-parser": "^1.19.0", "braces": "^3.0.2", "chokidar": "^3.5.1", - "colors": "1.4.0", "connect": "^3.7.0", "di": "^0.0.1", "dom-serialize": "^2.2.1", @@ -20474,19 +21064,29 @@ "http-proxy": "^1.18.1", "isbinaryfile": "^4.0.8", "lodash": "^4.17.21", - "log4js": "^6.3.0", + "log4js": "^6.4.1", "mime": "^2.5.2", "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", "qjobs": "^1.2.0", "range-parser": "^1.2.1", "rimraf": "^3.0.2", - "socket.io": "^4.2.0", + "socket.io": "^4.4.1", "source-map": "^0.6.1", "tmp": "^0.2.1", "ua-parser-js": "^0.7.30", "yargs": "^16.1.1" }, "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -20693,9 +21293,9 @@ } }, "license-webpack-plugin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.0.tgz", - "integrity": "sha512-b9iMrROrw2fTOJBZ57h0xJfT5/1Cxg4ucYbtpWoukv4Awb2TFPfDDFVHNM8w6SYQpVfB13a5tQJxgGamqwrsyw==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", "dev": true, "requires": { "webpack-sources": "^3.0.0" @@ -20891,18 +21491,18 @@ "dev": true }, "memfs": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz", - "integrity": "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==", + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.4.7.tgz", + "integrity": "sha512-ygaiUSNalBX85388uskeCyhSAoOSgzBbtVCr9jA2RROssFL9Q19/ZXFqS+2Th2sr1ewNIWgFdLzLC3Yl1Zv+lw==", "dev": true, "requires": { - "fs-monkey": "1.0.3" + "fs-monkey": "^1.0.3" } }, "merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "dev": true }, "merge-stream": { @@ -20920,7 +21520,7 @@ "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true }, "micromatch": { @@ -20990,18 +21590,18 @@ "dev": true }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, "minipass": { @@ -21106,7 +21706,7 @@ "multicast-dns-service-types": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=", + "integrity": "sha512-cnAsSVxIDsYt0v7HmC0hWZFwwXSh+E6PgCrREDuN/EsjgLwA5XRmlMHhSiDPrt6HxY1gTivEa/Zh7GtODoLevQ==", "dev": true }, "mute-stream": { @@ -21492,9 +22092,9 @@ "dev": true }, "node-fetch": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.3.tgz", - "integrity": "sha512-AXP18u4pidSZ1xYXRDPY/8jdv3RAozIt/WLNR/MBGZAz+xjtlr90RvCnsvHQRiXyWliZF/CpytExp32UU67/SA==", + "version": "3.2.10", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.10.tgz", + "integrity": "sha512-MhuzNwdURnZ1Cp4XTazr69K0BTizsBroX7Zx3UgDSVcZYKF/6p0CBe4EUb/hLqmzVhl0UpYfgRljQ4yxE+iCxA==", "dev": true, "requires": { "data-uri-to-buffer": "^4.0.0", @@ -21503,9 +22103,9 @@ } }, "node-forge": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.2.1.tgz", - "integrity": "sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true }, "node-gyp": { @@ -21688,6 +22288,12 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, "object-is": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", @@ -21882,12 +22488,12 @@ } }, "p-retry": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz", - "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", "dev": true, "requires": { - "@types/retry": "^0.12.0", + "@types/retry": "0.12.0", "retry": "^0.13.1" }, "dependencies": { @@ -22032,7 +22638,7 @@ "path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", "dev": true }, "path-type": { @@ -22091,6 +22697,15 @@ "mkdirp": "^0.5.5" }, "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, "debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -22101,12 +22716,12 @@ } }, "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "requires": { - "minimist": "^1.2.5" + "minimist": "^1.2.6" } } } @@ -22587,10 +23202,13 @@ "dev": true }, "qs": { - "version": "6.9.6", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz", - "integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ==", - "dev": true + "version": "6.10.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.3.tgz", + "integrity": "sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ==", + "dev": true, + "requires": { + "side-channel": "^1.0.4" + } }, "queue-microtask": { "version": "1.2.3", @@ -22614,13 +23232,13 @@ "dev": true }, "raw-body": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz", - "integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dev": true, "requires": { - "bytes": "3.1.1", - "http-errors": "1.8.1", + "bytes": "3.1.2", + "http-errors": "2.0.0", "iconv-lite": "0.4.24", "unpipe": "1.0.0" } @@ -22707,13 +23325,14 @@ "dev": true }, "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", "dev": true, "requires": { "call-bind": "^1.0.2", - "define-properties": "^1.1.3" + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" } }, "regexpp": { @@ -22924,9 +23543,9 @@ "dev": true }, "sass": { - "version": "1.49.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.0.tgz", - "integrity": "sha512-TVwVdNDj6p6b4QymJtNtRS2YtLJ/CqZriGg0eIAbAKMlN8Xy6kbv33FsEZSF7FufFFM705SQviHjjThfaQ4VNw==", + "version": "1.49.9", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.49.9.tgz", + "integrity": "sha512-YlYWkkHP9fbwaFRZQRXgDi3mXZShslVmmo+FVK3kHLUELHHEYrCmL1x6IUjC7wLS6VuJSAFXRQS/DxdsC4xL1A==", "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", @@ -22991,16 +23610,16 @@ "select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", "dev": true }, "selfsigned": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.0.tgz", - "integrity": "sha512-cUdFiCbKoa1mZ6osuJs2uDHrs0k0oprsKveFiiaBKCNq3SYyb5gs2HxhQyDNLCmL51ZZThqi4YNDpCK6GOP1iQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.0.1.tgz", + "integrity": "sha512-LmME957M1zOsUhG+67rAjKfiWFox3SBxE/yymatMZsAx+oMrJ0YQ8AToOnyCm7xbeg2ep37IHLxdu0o2MavQOQ==", "dev": true, "requires": { - "node-forge": "^1.2.0" + "node-forge": "^1" } }, "semver": { @@ -23013,24 +23632,24 @@ } }, "send": { - "version": "0.17.2", - "resolved": "https://registry.npmjs.org/send/-/send-0.17.2.tgz", - "integrity": "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "requires": { "debug": "2.6.9", - "depd": "~1.1.2", - "destroy": "~1.0.4", + "depd": "2.0.0", + "destroy": "1.2.0", "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "etag": "~1.8.1", "fresh": "0.5.2", - "http-errors": "1.8.1", + "http-errors": "2.0.0", "mime": "1.6.0", "ms": "2.1.3", - "on-finished": "~2.3.0", + "on-finished": "2.4.1", "range-parser": "~1.2.1", - "statuses": "~1.5.0" + "statuses": "2.0.1" }, "dependencies": { "debug": { @@ -23045,11 +23664,17 @@ "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true } } }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, "mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -23061,6 +23686,21 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "dev": true } } }, @@ -23076,7 +23716,7 @@ "serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", - "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", "dev": true, "requires": { "accepts": "~1.3.4", @@ -23100,7 +23740,7 @@ "http-errors": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", "dev": true, "requires": { "depd": "~1.1.2", @@ -23112,13 +23752,13 @@ "inherits": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", "dev": true }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, "setprototypeof": { @@ -23130,15 +23770,15 @@ } }, "serve-static": { - "version": "1.14.2", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz", - "integrity": "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, "requires": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.17.2" + "send": "0.18.0" } }, "set-blocking": { @@ -23177,6 +23817,17 @@ "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -23495,13 +24146,14 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "dev": true, "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" } }, @@ -23849,13 +24501,13 @@ "dev": true }, "webpack": { - "version": "5.67.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.67.0.tgz", - "integrity": "sha512-LjFbfMh89xBDpUMgA1W9Ur6Rn/gnr2Cq1jjHFPo4v6a79/ypznSYbAyPgGhwsxBtMIaEmDD1oJoA7BEYw/Fbrw==", + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", "dev": true, "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.50", + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", "@webassemblyjs/ast": "1.11.1", "@webassemblyjs/wasm-edit": "1.11.1", "@webassemblyjs/wasm-parser": "1.11.1", @@ -23863,7 +24515,7 @@ "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.3", + "enhanced-resolve": "^5.9.2", "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", diff --git a/angular-ngrx-scss/src/app/app.module.ts b/angular-ngrx-scss/src/app/app.module.ts index 5a64e9452..59ecb11be 100644 --- a/angular-ngrx-scss/src/app/app.module.ts +++ b/angular-ngrx-scss/src/app/app.module.ts @@ -11,6 +11,7 @@ import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './app.component'; import { TokenInterceptor } from './auth/services/token.interceptor'; import { reducers } from './state'; +import { AuthEffects } from './state/auth'; import { ProfileEffects } from './state/profile/profile.effects'; import { RepositoryEffects } from './state/repository/repository.effects'; import { UserEffects } from './state/user'; @@ -27,7 +28,12 @@ import { UserEffects } from './state/user'; logOnly: environment.production, autoPause: true, }), - EffectsModule.forRoot([UserEffects, ProfileEffects, RepositoryEffects]), + EffectsModule.forRoot([ + AuthEffects, + UserEffects, + ProfileEffects, + RepositoryEffects, + ]), ], declarations: [AppComponent], providers: [ diff --git a/angular-ngrx-scss/src/app/auth/auth.component.ts b/angular-ngrx-scss/src/app/auth/auth.component.ts index 8512a1734..ba0a0e525 100644 --- a/angular-ngrx-scss/src/app/auth/auth.component.ts +++ b/angular-ngrx-scss/src/app/auth/auth.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { FormControl, FormGroup } from '@angular/forms'; import { Store } from '@ngrx/store'; -import { startSignIn } from '../state/auth/auth.actions'; +import { signInUser } from '../state/auth/auth.actions'; @Component({ selector: 'app-auth', @@ -17,6 +17,6 @@ export class AuthComponent { constructor(private store: Store) {} onSubmit() { - this.store.dispatch(startSignIn()); + this.store.dispatch(signInUser()); } } diff --git a/angular-ngrx-scss/src/app/auth/auth.module.ts b/angular-ngrx-scss/src/app/auth/auth.module.ts index 891fc9dff..f89cc7062 100644 --- a/angular-ngrx-scss/src/app/auth/auth.module.ts +++ b/angular-ngrx-scss/src/app/auth/auth.module.ts @@ -4,17 +4,9 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { AuthComponent } from './auth.component'; import { AuthRoutingModule } from './auth-routing.module'; import { RedirectComponent } from './redirect/redirect.component'; -import { EffectsModule } from '@ngrx/effects'; -import { AuthEffects } from '../state/auth/auth.effects'; @NgModule({ declarations: [AuthComponent, RedirectComponent], - imports: [ - CommonModule, - AuthRoutingModule, - FormsModule, - ReactiveFormsModule, - EffectsModule.forFeature([AuthEffects]), - ], + imports: [CommonModule, AuthRoutingModule, FormsModule, ReactiveFormsModule], }) export class AuthModule {} diff --git a/angular-ngrx-scss/src/app/file-viewer/file-explorer-blob/file-explorer-blob.component.spec.ts b/angular-ngrx-scss/src/app/file-viewer/file-explorer-blob/file-explorer-blob.component.spec.ts index 87c4b05b2..eaab40ad0 100644 --- a/angular-ngrx-scss/src/app/file-viewer/file-explorer-blob/file-explorer-blob.component.spec.ts +++ b/angular-ngrx-scss/src/app/file-viewer/file-explorer-blob/file-explorer-blob.component.spec.ts @@ -4,7 +4,7 @@ import { FileExplorerBlobComponent } from './file-explorer-blob.component'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { AppState } from '../../state'; -import { fetchFileContents, RepoState } from '../../state/repository'; +import { fetchFileContents, RepositoryState } from '../../state/repository'; import { ActivatedRoute } from '@angular/router'; import { FileExplorerNavComponent } from '../file-explorer-nav/file-explorer-nav.component'; import { FileViewerComponent } from '../file-viewer/file-viewer.component'; @@ -15,14 +15,14 @@ describe('FileExplorerBlobComponent', () => { let fixture: ComponentFixture; let store: MockStore; const initialState: AppState = { - repo: { + repository: { selectedFile: { content: 'this is a readme file', name: 'starter.dev-github-showcases', type: 'file', size: 223, }, - } as RepoState, + } as RepositoryState, } as AppState; beforeEach(async () => { diff --git a/angular-ngrx-scss/src/app/file-viewer/file-explorer-container/file-explorer-container.component.spec.ts b/angular-ngrx-scss/src/app/file-viewer/file-explorer-container/file-explorer-container.component.spec.ts index 4ff4f0a16..a7f3e56dd 100644 --- a/angular-ngrx-scss/src/app/file-viewer/file-explorer-container/file-explorer-container.component.spec.ts +++ b/angular-ngrx-scss/src/app/file-viewer/file-explorer-container/file-explorer-container.component.spec.ts @@ -30,11 +30,17 @@ describe('FileExplorerContainerComponent', () => { name: '.github', type: 'file', path: '.github', + content: '', + encoding: '', + size: 0, }, { name: 'packages', type: 'dir', path: 'packages', + content: '', + encoding: '', + size: 0, }, ]; component.name = 'starter.dev-github-showcases'; @@ -60,6 +66,9 @@ describe('FileExplorerContainerComponent', () => { name: 'README.md', type: 'file', path: 'README.md', + content: '', + encoding: '', + size: 0, }), ).toEqual('/thisdot/starter.dev-github-showcases/blob/main/README.md'); }); @@ -70,6 +79,9 @@ describe('FileExplorerContainerComponent', () => { name: '.github', type: 'dir', path: '.github', + content: '', + encoding: '', + size: 0, }), ).toEqual('/thisdot/starter.dev-github-showcases/tree/main/.github'); }); diff --git a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.html b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.html index 05a703260..c2156eb09 100644 --- a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.html +++ b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.html @@ -4,14 +4,14 @@ diff --git a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.spec.ts b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.spec.ts index eb837d08c..6c533050e 100644 --- a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.spec.ts +++ b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.spec.ts @@ -4,7 +4,7 @@ import { FileExplorerComponent } from './file-explorer.component'; import { RouterTestingModule } from '@angular/router/testing'; import { provideMockStore } from '@ngrx/store/testing'; import { AppState } from '../../state'; -import { RepoState } from '../../state/repository'; +import { RepositoryState } from '../../state/repository'; import { ActivatedRoute } from '@angular/router'; import { of } from 'rxjs'; import { By } from '@angular/platform-browser'; @@ -13,7 +13,7 @@ describe('FileExplorerComponent', () => { let component: FileExplorerComponent; let fixture: ComponentFixture; const initialState: AppState = { - repo: { + repository: { tree: [ { name: 'packages', @@ -24,7 +24,7 @@ describe('FileExplorerComponent', () => { activeBranch: 'main', description: '', website: '', - } as RepoState, + } as RepositoryState, } as AppState; const activatedRouteStub = { paramMap: of({ diff --git a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.ts b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.ts index 5a6972323..05da3b823 100644 --- a/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.ts +++ b/angular-ngrx-scss/src/app/file-viewer/file-explorer/file-explorer.component.ts @@ -4,7 +4,7 @@ import { ActivatedRoute } from '@angular/router'; import { fetchRepository, RepoContents, - selectRepositoryState, + selectedRepository, } from '../../state/repository'; import { map, takeWhile, tap } from 'rxjs'; @@ -18,7 +18,7 @@ export class FileExplorerComponent implements OnInit, OnDestroy { repoName = ''; path = ''; branch = ''; - repo$ = this.store.select(selectRepositoryState).pipe( + repo$ = this.store.select(selectedRepository).pipe( map((repo) => { const fileItems: RepoContents[] = []; const dirItems: RepoContents[] = []; diff --git a/angular-ngrx-scss/src/app/home/home.component.ts b/angular-ngrx-scss/src/app/home/home.component.ts index 202525fda..1ae7cb789 100644 --- a/angular-ngrx-scss/src/app/home/home.component.ts +++ b/angular-ngrx-scss/src/app/home/home.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { Store } from '@ngrx/store'; -import { selectUserLoginName } from '../state/user'; +import { Subject, takeUntil } from 'rxjs'; +import { selectAuthUserName } from '../state/auth'; import { fetchUserData } from '../state/user/user.actions'; @Component({ @@ -8,12 +9,20 @@ import { fetchUserData } from '../state/user/user.actions'; templateUrl: './home.component.html', styleUrls: ['./home.component.scss'], }) -export class HomeComponent implements OnInit { - user$ = this.store.select(selectUserLoginName); +export class HomeComponent implements OnInit, OnDestroy { + destroy$: Subject = new Subject(); + user$ = this.store.select(selectAuthUserName); constructor(private store: Store) {} ngOnInit() { - this.store.dispatch(fetchUserData()); + this.user$.pipe(takeUntil(this.destroy$)).subscribe((user) => { + this.store.dispatch(fetchUserData({ username: user })); + }); + } + + ngOnDestroy(): void { + this.destroy$.next(true); + this.destroy$.unsubscribe(); } } diff --git a/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.spec.ts b/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.spec.ts index bc68c3dff..845c160b0 100644 --- a/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.spec.ts +++ b/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockStore, provideMockStore } from '@ngrx/store/testing'; -import { signOut } from 'src/app/state/auth/auth.actions'; +import { signOutUser } from 'src/app/state/auth/auth.actions'; import { NavBarComponent } from './nav-bar.component'; describe('NavbarComponent', () => { @@ -36,6 +36,6 @@ describe('NavbarComponent', () => { const dispatchSpy = spyOn(store, 'dispatch').and.callThrough(); component.signOut(); - expect(dispatchSpy).toHaveBeenCalledWith(signOut()); + expect(dispatchSpy).toHaveBeenCalledWith(signOutUser()); }); }); diff --git a/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.ts b/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.ts index db08035ec..f53edbc6d 100644 --- a/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.ts +++ b/angular-ngrx-scss/src/app/home/nav-bar/nav-bar.component.ts @@ -1,8 +1,8 @@ import { animate, style, transition, trigger } from '@angular/animations'; import { Component } from '@angular/core'; import { Store } from '@ngrx/store'; -import { signOut } from 'src/app/state/auth'; -import { selectUserAvatar, selectUserLoginName } from '../../state/user'; +import { signOutUser } from 'src/app/state/auth'; +import { selectAuthUserAvatar, selectAuthUserName } from '../../state/auth'; @Component({ selector: 'app-nav-bar', @@ -22,8 +22,8 @@ import { selectUserAvatar, selectUserLoginName } from '../../state/user'; }) export class NavBarComponent { dropdownMenuIsOpen = false; - userAvatar$ = this.store.select(selectUserAvatar); - username$ = this.store.select(selectUserLoginName); + userAvatar$ = this.store.select(selectAuthUserAvatar); + username$ = this.store.select(selectAuthUserName); constructor(private store: Store) {} @@ -37,6 +37,6 @@ export class NavBarComponent { signOut() { this.closeDropdown(); - this.store.dispatch(signOut()); + this.store.dispatch(signOutUser()); } } diff --git a/angular-ngrx-scss/src/app/home/profile/profile-about/profile-about.component.html b/angular-ngrx-scss/src/app/home/profile/profile-about/profile-about.component.html index 3a4e62b80..9aee946c3 100644 --- a/angular-ngrx-scss/src/app/home/profile/profile-about/profile-about.component.html +++ b/angular-ngrx-scss/src/app/home/profile/profile-about/profile-about.component.html @@ -35,7 +35,7 @@

{{ profile.user.blog }} -
+
- @{{ profile.user.twitter_username }}@{{ profile.user.twitterUsername }}
diff --git a/angular-ngrx-scss/src/app/pull-requests/pull-requests.component.spec.ts b/angular-ngrx-scss/src/app/pull-requests/pull-requests.component.spec.ts index bf7022d76..d9dc12c65 100644 --- a/angular-ngrx-scss/src/app/pull-requests/pull-requests.component.spec.ts +++ b/angular-ngrx-scss/src/app/pull-requests/pull-requests.component.spec.ts @@ -6,21 +6,21 @@ import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { AppState } from '../state'; -import { fetchPullRequests, RepoState } from '../state/repository'; +import { fetchPullRequests, RepositoryState } from '../state/repository'; describe('PullRequestsComponent', () => { let component: PullRequestsComponent; let fixture: ComponentFixture; let store: MockStore; const initialState: AppState = { - repo: { + repository: { selectedFile: { content: 'this is a readme file', name: 'starter.dev-github-showcases', type: 'file', size: 223, }, - } as RepoState, + } as RepositoryState, } as AppState; beforeEach(async () => { diff --git a/angular-ngrx-scss/src/app/repository/components/repo-header/repo-heading/repo-heading.component.ts b/angular-ngrx-scss/src/app/repository/components/repo-header/repo-heading/repo-heading.component.ts index 838988f04..288096eb6 100644 --- a/angular-ngrx-scss/src/app/repository/components/repo-header/repo-heading/repo-heading.component.ts +++ b/angular-ngrx-scss/src/app/repository/components/repo-header/repo-heading/repo-heading.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { RepoState } from 'src/app/state/repository'; +import { RepositoryState } from 'src/app/state/repository'; @Component({ selector: 'app-repo-heading', @@ -8,7 +8,7 @@ import { RepoState } from 'src/app/state/repository'; }) export class RepositoryHeadingComponent { @Input() - repo?: RepoState; + repo?: RepositoryState; get ownerPath(): string { return `/${this.repo?.ownerName}`; diff --git a/angular-ngrx-scss/src/app/repository/components/repo-header/repo-navigation/repo-navigation.component.ts b/angular-ngrx-scss/src/app/repository/components/repo-header/repo-navigation/repo-navigation.component.ts index dfe54ebc0..bd38797b0 100644 --- a/angular-ngrx-scss/src/app/repository/components/repo-header/repo-navigation/repo-navigation.component.ts +++ b/angular-ngrx-scss/src/app/repository/components/repo-header/repo-navigation/repo-navigation.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { RepoState } from 'src/app/state/repository'; +import { RepositoryState } from 'src/app/state/repository'; @Component({ selector: 'app-repo-navigation', @@ -7,7 +7,7 @@ import { RepoState } from 'src/app/state/repository'; styleUrls: ['./repo-navigation.component.scss'], }) export class RepositoryNavigationComponent { - @Input() repo?: RepoState; + @Input() repo?: RepositoryState; @Input() issuesCount = 0; @Input() pullsCount = 0; diff --git a/angular-ngrx-scss/src/app/repository/services/repository.service.spec.ts b/angular-ngrx-scss/src/app/repository/services/repository.service.spec.ts index 31b7d9b3e..de8633e92 100644 --- a/angular-ngrx-scss/src/app/repository/services/repository.service.spec.ts +++ b/angular-ngrx-scss/src/app/repository/services/repository.service.spec.ts @@ -1,12 +1,9 @@ import { HttpClient, HttpParams } from '@angular/common/http'; -import { of, delay } from 'rxjs'; +import { delay, of } from 'rxjs'; import { - FileContents, PullRequestAPIResponse, RepoApiResponse, - RepoContents, - RepoPullRequests, - RepoState, + RepoContentsApiResponse, } from 'src/app/state/repository'; import { IssueComments, @@ -15,11 +12,8 @@ import { PullRequests, } from './repository.interfaces'; +import { generatePullRequestAPIResponseFixture } from '../../fixtures/repository.fixtures'; import { RepositoryService } from './repository.service'; -import { - generatePullRequestAPIResponseFixture, - pullRequestFixture, -} from '../../fixtures/repository.fixtures'; const MOCK_ISSUES: Issues = [ { @@ -220,27 +214,7 @@ describe('RepositoryService', () => { }); it('should return information on the provided repository', (done) => { - const expectedResponse: RepoState = { - description: 'A collection of GitHub clone implementations.', - forkCount: 20, - issueCount: 30, - ownerName: '', - prCount: 0, - readme: '', - repoName: 'starter.dev-github-showcases', - starCount: 100, - tags: ['react', 'angular', 'vue', 'github'], - tree: [], - openPullRequests: null, - closedPullRequests: null, - activeBranch: 'main', - visibility: 'public', - selectedFile: null, - watchCount: 10, - website: 'https://starter.dev', - }; - - const expectedHttpResponse: Partial = { + const expectedHttpResponse = { name: 'starter.dev-github-showcases', description: 'A collection of GitHub clone implementations.', homepage: 'https://starter.dev', @@ -251,31 +225,68 @@ describe('RepositoryService', () => { open_issues_count: 30, topics: ['react', 'angular', 'vue', 'github'], default_branch: 'main', - }; + } as RepoApiResponse; - httpClientSpy.get.and.returnValue(of(expectedHttpResponse).pipe(delay(0))); + httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); repoService .getRepositoryInfo('thisdot', 'starter.dev-github-showcases') - .subscribe((res) => { - expect(res).toEqual(expectedResponse); - done(); - }); + .subscribe({ + next: (repoInfo) => { + expect(repoInfo).toEqual(expectedHttpResponse); + expect(httpClientSpy.get).toHaveBeenCalledOnceWith( + `https://api.github.com/repos/thisdot/starter.dev-github-showcases`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), + ); + done(); + }, + error: done.fail, + }); expect(httpClientSpy.get.calls.count()).withContext('called once').toBe(1); }); describe('getRepositoryContents', () => { - const expectedResponse: RepoContents[] = [ + const expectedResponse: RepoContentsApiResponse[] = [ { name: '.github', - type: 'file', path: '.github', + sha: '', + size: 1234, + url: '', + html_url: '', + git_url: '', + download_url: '', + type: 'file', + encoding: '', + content: 'file contents', + _links: { + self: '', + git: '', + html: '', + }, }, { name: 'angular-ngrx-scss', - type: 'dir', path: 'angular-ngrx-scss', + sha: '', + size: 1234, + url: '', + html_url: '', + git_url: '', + download_url: '', + type: 'dir', + encoding: '', + content: 'file contents', + _links: { + self: '', + git: '', + html: '', + }, }, ]; beforeEach(() => { @@ -307,40 +318,11 @@ describe('RepositoryService', () => { expect(httpClientSpy.get).toHaveBeenCalledOnceWith( 'https://api.github.com/repos/thisdot/starter.dev-github-showcases/contents/README.md', - ); - }); - }); - - describe('getFileContents', () => { - it('should make request and return file content response', (done) => { - const expectedResponse: FileContents = { - content: btoa('This is a readme file'), - name: 'starter.dev-github-showcases', - type: 'file', - size: 223, - }; - - httpClientSpy.get.and.returnValue(of(expectedResponse).pipe(delay(0))); - repoService - .getFileContents( - 'thisdot', - 'starter.dev-github-showcases', - 'README.md', - 'main', - ) - .subscribe((res) => { - expect(res).toEqual({ - ...expectedResponse, - content: 'This is a readme file', - }); - done(); - }); - - expect(httpClientSpy.get.calls.count()) - .withContext('called once') - .toBe(1); - expect(httpClientSpy.get).toHaveBeenCalledOnceWith( - 'https://api.github.com/repos/thisdot/starter.dev-github-showcases/contents/README.md?ref=main', + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), ); }); }); @@ -477,13 +459,12 @@ describe('RepositoryService', () => { it('should return pull request for given repository', (done) => { const apiResponse: PullRequestAPIResponse = generatePullRequestAPIResponseFixture(); - const expectedResponse: RepoPullRequests = pullRequestFixture; httpClientSpy.get.and.returnValue(of(apiResponse).pipe(delay(0))); repoService .getPullRequests('thisdot', 'starter.dev-github-showcases', 'open') .subscribe((res) => { - expect(res).toEqual(expectedResponse); + expect(res).toEqual(apiResponse); done(); }); @@ -492,6 +473,11 @@ describe('RepositoryService', () => { .toBe(1); expect(httpClientSpy.get).toHaveBeenCalledOnceWith( 'https://api.github.com/search/issues?q=repo:thisdot/starter.dev-github-showcases+type:pr+state:open', + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), ); }); }); diff --git a/angular-ngrx-scss/src/app/repository/services/repository.service.ts b/angular-ngrx-scss/src/app/repository/services/repository.service.ts index e02f5366f..c5a3e849f 100644 --- a/angular-ngrx-scss/src/app/repository/services/repository.service.ts +++ b/angular-ngrx-scss/src/app/repository/services/repository.service.ts @@ -1,17 +1,13 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { map, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { - FileContents, FileContentsApiResponse, PR_STATE, PullRequestAPIResponse, ReadmeApiResponse, RepoApiResponse, - RepoContents, RepoContentsApiResponse, - RepoPullRequests, - RepoState, } from 'src/app/state/repository'; import { environment } from 'src/environments/environment'; import { @@ -28,63 +24,40 @@ import { export class RepositoryService { constructor(private http: HttpClient) {} - getRepositoryInfo(owner: string, repoName: string): Observable { - const url = `${environment.githubUrl}/repos/${owner}/${repoName}`; - - return this.http.get(url).pipe( - map((data) => ({ - repoName: data.name, - description: data.description, - website: data.homepage, - visibility: data.visibility, - watchCount: data.watchers_count, - starCount: data.stargazers_count, - forkCount: data.forks_count, - issueCount: data.open_issues_count, - tags: data.topics, - selectedFile: null, - openPullRequests: null, - closedPullRequests: null, - activeBranch: data.default_branch, - ownerName: '', - prCount: 0, - readme: '', - tree: [], - })), - ); - } - - // TODO: set this method up to return the data as well as the count (issue #185) - // TODO: write test for this function when it's updated - getPullRequestList(owner: string, repoName: string): Observable { - const url = `${environment.githubUrl}/repos/${owner}/${repoName}/pulls`; - - return this.http.get<[]>(url).pipe(map((data) => data.length)); - } - - getRepositoryPullRequest( - owner: string, + /** + * Gets information on a single repository + * @param repoOwner who the repo belongs to + * @param repoName name of the repo + * @returns the full GH response with information on the specified repository + */ + getRepositoryInfo( + repoOwner: string, repoName: string, - pullNumber: number, - ): Observable { - const url = `${environment.githubUrl}/repos/${encodeURIComponent( - owner, - )}/${encodeURIComponent(repoName)}/pulls/${encodeURIComponent(pullNumber)}`; + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const url = `${environment.githubUrl}/repos/${owner}/${name}`; - return this.http.get(url, { + return this.http.get(url, { headers: { Accept: 'application/vnd.github.v3+json', }, }); } + /** + * Gets a list of all the pull requests for the specified repository + * @param repoOwner who the repo belongs to + * @param repoName name of the repo + * @returns the full GH response with the list of associated pull requests + */ getRepositoryPullRequests( - owner: string, + repoOwner: string, repoName: string, ): Observable { - const url = `${environment.githubUrl}/repos/${encodeURIComponent( - owner, - )}/${encodeURIComponent(repoName)}/pulls`; + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const url = `${environment.githubUrl}/repos/${owner}/${name}/pulls`; return this.http.get(url, { headers: { @@ -93,106 +66,88 @@ export class RepositoryService { }); } - getRepositoryPullRequestComments( - owner: string, + /** + * Gets pull request information for a single pull request + * @param repoOwner who the repo belongs to + * @param repoName name of the repo + * @param pullNumber the pull request identifier + * @returns the full GH response with info on the specified pull request + */ + getRepositoryPullRequest( + repoOwner: string, repoName: string, pullNumber: number, - ): Observable { - const url = `${environment.githubUrl}/repos/${encodeURIComponent( - owner, - )}/${encodeURIComponent(repoName)}/issues/${encodeURIComponent( - pullNumber, - )}/comments`; + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const pullId = encodeURIComponent(pullNumber); + const url = `${environment.githubUrl}/repos/${owner}/${name}/pulls/${pullId}`; - return this.http.get(url, { + return this.http.get(url, { headers: { Accept: 'application/vnd.github.v3+json', }, }); } - getRepositoryContents( - owner: string, + /** + * Gets comments on a specified pull request + * @param owner who it belongs to + * @param repoName name of repo + * @param pullNumber pull request identifier + * @returns the full GH response of comments on specified pull request + */ + getRepositoryPullRequestComments( + repoOwner: string, repoName: string, - path?: string, - ): Observable { - const url = path - ? `${environment.githubUrl}/repos/${owner}/${repoName}/contents/${path}` - : `${environment.githubUrl}/repos/${owner}/${repoName}/contents`; - - return this.http.get(url).pipe( - map((data) => { - return data.map((value) => ({ - name: value.name, - type: value.type, - path: value.path, - })); - }), - ); - } + pullNumber: number, + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const pullId = encodeURIComponent(pullNumber); + const url = `${environment.githubUrl}/repos/${owner}/${name}/issues/${pullId}/comments`; - getFileContents( - owner: string, - repoName: string, - path: string, - commitOrBranchOrTagName: string, - ): Observable { - const url = `${environment.githubUrl}/repos/${owner}/${repoName}/contents/${path}?ref=${commitOrBranchOrTagName}`; - return this.http.get(url).pipe( - map((data) => { - return { - name: data.name, - type: data.type, - // TODO: consider using a function that also takes encoding format to decode this - content: atob(data.content), - size: data.size, - }; - }), - ); + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } + /** + * NOTE: This call uses the search URL to find the information, and is a bit of a duplicate of other calls that use the repo URL. Both work fine and are provided currently. + * Gets a list of pull requests matching the provided state + * @param repoOwner who the repo belongs to + * @param repoName name of the repo + * @param prState if the pr is open or closed + * @returns the total count of state-matching pull requests and information for each of those pulls + */ getPullRequests( - owner: string, + repoOwner: string, repoName: string, prState: PR_STATE, - ): Observable { - const url = `${environment.githubUrl}/search/issues?q=repo:${owner}/${repoName}+type:pr+state:${prState}`; - return this.http.get(url).pipe( - map((data) => { - return { - totalCount: data.total_count, - pullRequests: data.items.map((item) => ({ - id: item.id, - login: item.user.login, - title: item.title, - number: item.number, - state: item.state, - closedAt: item.closed_at ? new Date(item.closed_at) : null, - mergedAt: item.pull_request.merged_at - ? new Date(item.pull_request.merged_at) - : null, - createdAt: new Date(item.created_at), - labels: item.labels, - commentCount: item.comments, - labelCount: item.labels.length, - })), - }; - }), - ); - } + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const state = encodeURIComponent(prState); + const url = `${environment.githubUrl}/search/issues?q=repo:${owner}/${name}+type:pr+state:${state}`; - // TODO: readme file is currently an encoded string - this method should be improved to either return the raw data, or include the fields needed to de-code the string when ready to display it - // TODO: write test for this function when it's updated - getReadmeContent(owner: string, repoName: string): Observable { - const url = `${environment.githubUrl}/repos/${owner}/${repoName}/readme`; - - return this.http - .get(url) - .pipe(map((file) => file.content)); + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } + /** + * Get a list of issues for the specified repository + * @param owner who the repo belongs to + * @param repoName name of repo + * @param params any filter or sort parameters + * @returns the full GH response of the issues associated with the specified repository + */ getRepositoryIssues( - owner: string, + repoOwner: string, repoName: string, params?: RepositoryIssuesApiParams, ): Observable { @@ -204,9 +159,9 @@ export class RepositoryService { page: 1, }; - const url = `${environment.githubUrl}/repos/${encodeURIComponent( - owner, - )}/${encodeURIComponent(repoName)}/issues`; + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const url = `${environment.githubUrl}/repos/${owner}/${name}/issues`; return this.http.get(url, { headers: { @@ -217,4 +172,90 @@ export class RepositoryService { }), }); } + + /** + * Gets the contents of a directory for the specified repository + * @param owner who the repo belongs to + * @param repoName name of the repo + * @param path (optional) if provided, the path to retrieve; defaults to the root directory + * @param commitOrBranchOrTagName (optional) if provided, the specific commit / branch / tag to retrieve; defaults to the main branch + * @returns the full GH response containing the repository contents + */ + getRepositoryContents( + repoOwner: string, + repoName: string, + pathName?: string, + commitOrBranchOrTagName?: string, + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const path = pathName && encodeURIComponent(pathName); + const refPath = + commitOrBranchOrTagName && encodeURIComponent(commitOrBranchOrTagName); + let url = `${environment.githubUrl}/repos/${owner}/${name}/contents`; + if (path) { + url += `/${path}`; + } + if (refPath) { + url += `?ref=${refPath}`; + } + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); + } + + /** + * Gets the contents of a file for the specified repository + * @param owner who the repo belongs to + * @param repoName name of the repo + * @param path the path to retrieve + * @param commitOrBranchOrTagName (optional) if provided, the specific commit / branch / tag to retrieve; defaults to the main branch + * @returns the full GH response containing the repository contents + */ + getFileContents( + repoOwner: string, + repoName: string, + pathName: string, + commitOrBranchOrTagName?: string, + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const path = encodeURIComponent(pathName); + const refPath = + commitOrBranchOrTagName && encodeURIComponent(commitOrBranchOrTagName); + let url = `${environment.githubUrl}/repos/${owner}/${name}/contents/${path}`; + if (refPath) { + url += `?ref=${refPath}`; + } + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); + } + + /** + * Gets the contents of the repository's readme file + * @param owner who the repo belongs to + * @param repoName name of the repo + * @returns the readme file for the repository + */ + getRepositoryReadme( + repoOwner: string, + repoName: string, + ): Observable { + const owner = encodeURIComponent(repoOwner); + const name = encodeURIComponent(repoName); + const url = `${environment.githubUrl}/repos/${owner}/${name}/readme`; + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); + } } diff --git a/angular-ngrx-scss/src/app/state/app.reducer.ts b/angular-ngrx-scss/src/app/state/app.reducer.ts index 20e3d1bbd..6836fcd7e 100644 --- a/angular-ngrx-scss/src/app/state/app.reducer.ts +++ b/angular-ngrx-scss/src/app/state/app.reducer.ts @@ -2,12 +2,12 @@ import { ActionReducerMap } from '@ngrx/store'; import { AppState } from './app.state'; import { authReducer } from './auth/auth.reducer'; import { profileReducer } from './profile/profile.reducer'; +import { repositoryReducer } from './repository/repository.reducer'; import { userReducer } from './user/user.reducer'; -import { repoReducer } from './repository/repository.reducer'; export const reducers: ActionReducerMap = { auth: authReducer, - user: userReducer, profile: profileReducer, - repo: repoReducer, + repository: repositoryReducer, + user: userReducer, }; diff --git a/angular-ngrx-scss/src/app/state/app.state.ts b/angular-ngrx-scss/src/app/state/app.state.ts index 8b9ca7ddf..187f22b33 100644 --- a/angular-ngrx-scss/src/app/state/app.state.ts +++ b/angular-ngrx-scss/src/app/state/app.state.ts @@ -1,11 +1,11 @@ import { AuthState } from './auth'; -import { ProfileState } from './profile/profile.state'; +import { ProfileState } from './profile'; +import { RepositoryState } from './repository'; import { UserState } from './user'; -import { RepoState } from './repository'; export interface AppState { auth: AuthState; - user: UserState; profile: ProfileState; - repo: RepoState; + repository: RepositoryState; + user: UserState; } diff --git a/angular-ngrx-scss/src/app/state/auth/auth.actions.ts b/angular-ngrx-scss/src/app/state/auth/auth.actions.ts index 64370c612..5066f1aa2 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.actions.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.actions.ts @@ -1,7 +1,8 @@ import { createAction, props } from '@ngrx/store'; +import { AuthUserData } from './auth.state'; -export const startSignIn = createAction('[Auth API] Start sign in process'); -export const signOut = createAction('[Auth API] Sign out Process'); +export const signInUser = createAction('[Auth API] Start sign in process'); +export const signOutUser = createAction('[Auth API] Start sign out process'); export const saveUserToken = createAction('[Auth API] Save user token'); export const removeUserToken = createAction( @@ -23,3 +24,17 @@ export const userTokenExists = createAction( '[Auth API] Verified user token exists', props<{ isAuthenticated: boolean }>(), ); + +export const authUserSaved = createAction( + '[Auth API] Authenticated user data already saved', +); + +export const fetchAuthenticatedUserDataSuccess = createAction( + '[Auth API] Successfully fetched authenticated user data', + props<{ userData: AuthUserData }>(), +); + +export const fetchAuthenticatedUserDataFailure = createAction( + '[Auth API] Unable the fetch authenticated user data', + props<{ error: object }>(), +); diff --git a/angular-ngrx-scss/src/app/state/auth/auth.effects.spec.ts b/angular-ngrx-scss/src/app/state/auth/auth.effects.spec.ts index f12d673f1..9cd66e0b7 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.effects.spec.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.effects.spec.ts @@ -3,13 +3,14 @@ import { TestBed } from '@angular/core/testing'; import { RouterTestingModule } from '@angular/router/testing'; import { Actions } from '@ngrx/effects'; import { provideMockActions } from '@ngrx/effects/testing'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { of } from 'rxjs'; import { AuthService } from 'src/app/auth/services/auth.service'; import { saveUserToken, saveUserTokenSuccess, - signOut, - startSignIn, + signInUser, + signOutUser, } from './auth.actions'; import { AuthEffects } from './auth.effects'; @@ -17,6 +18,7 @@ import { AuthEffects } from './auth.effects'; describe('AuthEffects', () => { let actions$: Actions; let effects: AuthEffects; + let store: MockStore; let mockHttpClient: jasmine.SpyObj; let authService: jasmine.SpyObj; @@ -35,6 +37,7 @@ describe('AuthEffects', () => { return of(); }, }); + const initialState = {}; // the name ('http') goes as the first argument and an array of public methods you want to spyOn mockHttpClient = jasmine.createSpyObj('http', ['get', 'put']); TestBed.configureTestingModule({ @@ -49,9 +52,12 @@ describe('AuthEffects', () => { provide: AuthService, useValue: authService, }, + provideMockStore({ initialState }), ], }); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + store = TestBed.inject(MockStore); actions$ = TestBed.inject(Actions); effects = TestBed.inject(AuthEffects); }); @@ -61,13 +67,13 @@ describe('AuthEffects', () => { }); it('should initiate the signIn process for the user', () => { - actions$ = of(startSignIn()); + actions$ = of(signInUser()); effects.signIn$.subscribe(); expect(authService.signIn).toHaveBeenCalled(); }); it('should call the signOut method to initiate the signout process', () => { - actions$ = of(signOut()); + actions$ = of(signOutUser()); effects.signOut$.subscribe(); expect(authService.signOut).toHaveBeenCalled(); }); diff --git a/angular-ngrx-scss/src/app/state/auth/auth.effects.ts b/angular-ngrx-scss/src/app/state/auth/auth.effects.ts index f48e777bd..d78b8ddfa 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.effects.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.effects.ts @@ -1,11 +1,32 @@ import { Injectable } from '@angular/core'; import { Router } from '@angular/router'; import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Store } from '@ngrx/store'; import { of } from 'rxjs'; -import { catchError, concatMap, map, switchMap, tap } from 'rxjs/operators'; -import { saveUserToken, saveUserTokenFailure, saveUserTokenSuccess } from '.'; +import { + catchError, + concatMap, + distinctUntilChanged, + exhaustMap, + map, + switchMap, + tap, +} from 'rxjs/operators'; +import { UserService } from 'src/app/user/services/user.service'; import { AuthService } from '../../auth/services/auth.service'; -import { removeUserToken, signOut, startSignIn } from './auth.actions'; +import { + fetchAuthenticatedUserDataFailure, + fetchAuthenticatedUserDataSuccess, + removeUserToken, + saveUserToken, + saveUserTokenFailure, + saveUserTokenSuccess, + signInUser, + signOutUser, + userTokenExists, +} from './auth.actions'; +import { selectAuthUserName } from './auth.selectors'; +import { AuthUserData } from './auth.state'; @Injectable() export class AuthEffects { @@ -16,7 +37,7 @@ export class AuthEffects { signIn$ = createEffect( () => this.actions$.pipe( - ofType(startSignIn), + ofType(signInUser), tap(() => this.authService.signIn()), ), { dispatch: false }, @@ -27,7 +48,7 @@ export class AuthEffects { */ signOut$ = createEffect(() => { return this.actions$.pipe( - ofType(signOut), + ofType(signOutUser), tap(() => this.authService.signOut()), tap(() => this.router.navigate(['/signin'])), switchMap(() => of(removeUserToken({ isAuthenticated: false }))), @@ -49,9 +70,40 @@ export class AuthEffects { ); }); + /** + * Gets authenticated user's name, photo, and email + */ + fetchAuthUserData$ = createEffect(() => { + return this.actions$.pipe( + ofType(saveUserTokenSuccess, userTokenExists), + switchMap(() => + this.store.select(selectAuthUserName).pipe( + distinctUntilChanged(), + exhaustMap(() => + this.userService.getAuthenticatedUserInfo().pipe( + map((userData) => { + const user: AuthUserData = { + avatar: userData.avatar_url, + email: userData.email, + username: userData.login, + }; + return fetchAuthenticatedUserDataSuccess({ userData: user }); + }), + catchError((error) => + of(fetchAuthenticatedUserDataFailure({ error })), + ), + ), + ), + ), + ), + ); + }); + constructor( private actions$: Actions, + private store: Store, private authService: AuthService, + private userService: UserService, private router: Router, ) {} } diff --git a/angular-ngrx-scss/src/app/state/auth/auth.reducer.ts b/angular-ngrx-scss/src/app/state/auth/auth.reducer.ts index 9365cee2c..8f853808b 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.reducer.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.reducer.ts @@ -5,12 +5,18 @@ import { saveUserTokenSuccess, removeUserToken, userTokenExists, + fetchAuthenticatedUserDataSuccess, } from './auth.actions'; import { AuthState } from './auth.state'; export const initialState: AuthState = { isAuthenticated: false, loading: false, + authUser: { + avatar: '', + email: '', + username: '', + }, }; const reducer = createReducer( @@ -39,6 +45,17 @@ const reducer = createReducer( ...state, isAuthenticated: true, })), + on( + fetchAuthenticatedUserDataSuccess, + (state, { userData: { avatar, email, username } }) => ({ + ...state, + authUser: { + avatar, + email, + username, + }, + }), + ), ); export function authReducer(state: AuthState | undefined, action: Action) { diff --git a/angular-ngrx-scss/src/app/state/auth/auth.selectors.ts b/angular-ngrx-scss/src/app/state/auth/auth.selectors.ts index 07f643e04..ee2d88250 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.selectors.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.selectors.ts @@ -7,5 +7,20 @@ export const selectAuthState = createFeatureSelector(authFeatureKey); export const selectIsAuthenticated = createSelector( selectAuthState, - (state: AuthState) => state.isAuthenticated, + (state) => state.isAuthenticated, +); + +export const selectAuthUser = createSelector( + selectAuthState, + (state) => state.authUser, +); + +export const selectAuthUserAvatar = createSelector( + selectAuthUser, + (authUser) => authUser.avatar, +); + +export const selectAuthUserName = createSelector( + selectAuthUser, + (authUser) => authUser.username, ); diff --git a/angular-ngrx-scss/src/app/state/auth/auth.state.ts b/angular-ngrx-scss/src/app/state/auth/auth.state.ts index 3b0870e47..6fa3b3bcf 100644 --- a/angular-ngrx-scss/src/app/state/auth/auth.state.ts +++ b/angular-ngrx-scss/src/app/state/auth/auth.state.ts @@ -1,4 +1,11 @@ export interface AuthState { isAuthenticated: boolean; loading: boolean; + authUser: AuthUserData; +} + +export interface AuthUserData { + avatar: string; + email: string; + username: string; } diff --git a/angular-ngrx-scss/src/app/state/profile/index.ts b/angular-ngrx-scss/src/app/state/profile/index.ts new file mode 100644 index 000000000..ce242baca --- /dev/null +++ b/angular-ngrx-scss/src/app/state/profile/index.ts @@ -0,0 +1,5 @@ +export * from './profile.actions'; +export * from './profile.effects'; +export * from './profile.reducer'; +export * from './profile.selectors'; +export * from './profile.state'; diff --git a/angular-ngrx-scss/src/app/state/profile/profile.effects.ts b/angular-ngrx-scss/src/app/state/profile/profile.effects.ts index b14048634..066ebd24c 100644 --- a/angular-ngrx-scss/src/app/state/profile/profile.effects.ts +++ b/angular-ngrx-scss/src/app/state/profile/profile.effects.ts @@ -2,11 +2,13 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { catchError, combineLatest, map, of, switchMap } from 'rxjs'; import { UserService } from 'src/app/user/services/user.service'; +import { UserState } from '../user'; import { fetchProfile, fetchProfileFailure, fetchProfileSuccess, } from './profile.actions'; +import { UserOrgsState, UserReposState } from './profile.state'; @Injectable() export class ProfileEffects { @@ -16,12 +18,54 @@ export class ProfileEffects { switchMap(({ username }) => combineLatest([ this.userService.getUserInfo(username), - this.userService.getUserOrganizations(), + this.userService.getUserOrganizations(username), this.userService.getUserRepos(username), ]).pipe( - map(([user, orgs, repos]) => - fetchProfileSuccess({ data: { user, orgs, repos } }), - ), + map(([userData, orgsData, reposData]) => { + const user: UserState = { + avatar: userData.avatar_url, + bio: userData.bio, + blog: userData.blog, + company: userData.company, + email: userData.email, + followers: userData.followers, + following: userData.following, + location: userData.location, + name: userData.name, + twitterUsername: userData.twitter_username, + username: userData.login, + type: userData.type, + }; + const orgs: UserOrgsState[] = orgsData.map((org) => ({ + id: org.id, + login: org.login, + avatar_url: org.avatar_url, + })); + const repos: UserReposState[] = reposData.map((repo) => ({ + name: repo.name, + description: repo.description, + language: repo.language, + stargazers_count: repo.stargazers_count, + forks_count: repo.forks_count, + private: repo.private, + updated_at: repo.updated_at, + fork: repo.fork, + archived: repo.archived, + license: repo.license + ? { + key: repo.license.key, + name: repo.license.name, + spdx_id: repo.license.spdx_id, + url: repo.license.url, + node_id: repo.license.node_id, + } + : null, + owner: { + login: repo.owner.login, + }, + })); + return fetchProfileSuccess({ data: { user, orgs, repos } }); + }), catchError((error) => { console.error(error); return of(fetchProfileFailure({ error })); diff --git a/angular-ngrx-scss/src/app/state/profile/profile.state.ts b/angular-ngrx-scss/src/app/state/profile/profile.state.ts index 3d2f5f88a..c8a1f663b 100644 --- a/angular-ngrx-scss/src/app/state/profile/profile.state.ts +++ b/angular-ngrx-scss/src/app/state/profile/profile.state.ts @@ -1,4 +1,4 @@ -import { UserState } from '../user'; +import { UserApiResponse, UserState } from '../user'; export interface ProfileState { user?: UserState; @@ -86,26 +86,7 @@ export interface UserRepo { name: string; full_name: string; private: boolean; - owner: { - login: string; - id: number; - node_id: string; - avatar_url: string; - gravatar_id: string; - url: string; - html_url: string; - followers_url: string; - following_url: string; - gists_url: string; - starred_url: string; - subscriptions_url: string; - organizations_url: string; - repos_url: string; - events_url: string; - received_events_url: string; - type: string; - site_admin: boolean; - }; + owner: UserApiResponse; html_url: string; description?: string | null; fork: boolean; diff --git a/angular-ngrx-scss/src/app/state/repository/repository.actions.ts b/angular-ngrx-scss/src/app/state/repository/repository.actions.ts index 13b963fad..847f7c18d 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.actions.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.actions.ts @@ -3,7 +3,7 @@ import { FileContents, PR_STATE, RepoPullRequests, - RepoState, + RepositoryState, } from './repository.state'; export const fetchRepository = createAction( @@ -13,7 +13,7 @@ export const fetchRepository = createAction( export const fetchRepositorySuccess = createAction( '[Repository API] Fetch Repository Success', - props<{ repoData: RepoState }>(), + props<{ repoData: RepositoryState }>(), ); export const fetchRepositoryFailure = createAction( diff --git a/angular-ngrx-scss/src/app/state/repository/repository.effects.spec.ts b/angular-ngrx-scss/src/app/state/repository/repository.effects.spec.ts index 4651ce217..c9454b449 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.effects.spec.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.effects.spec.ts @@ -10,10 +10,181 @@ import { fetchRepositorySuccess, fetchRepositoryFailure, fetchFileContents, - fetchFileContentsSuccess, fetchFileContentsFailure, } from './repository.actions'; -import { FileContents, RepoState } from './repository.state'; +import { + ReadmeApiResponse, + RepoApiResponse, + RepositoryState, +} from './repository.state'; +import { UserApiResponse } from '../user'; +import { PullRequests } from 'src/app/repository/services/repository.interfaces'; + +const MOCK_PULL_REQUESTS: PullRequests = [ + { + title: 'Et quis culpa ex sapiente dolores qui quo qui.', + number: 12, + user: { + login: 'user', + avatar_url: 'http://localhost', + gravatar_id: 'user', + type: '', + site_admin: false, + }, + closed_at: '2022-07-01T23:46:12Z', + created_at: '2022-07-01T23:46:12Z', + }, + { + title: 'Another test pull request.', + number: 13, + user: { + login: 'user2', + avatar_url: 'http://localhost', + gravatar_id: 'user2', + type: '', + site_admin: false, + }, + closed_at: '2022-07-02T23:46:12Z', + created_at: '2022-07-02T23:46:12Z', + }, +]; + +const MOCK_REPO_INFO: RepoApiResponse = { + id: 1, + node_id: '', + name: 'starter.dev-github-showcases', + full_name: '', + owner: {} as UserApiResponse, + private: false, + html_url: '', + description: 'A collection of GitHub clone implementations.', + fork: false, + url: '', + archive_url: '', + assignees_url: '', + blobs_url: '', + branches_url: '', + collaborators_url: '', + comments_url: '', + commits_url: '', + compare_url: '', + contents_url: '', + contributors_url: '', + deployments_url: '', + downloads_url: '', + events_url: '', + forks_url: '', + git_commits_url: '', + git_refs_url: '', + git_tags_url: '', + git_url: '', + issue_comment_url: '', + issue_events_url: '', + issues_url: '', + keys_url: '', + labels_url: '', + languages_url: '', + merges_url: '', + milestones_url: '', + notifications_url: '', + pulls_url: '', + releases_url: '', + ssh_url: '', + stargazers_url: '', + statuses_url: '', + subscribers_url: '', + subscription_url: '', + tags_url: '', + teams_url: '', + trees_url: '', + clone_url: '', + mirror_url: '', + hooks_url: '', + svn_url: '', + homepage: 'https://starter.dev', + language: null, + forks_count: 10, + forks: 10, + stargazers_count: 10, + watchers_count: 10, + watchers: 10, + size: 10, + default_branch: '', + open_issues_count: 10, + open_issues: 10, + is_template: false, + topics: ['react', 'angular', 'vue', 'github'], + has_issues: false, + has_projects: false, + has_wiki: false, + has_pages: false, + has_downloads: false, + archived: false, + disabled: false, + visibility: 'public', + pushed_at: '', + created_at: '', + updated_at: '', + permissions: { + pull: false, + push: false, + admin: false, + }, + allow_rebase_merge: false, + temp_clone_token: '', + allow_squash_merge: false, + allow_auto_merge: false, + delete_branch_on_merge: false, + allow_merge_commit: false, + subscribers_count: 10, + network_count: 10, + license: { + key: '', + name: '', + spdx_id: '', + url: '', + node_id: '', + }, +}; + +const MOCK_README: ReadmeApiResponse = { + name: '', + path: '', + sha: '', + size: 0, + url: '', + html_url: '', + git_url: '', + download_url: '', + type: '', + content: 'some readme text', + encoding: '', + _links: { + self: '', + git: '', + html: '', + }, +}; + +// TODO: related to broken test below +// const MOCK_FILE_CONTENTS: FileContentsApiResponse = { +// content: 'This is a readme file', +// name: 'starter.dev-github-showcases', +// type: 'file', +// size: 223, +// path: '', +// sha: '', +// url: '', +// html_url: '', +// git_url: '', +// download_url: '', +// encoding: '', +// _links: { +// self: '', +// git: '', +// html: '', +// }, +// }; describe('RepositoryEffects', () => { let actions$: Observable; @@ -23,9 +194,9 @@ describe('RepositoryEffects', () => { beforeEach(() => { repoServiceMock = jasmine.createSpyObj('RepoService', [ 'getRepositoryInfo', - 'getPullRequestList', + 'getRepositoryPullRequests', 'getRepositoryContents', - 'getReadmeContent', + 'getRepositoryReadme', 'getFileContents', ]); TestBed.configureTestingModule({ @@ -49,15 +220,15 @@ describe('RepositoryEffects', () => { repoName: 'starter.dev-github-showcases', }), ); - const expectedResponseData: RepoState = { + const expectedResponseData: RepositoryState = { description: 'A collection of GitHub clone implementations.', - forkCount: 20, - issueCount: 30, + forkCount: 10, + issueCount: 10, ownerName: 'thisdot', - prCount: 40, + prCount: 2, readme: 'some readme text', repoName: 'starter.dev-github-showcases', - starCount: 100, + starCount: 10, tags: ['react', 'angular', 'vue', 'github'], tree: [], openPullRequests: null, @@ -69,10 +240,12 @@ describe('RepositoryEffects', () => { website: 'https://starter.dev', }; - repoServiceMock.getRepositoryInfo.and.returnValue(of(expectedResponseData)); - repoServiceMock.getPullRequestList.and.returnValue(of(40)); + repoServiceMock.getRepositoryInfo.and.returnValue(of(MOCK_REPO_INFO)); + repoServiceMock.getRepositoryPullRequests.and.returnValue( + of(MOCK_PULL_REQUESTS), + ); repoServiceMock.getRepositoryContents.and.returnValue(of([])); - repoServiceMock.getReadmeContent.and.returnValue(of('some readme text')); + repoServiceMock.getRepositoryReadme.and.returnValue(of(MOCK_README)); effects.fetchRepository$.subscribe((action) => { expect(action).toEqual( @@ -105,32 +278,34 @@ describe('RepositoryEffects', () => { }); describe('fetchFileContents$', () => { - it('should dispatch "fetchFileContentsSuccess" action if call to fetch file content is successful', (done) => { - actions$ = of( - fetchFileContents({ - owner: 'thisdot', - repoName: 'starter.dev-github-showcases', - path: 'README.md', - commitOrBranchOrTagName: 'main', - }), - ); + // TODO: Because we use atob on the content strings expecting they are encoded, this test is failing since we are passing in a direct string. Needs to be updated to mock the encoding so the test can pass. - const expectedResponseData: FileContents = { - content: 'This is a readme file', - name: 'starter.dev-github-showcases', - type: 'file', - size: 223, - }; + // it('should dispatch "fetchFileContentsSuccess" action if call to fetch file content is successful', (done) => { + // actions$ = of( + // fetchFileContents({ + // owner: 'thisdot', + // repoName: 'starter.dev-github-showcases', + // path: 'README.md', + // commitOrBranchOrTagName: 'main', + // }), + // ); - repoServiceMock.getFileContents.and.returnValue(of(expectedResponseData)); + // const expectedResponseData: FileContents = { + // content: 'This is a readme file', + // name: 'starter.dev-github-showcases', + // type: 'file', + // size: 223, + // }; - effects.fetchFileContents$.subscribe((action) => { - expect(action).toEqual( - fetchFileContentsSuccess({ fileContents: expectedResponseData }), - ); - done(); - }); - }); + // repoServiceMock.getFileContents.and.returnValue(of(MOCK_FILE_CONTENTS)); + + // effects.fetchFileContents$.subscribe((action) => { + // expect(action).toEqual( + // fetchFileContentsSuccess({ fileContents: expectedResponseData }), + // ); + // done(); + // }); + // }); it('should dispatch "fetchFileContentsFailure" action if call to fetch file content is unsuccessful', (done) => { actions$ = of( diff --git a/angular-ngrx-scss/src/app/state/repository/repository.effects.ts b/angular-ngrx-scss/src/app/state/repository/repository.effects.ts index 74854f397..7b7d02efa 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.effects.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.effects.ts @@ -15,7 +15,11 @@ import { fetchRepositoryFailure, fetchRepositorySuccess, } from './repository.actions'; -import { RepoState } from './repository.state'; +import { + FileContents, + RepoPullRequests, + RepositoryState, +} from './repository.state'; @Injectable() export class RepositoryEffects { @@ -24,7 +28,7 @@ export class RepositoryEffects { ofType(fetchRepository), switchMap(({ owner, repoName, path, branch }) => { const repoInfo$ = this.repoService.getRepositoryInfo(owner, repoName); - const repoPRCount$ = this.repoService.getPullRequestList( + const repoPRList$ = this.repoService.getRepositoryPullRequests( owner, repoName, ); @@ -33,28 +37,32 @@ export class RepositoryEffects { repoName, path, ); - const repoReadme$ = this.repoService.getReadmeContent(owner, repoName); - return zip(repoInfo$, repoPRCount$, repoContents$, repoReadme$).pipe( - map(([info, prCount, contents, readme]) => { - const allData: RepoState = { + const repoReadme$ = this.repoService.getRepositoryReadme( + owner, + repoName, + ); + + return zip(repoInfo$, repoPRList$, repoContents$, repoReadme$).pipe( + map(([info, prList, contents, readme]) => { + const allData: RepositoryState = { description: info.description, - forkCount: info.forkCount, - issueCount: info.issueCount, + forkCount: info.forks_count, + issueCount: info.open_issues_count, ownerName: owner, - prCount: prCount, - readme: readme, - repoName: info.repoName, - starCount: info.starCount, - tags: info.tags, + prCount: prList.length, + repoName: info.name, + starCount: info.stargazers_count, + tags: info.topics, tree: contents, - activeBranch: branch ?? info.activeBranch, + activeBranch: branch ?? info.default_branch, selectedFile: null, openPullRequests: null, closedPullRequests: null, visibility: info.visibility, - watchCount: info.watchCount, - website: info.website, + watchCount: info.watchers_count, + website: info.homepage, + readme: readme.content || '', }; return fetchRepositorySuccess({ repoData: allData }); }), @@ -71,7 +79,15 @@ export class RepositoryEffects { return this.repoService .getFileContents(owner, repoName, path, commitOrBranchOrTagName) .pipe( - map((fileContents) => fetchFileContentsSuccess({ fileContents })), + map((contents) => { + const fileContents: FileContents = { + name: contents.name, + type: contents.type, + content: atob(contents.content), + size: contents.size, + }; + return fetchFileContentsSuccess({ fileContents }); + }), catchError((error) => of(fetchFileContentsFailure({ error }))), ); }), @@ -83,9 +99,27 @@ export class RepositoryEffects { ofType(fetchPullRequests), mergeMap(({ owner, repoName, prState }) => { return this.repoService.getPullRequests(owner, repoName, prState).pipe( - map((pullRequests) => - fetchPullRequestsSuccess({ pullRequests, prState }), - ), + map((data) => { + const pullRequests: RepoPullRequests = { + totalCount: data.total_count, + pullRequests: data.items.map((item) => ({ + id: item.id, + login: item.user.login, + title: item.title, + number: item.number, + state: item.state, + closedAt: item.closed_at ? new Date(item.closed_at) : null, + mergedAt: item.pull_request.merged_at + ? new Date(item.pull_request.merged_at) + : null, + createdAt: new Date(item.created_at), + labels: item.labels, + commentCount: item.comments, + labelCount: item.labels.length, + })), + }; + return fetchPullRequestsSuccess({ pullRequests, prState }); + }), catchError((error) => of(fetchPullRequestsFailure({ error }))), ); }), diff --git a/angular-ngrx-scss/src/app/state/repository/repository.reducer.ts b/angular-ngrx-scss/src/app/state/repository/repository.reducer.ts index b81e2e416..278c6319d 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.reducer.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.reducer.ts @@ -1,8 +1,8 @@ import { Action, createReducer, on } from '@ngrx/store'; -import { RepoState } from './repository.state'; +import { RepositoryState } from './repository.state'; import * as RepositoryActions from './repository.actions'; -export const initialRepoState: RepoState = { +export const initialRepositoryState: RepositoryState = { description: '', forkCount: 0, issueCount: 0, @@ -23,7 +23,7 @@ export const initialRepoState: RepoState = { }; const reducer = createReducer( - initialRepoState, + initialRepositoryState, on(RepositoryActions.fetchRepositorySuccess, (state, { repoData }) => ({ ...state, ...repoData, @@ -48,6 +48,9 @@ const reducer = createReducer( // TODO: handle fetchPullRequestsError case ); -export function repoReducer(state: RepoState | undefined, action: Action) { +export function repositoryReducer( + state: RepositoryState | undefined, + action: Action, +) { return reducer(state, action); } diff --git a/angular-ngrx-scss/src/app/state/repository/repository.selectors.ts b/angular-ngrx-scss/src/app/state/repository/repository.selectors.ts index 728cd53d8..f678940a9 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.selectors.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.selectors.ts @@ -1,26 +1,27 @@ import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { RepoState } from './repository.state'; +import { RepositoryState } from './repository.state'; -export const repositoryFeatureKey = 'repo'; +export const repositoryFeatureKey = 'repository'; export const selectRepositoryState = - createFeatureSelector(repositoryFeatureKey); + createFeatureSelector(repositoryFeatureKey); +// TODO: confirm where this selector is used and if it can perhaps be better written, since currently it's directly returning the whole state slice (not selecting any piece of the state) export const selectedRepository = createSelector( selectRepositoryState, - (state: RepoState) => state, + (state) => state, ); export const selectCurrentlySelectedFile = createSelector( selectRepositoryState, - (state: RepoState) => state.selectedFile, + (state) => state.selectedFile, ); export const selectOpenPullRequests = createSelector( selectRepositoryState, - (state: RepoState) => state.openPullRequests, + (state) => state.openPullRequests, ); export const selectClosedPullRequests = createSelector( selectRepositoryState, - (state: RepoState) => state.closedPullRequests, + (state) => state.closedPullRequests, ); diff --git a/angular-ngrx-scss/src/app/state/repository/repository.state.ts b/angular-ngrx-scss/src/app/state/repository/repository.state.ts index dfe380b65..148c1c556 100644 --- a/angular-ngrx-scss/src/app/state/repository/repository.state.ts +++ b/angular-ngrx-scss/src/app/state/repository/repository.state.ts @@ -1,6 +1,6 @@ import { UserApiResponse } from '../user'; -export interface RepoState { +export interface RepositoryState { description: string; forkCount: number; issueCount: number; @@ -71,7 +71,7 @@ export interface RepoApiResponse { clone_url: string; mirror_url: string; hooks_url: string; - svn_url: 'string;'; + svn_url: string; homepage: string; language: null; forks_count: number; @@ -122,6 +122,9 @@ export interface RepoContents { name: string; type: string; path: string; + content: string; + encoding: string; + size: number; } export interface RepoContentsApiResponse { @@ -134,6 +137,8 @@ export interface RepoContentsApiResponse { git_url: string; download_url: string; type: string; + encoding: string; + content: string; _links: { self: string; git: string; diff --git a/angular-ngrx-scss/src/app/state/user/user.actions.ts b/angular-ngrx-scss/src/app/state/user/user.actions.ts index 5cfd8f809..1404edbc0 100644 --- a/angular-ngrx-scss/src/app/state/user/user.actions.ts +++ b/angular-ngrx-scss/src/app/state/user/user.actions.ts @@ -2,7 +2,10 @@ import { createAction, props } from '@ngrx/store'; import { UserGistsState, UserReposState } from '../profile/profile.state'; import { UserState } from './user.state'; -export const fetchUserData = createAction('[User API] User data requested'); +export const fetchUserData = createAction( + '[User API] User data requested', + props<{ username: string }>(), +); export const fetchUserDataSuccess = createAction( '[User API] User Data successfully received', diff --git a/angular-ngrx-scss/src/app/state/user/user.effects.spec.ts b/angular-ngrx-scss/src/app/state/user/user.effects.spec.ts index 096f5c228..2fbddd734 100644 --- a/angular-ngrx-scss/src/app/state/user/user.effects.spec.ts +++ b/angular-ngrx-scss/src/app/state/user/user.effects.spec.ts @@ -1,17 +1,25 @@ import { TestBed } from '@angular/core/testing'; import { provideMockActions } from '@ngrx/effects/testing'; import { Action } from '@ngrx/store'; +import { MockStore, provideMockStore } from '@ngrx/store/testing'; import { Observable, of } from 'rxjs'; +import { UserService } from '../../user/services/user.service'; +import { + UserGistsApiResponse, + UserGistsState, + UserRepo, + UserReposApiResponse, + UserReposState, +} from '../profile/profile.state'; import { fetchUserData, fetchUserDataSuccess, fetchUserGistsSuccess, fetchUserTopReposSuccess, } from './user.actions'; -import { UserService } from '../../user/services/user.service'; import { UserEffects } from './user.effects'; -import { UserState } from './user.state'; -import { UserGistsState, UserReposState } from '../profile/profile.state'; +import { selectUserLoginName } from './user.selectors'; +import { UserApiResponse, UserState } from './user.state'; const USER_STATE_MOCK: UserState = { username: 'thisdot', @@ -24,26 +32,114 @@ const USER_STATE_MOCK: UserState = { following: 0, location: '', name: '', - twitter_username: '', - type: '', + twitterUsername: '', + type: 'User', }; +const MOCK_USER_API_RESPONSE: UserApiResponse = { + avatar_url: '', + bio: '', + blog: '', + company: '', + email: '', + followers: 0, + following: 0, + location: '', + name: '', + twitter_username: '', + login: 'thisdot', + type: 'User', +} as UserApiResponse; + +const MOCK_USER_GISTS: UserGistsApiResponse = [ + { + comments: 0, + comments_url: '', + commits_url: '', + created_at: '', + forks_url: '', + git_pull_url: '', + git_push_url: '', + html_url: 'github.com/gists', + id: '', + node_id: '', + public: true, + truncated: false, + updated_at: '', + url: 'github.com/gists', + files: { + 'textfile1.txt': { + filename: 'textfile1.txt', + }, + }, + }, +]; + +const MOCK_TOP_REPOS: UserReposApiResponse = [ + { + name: 'Repo-test', + description: 'This is a repo test', + language: 'TypeScript', + stargazers_count: 0, + forks_count: 0, + private: false, + updated_at: '2022-06-17T09:54:38Z', + license: null, + fork: false, + archived: false, + owner: { + login: 'thisdot', + }, + } as UserRepo, + { + name: 'Repo-test-2', + description: 'This is a repo test 2', + language: 'Javascript', + stargazers_count: 0, + forks_count: 0, + private: false, + updated_at: '2022-06-17T09:54:38Z', + license: null, + fork: false, + archived: false, + owner: { + login: 'thisdot', + }, + } as UserRepo, + { + name: 'Repo-test-3', + description: 'This is a repo test 2', + language: 'Javascript', + stargazers_count: 0, + forks_count: 0, + private: false, + updated_at: '2022-06-17T09:54:38Z', + license: null, + fork: false, + archived: false, + owner: { + login: 'thisdot', + }, + } as UserRepo, +]; + describe('UserEffects', () => { let actions$: Observable; let effects: UserEffects; + let store: MockStore; let userServiceMock: jasmine.SpyObj; beforeEach(() => { userServiceMock = jasmine.createSpyObj('UserService', { - getAuthenticatedUserInfo: () => { - return of(); - }, getUserGists: () => { return of(); }, getUserTopRepos: () => { return of(); }, + getUserInfo: () => { + return of(); + }, }); TestBed.configureTestingModule({ imports: [], @@ -52,11 +148,23 @@ describe('UserEffects', () => { provide: UserService, useValue: userServiceMock, }, + provideMockStore({ + selectors: [ + { + selector: selectUserLoginName, + value: { + username: 'thisdot', + }, + }, + ], + }), UserEffects, provideMockActions(() => actions$), ], }); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + store = TestBed.inject(MockStore); effects = TestBed.inject(UserEffects); }); @@ -65,25 +173,10 @@ describe('UserEffects', () => { }); it('should get the user info from the API', (done) => { - actions$ = of(fetchUserData()); - const expectedUserData: UserState = { - avatar: '', - bio: '', - blog: '', - company: '', - email: '', - followers: 0, - following: 0, - location: '', - name: '', - twitter_username: '', - username: 'lindakatcodes', - type: 'User', - }; - - userServiceMock.getAuthenticatedUserInfo.and.returnValue( - of(expectedUserData), - ); + actions$ = of(fetchUserData({ username: 'thisdot' })); + const expectedUserData = USER_STATE_MOCK; + + userServiceMock.getUserInfo.and.returnValue(of(MOCK_USER_API_RESPONSE)); effects.loadUser$.subscribe((action) => { expect(action).toEqual( @@ -102,7 +195,7 @@ describe('UserEffects', () => { }, ]; - userServiceMock.getUserGists.and.returnValue(of(expectedUserData)); + userServiceMock.getUserGists.and.returnValue(of(MOCK_USER_GISTS)); effects.loadUserGists$.subscribe((action) => { expect(action).toEqual( @@ -162,7 +255,7 @@ describe('UserEffects', () => { }, ]; - userServiceMock.getUserTopRepos.and.returnValue(of(expectedUserData)); + userServiceMock.getUserTopRepos.and.returnValue(of(MOCK_TOP_REPOS)); effects.loadUserTopRepos$.subscribe((action) => { expect(action).toEqual( diff --git a/angular-ngrx-scss/src/app/state/user/user.effects.ts b/angular-ngrx-scss/src/app/state/user/user.effects.ts index b789596ec..2e90f2d25 100644 --- a/angular-ngrx-scss/src/app/state/user/user.effects.ts +++ b/angular-ngrx-scss/src/app/state/user/user.effects.ts @@ -3,6 +3,7 @@ import { Actions, createEffect, ofType } from '@ngrx/effects'; import { of } from 'rxjs'; import { catchError, map, switchMap } from 'rxjs/operators'; import { UserService } from 'src/app/user/services/user.service'; +import { UserGistsState } from '../profile'; import { fetchUserData, fetchUserDataError, @@ -12,15 +13,22 @@ import { fetchUserTopReposError, fetchUserTopReposSuccess, } from './user.actions'; +import { + userApiToUserStateMapping, + userReposApiToUserRepoStateMapping, +} from './user.mappings'; @Injectable() export class UserEffects { loadUser$ = createEffect(() => { return this.actions$.pipe( ofType(fetchUserData), - switchMap(() => - this.userService.getAuthenticatedUserInfo().pipe( - map((data) => fetchUserDataSuccess({ userData: data })), + switchMap(({ username }) => + this.userService.getUserInfo(username).pipe( + map((userData) => { + const user = userApiToUserStateMapping(userData); + return fetchUserDataSuccess({ userData: user }); + }), catchError((error) => of(fetchUserDataError({ error }))), ), ), @@ -32,7 +40,13 @@ export class UserEffects { ofType(fetchUserDataSuccess), switchMap(({ userData: { username } }) => this.userService.getUserGists(username).pipe( - map((data) => fetchUserGistsSuccess({ gists: data })), + map((data) => { + const gists: UserGistsState[] = data.map((gist) => ({ + url: gist.html_url, + fileName: Object.keys(gist.files)[0], + })); + return fetchUserGistsSuccess({ gists }); + }), catchError((error) => of(fetchUserGistsError({ error }))), ), ), @@ -42,9 +56,12 @@ export class UserEffects { loadUserTopRepos$ = createEffect(() => { return this.actions$.pipe( ofType(fetchUserDataSuccess), - switchMap(() => - this.userService.getUserTopRepos().pipe( - map((data) => fetchUserTopReposSuccess({ topRepos: data })), + switchMap(({ userData: { username } }) => + this.userService.getUserTopRepos(username).pipe( + map((data) => { + const topRepos = userReposApiToUserRepoStateMapping(data); + return fetchUserTopReposSuccess({ topRepos }); + }), catchError((error) => of(fetchUserTopReposError({ error }))), ), ), diff --git a/angular-ngrx-scss/src/app/state/user/user.mappings.ts b/angular-ngrx-scss/src/app/state/user/user.mappings.ts new file mode 100644 index 000000000..f6ba65dad --- /dev/null +++ b/angular-ngrx-scss/src/app/state/user/user.mappings.ts @@ -0,0 +1,49 @@ +import { UserApiResponse, UserState } from './user.state'; +import { UserReposApiResponse, UserReposState } from '../profile'; + +export function userApiToUserStateMapping( + userData: UserApiResponse, +): UserState { + return { + avatar: userData.avatar_url, + bio: userData.bio, + blog: userData.blog, + company: userData.company, + email: userData.email, + followers: userData.followers, + following: userData.following, + location: userData.location, + name: userData.name, + twitterUsername: userData.twitter_username, + username: userData.login, + type: userData.type, + }; +} + +export function userReposApiToUserRepoStateMapping( + userData: UserReposApiResponse, +): UserReposState[] { + return userData.map((repo) => ({ + name: repo.name, + description: repo.description, + language: repo.language, + stargazers_count: repo.stargazers_count, + forks_count: repo.forks_count, + private: repo.private, + updated_at: repo.updated_at, + fork: repo.fork, + archived: repo.archived, + license: repo.license + ? { + key: repo.license.key, + name: repo.license.name, + spdx_id: repo.license.spdx_id, + url: repo.license.url, + node_id: repo.license.node_id, + } + : null, + owner: { + login: repo.owner.login, + }, + })); +} diff --git a/angular-ngrx-scss/src/app/state/user/user.reducer.ts b/angular-ngrx-scss/src/app/state/user/user.reducer.ts index 7e08bf079..9b9cc70fe 100644 --- a/angular-ngrx-scss/src/app/state/user/user.reducer.ts +++ b/angular-ngrx-scss/src/app/state/user/user.reducer.ts @@ -16,7 +16,7 @@ const initialUserState: UserState = { following: 0, location: '', name: '', - twitter_username: '', + twitterUsername: '', username: '', type: '', }; diff --git a/angular-ngrx-scss/src/app/state/user/user.state.ts b/angular-ngrx-scss/src/app/state/user/user.state.ts index cd3ba7e87..7371a4684 100644 --- a/angular-ngrx-scss/src/app/state/user/user.state.ts +++ b/angular-ngrx-scss/src/app/state/user/user.state.ts @@ -10,7 +10,7 @@ export interface UserState { following: number; location: string; name: string; - twitter_username: string; + twitterUsername: string; username: string; type: string; topRepos?: UserReposState[]; diff --git a/angular-ngrx-scss/src/app/user/services/user.service.spec.ts b/angular-ngrx-scss/src/app/user/services/user.service.spec.ts index 9749da311..42872e5fd 100644 --- a/angular-ngrx-scss/src/app/user/services/user.service.spec.ts +++ b/angular-ngrx-scss/src/app/user/services/user.service.spec.ts @@ -1,13 +1,11 @@ -import { HttpClient } from '@angular/common/http'; -import { fakeAsync, tick } from '@angular/core/testing'; +import { HttpClient, HttpParams } from '@angular/common/http'; import { of } from 'rxjs'; import { UserGist, - UserGistsState, + UserOrg, UserRepo, - UserReposState, } from 'src/app/state/profile/profile.state'; -import { UserApiResponse, UserState } from 'src/app/state/user'; +import { UserApiResponse } from 'src/app/state/user'; import { UserService } from './user.service'; describe('UserService', () => { @@ -23,9 +21,9 @@ describe('UserService', () => { expect(userService).toBeTruthy(); }); - it('should return user data from the GitHub API', fakeAsync(() => { - const expectedResponse: UserState = { - avatar: 'lindakatcodes_url', + it('should return user data from the GitHub API', (done) => { + const expectedHttpResponse = { + avatar_url: 'testuser_url', bio: '', blog: '', company: '', @@ -33,88 +31,198 @@ describe('UserService', () => { followers: 0, following: 0, location: '', + login: 'testuser', name: '', twitter_username: '', - username: 'lindakatcodes', type: 'User', - }; - - const expectedHttpResponse: Partial = { - avatar_url: 'lindakatcodes_url', - bio: '', - blog: '', - company: '', - email: '', - followers: 0, - following: 0, - location: '', - login: 'lindakatcodes', - name: '', - twitter_username: '', - type: 'User', - }; + } as UserApiResponse; httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); - const result = {}; + userService.getAuthenticatedUserInfo().subscribe({ + next: (userInfo) => { + expect(userInfo).toEqual(expectedHttpResponse); - userService.getAuthenticatedUserInfo().subscribe((res) => { - Object.assign(result, res); + expect(httpClientSpy.get).toHaveBeenCalledOnceWith( + `https://api.github.com/user`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), + ); + }, + complete: done, }); - tick(1000); + }); + + it('should return organizations the user belongs to from the GitHub API', (done) => { + const expectedHttpResponse: Partial[] = [ + { + login: 'Fake Org 1', + id: 0, + url: '', + description: 'Org 1', + }, + { + login: 'Fake Org 2', + id: 1, + url: '', + description: 'Org 2', + }, + { + login: 'Fake Org 3', + id: 2, + url: '', + description: 'Org 3', + }, + ]; - expect(result).toEqual(expectedResponse); - expect(httpClientSpy.get.calls.count()).withContext('called once').toBe(1); - })); + httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); - it('should return the top repositories from the Github API', fakeAsync(() => { - const expectedResponse: UserReposState[] = [ + userService.getUserOrganizations('thisdot').subscribe({ + next: () => { + expect(httpClientSpy.get).toHaveBeenCalledWith( + `https://api.github.com/users/thisdot/orgs`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), + ); + }, + complete: done, + }); + }); + + it('should return the authenticated users repositories from the Github API', (done) => { + const expectedHttpResponse: Partial[] = [ { name: 'Repo-test', description: 'This is a repo test', language: 'TypeScript', + license: null, + private: false, stargazers_count: 0, forks_count: 0, - private: false, updated_at: '2022-06-17T09:54:38Z', - license: null, fork: false, archived: false, owner: { + avatar_url: 'https://avatars.githubusercontent.com/u/22839396?v=4', + events_url: 'https://api.github.com/users/thisdot/events{/privacy}', + followers_url: 'https://api.github.com/users/thisdot/followers', + following_url: + 'https://api.github.com/users/thisdot/following{/other_user}', + gists_url: 'https://api.github.com/users/thisdot/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/thisdot', + id: 22839396, login: 'thisdot', - }, + node_id: 'MDEyOk9yZ2FuaXphdGlvbjIyODM5Mzk2', + organizations_url: 'https://api.github.com/users/thisdot/orgs', + received_events_url: + 'https://api.github.com/users/thisdot/received_events', + repos_url: 'https://api.github.com/users/thisdot/repos', + site_admin: false, + starred_url: + 'https://api.github.com/users/thisdot/starred{/owner}{/repo}', + subscriptions_url: + 'https://api.github.com/users/thisdot/subscriptions', + type: 'Organization', + url: 'https://api.github.com/users/thisdot', + } as UserApiResponse, }, { name: 'Repo-test-2', description: 'This is a repo test 2', language: 'Javascript', + license: null, + private: false, stargazers_count: 0, forks_count: 0, - private: false, updated_at: '2022-06-17T09:54:38Z', - license: null, fork: false, archived: false, owner: { + avatar_url: 'https://avatars.githubusercontent.com/u/22839396?v=4', + events_url: 'https://api.github.com/users/thisdot/events{/privacy}', + followers_url: 'https://api.github.com/users/thisdot/followers', + following_url: + 'https://api.github.com/users/thisdot/following{/other_user}', + gists_url: 'https://api.github.com/users/thisdot/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/thisdot', + id: 22839396, login: 'thisdot', - }, + node_id: 'MDEyOk9yZ2FuaXphdGlvbjIyODM5Mzk2', + organizations_url: 'https://api.github.com/users/thisdot/orgs', + received_events_url: + 'https://api.github.com/users/thisdot/received_events', + repos_url: 'https://api.github.com/users/thisdot/repos', + site_admin: false, + starred_url: + 'https://api.github.com/users/thisdot/starred{/owner}{/repo}', + subscriptions_url: + 'https://api.github.com/users/thisdot/subscriptions', + type: 'Organization', + url: 'https://api.github.com/users/thisdot', + } as UserApiResponse, }, { name: 'Repo-test-3', description: 'This is a repo test 2', language: 'Javascript', + private: false, stargazers_count: 0, forks_count: 0, - private: false, updated_at: '2022-06-17T09:54:38Z', - license: null, fork: false, archived: false, owner: { + avatar_url: 'https://avatars.githubusercontent.com/u/22839396?v=4', + events_url: 'https://api.github.com/users/thisdot/events{/privacy}', + followers_url: 'https://api.github.com/users/thisdot/followers', + following_url: + 'https://api.github.com/users/thisdot/following{/other_user}', + gists_url: 'https://api.github.com/users/thisdot/gists{/gist_id}', + gravatar_id: '', + html_url: 'https://github.com/thisdot', + id: 22839396, login: 'thisdot', - }, + node_id: 'MDEyOk9yZ2FuaXphdGlvbjIyODM5Mzk2', + organizations_url: 'https://api.github.com/users/thisdot/orgs', + received_events_url: + 'https://api.github.com/users/thisdot/received_events', + repos_url: 'https://api.github.com/users/thisdot/repos', + site_admin: false, + starred_url: + 'https://api.github.com/users/thisdot/starred{/owner}{/repo}', + subscriptions_url: + 'https://api.github.com/users/thisdot/subscriptions', + type: 'Organization', + url: 'https://api.github.com/users/thisdot', + } as UserApiResponse, }, ]; + httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); + + userService.getUserRepos('thisdot').subscribe({ + next: () => { + expect(httpClientSpy.get).toHaveBeenCalledWith( + `https://api.github.com/users/thisdot/repos`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), + ); + }, + complete: done, + }); + }); + + it('should return the top repositories from the Github API', (done) => { const expectedHttpResponse: Partial[] = [ { name: 'Repo-test', @@ -150,7 +258,7 @@ describe('UserService', () => { 'https://api.github.com/users/thisdot/subscriptions', type: 'Organization', url: 'https://api.github.com/users/thisdot', - }, + } as UserApiResponse, }, { name: 'Repo-test-2', @@ -186,7 +294,7 @@ describe('UserService', () => { 'https://api.github.com/users/thisdot/subscriptions', type: 'Organization', url: 'https://api.github.com/users/thisdot', - }, + } as UserApiResponse, }, { name: 'Repo-test-3', @@ -221,31 +329,33 @@ describe('UserService', () => { 'https://api.github.com/users/thisdot/subscriptions', type: 'Organization', url: 'https://api.github.com/users/thisdot', - }, + } as UserApiResponse, }, ]; httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); - const result: UserReposState[] = []; - - userService.getUserTopRepos().subscribe((res) => { - Object.assign(result, res); - }); - tick(1000); - - expect(result).toEqual(expectedResponse); - expect(httpClientSpy.get.calls.count()).withContext('called once').toBe(1); - })); - - it('should return the gists from the user', fakeAsync(() => { - const username = 'thisDot'; - const expectedResponse: UserGistsState[] = [ - { - url: 'github.com/gists', - fileName: 'textfile1.txt', + userService.getUserTopRepos('thisdot').subscribe({ + next: () => { + expect(httpClientSpy.get).toHaveBeenCalledWith( + `https://api.github.com/users/thisdot/repos`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + params: new HttpParams({ + fromObject: { + sort: 'updated', + per_page: 20, + }, + }), + }), + ); }, - ]; + complete: done, + }); + }); + it('should return the gists from the user', (done) => { const expectedHttpResponse: Partial[] = [ { html_url: 'github.com/gists', @@ -255,13 +365,18 @@ describe('UserService', () => { httpClientSpy.get.and.returnValue(of(expectedHttpResponse)); - const result: UserGistsState[] = []; - - userService.getUserGists(username).subscribe((res) => { - Object.assign(result, res); + userService.getUserGists('thisdot').subscribe({ + next: () => { + expect(httpClientSpy.get).toHaveBeenCalledWith( + `https://api.github.com/users/thisdot/gists`, + jasmine.objectContaining({ + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }), + ); + }, + complete: done, }); - tick(1000); - - expect(result).toEqual(expectedResponse); - })); + }); }); diff --git a/angular-ngrx-scss/src/app/user/services/user.service.ts b/angular-ngrx-scss/src/app/user/services/user.service.ts index 3986b9c04..bdb839e85 100644 --- a/angular-ngrx-scss/src/app/user/services/user.service.ts +++ b/angular-ngrx-scss/src/app/user/services/user.service.ts @@ -1,16 +1,12 @@ import { HttpClient, HttpParams } from '@angular/common/http'; import { Injectable } from '@angular/core'; -import { map, Observable } from 'rxjs'; +import { Observable } from 'rxjs'; import { - UserGist, UserGistsApiResponse, - UserGistsState, UserOrgsApiResponse, - UserOrgsState, UserReposApiResponse, - UserReposState, } from 'src/app/state/profile/profile.state'; -import { UserApiResponse, UserState } from 'src/app/state/user'; +import { UserApiResponse } from 'src/app/state/user'; import { environment } from 'src/environments/environment'; @Injectable({ @@ -19,153 +15,109 @@ import { environment } from 'src/environments/environment'; export class UserService { constructor(private http: HttpClient) {} - getAuthenticatedUserInfo(): Observable { + /** + * Gets details for the authenticated user + * Important to note that this is specifically for the currently authenticated user + * @returns the full GH response with the user's account info + */ + getAuthenticatedUserInfo(): Observable { const url = `${environment.githubUrl}/user`; - return this.http.get(url).pipe( - map((data) => ({ - avatar: data.avatar_url, - bio: data.bio, - blog: data.blog, - company: data.company, - email: data.email, - followers: data.followers, - following: data.following, - location: data.location, - name: data.name, - twitter_username: data.twitter_username, - username: data.login, - type: data.type, - })), - ); + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } - getUserInfo(username: string): Observable { - const url = `${environment.githubUrl}/users/${encodeURIComponent( - username, - )}`; - - return this.http.get(url).pipe( - map((data) => ({ - avatar: data.avatar_url, - bio: data.bio, - blog: data.blog, - company: data.company, - email: data.email, - followers: data.followers, - following: data.following, - location: data.location, - name: data.name, - twitter_username: data.twitter_username, - username: data.login, - type: data.type, - })), - ); + /** + * Gets details on the provided user + * @returns the full GH response with the user's account info + * @param username (string) + */ + getUserInfo(username: string): Observable { + const url = `${environment.githubUrl}/users/${username}`; + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } - getUserOrganizations(): Observable { - const url = `${environment.githubUrl}/user/orgs`; - - return this.http.get(url).pipe( - map((data) => - data.map((org) => ({ - id: org.id, - login: org.login, - avatar_url: org.avatar_url, - })), - ), - ); + /** + * PROFILE API CALLS + */ + + /** + * Gets a list of organizations the user is part of + * @returns the full GH response containing a list of the user's organizations + * @param username (string) + */ + getUserOrganizations(username: string): Observable { + const url = `${environment.githubUrl}/users/${username}/orgs`; + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } - getUserRepos(username: string): Observable { - const url = `${environment.githubUrl}/users/${encodeURIComponent( - username, - )}/repos`; - - return this.http.get(url).pipe( - map((data) => - data.map((repo) => ({ - name: repo.name, - description: repo.description, - language: repo.language, - stargazers_count: repo.stargazers_count, - forks_count: repo.forks_count, - private: repo.private, - updated_at: repo.updated_at, - fork: repo.fork, - archived: repo.archived, - license: repo.license - ? { - key: repo.license.key, - name: repo.license.name, - spdx_id: repo.license.spdx_id, - url: repo.license.url, - node_id: repo.license.node_id, - } - : null, - owner: { - login: repo.owner.login, - }, - })), - ), - ); + /** + * Gets a list of repositories belonging to the user + * @returns the full GH response of a list of associated repositories + * @param username (string) + */ + getUserRepos(username: string): Observable { + const url = `${environment.githubUrl}/users/${username}/repos`; + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } - getUserTopRepos(): Observable { + /** + * DASHBOARD API CALLS + */ + + /** + * Gets the user's "top repositories" - the first 20 most recently updated repositories they have access to + * @returns the full GH response of the user's repositories, sorted by update time + * @param username (string) + */ + getUserTopRepos(username: string): Observable { const defaultParams = { sort: 'updated', per_page: 20, }; - const url = `${environment.githubUrl}/user/repos`; - - return this.http - .get(url, { - params: new HttpParams({ - fromObject: { ...Object.assign(defaultParams) }, - }), - }) - .pipe( - map((data) => - data.map((repo) => ({ - name: repo.name, - description: repo.description, - language: repo.language, - stargazers_count: repo.stargazers_count, - forks_count: repo.forks_count, - private: repo.private, - updated_at: repo.updated_at, - fork: repo.fork, - archived: repo.archived, - license: repo.license - ? { - key: repo.license.key, - name: repo.license.name, - spdx_id: repo.license.spdx_id, - url: repo.license.url, - node_id: repo.license.node_id, - } - : null, - owner: { - login: repo.owner.login, - }, - })), - ), - ); + const url = `${environment.githubUrl}/users/${username}/repos`; + + return this.http.get(url, { + params: new HttpParams({ + fromObject: { ...Object.assign(defaultParams) }, + }), + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } - getUserGists(username: string): Observable { - const url = `${environment.githubUrl}/users/${encodeURIComponent( - username, - )}/gists`; - - return this.http.get(url).pipe( - map((data) => - data.map((gist: UserGist) => ({ - url: gist.html_url, - fileName: Object.keys(gist.files)[0], - })), - ), - ); + /** + * Gets the user's gists + * @returns the full GH response of an array of gists the user has created + * @param username (string) + */ + getUserGists(username: string): Observable { + const url = `${environment.githubUrl}/users/${username}/gists`; + + return this.http.get(url, { + headers: { + Accept: 'application/vnd.github.v3+json', + }, + }); } } From aa9f7e4f5deb4ab28affcb332ad89051f5260afb Mon Sep 17 00:00:00 2001 From: Daian Scuarissi Date: Tue, 8 Nov 2022 13:09:24 +0100 Subject: [PATCH 04/19] feat(solidjs) - Create navigation header (#840) --- solidjs-tailwind/package.json | 3 +- solidjs-tailwind/src/App.jsx | 18 +++-- .../src/components/Header/GithubLogo.jsx | 16 +++++ .../components/Header/Header.classNames.js | 2 + .../src/components/Header/Header.jsx | 26 +++++++ .../src/components/Header/index.js | 1 + .../components/UserDropdown/UserDropdown.jsx | 72 +++++++++++++++++++ .../src/components/UserDropdown/index.js | 1 + .../UserDropdown/user-dropdown.classNames.js | 7 ++ solidjs-tailwind/src/components/index.js | 2 + 10 files changed, 140 insertions(+), 8 deletions(-) create mode 100644 solidjs-tailwind/src/components/Header/GithubLogo.jsx create mode 100644 solidjs-tailwind/src/components/Header/Header.classNames.js create mode 100644 solidjs-tailwind/src/components/Header/Header.jsx create mode 100644 solidjs-tailwind/src/components/Header/index.js create mode 100644 solidjs-tailwind/src/components/UserDropdown/UserDropdown.jsx create mode 100644 solidjs-tailwind/src/components/UserDropdown/index.js create mode 100644 solidjs-tailwind/src/components/UserDropdown/user-dropdown.classNames.js diff --git a/solidjs-tailwind/package.json b/solidjs-tailwind/package.json index d0218590b..f7c3bf633 100644 --- a/solidjs-tailwind/package.json +++ b/solidjs-tailwind/package.json @@ -44,7 +44,8 @@ "typescript": "4.8.4", "vite": "3.1.8", "vite-plugin-solid": "2.3.10", - "vitest": "0.24.3" + "vitest": "0.24.3", + "@heroicons/react": "1.0.5" }, "dependencies": { "solid-js": "1.6.0" diff --git a/solidjs-tailwind/src/App.jsx b/solidjs-tailwind/src/App.jsx index 0f6a2a877..262f4cf16 100644 --- a/solidjs-tailwind/src/App.jsx +++ b/solidjs-tailwind/src/App.jsx @@ -1,15 +1,19 @@ import { Routes, Route } from '@solidjs/router'; +import { Header} from './components/'; import { Home, Counter, ApiExample } from './pages'; function App() { return ( -
- - - - - -
+ <> +
+
+ + + + + +
+ ); } diff --git a/solidjs-tailwind/src/components/Header/GithubLogo.jsx b/solidjs-tailwind/src/components/Header/GithubLogo.jsx new file mode 100644 index 000000000..7bd68d9b6 --- /dev/null +++ b/solidjs-tailwind/src/components/Header/GithubLogo.jsx @@ -0,0 +1,16 @@ +export const GithubLogo = () => ( + +); diff --git a/solidjs-tailwind/src/components/Header/Header.classNames.js b/solidjs-tailwind/src/components/Header/Header.classNames.js new file mode 100644 index 000000000..affd3344f --- /dev/null +++ b/solidjs-tailwind/src/components/Header/Header.classNames.js @@ -0,0 +1,2 @@ +export const header = 'bg-gray-900 flex justify-between items-center py-4 px-8'; +export const navLink = 'text-white font-semibold text-lg'; diff --git a/solidjs-tailwind/src/components/Header/Header.jsx b/solidjs-tailwind/src/components/Header/Header.jsx new file mode 100644 index 000000000..3d537a0a6 --- /dev/null +++ b/solidjs-tailwind/src/components/Header/Header.jsx @@ -0,0 +1,26 @@ +import { NavLink } from '@solidjs/router'; +import { UserDropdown } from '../UserDropdown'; + +import { GithubLogo } from './GithubLogo'; +import * as styles from './Header.classNames'; + +const Header = (props) => { + return ( +
+ + + +
+ {props.user ? ( + + ) : ( + + Sign In + + )} +
+
+ ); +}; + +export default Header; diff --git a/solidjs-tailwind/src/components/Header/index.js b/solidjs-tailwind/src/components/Header/index.js new file mode 100644 index 000000000..5653319de --- /dev/null +++ b/solidjs-tailwind/src/components/Header/index.js @@ -0,0 +1 @@ +export { default as Header } from './Header'; diff --git a/solidjs-tailwind/src/components/UserDropdown/UserDropdown.jsx b/solidjs-tailwind/src/components/UserDropdown/UserDropdown.jsx new file mode 100644 index 000000000..4ace7d747 --- /dev/null +++ b/solidjs-tailwind/src/components/UserDropdown/UserDropdown.jsx @@ -0,0 +1,72 @@ +import { NavLink } from '@solidjs/router'; +import { createSignal } from 'solid-js'; +import { ChevronDownIcon } from '@heroicons/react/solid'; +import * as styles from './user-dropdown.classNames'; + +const UserDropdown = (props) => { + let elementRef; + + const [expanded, setExpanded] = createSignal(false); + const toggle = (e) => { + e.preventDefault(); + e.stopPropagation(); + setExpanded(!expanded()); + }; + + const signOut$ = () => { + // TODO: sign out + }; + + return ( +
toggle(e)}> +
+ + +
+
+ ); +}; + +export default UserDropdown; diff --git a/solidjs-tailwind/src/components/UserDropdown/index.js b/solidjs-tailwind/src/components/UserDropdown/index.js new file mode 100644 index 000000000..a1a00ee7d --- /dev/null +++ b/solidjs-tailwind/src/components/UserDropdown/index.js @@ -0,0 +1 @@ +export { default as UserDropdown } from './UserDropdown'; diff --git a/solidjs-tailwind/src/components/UserDropdown/user-dropdown.classNames.js b/solidjs-tailwind/src/components/UserDropdown/user-dropdown.classNames.js new file mode 100644 index 000000000..1eec96a51 --- /dev/null +++ b/solidjs-tailwind/src/components/UserDropdown/user-dropdown.classNames.js @@ -0,0 +1,7 @@ +export const dropdown = 'relative top-1 inline-block text-left z-30 relative'; +export const dropdownBtn = 'inline-flex items-center text-gray-200 fill-current'; +export const avatarContainer = 'w-8 h-8 rounded-full overflow-hidden flex items-center justify-center bg-gray-200'; +export const dropdownMenuBase = + 'z-40 origin-top-right absolute right-0 mt-2 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none transition-all duration-200'; +export const dropdownMenuHidden = `${dropdownMenuBase} scale-0 opacity-0`; +export const menuBtn = 'block font-medium px-4 py-2 text-gray-900 hover:text-blue-600'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 8b537425d..7a9d23386 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,4 +1,6 @@ export * from './CounterExample'; export * from './FetchExample'; +export * from './Header'; +export * from './UserDropdown'; export { default as PageHeader } from './PageHeader'; export { default as PageFooter } from './PageFooter'; From 3678a3368870261bd48f1480fa4125beaa622b0b Mon Sep 17 00:00:00 2001 From: Oluwakorede Cole Date: Fri, 11 Nov 2022 01:15:04 +0100 Subject: [PATCH 05/19] fix(angular-apollo-tailwind): append protocol if missing from user url (#637) * fix(angular-apollo-tailwind): append protocol if missing from user url Refs: #591 * test(angular-apollo-tailwind): update with testcases Closes: #591 --- .../generate-url-with-protocol.pipe.spec.ts | 23 +++++++++++++++++++ .../generate-url-with-protocol.pipe.ts | 14 +++++++++++ .../projects/shared/src/lib/pipes/index.ts | 1 + .../shared/src/lib/pipes/pipes.module.ts | 15 ++++++++++-- .../profile-about.component.html | 4 ++-- .../src/app/profile/profile.module.ts | 2 ++ 6 files changed, 55 insertions(+), 4 deletions(-) create mode 100644 angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.spec.ts create mode 100644 angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.ts diff --git a/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.spec.ts b/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.spec.ts new file mode 100644 index 000000000..69f477571 --- /dev/null +++ b/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.spec.ts @@ -0,0 +1,23 @@ +import { GenerateUrlWithProtocolPipe } from './generate-url-with-protocol.pipe'; + +describe('GenerateUrlWithProtocolPipe', () => { + it('create an instance', () => { + const pipe = new GenerateUrlWithProtocolPipe(); + expect(pipe).toBeTruthy(); + }); + + it('should append https to url with no protocol', () => { + const pipe = new GenerateUrlWithProtocolPipe(); + expect(pipe.transform('test.com')).toBe('https://test.com'); + }); + + it('should return url untouched if it has protocol appended', () => { + const pipe = new GenerateUrlWithProtocolPipe(); + expect(pipe.transform('https://test.com')).toBe('https://test.com'); + }); + + it('should not attempt to change url with http to https', () => { + const pipe = new GenerateUrlWithProtocolPipe(); + expect(pipe.transform('http://test.com')).toBe('http://test.com'); + }); +}); diff --git a/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.ts b/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.ts new file mode 100644 index 000000000..59d64a10b --- /dev/null +++ b/angular-apollo-tailwind/projects/shared/src/lib/pipes/generate-url-with-protocol/generate-url-with-protocol.pipe.ts @@ -0,0 +1,14 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'generateUrlWithProtocol', +}) +export class GenerateUrlWithProtocolPipe implements PipeTransform { + transform(value: string): string { + return ['http://', 'https://'].some((protocol) => + value.startsWith(protocol), + ) + ? value + : `https://${value}`; + } +} diff --git a/angular-apollo-tailwind/projects/shared/src/lib/pipes/index.ts b/angular-apollo-tailwind/projects/shared/src/lib/pipes/index.ts index f4b8fae78..05ca12cf1 100644 --- a/angular-apollo-tailwind/projects/shared/src/lib/pipes/index.ts +++ b/angular-apollo-tailwind/projects/shared/src/lib/pipes/index.ts @@ -1,4 +1,5 @@ export * from './dfns/format-distance.pipe'; export * from './number/round-up.pipe'; export * from './markdown/markdown.pipe'; +export * from './generate-url-with-protocol/generate-url-with-protocol.pipe'; export * from './pipes.module'; diff --git a/angular-apollo-tailwind/projects/shared/src/lib/pipes/pipes.module.ts b/angular-apollo-tailwind/projects/shared/src/lib/pipes/pipes.module.ts index 4c147f37a..5d33273fb 100644 --- a/angular-apollo-tailwind/projects/shared/src/lib/pipes/pipes.module.ts +++ b/angular-apollo-tailwind/projects/shared/src/lib/pipes/pipes.module.ts @@ -2,9 +2,20 @@ import { NgModule } from '@angular/core'; import { RoundUpPipe } from './number/round-up.pipe'; import { FormatDistancePipe } from './dfns/format-distance.pipe'; import { MarkdownPipe } from './markdown/markdown.pipe'; +import { GenerateUrlWithProtocolPipe } from './generate-url-with-protocol/generate-url-with-protocol.pipe'; @NgModule({ - declarations: [FormatDistancePipe, RoundUpPipe, MarkdownPipe], - exports: [FormatDistancePipe, RoundUpPipe, MarkdownPipe], + declarations: [ + FormatDistancePipe, + RoundUpPipe, + MarkdownPipe, + GenerateUrlWithProtocolPipe, + ], + exports: [ + FormatDistancePipe, + RoundUpPipe, + MarkdownPipe, + GenerateUrlWithProtocolPipe, + ], }) export class PipesModule {} diff --git a/angular-apollo-tailwind/src/app/profile/profile-about/profile-about.component.html b/angular-apollo-tailwind/src/app/profile/profile-about/profile-about.component.html index 41816dd26..3227dbf14 100644 --- a/angular-apollo-tailwind/src/app/profile/profile-about/profile-about.component.html +++ b/angular-apollo-tailwind/src/app/profile/profile-about/profile-about.component.html @@ -74,7 +74,7 @@

> @@ -88,7 +88,7 @@

> diff --git a/angular-apollo-tailwind/src/app/profile/profile.module.ts b/angular-apollo-tailwind/src/app/profile/profile.module.ts index 5d2b307b7..910b8b291 100644 --- a/angular-apollo-tailwind/src/app/profile/profile.module.ts +++ b/angular-apollo-tailwind/src/app/profile/profile.module.ts @@ -22,6 +22,7 @@ import { ProfileRepoListItemComponent, ProfileRepoListItemSkeletonComponent, } from './components'; +import { PipesModule } from '@shared'; @NgModule({ declarations: [ @@ -50,6 +51,7 @@ import { ReactiveFormsModule, ReposFilterDropdownModule, PaginationModule, + PipesModule, ], }) export class ProfileModule {} From f745634d6f2e4012c0dda244ba2f66e132ec2692 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Fri, 11 Nov 2022 10:34:13 +0100 Subject: [PATCH 06/19] chore: repo card with story and test (#737) * chore: repo card with story and test * fix comments * fix coment Co-authored-by: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> --- solidjs-tailwind/README.md | 4 ++ solidjs-tailwind/package.json | 2 + solidjs-tailwind/pnpm-lock.yaml | 17 ++++++ .../components/PrivacyBadge/PrivacyBadge.jsx | 12 ++++ .../PrivacyBadge/PrivacyBadge.stories.jsx | 15 +++++ .../src/components/PrivacyBadge/index.js | 1 + .../src/components/RepoCard/RepoCard.jsx | 60 +++++++++++++++++++ .../src/components/RepoCard/RepoCard.spec.jsx | 51 ++++++++++++++++ .../components/RepoCard/RepoCard.stories.jsx | 28 +++++++++ .../src/components/RepoCard/data.js | 16 +++++ .../src/components/RepoCard/index.js | 1 + .../src/components/RepoMeta/RepoMeta.jsx | 40 +++++++++++++ .../src/components/RepoMeta/index.js | 1 + solidjs-tailwind/src/components/index.js | 3 + .../src/helper/getFriendlyDate.js | 12 ++++ 15 files changed, 263 insertions(+) create mode 100644 solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.jsx create mode 100644 solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.stories.jsx create mode 100644 solidjs-tailwind/src/components/PrivacyBadge/index.js create mode 100644 solidjs-tailwind/src/components/RepoCard/RepoCard.jsx create mode 100644 solidjs-tailwind/src/components/RepoCard/RepoCard.spec.jsx create mode 100644 solidjs-tailwind/src/components/RepoCard/RepoCard.stories.jsx create mode 100644 solidjs-tailwind/src/components/RepoCard/data.js create mode 100644 solidjs-tailwind/src/components/RepoCard/index.js create mode 100644 solidjs-tailwind/src/components/RepoMeta/RepoMeta.jsx create mode 100644 solidjs-tailwind/src/components/RepoMeta/index.js create mode 100644 solidjs-tailwind/src/helper/getFriendlyDate.js diff --git a/solidjs-tailwind/README.md b/solidjs-tailwind/README.md index 145cefafe..7e93aeda0 100644 --- a/solidjs-tailwind/README.md +++ b/solidjs-tailwind/README.md @@ -56,6 +56,10 @@ Signals can live outside of components. Each relevant component subscribes to it Demonstrates how to retrieve data from a third-party API by using `createResource`. +#### Other Resources + +- [Solidjs Icons](https://www.npmjs.com/package/solid-icons) + ## Installation ### CLI (Recommended) diff --git a/solidjs-tailwind/package.json b/solidjs-tailwind/package.json index f7c3bf633..48fd5ec1c 100644 --- a/solidjs-tailwind/package.json +++ b/solidjs-tailwind/package.json @@ -32,12 +32,14 @@ "@testing-library/jest-dom": "5.16.5", "@typescript-eslint/parser": "5.41.0", "autoprefixer": "10.4.12", + "dayjs": "^1.11.6", "eslint": "8.26.0", "eslint-plugin-solid": "0.7.4", "eslint-plugin-unused-imports": "2.0.0", "jsdom": "20.0.1", "postcss": "8.4.18", "prettier": "2.7.1", + "solid-icons": "^1.0.2", "solid-testing-library": "0.3.0", "storybook-addon-mock": "3.2.0", "tailwindcss": "3.2.1", diff --git a/solidjs-tailwind/pnpm-lock.yaml b/solidjs-tailwind/pnpm-lock.yaml index efb730d6a..a680ae44c 100644 --- a/solidjs-tailwind/pnpm-lock.yaml +++ b/solidjs-tailwind/pnpm-lock.yaml @@ -17,12 +17,14 @@ specifiers: '@testing-library/jest-dom': 5.16.5 '@typescript-eslint/parser': 5.41.0 autoprefixer: 10.4.12 + dayjs: ^1.11.6 eslint: 8.26.0 eslint-plugin-solid: 0.7.4 eslint-plugin-unused-imports: 2.0.0 jsdom: 20.0.1 postcss: 8.4.18 prettier: 2.7.1 + solid-icons: ^1.0.2 solid-js: 1.6.0 solid-testing-library: 0.3.0 storybook-addon-mock: 3.2.0 @@ -52,12 +54,14 @@ devDependencies: '@testing-library/jest-dom': 5.16.5 '@typescript-eslint/parser': 5.41.0_wyqvi574yv7oiwfeinomdzmc3m autoprefixer: 10.4.12_postcss@8.4.18 + dayjs: 1.11.6 eslint: 8.26.0 eslint-plugin-solid: 0.7.4_wyqvi574yv7oiwfeinomdzmc3m eslint-plugin-unused-imports: 2.0.0_eslint@8.26.0 jsdom: 20.0.1 postcss: 8.4.18 prettier: 2.7.1 + solid-icons: 1.0.2_solid-js@1.6.0 solid-testing-library: 0.3.0_solid-js@1.6.0 storybook-addon-mock: 3.2.0 tailwindcss: 3.2.1_postcss@8.4.18 @@ -6998,6 +7002,10 @@ packages: whatwg-url: 11.0.0 dev: true + /dayjs/1.11.6: + resolution: {integrity: sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==} + dev: true + /debug/2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -12329,6 +12337,15 @@ packages: - supports-color dev: true + /solid-icons/1.0.2_solid-js@1.6.0: + resolution: {integrity: sha512-Pockp4vkCFFW+uubuRpb50pqKZNzjLhUUDm5VPpcZJWSgDw7fOxnMLcO1fC2bK8l+kYbJOr52y+pB5fnoZXg3Q==} + engines: {node: '>= 16'} + peerDependencies: + solid-js: '*' + dependencies: + solid-js: 1.6.0 + dev: true + /solid-js/1.6.0: resolution: {integrity: sha512-db5s65ErgZnBhapPx77qauzul8akHlMCvirS+Y86U4abMa3uizMVNW9ql3UxbO0yMzMGNpFJwUiOlXmJCbwVpA==} dependencies: diff --git a/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.jsx b/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.jsx new file mode 100644 index 000000000..0e101b706 --- /dev/null +++ b/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.jsx @@ -0,0 +1,12 @@ +import { splitProps } from 'solid-js'; + +const PrivacyBadge = (props) => { + const [local] = splitProps(props, ['visibility']); + return ( + + {local.visibility} + + ); +}; + +export default PrivacyBadge; diff --git a/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.stories.jsx b/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.stories.jsx new file mode 100644 index 000000000..d689f1d65 --- /dev/null +++ b/solidjs-tailwind/src/components/PrivacyBadge/PrivacyBadge.stories.jsx @@ -0,0 +1,15 @@ +import PrivacyBadge from './PrivacyBadge'; + +export default { + title: 'Components/PrivacyBadge', + argTypes: { + visibility: {}, + }, +}; + +const Template = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + visibility: 'Public', +}; diff --git a/solidjs-tailwind/src/components/PrivacyBadge/index.js b/solidjs-tailwind/src/components/PrivacyBadge/index.js new file mode 100644 index 000000000..b351cd746 --- /dev/null +++ b/solidjs-tailwind/src/components/PrivacyBadge/index.js @@ -0,0 +1 @@ +export { default as PrivacyBadge } from './PrivacyBadge'; diff --git a/solidjs-tailwind/src/components/RepoCard/RepoCard.jsx b/solidjs-tailwind/src/components/RepoCard/RepoCard.jsx new file mode 100644 index 000000000..001d7d053 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoCard/RepoCard.jsx @@ -0,0 +1,60 @@ +import { Link } from '@solidjs/router'; +import { Show, splitProps } from 'solid-js'; +import RepoMeta from '../RepoMeta/RepoMeta'; +import { OcStar2 } from 'solid-icons/oc'; +import PrivacyBadge from '../PrivacyBadge/PrivacyBadge'; + +const RepoCard = (props) => { + const [local] = splitProps(props, [ + 'name', + 'description', + 'primaryLanguage', + 'stargazerCount', + 'owner', + 'isProfilePage', + 'updatedAt', + 'visibility', + ]); + const repoNameWithOwnerLink = () => + `${local.owner?.login || ''}/${local.name || ''}`; + const repoNameWithOwner = () => + `${!local.isProfilePage ? `${local.owner?.login || ''}/` : ''}${ + local.name || '' + }`; + + return ( +
+
+

+ + + {repoNameWithOwner()} + + + +

+ +
+ {local.description} +
+
+ +
+
+ +
+
+ ); +}; + + +export default RepoCard; diff --git a/solidjs-tailwind/src/components/RepoCard/RepoCard.spec.jsx b/solidjs-tailwind/src/components/RepoCard/RepoCard.spec.jsx new file mode 100644 index 000000000..73c862d58 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoCard/RepoCard.spec.jsx @@ -0,0 +1,51 @@ +import { Router } from '@solidjs/router'; +import { render } from 'solid-testing-library'; +import { beforeEach, describe, expect, it } from 'vitest'; +import RepoCard from './RepoCard'; +import { repoCardProps } from './data'; + +describe('RepoCard for profilepage', () => { + let wrapper; + beforeEach(async () => { + wrapper = await render(() => ( + + + + )); + }); + + it('should mount', () => { + expect(wrapper).toBeTruthy(); + }); + + it('a tag text should contain only name', async () => { + const repoName = await wrapper.getByText(repoCardProps.name); + expect(repoName).toBeVisible(); + }); +}); +describe('RepoCard for non profile page', () => { + let wrapper; + const notProfileData = { + ...repoCardProps, + isProfilePage: false, + }; + + beforeEach(async () => { + wrapper = await render(() => ( + + + + )); + }); + + it('should mount', () => { + expect(wrapper).toBeTruthy(); + }); + + it('a tag text should contain owner/name', async () => { + const repowithOwner = await wrapper.getByText( + `${notProfileData.owner.login}/${notProfileData.name}` + ); + expect(repowithOwner).toBeVisible(); + }); +}); diff --git a/solidjs-tailwind/src/components/RepoCard/RepoCard.stories.jsx b/solidjs-tailwind/src/components/RepoCard/RepoCard.stories.jsx new file mode 100644 index 000000000..d621d0f98 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoCard/RepoCard.stories.jsx @@ -0,0 +1,28 @@ +import { Router } from '@solidjs/router'; +import RepoCard from './RepoCard'; +import { repoCardProps } from './data'; + +export default { + title: 'Components/Repo Card', + component: RepoCard, + argTypes: { + name: {}, + description: {}, + primaryLanguage: {}, + owner: {}, + isProfilePage: {}, + stargazerCount: {}, + }, +}; + +const Template = (args) => ( + + + +); + +export const Default = Template.bind({}); + +Default.args = { + ...repoCardProps, +}; diff --git a/solidjs-tailwind/src/components/RepoCard/data.js b/solidjs-tailwind/src/components/RepoCard/data.js new file mode 100644 index 000000000..c85599066 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoCard/data.js @@ -0,0 +1,16 @@ +export const repoCardProps = { + name: 'cowrywise-unsplashed', + owner: { + login: 'hdjerry', + }, + isProfilePage: true, + stargazerCount: 2, + visibility: 'Private', + primaryLanguage: { + color: 'yellow', + name: 'Javascript', + }, + description: + 'Using basic pull requests to add your name and github link to BE A MEMBER of ZTM-ng', + updatedAt: '23 Sep 2020', +}; diff --git a/solidjs-tailwind/src/components/RepoCard/index.js b/solidjs-tailwind/src/components/RepoCard/index.js new file mode 100644 index 000000000..dda4f06a3 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoCard/index.js @@ -0,0 +1 @@ +export { default as RepoCard } from './RepoCard'; diff --git a/solidjs-tailwind/src/components/RepoMeta/RepoMeta.jsx b/solidjs-tailwind/src/components/RepoMeta/RepoMeta.jsx new file mode 100644 index 000000000..d46cea575 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoMeta/RepoMeta.jsx @@ -0,0 +1,40 @@ +import { Show, splitProps } from 'solid-js'; +import { OcStar2 } from 'solid-icons/oc'; +import getFriendlyDate from '../../helper/getFriendlyDate'; + +const RepoMeta = (props) => { + const [local] = splitProps(props, [ + 'primaryLanguage', + 'stargazerCount', + 'updatedAt', + ]); + + const friendlyUpdatedAt = () => getFriendlyDate(local.updatedAt); + + return ( +
+ +
+ + {local.primaryLanguage.name} +
+
+ +
+ + + + {local.stargazerCount} +
+
+ Updated {friendlyUpdatedAt()} +
+ ); +}; + +export default RepoMeta; diff --git a/solidjs-tailwind/src/components/RepoMeta/index.js b/solidjs-tailwind/src/components/RepoMeta/index.js new file mode 100644 index 000000000..12b089b8a --- /dev/null +++ b/solidjs-tailwind/src/components/RepoMeta/index.js @@ -0,0 +1 @@ +export { default as RepoMeta } from './RepoMeta'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 7a9d23386..567fe096c 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,5 +1,8 @@ export * from './CounterExample'; export * from './FetchExample'; +export * from './RepoMeta'; +export * from './RepoCard'; +export * from './PrivacyBadge'; export * from './Header'; export * from './UserDropdown'; export { default as PageHeader } from './PageHeader'; diff --git a/solidjs-tailwind/src/helper/getFriendlyDate.js b/solidjs-tailwind/src/helper/getFriendlyDate.js new file mode 100644 index 000000000..51a0a8936 --- /dev/null +++ b/solidjs-tailwind/src/helper/getFriendlyDate.js @@ -0,0 +1,12 @@ +import dayjs from 'dayjs'; +import relativeTime from 'dayjs/plugin/relativeTime'; + +const getFriendlyDate = (dateStr) => { + dayjs.extend(relativeTime); + + const formatted = dayjs(dateStr).fromNow(); + + return formatted; +}; + +export default getFriendlyDate; From e3a5ca9eec182279010c24107cf83b86e7d25b13 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Fri, 11 Nov 2022 10:51:40 +0100 Subject: [PATCH 07/19] chore: gist panel UI (#741) * chore: gist panel UI * fix coment * fix coment Co-authored-by: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> --- .../src/components/GistPanel/GistPanel.jsx | 27 +++++++++++++++++++ .../GistPanel/GistPanel.stories.jsx | 26 ++++++++++++++++++ .../src/components/GistPanel/data.js | 25 +++++++++++++++++ .../src/components/GistPanel/index.js | 1 + solidjs-tailwind/src/components/index.js | 1 + solidjs-tailwind/tailwind.config.js | 18 ++++++++++++- 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 solidjs-tailwind/src/components/GistPanel/GistPanel.jsx create mode 100644 solidjs-tailwind/src/components/GistPanel/GistPanel.stories.jsx create mode 100644 solidjs-tailwind/src/components/GistPanel/data.js create mode 100644 solidjs-tailwind/src/components/GistPanel/index.js diff --git a/solidjs-tailwind/src/components/GistPanel/GistPanel.jsx b/solidjs-tailwind/src/components/GistPanel/GistPanel.jsx new file mode 100644 index 000000000..b7bf0b670 --- /dev/null +++ b/solidjs-tailwind/src/components/GistPanel/GistPanel.jsx @@ -0,0 +1,27 @@ +import { gists } from './data'; +import { For } from 'solid-js'; +import { Link } from '@solidjs/router'; + +const GistPanel = () => { + const dummyGists = gists; + return ( +
+
+

Gists

+
+
    + + {(gist) => ( +
  • + + {gist.name} + +
  • + )} +
    +
+
+ ); +}; + +export default GistPanel; diff --git a/solidjs-tailwind/src/components/GistPanel/GistPanel.stories.jsx b/solidjs-tailwind/src/components/GistPanel/GistPanel.stories.jsx new file mode 100644 index 000000000..e8d6a113f --- /dev/null +++ b/solidjs-tailwind/src/components/GistPanel/GistPanel.stories.jsx @@ -0,0 +1,26 @@ +import { Router } from '@solidjs/router'; +import GistPanel from './GistPanel'; +import { gists } from './data'; + +export default { + title: 'Components/Gist Panel', + parameters: { + mockData: [ + { + url: 'https://api.starter.dev/hello?greeting=', + method: 'GET', + status: 200, + response: () => gists, + delay: 1000, + }, + ], + }, +}; + +const Template = (args) => ( + + + +); + +export const Default = Template.bind({}); diff --git a/solidjs-tailwind/src/components/GistPanel/data.js b/solidjs-tailwind/src/components/GistPanel/data.js new file mode 100644 index 000000000..ae80118b1 --- /dev/null +++ b/solidjs-tailwind/src/components/GistPanel/data.js @@ -0,0 +1,25 @@ +export const gists = [ + { + id: 'G_kwDOADjK-doAIGU0OTc3ODQ1ZmRlOGNjZmU1Yzc0MjQxNzlmZGMyZmVh', + description: 'A react hook that handles firebase storage uploading', + url: 'https://gist.github.com/e4977845fde8ccfe5c7424179fdc2fea', + name: 'FormStore.js', + files: [ + { + name: 'useFirebaseUploader.ts', + }, + ], + }, + { + id: 'MDQ6R2lzdGQ1Yzc1NTIwMWJiMTI1MmJiNzI2YzQ2ZTIzOTE1Mzgw', + description: + 'Mobx store for managing form state (built for my react-native app)', + url: 'https://gist.github.com/d5c755201bb1252bb726c46e23915380', + name: 'MyFormStore.js', + files: [ + { + name: 'MyFormStore.js', + }, + ], + }, +]; diff --git a/solidjs-tailwind/src/components/GistPanel/index.js b/solidjs-tailwind/src/components/GistPanel/index.js new file mode 100644 index 000000000..a71083642 --- /dev/null +++ b/solidjs-tailwind/src/components/GistPanel/index.js @@ -0,0 +1 @@ +export { default as GistPanel } from './GistPanel'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 567fe096c..368fd9929 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,5 +1,6 @@ export * from './CounterExample'; export * from './FetchExample'; +export * from './GistPanel'; export * from './RepoMeta'; export * from './RepoCard'; export * from './PrivacyBadge'; diff --git a/solidjs-tailwind/tailwind.config.js b/solidjs-tailwind/tailwind.config.js index 0b96aaa0c..0e4419be2 100644 --- a/solidjs-tailwind/tailwind.config.js +++ b/solidjs-tailwind/tailwind.config.js @@ -2,7 +2,23 @@ module.exports = { content: ["./src/**/*.{js,jsx}", ], theme: { - extend: {}, + extend: { + colors: { + 'primary': '#0969da', + 'primary-100': '#f6f8fa', + 'primary-200': '#ddf4ff', + 'primary-400': '#4078c0', + 'secondary': '#586069', + 'secondary-100': '#d0d7de', + 'secondary-200': '#57606a', + 'secondary-300': '#eaecef', + 'accent': '#6e5494', + 'success': '#2ea44f', + 'dark': '#111827', + 'dark-300': '#1b1f2414', + 'dark-800': '#24292f', + } + }, }, plugins: [], } From 2e5bc034ecdb3f1515cfdd1229cf8d79ac2ce2aa Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 09:53:03 +0100 Subject: [PATCH 08/19] [solidjs-pod] : Create component for search input and filter sort buttons (#831) * in progress * in progress * in progress, paused for now * chore: search filter sort component * fixed comments on icons --- .../components/RepoFilter/FilterDropdown.jsx | 87 +++++++++++++++++++ .../src/components/RepoFilter/FilterText.jsx | 63 ++++++++++++++ .../RepoFilter/RepoFIlter.stories.jsx | 13 +++ .../src/components/RepoFilter/RepoFilter.jsx | 62 +++++++++++++ .../components/RepoFilter/RepoFilter.store.js | 17 ++++ .../src/components/RepoFilter/SearchInput.jsx | 18 ++++ .../src/components/RepoFilter/data.js | 14 +++ .../src/components/RepoFilter/index.js | 1 + .../src/components/icons/caret.jsx | 15 ++++ .../src/components/icons/close.jsx | 20 +++++ .../src/components/icons/correct.jsx | 18 ++++ .../src/components/icons/index.js | 4 + .../src/components/icons/repo-book.jsx | 19 ++++ solidjs-tailwind/src/components/index.js | 1 + 14 files changed, 352 insertions(+) create mode 100644 solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx create mode 100644 solidjs-tailwind/src/components/RepoFilter/FilterText.jsx create mode 100644 solidjs-tailwind/src/components/RepoFilter/RepoFIlter.stories.jsx create mode 100644 solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx create mode 100644 solidjs-tailwind/src/components/RepoFilter/RepoFilter.store.js create mode 100644 solidjs-tailwind/src/components/RepoFilter/SearchInput.jsx create mode 100644 solidjs-tailwind/src/components/RepoFilter/data.js create mode 100644 solidjs-tailwind/src/components/RepoFilter/index.js create mode 100644 solidjs-tailwind/src/components/icons/caret.jsx create mode 100644 solidjs-tailwind/src/components/icons/close.jsx create mode 100644 solidjs-tailwind/src/components/icons/correct.jsx create mode 100644 solidjs-tailwind/src/components/icons/index.js create mode 100644 solidjs-tailwind/src/components/icons/repo-book.jsx diff --git a/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx new file mode 100644 index 000000000..e59c6a948 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx @@ -0,0 +1,87 @@ +import { + createSignal, + Show, + onCleanup, + splitProps, + For, + Switch, + Match, +} from 'solid-js'; +import { CaretIcon, CloseIcon, CorrectIcon } from '../icons'; + +function clickOutside(el, accessor) { + const onClick = (e) => { + !el.contains(e.target) && accessor()?.(); + }; + document.body.addEventListener('click', onClick); + + onCleanup(() => document.body.removeEventListener('click', onClick)); +} + +const FilterDropdown = (props) => { + const [local] = splitProps(props, ['name', 'title', 'items', 'selectOption']); + const [showOptions, setShowOptions] = createSignal(false); + const toggleOption = () => setShowOptions(!showOptions()); + + return ( +
setShowOptions(false)} + > +
+ +
+ + + +
+ ); +}; + +export default FilterDropdown; diff --git a/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx b/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx new file mode 100644 index 000000000..7f26730e1 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx @@ -0,0 +1,63 @@ +import { Show, splitProps } from 'solid-js'; +import { CloseIcon } from '../icons'; + +const modifyFilterTypeText = (filterText = 'test') => { + if (filterText.endsWith('s')) { + if (filterText.match(new RegExp('forks', 'i'))) { + filterText = filterText.replace('s', 'ed'); + } else { + filterText = filterText.replace('s', ''); + } + } + return filterText; +}; + +const FilterText = (props) => { + const [local] = splitProps(props, ['username']); + + return ( +
+ ); +}; + +export default FilterText; diff --git a/solidjs-tailwind/src/components/RepoFilter/RepoFIlter.stories.jsx b/solidjs-tailwind/src/components/RepoFilter/RepoFIlter.stories.jsx new file mode 100644 index 000000000..28f6db507 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/RepoFIlter.stories.jsx @@ -0,0 +1,13 @@ +import RepoFilter from './RepoFilter'; + +export default { + title: 'components/ Repo filter', + argTypes: {}, +}; + +const Template = (args) => ; + +export const Default = Template.bind({}); +Default.args = { + repoText: 'New', +}; diff --git a/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx new file mode 100644 index 000000000..c977f8a5b --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx @@ -0,0 +1,62 @@ +import { mergeProps, Show } from 'solid-js'; +import { RepoBookIcon } from '../icons'; +import { FILTER_TYPE_OPTIONS, SORT_OPTIONS } from './data'; +import FilterDropdown from './FilterDropdown'; +import FilterText from './FilterText'; +import SearchInput from './SearchInput'; + +const RepoFilter = (props) => { + const typeOptions = Object.values(FILTER_TYPE_OPTIONS); + const sortOptions = Object.values(SORT_OPTIONS); + const languageOptions = ['All', 'HTML', 'CSS', 'PHP']; + + const merged = mergeProps({ repoBtnText: 'New' }, props); + + const selectLanguage = (value) => console.log(value); + const selectType = (value) => console.log(value); + const selectSort = (value) => console.log(value); + const isOnlySorted = true; + + return ( + <> +
+
+
+ +
+
+ + + +
+
+ +
+ + + + + ); +}; + +export default RepoFilter; diff --git a/solidjs-tailwind/src/components/RepoFilter/RepoFilter.store.js b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.store.js new file mode 100644 index 000000000..a0e0a8f63 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.store.js @@ -0,0 +1,17 @@ +import { createSignal } from 'solid-js'; + +const [search, setSearch] = createSignal(''); +const [language, setLanguage] = createSignal(''); +const [sortBy, setSortBy] = createSignal(''); +const [sortType, setSortType] = createSignal(''); + +export { + search, + language, + sortBy, + sortType, + setSearch, + setLanguage, + setSortBy, + setSortType, +}; diff --git a/solidjs-tailwind/src/components/RepoFilter/SearchInput.jsx b/solidjs-tailwind/src/components/RepoFilter/SearchInput.jsx new file mode 100644 index 000000000..c4564e920 --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/SearchInput.jsx @@ -0,0 +1,18 @@ +import { setSearch } from './RepoFilter.store'; + +const SearchInput = () => { + const handleChange = (e) => { + setSearch(e.target.value); + }; + return ( + + ); +}; + +export default SearchInput; diff --git a/solidjs-tailwind/src/components/RepoFilter/data.js b/solidjs-tailwind/src/components/RepoFilter/data.js new file mode 100644 index 000000000..e47a89c9a --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/data.js @@ -0,0 +1,14 @@ +export const defaultFilterType = 'All'; +export const defaultLanguage = 'All'; +export const defaultSortBy = 'Last updated'; + +export const FILTER_TYPE_OPTIONS = { + default: defaultFilterType, + forks: 'Forks', + archived: 'Archived', +}; +export const SORT_OPTIONS = { + default: defaultSortBy, + name: 'Name', + stars: 'Stars', +}; diff --git a/solidjs-tailwind/src/components/RepoFilter/index.js b/solidjs-tailwind/src/components/RepoFilter/index.js new file mode 100644 index 000000000..9a44c4a3d --- /dev/null +++ b/solidjs-tailwind/src/components/RepoFilter/index.js @@ -0,0 +1 @@ +export { default as RepoFilter } from './RepoFilter'; diff --git a/solidjs-tailwind/src/components/icons/caret.jsx b/solidjs-tailwind/src/components/icons/caret.jsx new file mode 100644 index 000000000..5eba34594 --- /dev/null +++ b/solidjs-tailwind/src/components/icons/caret.jsx @@ -0,0 +1,15 @@ +const CaretIcon = () => ( + +); + +export default CaretIcon; diff --git a/solidjs-tailwind/src/components/icons/close.jsx b/solidjs-tailwind/src/components/icons/close.jsx new file mode 100644 index 000000000..cfa592237 --- /dev/null +++ b/solidjs-tailwind/src/components/icons/close.jsx @@ -0,0 +1,20 @@ +const CloseIcon = () => ( + + + +); + +export default CloseIcon; diff --git a/solidjs-tailwind/src/components/icons/correct.jsx b/solidjs-tailwind/src/components/icons/correct.jsx new file mode 100644 index 000000000..46938adfc --- /dev/null +++ b/solidjs-tailwind/src/components/icons/correct.jsx @@ -0,0 +1,18 @@ +const CorrectIcon = () => ( + + + +); + +export default CorrectIcon; diff --git a/solidjs-tailwind/src/components/icons/index.js b/solidjs-tailwind/src/components/icons/index.js new file mode 100644 index 000000000..e00402d99 --- /dev/null +++ b/solidjs-tailwind/src/components/icons/index.js @@ -0,0 +1,4 @@ +export { default as CaretIcon } from './caret'; +export { default as CloseIcon } from './close'; +export { default as CorrectIcon } from './correct'; +export { default as RepoBookIcon } from './repo-book'; diff --git a/solidjs-tailwind/src/components/icons/repo-book.jsx b/solidjs-tailwind/src/components/icons/repo-book.jsx new file mode 100644 index 000000000..4c103f645 --- /dev/null +++ b/solidjs-tailwind/src/components/icons/repo-book.jsx @@ -0,0 +1,19 @@ +const RepoBookIcon = () => ( + + + +); + +export default RepoBookIcon; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 368fd9929..70f011b51 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,5 +1,6 @@ export * from './CounterExample'; export * from './FetchExample'; +export * from './RepoFilter'; export * from './GistPanel'; export * from './RepoMeta'; export * from './RepoCard'; From 716d9d6035642c0d9e47bd4c14bb11f749e0b20d Mon Sep 17 00:00:00 2001 From: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> Date: Thu, 17 Nov 2022 11:02:46 +0100 Subject: [PATCH 09/19] [solidjs-tailwinf] Add user profile card (#830) --- solidjs-tailwind/README.md | 2 +- solidjs-tailwind/package.json | 1 + solidjs-tailwind/pnpm-lock.yaml | 9 ++ .../src/components/Icons/TwitterIcon.jsx | 15 +++ .../src/components/Icons/index.js | 1 + .../src/components/UserProfile/OrgList.jsx | 19 ++++ .../components/UserProfile/UserProfile.jsx | 101 ++++++++++++++++++ .../UserProfile/UserProfile.spec.jsx | 30 ++++++ .../UserProfile/UserProfile.stories.jsx | 19 ++++ .../src/components/UserProfile/data.js | 18 ++++ .../src/components/UserProfile/index.js | 1 + solidjs-tailwind/src/components/index.js | 2 + 12 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 solidjs-tailwind/src/components/Icons/TwitterIcon.jsx create mode 100644 solidjs-tailwind/src/components/Icons/index.js create mode 100644 solidjs-tailwind/src/components/UserProfile/OrgList.jsx create mode 100644 solidjs-tailwind/src/components/UserProfile/UserProfile.jsx create mode 100644 solidjs-tailwind/src/components/UserProfile/UserProfile.spec.jsx create mode 100644 solidjs-tailwind/src/components/UserProfile/UserProfile.stories.jsx create mode 100644 solidjs-tailwind/src/components/UserProfile/data.js create mode 100644 solidjs-tailwind/src/components/UserProfile/index.js diff --git a/solidjs-tailwind/README.md b/solidjs-tailwind/README.md index 7e93aeda0..afa75b8a2 100644 --- a/solidjs-tailwind/README.md +++ b/solidjs-tailwind/README.md @@ -89,7 +89,7 @@ git clone https://github.com/thisdot/starter.dev.git - `pnpm run dev` - Runs the development server on localhost port 3000 with HMR - `pnpm run test` - Runs the test suite -- `pnpm run storbook` - To showcase the component library +- `pnpm run storybook` - To showcase the component library - `pnpm run build` - Builds a production version of the app to deploy - `pnpm run serve` - Serves a production build on localhost port 4173 - `pnpm run lint` - Uses eslint to find potential issues in the codebase diff --git a/solidjs-tailwind/package.json b/solidjs-tailwind/package.json index 48fd5ec1c..6939178b6 100644 --- a/solidjs-tailwind/package.json +++ b/solidjs-tailwind/package.json @@ -50,6 +50,7 @@ "@heroicons/react": "1.0.5" }, "dependencies": { + "solid-heroicons": "^3.1.0", "solid-js": "1.6.0" }, "keywords": [ diff --git a/solidjs-tailwind/pnpm-lock.yaml b/solidjs-tailwind/pnpm-lock.yaml index a680ae44c..e4401d8b1 100644 --- a/solidjs-tailwind/pnpm-lock.yaml +++ b/solidjs-tailwind/pnpm-lock.yaml @@ -24,6 +24,7 @@ specifiers: jsdom: 20.0.1 postcss: 8.4.18 prettier: 2.7.1 + solid-heroicons: ^3.1.0 solid-icons: ^1.0.2 solid-js: 1.6.0 solid-testing-library: 0.3.0 @@ -35,6 +36,7 @@ specifiers: vitest: 0.24.3 dependencies: + solid-heroicons: 3.1.0_solid-js@1.6.0 solid-js: 1.6.0 devDependencies: @@ -12337,6 +12339,13 @@ packages: - supports-color dev: true + /solid-heroicons/3.1.0_solid-js@1.6.0: + resolution: {integrity: sha512-cOw5cxS3zgcoOChyvobvHZmHSCinnkkpsiyEiMW+irltb/6iwKq123CUD/W70astfwBvVopnixCQIF19JUzzMA==} + peerDependencies: + solid-js: '>= ^1.2.5' + dependencies: + solid-js: 1.6.0 + dev: false /solid-icons/1.0.2_solid-js@1.6.0: resolution: {integrity: sha512-Pockp4vkCFFW+uubuRpb50pqKZNzjLhUUDm5VPpcZJWSgDw7fOxnMLcO1fC2bK8l+kYbJOr52y+pB5fnoZXg3Q==} engines: {node: '>= 16'} diff --git a/solidjs-tailwind/src/components/Icons/TwitterIcon.jsx b/solidjs-tailwind/src/components/Icons/TwitterIcon.jsx new file mode 100644 index 000000000..8bb5a2924 --- /dev/null +++ b/solidjs-tailwind/src/components/Icons/TwitterIcon.jsx @@ -0,0 +1,15 @@ +function TwitterIcon(className) { + return ( + + + + + ); +} + +export default TwitterIcon; diff --git a/solidjs-tailwind/src/components/Icons/index.js b/solidjs-tailwind/src/components/Icons/index.js new file mode 100644 index 000000000..93e73e0cc --- /dev/null +++ b/solidjs-tailwind/src/components/Icons/index.js @@ -0,0 +1 @@ +export { default as TwitterIcon } from './TwitterIcon'; diff --git a/solidjs-tailwind/src/components/UserProfile/OrgList.jsx b/solidjs-tailwind/src/components/UserProfile/OrgList.jsx new file mode 100644 index 000000000..44072c242 --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/OrgList.jsx @@ -0,0 +1,19 @@ +import { For } from 'solid-js'; +function OrgList(props) { + return ( +
+

Organizations

+
+ + {(props) => ( +
+ Organization +
+ )} +
+
+
+ ); +} + +export default OrgList; diff --git a/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx new file mode 100644 index 000000000..2cc7ad7ab --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx @@ -0,0 +1,101 @@ +import { + users, + star, + buildingOffice, + mapPin, + link, +} from 'solid-heroicons/outline'; +import { Icon } from 'solid-heroicons'; +import { TwitterIcon } from '../Icons'; +import OrgList from './OrgList'; + +const UserProfile = (userProfileProps) => { + return ( +
+ Avatar +

+
+ {userProfileProps.name} +
+
+ {userProfileProps.username} +
+

+
{userProfileProps.bio}
+
+ + + + {userProfileProps.followers} + {' '} + followers + + · + + + {userProfileProps.following} + {' '} + following + + · + + + + {userProfileProps.starredRepos} + {' '} + +
+
+ {userProfileProps.company && ( +
+ + {userProfileProps.company} +
+ )} + {userProfileProps.location && ( +
+ + {userProfileProps.location} +
+ )} + {userProfileProps.websiteUrl && ( + + )} + {userProfileProps.twitterUsername && ( + + )} +
+ {userProfileProps.organizations.length > 0 && ( + + )} +
+ ); +}; + +export default UserProfile; diff --git a/solidjs-tailwind/src/components/UserProfile/UserProfile.spec.jsx b/solidjs-tailwind/src/components/UserProfile/UserProfile.spec.jsx new file mode 100644 index 000000000..95054e474 --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/UserProfile.spec.jsx @@ -0,0 +1,30 @@ +import { Router } from '@solidjs/router'; +import { render } from 'solid-testing-library'; +import { beforeEach, describe, expect, it } from 'vitest'; +import UserProfile from './UserProfile.jsx'; +import { userProfileProps } from './data'; + +describe('User profile card', () => { + let wrapper; + beforeEach(async () => { + wrapper = await render(() => ( + + + + )); + }); + + it('should mount', () => { + expect(wrapper).toBeTruthy(); + }); + + it('should show the user display name', async () => { + const fullName = await wrapper.getByText(userProfileProps.name); + expect(fullName).toBeVisible(); + }); + + it('should have a link for user profile picture', async () => { + const avatar = await wrapper.getByAltText('Avatar'); + expect(avatar).toBeVisible(); + }); +}); diff --git a/solidjs-tailwind/src/components/UserProfile/UserProfile.stories.jsx b/solidjs-tailwind/src/components/UserProfile/UserProfile.stories.jsx new file mode 100644 index 000000000..e1e97dd4f --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/UserProfile.stories.jsx @@ -0,0 +1,19 @@ +import { Router } from '@solidjs/router'; +import { UserProfile } from '.'; +import { userProfileProps } from './data.js'; + +export default { + title: 'Components/User Profile Card', + component: UserProfile, +}; + +const Template = (args) => ( + + + +); +export const Default = Template.bind({}); + +Default.args = { + ...userProfileProps, +}; diff --git a/solidjs-tailwind/src/components/UserProfile/data.js b/solidjs-tailwind/src/components/UserProfile/data.js new file mode 100644 index 000000000..eb6df462c --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/data.js @@ -0,0 +1,18 @@ +export const userProfileProps = { + avatarUrl: 'https://avatars.githubusercontent.com/u/2487968?v=4', + bio: `Senior Software Engineer @thisdot`, + company: '@thisdot', + followers: 24, + following: 20, + location: 'Washington, DC', + login: 'tvanantwerp', + name: 'Tom VanAntwerp', + twitterUsername: 'tvanantwerp', + websiteUrl: 'https://tomvanantwerp.com', + organizations: [ + { + avatarUrl: 'https://avatars.githubusercontent.com/u/22839396?v=4', + login: 'thisdot', + }, + ], +}; diff --git a/solidjs-tailwind/src/components/UserProfile/index.js b/solidjs-tailwind/src/components/UserProfile/index.js new file mode 100644 index 000000000..9281f73c1 --- /dev/null +++ b/solidjs-tailwind/src/components/UserProfile/index.js @@ -0,0 +1 @@ +export {default as UserProfile } from './UserProfile'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 70f011b51..b6eda55dd 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,5 +1,7 @@ export * from './CounterExample'; export * from './FetchExample'; +export * from './UserProfile'; +export * from './Icons'; export * from './RepoFilter'; export * from './GistPanel'; export * from './RepoMeta'; From 8dd813c9fc3fad3772e1f728adfc0e905c8ca47a Mon Sep 17 00:00:00 2001 From: Maarten Bicknese Date: Thu, 17 Nov 2022 13:44:05 +0100 Subject: [PATCH 10/19] [SolidJS-Tailwind] Implement authentication (#734) * chore(solidjs): remove example components * feat(solidjs): add signin page * refactor(solidjs): improve auth setup * feat(solidjs): pencil in auth flow * feat(solidjs): add example github communication * [Angular - NgRx - SCSS] 440: state & service refactor (#527) * setup: get branch caught up and ready for work * feat: refactored repository service and test * feat: refactor of user service and test * feat: updated user service spec * feat: created dashboard store files; updated global state files; renamed RepoState and updated all calls * attempt to fix issues with service updates; some refactoring and adjusting so app compiles * feat: added auth user data to auth state; updated nav component to use auth state * feat: adjusted auth call; fixed user call so home page loads * moved some user logic; still having reload issues and repo view issues * feat: got app working again! cleaned out console logs * rebased and fixed most files * fix broken tests * removed unused code * fix: fix pr comments and most tests * fix: fixed final broken unit test * fix: updated test; removed unused code in user effect; new user mapping file * add todo for refactor improvements; update authUser effect to use different rxjs operation Co-authored-by: LindaT * feat(solidjs) - Create navigation header (#840) * fix(angular-apollo-tailwind): append protocol if missing from user url (#637) * fix(angular-apollo-tailwind): append protocol if missing from user url Refs: #591 * test(angular-apollo-tailwind): update with testcases Closes: #591 * chore: repo card with story and test (#737) * chore: repo card with story and test * fix comments * fix coment Co-authored-by: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> * chore: gist panel UI (#741) * chore: gist panel UI * fix coment * fix coment Co-authored-by: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> * chore(solidjs): remove example components * fixed comments, clean ups Co-authored-by: Linda Thompson Co-authored-by: LindaT Co-authored-by: Daian Scuarissi Co-authored-by: Oluwakorede Cole Co-authored-by: Jerry Hogan Co-authored-by: Victor Chukwuebuka Umeh <41862157+vyktoremario@users.noreply.github.com> --- solidjs-tailwind/.env.example | 3 + solidjs-tailwind/.gitignore | 5 + solidjs-tailwind/index.html | 24 +-- solidjs-tailwind/package.json | 2 + solidjs-tailwind/pnpm-lock.yaml | 167 +++++++++++++++++- solidjs-tailwind/src/App.jsx | 21 +-- solidjs-tailwind/src/auth/AuthStore.js | 11 ++ solidjs-tailwind/src/auth/index.js | 11 ++ .../src/auth/preventUnauthorised.js | 13 ++ .../CounterExample/Counter.spec.jsx | 19 -- .../CounterExample/CounterButton.jsx | 19 -- .../CounterExample/CounterDisplay.jsx | 9 - .../CounterExample/CounterExample.stories.jsx | 10 -- .../components/CounterExample/CounterStore.js | 9 - .../src/components/CounterExample/index.jsx | 22 --- .../src/components/FetchExample/Greeting.jsx | 21 --- .../components/FetchExample/Greeting.spec.jsx | 30 ---- .../FetchExample/Greeting.stories.jsx | 20 --- .../FetchExample/GreetingFetcher.js | 11 -- .../src/components/FetchExample/index.js | 1 - solidjs-tailwind/src/components/index.js | 2 - solidjs-tailwind/src/github/index.js | 15 ++ solidjs-tailwind/src/helper/constants.js | 9 + solidjs-tailwind/src/pages/ApiExample.jsx | 13 -- solidjs-tailwind/src/pages/Counter.jsx | 13 -- solidjs-tailwind/src/pages/Home.jsx | 37 ++-- solidjs-tailwind/src/pages/Redirect.jsx | 19 ++ solidjs-tailwind/src/pages/Signin.jsx | 44 +++++ solidjs-tailwind/src/pages/index.js | 4 +- solidjs-tailwind/src/routes.js | 7 + solidjs-tailwind/vite.config.js | 11 +- 31 files changed, 349 insertions(+), 253 deletions(-) create mode 100644 solidjs-tailwind/.env.example create mode 100644 solidjs-tailwind/src/auth/AuthStore.js create mode 100644 solidjs-tailwind/src/auth/index.js create mode 100644 solidjs-tailwind/src/auth/preventUnauthorised.js delete mode 100644 solidjs-tailwind/src/components/CounterExample/Counter.spec.jsx delete mode 100644 solidjs-tailwind/src/components/CounterExample/CounterButton.jsx delete mode 100644 solidjs-tailwind/src/components/CounterExample/CounterDisplay.jsx delete mode 100644 solidjs-tailwind/src/components/CounterExample/CounterExample.stories.jsx delete mode 100644 solidjs-tailwind/src/components/CounterExample/CounterStore.js delete mode 100644 solidjs-tailwind/src/components/CounterExample/index.jsx delete mode 100644 solidjs-tailwind/src/components/FetchExample/Greeting.jsx delete mode 100644 solidjs-tailwind/src/components/FetchExample/Greeting.spec.jsx delete mode 100644 solidjs-tailwind/src/components/FetchExample/Greeting.stories.jsx delete mode 100644 solidjs-tailwind/src/components/FetchExample/GreetingFetcher.js delete mode 100644 solidjs-tailwind/src/components/FetchExample/index.js create mode 100644 solidjs-tailwind/src/github/index.js create mode 100644 solidjs-tailwind/src/helper/constants.js delete mode 100644 solidjs-tailwind/src/pages/ApiExample.jsx delete mode 100644 solidjs-tailwind/src/pages/Counter.jsx create mode 100644 solidjs-tailwind/src/pages/Redirect.jsx create mode 100644 solidjs-tailwind/src/pages/Signin.jsx create mode 100644 solidjs-tailwind/src/routes.js diff --git a/solidjs-tailwind/.env.example b/solidjs-tailwind/.env.example new file mode 100644 index 000000000..511841197 --- /dev/null +++ b/solidjs-tailwind/.env.example @@ -0,0 +1,3 @@ +VITE_API_URL=https://api.starter.dev/api +VITE_GITHUB_URL=https://api.github.com +VITE_BASE_URL=http://localhost:3000 diff --git a/solidjs-tailwind/.gitignore b/solidjs-tailwind/.gitignore index ae51d0111..1c2db3da9 100644 --- a/solidjs-tailwind/.gitignore +++ b/solidjs-tailwind/.gitignore @@ -1,5 +1,10 @@ node_modules dist +# env file +.env.development +.env.production +.env.local + # .vscode .vscode/* diff --git a/solidjs-tailwind/index.html b/solidjs-tailwind/index.html index ad397b420..ce4d3c8b0 100644 --- a/solidjs-tailwind/index.html +++ b/solidjs-tailwind/index.html @@ -1,16 +1,16 @@ - - - - - - solidjs-tailwindcss starter kit - - - -
+ + + + + + solidjs-tailwindcss starter kit + + + +
- - + + diff --git a/solidjs-tailwind/package.json b/solidjs-tailwind/package.json index 6939178b6..63b9adc35 100644 --- a/solidjs-tailwind/package.json +++ b/solidjs-tailwind/package.json @@ -50,6 +50,8 @@ "@heroicons/react": "1.0.5" }, "dependencies": { + "@octokit/rest": "^19.0.5", + "isomorphic-fetch": "^3.0.0", "solid-heroicons": "^3.1.0", "solid-js": "1.6.0" }, diff --git a/solidjs-tailwind/pnpm-lock.yaml b/solidjs-tailwind/pnpm-lock.yaml index e4401d8b1..d1e87167a 100644 --- a/solidjs-tailwind/pnpm-lock.yaml +++ b/solidjs-tailwind/pnpm-lock.yaml @@ -1,6 +1,8 @@ lockfileVersion: 5.4 specifiers: + '@heroicons/react': 1.0.5 + '@octokit/rest': ^19.0.5 '@solidjs/router': 0.5.0 '@storybook/addon-actions': 6.5.13 '@storybook/addon-backgrounds': 6.5.13 @@ -21,6 +23,7 @@ specifiers: eslint: 8.26.0 eslint-plugin-solid: 0.7.4 eslint-plugin-unused-imports: 2.0.0 + isomorphic-fetch: ^3.0.0 jsdom: 20.0.1 postcss: 8.4.18 prettier: 2.7.1 @@ -36,10 +39,13 @@ specifiers: vitest: 0.24.3 dependencies: + '@octokit/rest': 19.0.5 + isomorphic-fetch: 3.0.0 solid-heroicons: 3.1.0_solid-js@1.6.0 solid-js: 1.6.0 devDependencies: + '@heroicons/react': 1.0.5 '@solidjs/router': 0.5.0_solid-js@1.6.0 '@storybook/addon-actions': 6.5.13 '@storybook/addon-backgrounds': 6.5.13 @@ -2899,6 +2905,15 @@ packages: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true + /@heroicons/react/1.0.5: + resolution: {integrity: sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==} + peerDependencies: + react: '>= 16' + peerDependenciesMeta: + react: + optional: true + dev: true + /@humanwhocodes/config-array/0.11.6: resolution: {integrity: sha512-jJr+hPTJYKyDILJfhNSHsjiwXYf26Flsz8DvNndOsHs5pwSnpGUEy8yzF0JYhCEvTDdV2vuOK5tt8BVhwO5/hg==} engines: {node: '>=10.10.0'} @@ -3154,6 +3169,122 @@ packages: rimraf: 3.0.2 dev: true + /@octokit/auth-token/3.0.2: + resolution: {integrity: sha512-pq7CwIMV1kmzkFTimdwjAINCXKTajZErLB4wMLYapR2nuB/Jpr66+05wOTZMSCBXP6n4DdDWT2W19Bm17vU69Q==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 8.0.0 + dev: false + + /@octokit/core/4.1.0: + resolution: {integrity: sha512-Czz/59VefU+kKDy+ZfDwtOIYIkFjExOKf+HA92aiTZJ6EfWpFzYQWw0l54ji8bVmyhc+mGaLUbSUmXazG7z5OQ==} + engines: {node: '>= 14'} + dependencies: + '@octokit/auth-token': 3.0.2 + '@octokit/graphql': 5.0.4 + '@octokit/request': 6.2.2 + '@octokit/request-error': 3.0.2 + '@octokit/types': 8.0.0 + before-after-hook: 2.2.3 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: false + + /@octokit/endpoint/7.0.3: + resolution: {integrity: sha512-57gRlb28bwTsdNXq+O3JTQ7ERmBTuik9+LelgcLIVfYwf235VHbN9QNo4kXExtp/h8T423cR5iJThKtFYxC7Lw==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 8.0.0 + is-plain-object: 5.0.0 + universal-user-agent: 6.0.0 + dev: false + + /@octokit/graphql/5.0.4: + resolution: {integrity: sha512-amO1M5QUQgYQo09aStR/XO7KAl13xpigcy/kI8/N1PnZYSS69fgte+xA4+c2DISKqUZfsh0wwjc2FaCt99L41A==} + engines: {node: '>= 14'} + dependencies: + '@octokit/request': 6.2.2 + '@octokit/types': 8.0.0 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: false + + /@octokit/openapi-types/14.0.0: + resolution: {integrity: sha512-HNWisMYlR8VCnNurDU6os2ikx0s0VyEjDYHNS/h4cgb8DeOxQ0n72HyinUtdDVxJhFy3FWLGl0DJhfEWk3P5Iw==} + dev: false + + /@octokit/plugin-paginate-rest/5.0.1_@octokit+core@4.1.0: + resolution: {integrity: sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=4' + dependencies: + '@octokit/core': 4.1.0 + '@octokit/types': 8.0.0 + dev: false + + /@octokit/plugin-request-log/1.0.4_@octokit+core@4.1.0: + resolution: {integrity: sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 4.1.0 + dev: false + + /@octokit/plugin-rest-endpoint-methods/6.7.0_@octokit+core@4.1.0: + resolution: {integrity: sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==} + engines: {node: '>= 14'} + peerDependencies: + '@octokit/core': '>=3' + dependencies: + '@octokit/core': 4.1.0 + '@octokit/types': 8.0.0 + deprecation: 2.3.1 + dev: false + + /@octokit/request-error/3.0.2: + resolution: {integrity: sha512-WMNOFYrSaX8zXWoJg9u/pKgWPo94JXilMLb2VManNOby9EZxrQaBe/QSC4a1TzpAlpxofg2X/jMnCyZgL6y7eg==} + engines: {node: '>= 14'} + dependencies: + '@octokit/types': 8.0.0 + deprecation: 2.3.1 + once: 1.4.0 + dev: false + + /@octokit/request/6.2.2: + resolution: {integrity: sha512-6VDqgj0HMc2FUX2awIs+sM6OwLgwHvAi4KCK3mT2H2IKRt6oH9d0fej5LluF5mck1lRR/rFWN0YIDSYXYSylbw==} + engines: {node: '>= 14'} + dependencies: + '@octokit/endpoint': 7.0.3 + '@octokit/request-error': 3.0.2 + '@octokit/types': 8.0.0 + is-plain-object: 5.0.0 + node-fetch: 2.6.7 + universal-user-agent: 6.0.0 + transitivePeerDependencies: + - encoding + dev: false + + /@octokit/rest/19.0.5: + resolution: {integrity: sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==} + engines: {node: '>= 14'} + dependencies: + '@octokit/core': 4.1.0 + '@octokit/plugin-paginate-rest': 5.0.1_@octokit+core@4.1.0 + '@octokit/plugin-request-log': 1.0.4_@octokit+core@4.1.0 + '@octokit/plugin-rest-endpoint-methods': 6.7.0_@octokit+core@4.1.0 + transitivePeerDependencies: + - encoding + dev: false + + /@octokit/types/8.0.0: + resolution: {integrity: sha512-65/TPpOJP1i3K4lBJMnWqPUJ6zuOtzhtagDvydAWbEXpbFYA0oMKKyLb95NFZZP0lSh/4b6K+DQlzvYQJQQePg==} + dependencies: + '@octokit/openapi-types': 14.0.0 + dev: false + /@rollup/pluginutils/4.2.1: resolution: {integrity: sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==} engines: {node: '>= 8.0.0'} @@ -6066,6 +6197,10 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true + /before-after-hook/2.2.3: + resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} + dev: false + /better-opn/2.1.1: resolution: {integrity: sha512-kIPXZS5qwyKiX/HcRvDYfmBQUa8XP17I0mYZZ0y4UhpYOSvtsLHDYqmomS+Mj20aDvD3knEiQ0ecQy2nhio3yA==} engines: {node: '>8.0.0'} @@ -7158,6 +7293,10 @@ packages: engines: {node: '>= 0.8'} dev: true + /deprecation/2.3.1: + resolution: {integrity: sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==} + dev: false + /des.js/1.0.1: resolution: {integrity: sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==} dependencies: @@ -9456,6 +9595,11 @@ packages: isobject: 3.0.1 dev: true + /is-plain-object/5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: false + /is-potential-custom-element-name/1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} dev: true @@ -9602,6 +9746,15 @@ packages: engines: {node: '>=0.10.0'} dev: true + /isomorphic-fetch/3.0.0: + resolution: {integrity: sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==} + dependencies: + node-fetch: 2.6.7 + whatwg-fetch: 3.6.2 + transitivePeerDependencies: + - encoding + dev: false + /isomorphic-unfetch/3.1.0: resolution: {integrity: sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q==} dependencies: @@ -10562,7 +10715,6 @@ packages: optional: true dependencies: whatwg-url: 5.0.0 - dev: true /node-int64/0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} @@ -10776,7 +10928,6 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /onetime/5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} @@ -13037,7 +13188,6 @@ packages: /tr46/0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - dev: true /tr46/3.0.0: resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==} @@ -13299,6 +13449,10 @@ packages: unist-util-visit-parents: 3.1.1 dev: true + /universal-user-agent/6.0.0: + resolution: {integrity: sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w==} + dev: false + /universalify/0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -13622,7 +13776,6 @@ packages: /webidl-conversions/3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - dev: true /webidl-conversions/7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} @@ -13781,6 +13934,10 @@ packages: iconv-lite: 0.6.3 dev: true + /whatwg-fetch/3.6.2: + resolution: {integrity: sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==} + dev: false + /whatwg-mimetype/3.0.0: resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==} engines: {node: '>=12'} @@ -13799,7 +13956,6 @@ packages: dependencies: tr46: 0.0.3 webidl-conversions: 3.0.1 - dev: true /which-boxed-primitive/1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} @@ -13892,7 +14048,6 @@ packages: /wrappy/1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /write-file-atomic/3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} diff --git a/solidjs-tailwind/src/App.jsx b/solidjs-tailwind/src/App.jsx index 262f4cf16..6a9bf9f5d 100644 --- a/solidjs-tailwind/src/App.jsx +++ b/solidjs-tailwind/src/App.jsx @@ -1,19 +1,14 @@ -import { Routes, Route } from '@solidjs/router'; -import { Header} from './components/'; -import { Home, Counter, ApiExample } from './pages'; +import { Route, Routes } from '@solidjs/router'; +import { Home, RedirectPage, SigninPage } from './pages'; +import ROUTES from './routes'; function App() { return ( - <> -
-
- - - - - -
- + + + + + ); } diff --git a/solidjs-tailwind/src/auth/AuthStore.js b/solidjs-tailwind/src/auth/AuthStore.js new file mode 100644 index 000000000..89782e896 --- /dev/null +++ b/solidjs-tailwind/src/auth/AuthStore.js @@ -0,0 +1,11 @@ +import { createStore } from 'solid-js/store'; + +const createAuthStore = () => + createStore({ + token: null, + get isAuthenticated() { + return !!this.token; + }, + }); + +export default createAuthStore; diff --git a/solidjs-tailwind/src/auth/index.js b/solidjs-tailwind/src/auth/index.js new file mode 100644 index 000000000..f127f28fd --- /dev/null +++ b/solidjs-tailwind/src/auth/index.js @@ -0,0 +1,11 @@ +import createAuthStore from './AuthStore'; +import ROUTES from '../routes'; +import createPreventUnauthorised from './preventUnauthorised'; + +const [authStore, setAuth] = createAuthStore(); +const preventUnauthorised = createPreventUnauthorised(authStore, ROUTES.SIGNIN); +export const useAuth = () => ({ + authStore, + preventUnauthorised, + setAuth, +}); diff --git a/solidjs-tailwind/src/auth/preventUnauthorised.js b/solidjs-tailwind/src/auth/preventUnauthorised.js new file mode 100644 index 000000000..8553e9abc --- /dev/null +++ b/solidjs-tailwind/src/auth/preventUnauthorised.js @@ -0,0 +1,13 @@ +import { useLocation, useNavigate } from '@solidjs/router'; + +const preventUnauthorised = (authStore, redirectPath) => () => { + const navigate = useNavigate(); + const location = useLocation(); + + if (!authStore.isAuthenticated) { + sessionStorage.setItem('auth_return_path', location.pathname); + navigate(redirectPath, { replace: true }); + } +}; + +export default preventUnauthorised; diff --git a/solidjs-tailwind/src/components/CounterExample/Counter.spec.jsx b/solidjs-tailwind/src/components/CounterExample/Counter.spec.jsx deleted file mode 100644 index 5e0a172ff..000000000 --- a/solidjs-tailwind/src/components/CounterExample/Counter.spec.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import { fireEvent, render, screen } from 'solid-testing-library'; -import { describe, expect, it } from 'vitest'; -import { CounterExample } from '.'; - -describe('CounterExample', () => { - it('should mount', async () => { - const wrapper = await render(() => ); - expect(wrapper).toBeTruthy(); - }); - - it('should mount and increment', async () => { - await render(() => ); - const button = await screen.getByText('Increment'); - expect(button).toBeVisible(); - fireEvent.click(button); - const countText = await screen.getByText('Count: 1'); - expect(countText).toBeVisible(); - }); -}); diff --git a/solidjs-tailwind/src/components/CounterExample/CounterButton.jsx b/solidjs-tailwind/src/components/CounterExample/CounterButton.jsx deleted file mode 100644 index e0b037725..000000000 --- a/solidjs-tailwind/src/components/CounterExample/CounterButton.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import { children, splitProps } from 'solid-js'; - -const CounterButton = (props) => { - const [local, others] = splitProps(props, ['onClick']); - const c = children(() => props.children); - - return ( - - ); -}; - -export default CounterButton; diff --git a/solidjs-tailwind/src/components/CounterExample/CounterDisplay.jsx b/solidjs-tailwind/src/components/CounterExample/CounterDisplay.jsx deleted file mode 100644 index 1ddd12144..000000000 --- a/solidjs-tailwind/src/components/CounterExample/CounterDisplay.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import { count } from './CounterStore'; - -const CounterDisplay = () => ( - - Count: {count()} - -); - -export default CounterDisplay; diff --git a/solidjs-tailwind/src/components/CounterExample/CounterExample.stories.jsx b/solidjs-tailwind/src/components/CounterExample/CounterExample.stories.jsx deleted file mode 100644 index 4e956f5b7..000000000 --- a/solidjs-tailwind/src/components/CounterExample/CounterExample.stories.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import { CounterExample } from '.'; - -export default { - title: 'Example/ Counter Example', - argTypes: {}, -}; - -const Template = (args) => ; - -export const Default = Template.bind({}); diff --git a/solidjs-tailwind/src/components/CounterExample/CounterStore.js b/solidjs-tailwind/src/components/CounterExample/CounterStore.js deleted file mode 100644 index fcb410b08..000000000 --- a/solidjs-tailwind/src/components/CounterExample/CounterStore.js +++ /dev/null @@ -1,9 +0,0 @@ -import { createSignal } from 'solid-js'; - -const [count, setCount] = createSignal(0); - -const increase = () => setCount(count() + 1); -const decrease = () => setCount(count() > 0 ? count() - 1 : 0); -const reset = () => setCount(0); - -export { count, increase, decrease, reset }; diff --git a/solidjs-tailwind/src/components/CounterExample/index.jsx b/solidjs-tailwind/src/components/CounterExample/index.jsx deleted file mode 100644 index a477a8fa6..000000000 --- a/solidjs-tailwind/src/components/CounterExample/index.jsx +++ /dev/null @@ -1,22 +0,0 @@ -import CounterButton from './CounterButton'; -import CounterDisplay from './CounterDisplay'; -import { decrease, increase, reset } from './CounterStore'; - -export const CounterExample = () => { - return ( -
- -
- - Increment - - - Decrement - - - Reset - -
-
- ); -}; diff --git a/solidjs-tailwind/src/components/FetchExample/Greeting.jsx b/solidjs-tailwind/src/components/FetchExample/Greeting.jsx deleted file mode 100644 index 1e8d0a108..000000000 --- a/solidjs-tailwind/src/components/FetchExample/Greeting.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import { createResource, Match, Switch } from 'solid-js'; -import greetingFetcher from './GreetingFetcher'; - -const Greeting = () => { - const [message] = createResource(greetingFetcher()); - return ( - - -

There was an error loading your greeting :(

-
- -

Message: {message()}

-
- -
- - - ); -}; - -export default Greeting; diff --git a/solidjs-tailwind/src/components/FetchExample/Greeting.spec.jsx b/solidjs-tailwind/src/components/FetchExample/Greeting.spec.jsx deleted file mode 100644 index fc6ab0308..000000000 --- a/solidjs-tailwind/src/components/FetchExample/Greeting.spec.jsx +++ /dev/null @@ -1,30 +0,0 @@ -import { render, screen } from 'solid-testing-library'; -import { describe, expect, it, vi } from 'vitest'; - -import Greeting from './Greeting'; -import greetingFetcher from './GreetingFetcher'; - -vi.mock('./GreetingFetcher', () => ({ - default: vi.fn(() => () => Promise.resolve('Hi tester!')), -})); - -describe('Greeting', () => { - it('should mount', async () => { - const wrapper = await render(() => ); - expect(wrapper).toBeTruthy(); - }); - - it('should show the mocked greeting', async () => { - await render(() => ); - const text = await screen.getByText('Message: Hi tester!'); - expect(text).toBeVisible(); - }); - it("should show an error when api doesn't respond", async () => { - greetingFetcher.mockImplementationOnce(() => () => Promise.reject()); - await render(() => ); - const text = await screen.getByText( - 'There was an error loading your greeting :(' - ); - expect(text).toBeVisible(); - }); -}); diff --git a/solidjs-tailwind/src/components/FetchExample/Greeting.stories.jsx b/solidjs-tailwind/src/components/FetchExample/Greeting.stories.jsx deleted file mode 100644 index 692e28685..000000000 --- a/solidjs-tailwind/src/components/FetchExample/Greeting.stories.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import { Greeting } from '.'; - -export default { - title: 'Example/Fetch Example', - component: Greeting, - argTypes: {}, - parameters: { - mockData: [ - { - url: 'https://api.starter.dev/hello?greeting=', - method: 'GET', - status: 200, - response: () => 'Hi storybook user!', - delay: 1000, - }, - ], - }, -}; - -export const FetchExample = (args) => ; diff --git a/solidjs-tailwind/src/components/FetchExample/GreetingFetcher.js b/solidjs-tailwind/src/components/FetchExample/GreetingFetcher.js deleted file mode 100644 index a7f6b967b..000000000 --- a/solidjs-tailwind/src/components/FetchExample/GreetingFetcher.js +++ /dev/null @@ -1,11 +0,0 @@ -const DEFAULT_MESSAGE = 'solidjs-tailwind starter.dev!'; -const greetingFetcher = - (message = DEFAULT_MESSAGE) => - async () => { - const encodedMessage = encodeURIComponent(message); - const endpoint = `https://api.starter.dev/hello?greeting=${encodedMessage}`; - - return fetch(endpoint).then((result) => result.text()); - }; - -export default greetingFetcher; diff --git a/solidjs-tailwind/src/components/FetchExample/index.js b/solidjs-tailwind/src/components/FetchExample/index.js deleted file mode 100644 index 368719ec5..000000000 --- a/solidjs-tailwind/src/components/FetchExample/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as Greeting } from './Greeting'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index b6eda55dd..6885ea85e 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -1,5 +1,3 @@ -export * from './CounterExample'; -export * from './FetchExample'; export * from './UserProfile'; export * from './Icons'; export * from './RepoFilter'; diff --git a/solidjs-tailwind/src/github/index.js b/solidjs-tailwind/src/github/index.js new file mode 100644 index 000000000..f9289a18a --- /dev/null +++ b/solidjs-tailwind/src/github/index.js @@ -0,0 +1,15 @@ +import { Octokit } from '@octokit/rest'; +import { useAuth } from '../auth'; + +export const useOctokit = () => { + const { authStore } = useAuth(); + if (!authStore.isAuthenticated) { + throw new Error( + 'Trying to use GitHub without authentication, did you forget to use `preventUnauthenticated`?' + ); + } + + return new Octokit({ + auth: authStore.token, + }); +}; diff --git a/solidjs-tailwind/src/helper/constants.js b/solidjs-tailwind/src/helper/constants.js new file mode 100644 index 000000000..d550960a4 --- /dev/null +++ b/solidjs-tailwind/src/helper/constants.js @@ -0,0 +1,9 @@ +export const API_URL = import.meta.env.VITE_API_URL; +export const APP_BASE_URL = import.meta.env.VITE_BASE_URL; +export const GITHUB_URL_BASE = import.meta.env.VITE_GITHUB_URL; + +export const REDIRECT_URL = `${APP_BASE_URL}/auth/redirect`; + +export const SIGN_IN_BASE_URL = `${API_URL}/auth/signin`; + +export const GITHUB_GRAPHQL = `${GITHUB_URL_BASE}/graphql`; diff --git a/solidjs-tailwind/src/pages/ApiExample.jsx b/solidjs-tailwind/src/pages/ApiExample.jsx deleted file mode 100644 index cf08b4e73..000000000 --- a/solidjs-tailwind/src/pages/ApiExample.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import { Greeting, PageFooter, PageHeader } from '../components'; - -const ApiExample = () => { - return ( - <> - SolidJS Fetch Data from API - - - - ); -}; - -export default ApiExample; diff --git a/solidjs-tailwind/src/pages/Counter.jsx b/solidjs-tailwind/src/pages/Counter.jsx deleted file mode 100644 index d407a34c7..000000000 --- a/solidjs-tailwind/src/pages/Counter.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import { CounterExample, PageFooter, PageHeader } from '../components'; - -const Counter = () => { - return ( - <> - Increment, Decrement and Reset Button Example - - - - ); -}; - -export default Counter; diff --git a/solidjs-tailwind/src/pages/Home.jsx b/solidjs-tailwind/src/pages/Home.jsx index f1e679623..acffce29b 100644 --- a/solidjs-tailwind/src/pages/Home.jsx +++ b/solidjs-tailwind/src/pages/Home.jsx @@ -1,25 +1,28 @@ -import { NavLink } from '@solidjs/router'; +import { createResource, Show } from 'solid-js'; +import { useAuth } from '../auth'; +import { useOctokit } from '../github'; const Home = () => { + useAuth().preventUnauthorised(); + + const [data] = createResource(() => { + try { + return useOctokit() + .rest.users.getAuthenticated() + .then((response) => response.data); + } catch { + return Promise.resolve({}); + } + }); + return ( <> -
+

SolidJs and Tailwind CSS Starter kit -

-
- - See Counter example component - - - See API example component - -
+

+ +

Welcome {data().login}

+
); }; diff --git a/solidjs-tailwind/src/pages/Redirect.jsx b/solidjs-tailwind/src/pages/Redirect.jsx new file mode 100644 index 000000000..7317ee3a1 --- /dev/null +++ b/solidjs-tailwind/src/pages/Redirect.jsx @@ -0,0 +1,19 @@ +import { useNavigate } from "@solidjs/router"; +import { createEffect, onCleanup } from "solid-js"; + +const Redirect = () => { + const route = useNavigate() + createEffect(() => { + const timer = setTimeout(() => { + const last_visted_path = sessionStorage.getItem('auth_return_path'); + const isAuthPage = last_visted_path.includes('signin'); + const to = isAuthPage ? '/' : last_visted_path; + route(to, { replace: true }); + }, 3000); + onCleanup(() => clearTimeout(timer)); + + }) + return
Redirecting...
; +} + +export default Redirect; diff --git a/solidjs-tailwind/src/pages/Signin.jsx b/solidjs-tailwind/src/pages/Signin.jsx new file mode 100644 index 000000000..9188b5390 --- /dev/null +++ b/solidjs-tailwind/src/pages/Signin.jsx @@ -0,0 +1,44 @@ +import { createEffect, createResource } from 'solid-js'; +import { useAuth } from '../auth'; +import { useNavigate } from '@solidjs/router'; +import { API_URL, REDIRECT_URL, SIGN_IN_BASE_URL } from '../helper/constants'; + +const fetchToken = () => + fetch(`${API_URL}/auth/token`, { + credentials: 'include', + }) + .then((response) => { + return response.json() + }) + .then((data) => { + return data.access_token + }); + + const SigninPage = () => { + const signInHref = `${SIGN_IN_BASE_URL}?redirect_url=${REDIRECT_URL}`; + const { setAuth } = useAuth(); + const navigate = useNavigate(); + const [token] = createResource(fetchToken); + + createEffect(() => { + if (token() && !token.loading) { + setAuth({ token: token() }); + navigate(sessionStorage.getItem('auth_return_path')); + } + }); + + return ( +
+ +
+ ); +}; + +export default SigninPage; diff --git a/solidjs-tailwind/src/pages/index.js b/solidjs-tailwind/src/pages/index.js index 57f34e3ec..59e94a5d5 100644 --- a/solidjs-tailwind/src/pages/index.js +++ b/solidjs-tailwind/src/pages/index.js @@ -1,3 +1,3 @@ export { default as Home } from './Home'; -export { default as Counter } from './Counter'; -export { default as ApiExample } from './ApiExample'; +export { default as SigninPage } from './Signin'; +export { default as RedirectPage } from './Redirect'; diff --git a/solidjs-tailwind/src/routes.js b/solidjs-tailwind/src/routes.js new file mode 100644 index 000000000..f0dd88172 --- /dev/null +++ b/solidjs-tailwind/src/routes.js @@ -0,0 +1,7 @@ +const ROUTES = { + HOME: '/', + SIGNIN: '/signin', + REDIRECT: '/auth/redirect', +}; + +export default ROUTES; diff --git a/solidjs-tailwind/vite.config.js b/solidjs-tailwind/vite.config.js index 9ad1e816e..319511627 100644 --- a/solidjs-tailwind/vite.config.js +++ b/solidjs-tailwind/vite.config.js @@ -13,13 +13,16 @@ export default defineConfig({ }, test: { globals: true, - environment: "jsdom", + environment: 'jsdom', setupFiles: './setupVitest.js', deps: { inline: [/solid-js/, /solid-testing-library/], }, }, - resolve: { - conditions: ['development', 'browser'], - }, + resolve: { + conditions: ['development', 'browser'], + alias: { + 'node-fetch': 'isomorphic-fetch', + }, + }, }); From 02c5cb38f1fc8003237ee6f182f51bd73bf9bd3c Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 13:44:42 +0100 Subject: [PATCH 11/19] chore: updated amplify.yml file (#729) * chore: updated amplify.yml file * changed pnpm to npm --- amplify.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/amplify.yml b/amplify.yml index bbccbd495..94da5240f 100644 --- a/amplify.yml +++ b/amplify.yml @@ -125,6 +125,25 @@ applications: baseDirectory: .nuxt files: - "**/*" + cache: + paths: + - node_modules/**/* + + - appRoot: solidjs-tailwind + frontend: + phases: + preBuild: + commands: + - nvm install --lts=gallium + - npm install + build: + commands: + - node -v + - npm run build + artifacts: + baseDirectory: dist/ + files: + - "**/*" cache: paths: - node_modules/**/* \ No newline at end of file From e50f56b1d3c7f8508a3544ab35f5cbfdcc419a09 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 13:45:02 +0100 Subject: [PATCH 12/19] chore: workflow added (#745) * chore: workflow added * CI setup fixes and testing * CI setup fixes and testing * CI setup fixes and testing * tried everything but doesn't work, i think we have to merge this --- .github/workflows/ci-solidjs-tailwind.yml | 94 +++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/ci-solidjs-tailwind.yml diff --git a/.github/workflows/ci-solidjs-tailwind.yml b/.github/workflows/ci-solidjs-tailwind.yml new file mode 100644 index 000000000..b55d1cdfe --- /dev/null +++ b/.github/workflows/ci-solidjs-tailwind.yml @@ -0,0 +1,94 @@ +name: Solidjs TailwindCSS CI + +on: + push: + branches: [main] + paths: + - "solidjs-tailwind/**" + pull_request: + branches: [main] + paths: + - "solidjs-tailwind/**" + + +jobs: + lint: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [16.x] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: 'pnpm' + cache-dependency-path: solidjs-tailwind/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + working-directory: solidjs-tailwind + + - name: Lint files + run: pnpm run lint + working-directory: solidjs-tailwind + + + run-unit-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: "pnpm" + cache-dependency-path: solidjs-tailwind/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + working-directory: solidjs-tailwind + + - name: Run tests + run: pnpm run test + working-directory: solidjs-tailwind + + + build: + runs-on: ubuntu-latest + needs: [lint, run-unit-tests] + + strategy: + fail-fast: false + matrix: + node-version: [14.x, 16.x] + + steps: + - uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node-version }} + cache: "pnpm" + cache-dependency-path: solidjs-tailwind/pnpm-lock.yaml + + - name: Install dependencies + run: pnpm install --frozen-lockfile + working-directory: solidjs-tailwind + + - name: Build Project + run: pnpm run build + working-directory: solidjs-tailwind \ No newline at end of file From 9710312ad1708621d1322a407a98f11e794db2ba Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 15:14:39 +0100 Subject: [PATCH 13/19] auth token added to header --- solidjs-tailwind/src/components/icons/index.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/solidjs-tailwind/src/components/icons/index.js b/solidjs-tailwind/src/components/icons/index.js index e00402d99..93e73e0cc 100644 --- a/solidjs-tailwind/src/components/icons/index.js +++ b/solidjs-tailwind/src/components/icons/index.js @@ -1,4 +1 @@ -export { default as CaretIcon } from './caret'; -export { default as CloseIcon } from './close'; -export { default as CorrectIcon } from './correct'; -export { default as RepoBookIcon } from './repo-book'; +export { default as TwitterIcon } from './TwitterIcon'; From 457d31176875a8453d0f8335616147e6ac1c0411 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 14:11:42 +0100 Subject: [PATCH 14/19] ..updates --- solidjs-tailwind/src/components/Icons/index.js | 1 - .../src/components/RepoFilter/FilterDropdown.jsx | 2 +- solidjs-tailwind/src/components/UserProfile/UserProfile.jsx | 2 +- solidjs-tailwind/src/components/icons/index.js | 1 - solidjs-tailwind/src/components/index.js | 6 ++++++ 5 files changed, 8 insertions(+), 4 deletions(-) delete mode 100644 solidjs-tailwind/src/components/Icons/index.js delete mode 100644 solidjs-tailwind/src/components/icons/index.js diff --git a/solidjs-tailwind/src/components/Icons/index.js b/solidjs-tailwind/src/components/Icons/index.js deleted file mode 100644 index 93e73e0cc..000000000 --- a/solidjs-tailwind/src/components/Icons/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as TwitterIcon } from './TwitterIcon'; diff --git a/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx index e59c6a948..48f516af1 100644 --- a/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx +++ b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx @@ -7,7 +7,7 @@ import { Switch, Match, } from 'solid-js'; -import { CaretIcon, CloseIcon, CorrectIcon } from '../icons'; +import { CaretIcon, CloseIcon, CorrectIcon } from '../index'; function clickOutside(el, accessor) { const onClick = (e) => { diff --git a/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx index 2cc7ad7ab..cd704d496 100644 --- a/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx +++ b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx @@ -6,7 +6,7 @@ import { link, } from 'solid-heroicons/outline'; import { Icon } from 'solid-heroicons'; -import { TwitterIcon } from '../Icons'; +import { TwitterIcon } from '../index'; import OrgList from './OrgList'; const UserProfile = (userProfileProps) => { diff --git a/solidjs-tailwind/src/components/icons/index.js b/solidjs-tailwind/src/components/icons/index.js deleted file mode 100644 index 93e73e0cc..000000000 --- a/solidjs-tailwind/src/components/icons/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default as TwitterIcon } from './TwitterIcon'; diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 6885ea85e..0d3312ed4 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -9,3 +9,9 @@ export * from './Header'; export * from './UserDropdown'; export { default as PageHeader } from './PageHeader'; export { default as PageFooter } from './PageFooter'; +// Icons +export { default as CaretIcon } from './icons/caret'; +export { default as CloseIcon } from './icons/close'; +export { default as CorrectIcon } from './icons/correct'; +export { default as RepoBookIcon } from './icons/repo-book'; +export { default as TwitterIcon } from './icons/TwitterIcon'; From e8b67d54adb230b73dc940014466da37904beef3 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 14:49:22 +0100 Subject: [PATCH 15/19] ..updates --- solidjs-tailwind/src/components/Icons/index.js | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 solidjs-tailwind/src/components/Icons/index.js diff --git a/solidjs-tailwind/src/components/Icons/index.js b/solidjs-tailwind/src/components/Icons/index.js new file mode 100644 index 000000000..c8291f64f --- /dev/null +++ b/solidjs-tailwind/src/components/Icons/index.js @@ -0,0 +1,5 @@ +export { default as TwitterIcon } from './TwitterIcon'; +export { default as CaretIcon } from './caret'; +export { default as CloseIcon } from './close'; +export { default as CorrectIcon } from './correct'; +export { default as RepoBookIcon } from './repo-book'; From 6832a9c30cd73705927f8cacbc077a8986845f77 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 15:12:30 +0100 Subject: [PATCH 16/19] auth token added to header --- solidjs-tailwind/src/services/user-repos.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/solidjs-tailwind/src/services/user-repos.js b/solidjs-tailwind/src/services/user-repos.js index 03a66f3b2..7e488ae57 100644 --- a/solidjs-tailwind/src/services/user-repos.js +++ b/solidjs-tailwind/src/services/user-repos.js @@ -1,15 +1,17 @@ +import { useAuth } from "../auth"; import FetchApi from "./api"; import { USER_REPOS_QUERY } from "./queries/all-repos"; const getUserRepos = async ({ url }) => { + const { authStore } = useAuth(); const data = { url, query: USER_REPOS_QUERY, variable: null, headersOptions: { - authorization: `Bearer tokenvalue`, + authorization: `Bearer ${authStore.token}`, } } const resp = await FetchApi(data); From 9df976726e76e137ed0155eb81fb1011b1b74a5d Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 15:23:17 +0100 Subject: [PATCH 17/19] fix file issues --- .../src/components/RepoFilter/FilterDropdown.jsx | 2 +- solidjs-tailwind/src/components/RepoFilter/FilterText.jsx | 2 +- solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx | 2 +- solidjs-tailwind/src/components/UserProfile/UserProfile.jsx | 2 +- solidjs-tailwind/src/components/index.js | 6 ------ 5 files changed, 4 insertions(+), 10 deletions(-) diff --git a/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx index 48f516af1..c776915c9 100644 --- a/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx +++ b/solidjs-tailwind/src/components/RepoFilter/FilterDropdown.jsx @@ -7,7 +7,7 @@ import { Switch, Match, } from 'solid-js'; -import { CaretIcon, CloseIcon, CorrectIcon } from '../index'; +import { CaretIcon, CloseIcon, CorrectIcon } from '../Icons'; function clickOutside(el, accessor) { const onClick = (e) => { diff --git a/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx b/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx index 7f26730e1..2261f49ad 100644 --- a/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx +++ b/solidjs-tailwind/src/components/RepoFilter/FilterText.jsx @@ -1,5 +1,5 @@ import { Show, splitProps } from 'solid-js'; -import { CloseIcon } from '../icons'; +import { CloseIcon } from '../Icons'; const modifyFilterTypeText = (filterText = 'test') => { if (filterText.endsWith('s')) { diff --git a/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx index c977f8a5b..7db66b8b9 100644 --- a/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx +++ b/solidjs-tailwind/src/components/RepoFilter/RepoFilter.jsx @@ -1,5 +1,5 @@ import { mergeProps, Show } from 'solid-js'; -import { RepoBookIcon } from '../icons'; +import { RepoBookIcon } from '../Icons'; import { FILTER_TYPE_OPTIONS, SORT_OPTIONS } from './data'; import FilterDropdown from './FilterDropdown'; import FilterText from './FilterText'; diff --git a/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx index cd704d496..2cc7ad7ab 100644 --- a/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx +++ b/solidjs-tailwind/src/components/UserProfile/UserProfile.jsx @@ -6,7 +6,7 @@ import { link, } from 'solid-heroicons/outline'; import { Icon } from 'solid-heroicons'; -import { TwitterIcon } from '../index'; +import { TwitterIcon } from '../Icons'; import OrgList from './OrgList'; const UserProfile = (userProfileProps) => { diff --git a/solidjs-tailwind/src/components/index.js b/solidjs-tailwind/src/components/index.js index 0d3312ed4..6885ea85e 100644 --- a/solidjs-tailwind/src/components/index.js +++ b/solidjs-tailwind/src/components/index.js @@ -9,9 +9,3 @@ export * from './Header'; export * from './UserDropdown'; export { default as PageHeader } from './PageHeader'; export { default as PageFooter } from './PageFooter'; -// Icons -export { default as CaretIcon } from './icons/caret'; -export { default as CloseIcon } from './icons/close'; -export { default as CorrectIcon } from './icons/correct'; -export { default as RepoBookIcon } from './icons/repo-book'; -export { default as TwitterIcon } from './icons/TwitterIcon'; From c3de4cba140f40c35ef70f7591b4db756676bbe9 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 15:36:07 +0100 Subject: [PATCH 18/19] CI adjustments --- solidjs-tailwind/src/components/icons/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/solidjs-tailwind/src/components/icons/index.js b/solidjs-tailwind/src/components/icons/index.js index e00402d99..c8291f64f 100644 --- a/solidjs-tailwind/src/components/icons/index.js +++ b/solidjs-tailwind/src/components/icons/index.js @@ -1,3 +1,4 @@ +export { default as TwitterIcon } from './TwitterIcon'; export { default as CaretIcon } from './caret'; export { default as CloseIcon } from './close'; export { default as CorrectIcon } from './correct'; From b886b645cdb6eda5847b7890fea422201ec015f7 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Nov 2022 15:34:29 +0100 Subject: [PATCH 19/19] CI adjustments --- .github/workflows/ci-solidjs-tailwind.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci-solidjs-tailwind.yml b/.github/workflows/ci-solidjs-tailwind.yml index b55d1cdfe..357a34a48 100644 --- a/.github/workflows/ci-solidjs-tailwind.yml +++ b/.github/workflows/ci-solidjs-tailwind.yml @@ -21,11 +21,13 @@ jobs: steps: - uses: actions/checkout@v2 + uses: pnpm/action-setup@v2.2.4 with: fetch-depth: 0 - name: Use Node.js uses: actions/setup-node@v2 + uses: pnpm/action-setup@v2.2.4 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' @@ -45,11 +47,13 @@ jobs: steps: - name: Checkout code uses: actions/checkout@v2 + uses: pnpm/action-setup@v2.2.4 with: fetch-depth: 0 - name: Use Node.js uses: actions/setup-node@v2 + uses: pnpm/action-setup@v2.2.4 with: node-version: ${{ matrix.node-version }} cache: "pnpm" @@ -75,11 +79,13 @@ jobs: steps: - uses: actions/checkout@v2 + uses: pnpm/action-setup@v2.2.4 with: fetch-depth: 0 - name: Use Node.js uses: actions/setup-node@v2 + uses: pnpm/action-setup@v2.2.4 with: node-version: ${{ matrix.node-version }} cache: "pnpm"