diff --git a/backend/package-lock.json b/backend/package-lock.json index a35345adb..72283be58 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -14,6 +14,7 @@ "@graphql-tools/schema": "^10.0.0", "@graphql-tools/utils": "^10.0.7", "axios": "^1.5.1", + "compression": "^1.7.4", "connect-redis": "^7.1.1", "cors": "^2.8.5", "dotenv": "^8.2.0", @@ -38,6 +39,7 @@ "@graphql-codegen/introspection": "2.2.1", "@graphql-codegen/typescript": "^2.7.4", "@graphql-codegen/typescript-resolvers": "^2.7.4", + "@types/compression": "^1.7.5", "@types/cors": "^2.8.12", "@types/express-session": "^1.17.6", "@types/helmet": "0.0.46", @@ -56,23 +58,15 @@ "typescript": "^5.2.2" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -82,6 +76,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/@apollo/cache-control-types/-/cache-control-types-1.0.3.tgz", "integrity": "sha512-F17/vCp7QVwom9eG7ToauIKdAxpSoadsJnqIfyryLFSkLSOEqu+eC5Z3N8OXcUVStuOMcNHlyraRsA6rRICu4g==", + "license": "MIT", "peerDependencies": { "graphql": "14.x || 15.x || 16.x" } @@ -91,6 +86,7 @@ "resolved": "https://registry.npmjs.org/@apollo/protobufjs/-/protobufjs-1.2.7.tgz", "integrity": "sha512-Lahx5zntHPZia35myYDBRuF58tlwPskwHc5CWBZC/4bMKB6siTBWwtMrkqXcsNwQiFSzSx5hKdRPUmemrEp3Gg==", "hasInstallScript": true, + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", @@ -111,9 +107,10 @@ } }, "node_modules/@apollo/server": { - "version": "4.9.4", - "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.9.4.tgz", - "integrity": "sha512-lopNDM3sZerTcYH/P85QX5HqSNV4HoVbtX3zOrf0ak7eplhPDiGVyF0jQWRbL64znG6KXW+nMuLDTyFTMQnvgA==", + "version": "4.10.4", + "resolved": "https://registry.npmjs.org/@apollo/server/-/server-4.10.4.tgz", + "integrity": "sha512-HS12CUa1wq8f5zKXOKJRwRdESFp4por9AINecpcsEUV9jsCP/NqPILgx0hCOOFJuKxmnaL7070xO6l5xmOq4Fw==", + "license": "MIT", "dependencies": { "@apollo/cache-control-types": "^1.0.3", "@apollo/server-gateway-interface": "^1.1.1", @@ -131,7 +128,6 @@ "@types/express-serve-static-core": "^4.17.30", "@types/node-fetch": "^2.6.1", "async-retry": "^1.2.1", - "body-parser": "^1.20.0", "cors": "^2.8.5", "express": "^4.17.1", "loglevel": "^1.6.8", @@ -153,6 +149,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@apollo/server-gateway-interface/-/server-gateway-interface-1.1.1.tgz", "integrity": "sha512-pGwCl/po6+rxRmDMFgozKQo2pbsSwE91TpsDBAOgf74CRDPXHHtM88wbwjab0wMMZh95QfR45GGyDIdhY24bkQ==", + "license": "MIT", "dependencies": { "@apollo/usage-reporting-protobuf": "^4.1.1", "@apollo/utils.fetcher": "^2.0.0", @@ -167,6 +164,7 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/@apollo/server-plugin-response-cache/-/server-plugin-response-cache-4.1.3.tgz", "integrity": "sha512-8WaP4Xo9GGIbWn4ZG/TlYKZLo/YI8tuORvxzLOKnZa3EqUvt7iTCGHX491dWNiGkm93VgDDdo5r0WEvLDdHSmQ==", + "license": "MIT", "dependencies": { "@apollo/utils.createhash": "^2.0.0", "@apollo/utils.keyvaluecache": "^2.1.0" @@ -179,10 +177,24 @@ "graphql": "^16.6.0" } }, + "node_modules/@apollo/server/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@apollo/server/node_modules/@graphql-tools/schema": { "version": "9.0.19", "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", + "license": "MIT", "dependencies": { "@graphql-tools/merge": "^8.4.1", "@graphql-tools/utils": "^9.2.1", @@ -197,6 +209,7 @@ "version": "9.2.1", "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -209,6 +222,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/@apollo/usage-reporting-protobuf/-/usage-reporting-protobuf-4.1.1.tgz", "integrity": "sha512-u40dIUePHaSKVshcedO7Wp+mPiZsaU6xjv9J+VyxpoU/zL6Jle+9zWeG98tr/+SZ0nZ4OXhrbb8SNr0rAPpIDA==", + "license": "MIT", "dependencies": { "@apollo/protobufjs": "1.2.7" } @@ -217,6 +231,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.createhash/-/utils.createhash-2.0.1.tgz", "integrity": "sha512-fQO4/ZOP8LcXWvMNhKiee+2KuKyqIcfHrICA+M4lj/h/Lh1H10ICcUtk6N/chnEo5HXu0yejg64wshdaiFitJg==", + "license": "MIT", "dependencies": { "@apollo/utils.isnodelike": "^2.0.1", "sha.js": "^2.4.11" @@ -229,6 +244,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.dropunuseddefinitions/-/utils.dropunuseddefinitions-2.0.1.tgz", "integrity": "sha512-EsPIBqsSt2BwDsv8Wu76LK5R1KtsVkNoO4b0M5aK0hx+dGg9xJXuqlr7Fo34Dl+y83jmzn+UvEW+t1/GP2melA==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -240,6 +256,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.fetcher/-/utils.fetcher-2.0.1.tgz", "integrity": "sha512-jvvon885hEyWXd4H6zpWeN3tl88QcWnHp5gWF5OPF34uhvoR+DFqcNxs9vrRaBBSY3qda3Qe0bdud7tz2zGx1A==", + "license": "MIT", "engines": { "node": ">=14" } @@ -248,6 +265,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.isnodelike/-/utils.isnodelike-2.0.1.tgz", "integrity": "sha512-w41XyepR+jBEuVpoRM715N2ZD0xMD413UiJx8w5xnAZD2ZkSJnMJBoIzauK83kJpSgNuR6ywbV29jG9NmxjK0Q==", + "license": "MIT", "engines": { "node": ">=14" } @@ -256,6 +274,7 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/@apollo/utils.keyvaluecache/-/utils.keyvaluecache-2.1.1.tgz", "integrity": "sha512-qVo5PvUUMD8oB9oYvq4ViCjYAMWnZ5zZwEjNF37L2m1u528x5mueMlU+Cr1UinupCgdB78g+egA1G98rbJ03Vw==", + "license": "MIT", "dependencies": { "@apollo/utils.logger": "^2.0.1", "lru-cache": "^7.14.1" @@ -268,6 +287,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.logger/-/utils.logger-2.0.1.tgz", "integrity": "sha512-YuplwLHaHf1oviidB7MxnCXAdHp3IqYV8n0momZ3JfLniae92eYqMIx+j5qJFX6WKJPs6q7bczmV4lXIsTu5Pg==", + "license": "MIT", "engines": { "node": ">=14" } @@ -276,6 +296,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.printwithreducedwhitespace/-/utils.printwithreducedwhitespace-2.0.1.tgz", "integrity": "sha512-9M4LUXV/fQBh8vZWlLvb/HyyhjJ77/I5ZKu+NBWV/BmYGyRmoEP9EVAy7LCVoY3t8BDcyCAGfxJaLFCSuQkPUg==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -287,6 +308,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.removealiases/-/utils.removealiases-2.0.1.tgz", "integrity": "sha512-0joRc2HBO4u594Op1nev+mUF6yRnxoUH64xw8x3bX7n8QBDYdeYgY4tF0vJReTy+zdn2xv6fMsquATSgC722FA==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -298,6 +320,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.sortast/-/utils.sortast-2.0.1.tgz", "integrity": "sha512-eciIavsWpJ09za1pn37wpsCGrQNXUhM0TktnZmHwO+Zy9O4fu/WdB4+5BvVhFiZYOXvfjzJUcc+hsIV8RUOtMw==", + "license": "MIT", "dependencies": { "lodash.sortby": "^4.7.0" }, @@ -312,6 +335,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.stripsensitiveliterals/-/utils.stripsensitiveliterals-2.0.1.tgz", "integrity": "sha512-QJs7HtzXS/JIPMKWimFnUMK7VjkGQTzqD9bKD1h3iuPAqLsxd0mUNVbkYOPTsDhUKgcvUOfOqOJWYohAKMvcSA==", + "license": "MIT", "engines": { "node": ">=14" }, @@ -323,6 +347,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/@apollo/utils.usagereporting/-/utils.usagereporting-2.1.0.tgz", "integrity": "sha512-LPSlBrn+S17oBy5eWkrRSGb98sWmnEzo3DPTZgp8IQc8sJe0prDgDuppGq4NeQlpoqEHz0hQeYHAOA0Z3aQsxQ==", + "license": "MIT", "dependencies": { "@apollo/usage-reporting-protobuf": "^4.1.0", "@apollo/utils.dropunuseddefinitions": "^2.0.1", @@ -342,6 +367,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/@apollo/utils.withrequired/-/utils.withrequired-2.0.1.tgz", "integrity": "sha512-YBDiuAX9i1lLc6GeTy1m7DGLFn/gMnvXqlalOIMjM7DeOgIacEjjfwPqb0M1CQ2v11HhR15d1NmxJoRCfrNqcA==", + "license": "MIT", "engines": { "node": ">=14" } @@ -351,6 +377,7 @@ "resolved": "https://registry.npmjs.org/@ardatan/relay-compiler/-/relay-compiler-12.0.0.tgz", "integrity": "sha512-9anThAaj1dQr6IGmzBMcfzOQKTa5artjuPmw8NYK/fiGEMjADbSguBY2FMDykt+QhilR3wc9VA/3yVju7JHg7Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.14.0", "@babel/generator": "^7.14.0", @@ -377,22 +404,77 @@ "graphql": "*" } }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT", + "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/@ardatan/relay-compiler/node_modules/cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" } }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT" + }, "node_modules/@ardatan/relay-compiler/node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -401,11 +483,22 @@ "node": ">=8" } }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/@ardatan/relay-compiler/node_modules/locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -418,6 +511,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -433,6 +527,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -440,17 +535,32 @@ "node": ">=8" } }, + "node_modules/@ardatan/relay-compiler/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@ardatan/relay-compiler/node_modules/y18n": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@ardatan/relay-compiler/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -473,6 +583,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -486,6 +597,7 @@ "resolved": "https://registry.npmjs.org/@ardatan/sync-fetch/-/sync-fetch-0.0.1.tgz", "integrity": "sha512-xhlTqH0m31mnsG0tIP4ETgfSB6gXDaYYsUWTrlUV93fFQPI9dd8hE0Ot6MHLCtqgB32hwJAC3YZMWlXZw7AleA==", "dev": true, + "license": "MIT", "dependencies": { "node-fetch": "^2.6.1" }, @@ -494,114 +606,46 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", "dev": true, + "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -617,10 +661,11 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.22.15.tgz", - "integrity": "sha512-yc8OOBIQk1EcRrpizuARSQS0TWAcOMpEJ1aafhNznaeYkeL+OhqnDObGFylB8ka8VFF/sZc+S4RzHyO+3LjQxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.24.7.tgz", + "integrity": "sha512-SO5E3bVxDuxyNxM5agFv480YA2HO6ohZbGxbazZdIk3KQOPOGVNw6q78I9/lbviIf95eq6tPozeYnJLbjnC8IA==", "dev": true, + "license": "MIT", "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -631,27 +676,19 @@ }, "peerDependencies": { "@babel/core": "^7.11.0", - "eslint": "^7.5.0 || ^8.0.0" - } - }, - "node_modules/@babel/eslint-parser/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" + "eslint": "^7.5.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -659,26 +696,28 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", - "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -691,24 +730,33 @@ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, + "license": "ISC", "dependencies": { "yallist": "^3.0.2" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz", - "integrity": "sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz", + "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", "semver": "^6.3.1" }, "engines": { @@ -719,74 +767,85 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", - "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz", + "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.23.0" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -796,35 +855,38 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", - "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz", + "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", - "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz", + "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-member-expression-to-functions": "^7.22.15", - "@babel/helper-optimise-call-expression": "^7.22.5" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.7", + "@babel/helper-optimise-call-expression": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -834,172 +896,112 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", - "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/highlight/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, + "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -1013,6 +1015,7 @@ "integrity": "sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-class-properties instead.", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-create-class-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1030,6 +1033,7 @@ "integrity": "sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg==", "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-object-rest-spread instead.", "dev": true, + "license": "MIT", "dependencies": { "@babel/compat-data": "^7.20.5", "@babel/helper-compilation-targets": "^7.20.7", @@ -1049,6 +1053,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1061,6 +1066,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1073,6 +1079,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -1081,12 +1088,13 @@ } }, "node_modules/@babel/plugin-syntax-flow": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.22.5.tgz", - "integrity": "sha512-9RdCl0i+q0QExayk2nOS7853w08yLucnnPML6EN9S8fgMPVtdLDCdx/cOQ/i44Lb9UeQX9A35yaqBBOMMZxPxQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.7.tgz", + "integrity": "sha512-9G8GYT/dxn/D1IIKOUBmGX0mnmj46mGH9NnZyJLwtCpgh5f7D2VbuKodb+2s9m1Yavh1s7ASQN8lf0eqrb1LTw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1096,12 +1104,13 @@ } }, "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.22.5.tgz", - "integrity": "sha512-rdV97N7KqsRzeNGoWUOK6yUsWarLjE5Su/Snk9IYPU9CwkWHs4t+rTGOvffTR8XGkJMTAdLfO0xVnXm8wugIJg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.7.tgz", + "integrity": "sha512-Ec3NRUMoi8gskrkBe3fNmEQfxDvY8bgfQpz6jlk/41kX9eUjvpyqWU7PBP/pLAvMaSQjbMNKJmvX57jP+M6bPg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1115,6 +1124,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1127,6 +1137,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1135,12 +1146,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.22.5.tgz", - "integrity": "sha512-gvyP4hZrgrs/wWMaocvxZ44Hw0b3W8Pe+cMxc8V1ULQ07oh8VNbIRaoD1LRZVTvD+0nieDKjfgKg89sD7rrKrg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz", + "integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1154,6 +1166,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1166,6 +1179,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1178,6 +1192,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -1190,6 +1205,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1202,6 +1218,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1214,6 +1231,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -1226,6 +1244,7 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1237,12 +1256,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", - "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz", + "integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1252,12 +1272,13 @@ } }, "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.22.5.tgz", - "integrity": "sha512-26lTNXoVRdAnsaDXPpvCNUq+OVWEVC6bx7Vvz9rC53F2bagUWW4u4ii2+h8Fejfh7RYqPxn+libeFBBck9muEw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.7.tgz", + "integrity": "sha512-Dt9LQs6iEY++gXUwY03DNFat5C2NbO48jj+j/bSAz6b3HgPs39qcPiYt77fDObIcFwj3/C2ICX9YMwGflUoSHQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1267,12 +1288,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.22.5.tgz", - "integrity": "sha512-tdXZ2UdknEKQWKJP1KMNmuF5Lx3MymtMN/pvA+p/VEkhK8jVcQ1fzSy8KM9qRYhAf2/lV33hoMPKI/xaI9sADA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.7.tgz", + "integrity": "sha512-yO7RAz6EsVQDaBH18IDJcMB1HnrUn2FJ/Jslc/WtPPWcjhpUJXU/rjbwmluzp7v/ZzWcEhTMXELnnsz8djWDwQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1282,12 +1304,13 @@ } }, "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.0.tgz", - "integrity": "sha512-cOsrbmIOXmf+5YbL99/S49Y3j46k/T16b9ml8bm9lP6N9US5iQ2yBK7gpui1pg0V/WMcXdkfKbTb7HXq9u+v4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.7.tgz", + "integrity": "sha512-Nd5CvgMbWc+oWzBsuaMcbwjJWAcp5qzrbg69SZdHSP7AMY0AbWFqFO0WTFCA1jxhMCwodRwvRec8k0QUbZk7RQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1297,19 +1320,19 @@ } }, "node_modules/@babel/plugin-transform-classes": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz", - "integrity": "sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-optimise-call-expression": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.9", - "@babel/helper-split-export-declaration": "^7.22.6", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.7.tgz", + "integrity": "sha512-CFbbBigp8ln4FU6Bpy6g7sE8B/WmCmzvivzUC6xDAdWVsjYTXijpuuGJmYkAaoWAzcItGKT3IOAbxRItZ5HTjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", "globals": "^11.1.0" }, "engines": { @@ -1320,13 +1343,14 @@ } }, "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.22.5.tgz", - "integrity": "sha512-4GHWBgRf0krxPX+AaPtgBAlTgTeZmqDynokHOX7aqqAB4tHs3U2Y02zH6ETFdLZGcg9UQSD1WCmkVrE9ErHeOg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.7.tgz", + "integrity": "sha512-25cS7v+707Gu6Ds2oY6tCkUwsJ9YIDbggd9+cu9jzzDgiNq7hR/8dkzxWfKWnTic26vsI3EsCXNd4iEB6e8esQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/template": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/template": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1336,12 +1360,13 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.0.tgz", - "integrity": "sha512-vaMdgNXFkYrB+8lbgniSYWHsgqK5gjaMNcc84bMIOMRLH0L9AqYq3hwMdvnyqj1OPqea8UtjPEuS/DCenah1wg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.7.tgz", + "integrity": "sha512-19eJO/8kdCQ9zISOf+SEUJM/bAUIsvY3YDnXZTupUCQ8LgrWnsG/gFB9dvXqdXnRXMAM8fvt7b0CBKQHNGy1mw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1351,13 +1376,14 @@ } }, "node_modules/@babel/plugin-transform-flow-strip-types": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.22.5.tgz", - "integrity": "sha512-tujNbZdxdG0/54g/oua8ISToaXTFBf8EnSb5PgQSciIXWOWKX3S4+JR7ZE9ol8FZwf9kxitzkGQ+QWeov/mCiA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.7.tgz", + "integrity": "sha512-cjRKJ7FobOH2eakx7Ja+KpJRj8+y+/SiB3ooYm/n2UJfxu0oEaOoxOinitkJcPqv9KxS0kxTGPUaR7L2XcXDXA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-flow": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-flow": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1367,12 +1393,14 @@ } }, "node_modules/@babel/plugin-transform-for-of": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz", - "integrity": "sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.7.tgz", + "integrity": "sha512-wo9ogrDG1ITTTBsy46oGiN1dS9A7MROBTcYsfS8DtsImMkHk9JXJ3EWQM6X2SUw4x80uGPlwj0o00Uoc6nEE3g==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1382,14 +1410,15 @@ } }, "node_modules/@babel/plugin-transform-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.22.5.tgz", - "integrity": "sha512-UIzQNMS0p0HHiQm3oelztj+ECwFnj+ZRV4KnguvlsD2of1whUeM6o7wGNj6oLwcDoAXQ8gEqfgC24D+VdIcevg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.7.tgz", + "integrity": "sha512-U9FcnA821YoILngSmYkW6FjyQe2TyZD5pHt4EVIhmcTkrJw/3KqcrRSxuOo5tFZJi7TE19iDyI1u+weTI7bn2w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-compilation-targets": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1399,12 +1428,13 @@ } }, "node_modules/@babel/plugin-transform-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.22.5.tgz", - "integrity": "sha512-fTLj4D79M+mepcw3dgFBTIDYpbcB9Sm0bpm4ppXPaO+U+PKFFyV9MGRvS0gvGw62sd10kT5lRMKXAADb9pWy8g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.7.tgz", + "integrity": "sha512-vcwCbb4HDH+hWi8Pqenwnjy+UiklO4Kt1vfspcQYFhJdpthSnW8XvWGyDZWKNVrVbVViI/S7K9PDJZiUmP2fYQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1414,12 +1444,13 @@ } }, "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.22.5.tgz", - "integrity": "sha512-RZEdkNtzzYCFl9SE9ATaUMTj2hqMb4StarOJLrZRbqqU4HSBE7UlBw9WBWQiDzrJZJdUWiMTVDI6Gv/8DPvfew==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.7.tgz", + "integrity": "sha512-T/hRC1uqrzXMKLQ6UCwMT85S3EvqaBXDGf0FaMf4446Qx9vKwlghvee0+uuZcDUCZU5RuNi4781UQ7R308zzBw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1429,14 +1460,15 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.0.tgz", - "integrity": "sha512-32Xzss14/UVc7k9g775yMIvkVK8xwKE0DPdP5JTapr3+Z9w4tzeOuLNY6BXDQR6BdnzIlXnCGAzsk/ICHBLVWQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.7.tgz", + "integrity": "sha512-iFI8GDxtevHJ/Z22J5xQpVqFLlMNstcLXh994xifFwxxGslr2ZXXLWgtBeLctOD63UFDArdvN6Tg8RFw+aEmjQ==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-simple-access": "^7.22.5" + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1446,13 +1478,14 @@ } }, "node_modules/@babel/plugin-transform-object-super": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.22.5.tgz", - "integrity": "sha512-klXqyaT9trSjIUrcsYIfETAzmOEZL3cBYqOYLJxBHfMFFggmXOv+NYSX/Jbs9mzMVESw/WycLFPRx8ba/b2Ipw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.7.tgz", + "integrity": "sha512-A/vVLwN6lBrMFmMDmPPz0jnE6ZGx7Jq7d6sT/Ev4H65RER6pZ+kczlf1DthF5N0qaPHBsI7UXiE8Zy66nmAovg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-replace-supers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-replace-supers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1462,12 +1495,13 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz", - "integrity": "sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.7.tgz", + "integrity": "sha512-yGWW5Rr+sQOhK0Ot8hjDJuxU3XLRQGflvT4lhlSY0DFvdb3TwKaY26CJzHtYllU0vT9j58hc37ndFPsqT1SrzA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1477,12 +1511,13 @@ } }, "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.22.5.tgz", - "integrity": "sha512-TiOArgddK3mK/x1Qwf5hay2pxI6wCZnvQqrFSqbtg1GLl2JcNMitVH/YnqjP+M31pLUeTfzY1HAXFDnUBV30rQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.7.tgz", + "integrity": "sha512-EMi4MLQSHfd2nrCqQEWxFdha2gBCqU4ZcCng4WBGZ5CJL4bBRW0ptdqqDdeirGZcpALazVVNJqRmsO8/+oNCBA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1492,12 +1527,13 @@ } }, "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.22.5.tgz", - "integrity": "sha512-PVk3WPYudRF5z4GKMEYUrLjPl38fJSKNaEOkFuoprioowGuWN6w2RKznuFNSlJx7pzzXXStPUnNSOEO0jL5EVw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.7.tgz", + "integrity": "sha512-H/Snz9PFxKsS1JLI4dJLtnJgCJRoo0AUm3chP6NYr+9En1JMKloheEiLIhlp5MDVznWo+H3AAC1Mc8lmUEpsgg==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1507,16 +1543,17 @@ } }, "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.22.15.tgz", - "integrity": "sha512-oKckg2eZFa8771O/5vi7XeTvmM6+O9cxZu+kanTU7tD4sin5nO/G8jGJhq8Hvt2Z0kUoEDRayuZLaUlYl8QuGA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.24.7.tgz", + "integrity": "sha512-+Dj06GDZEFRYvclU6k4bme55GKBEWUmByM/eoKuqg4zTNQHiApWRhQph5fxQB2wAEFvRzL1tOEj1RJ19wJrhoA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/plugin-syntax-jsx": "^7.22.5", - "@babel/types": "^7.22.15" + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/plugin-syntax-jsx": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1526,12 +1563,13 @@ } }, "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.22.5.tgz", - "integrity": "sha512-vM4fq9IXHscXVKzDv5itkO1X52SmdFBFcMIBZ2FRn2nqVYqw6dBexUgMvAjHW+KXpPPViD/Yo3GrDEBaRC0QYA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.7.tgz", + "integrity": "sha512-KsDsevZMDsigzbA09+vacnLpmPH4aWjcZjXdyFKGzpplxhbeB4wYtury3vglQkg6KM/xEPKt73eCjPPf1PgXBA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1541,13 +1579,14 @@ } }, "node_modules/@babel/plugin-transform-spread": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.22.5.tgz", - "integrity": "sha512-5ZzDQIGyvN4w8+dMmpohL6MBo+l2G7tfC/O2Dg7/hjpgeWvUx8FzfeOKxGog9IimPa4YekaQ9PlDqTLOljkcxg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.7.tgz", + "integrity": "sha512-x96oO0I09dgMDxJaANcRyD4ellXFLLiWhuwDxKZX5g2rWP1bTPkBSwCYv96VDXVT1bD9aPj8tppr5ITIh8hBng==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1557,12 +1596,13 @@ } }, "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.22.5.tgz", - "integrity": "sha512-5ciOehRNf+EyUeewo8NkbQiUs4d6ZxiHo6BcBcnFlgiJfu16q0bQUw9Jvo0b0gBKFG1SMhDSjeKXSYuJLeFSMA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.7.tgz", + "integrity": "sha512-AfDTQmClklHCOLxtGoP7HkeMw56k1/bTQjwsfhL6pppo/M4TOBSq+jjBUBLmV/4oeFg4GWMavIl44ZeCtmmZTw==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1572,10 +1612,11 @@ } }, "node_modules/@babel/runtime": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", - "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", "dev": true, + "license": "MIT", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -1584,34 +1625,36 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -1619,13 +1662,14 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -1636,13 +1680,15 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -1655,6 +1701,7 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -1665,6 +1712,7 @@ "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -1675,20 +1723,35 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.9.1.tgz", - "integrity": "sha512-Y27x+MBLjXa+0JWDhykM3+JE+il3kHKAEqabfEWq3SDhZjLYb6/BHL/JKFnH3fe207JaXkyDo685Oc2Glt6ifA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -1708,10 +1771,11 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.20.2" }, @@ -1722,11 +1786,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/eslintrc/node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -1735,19 +1813,21 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@fastify/busboy": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.0.0.tgz", - "integrity": "sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", + "integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" } @@ -1757,6 +1837,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.13.7.tgz", "integrity": "sha512-Rpk4WWrDgkDoVELftBr7/74MPiYmCITEF2+AWmyZZ2xzaC9cO2PqzZ+OYDEBNWD6UEk0RrIfVSa+slDKjhY59w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/generator": "^7.18.13", "@babel/template": "^7.18.10", @@ -1810,6 +1891,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz", "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.4.0" }, @@ -1817,11 +1899,88 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-codegen/cli/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@graphql-codegen/cli/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, + "license": "MIT", + "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/@graphql-codegen/cli/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@graphql-codegen/cli/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, + "license": "MIT" + }, + "node_modules/@graphql-codegen/cli/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-codegen/cli/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@graphql-codegen/core": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/core/-/core-2.6.2.tgz", "integrity": "sha512-58T5yf9nEfAhDwN1Vz1hImqpdJ/gGpCGUaroQ5tqskZPf7eZYYVkEXbtqRZZLx1MCCKwjWX4hMtTPpHhwKCkng==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^2.6.2", "@graphql-tools/schema": "^9.0.0", @@ -1832,11 +1991,40 @@ "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/@graphql-codegen/core/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-codegen/core/node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@graphql-codegen/core/node_modules/@graphql-tools/schema": { "version": "9.0.19", "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/merge": "^8.4.1", "@graphql-tools/utils": "^9.2.1", @@ -1852,6 +2040,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -1865,6 +2054,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz", "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.4.0" }, @@ -1876,13 +2066,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/graphql-modules-preset": { "version": "2.5.12", "resolved": "https://registry.npmjs.org/@graphql-codegen/graphql-modules-preset/-/graphql-modules-preset-2.5.12.tgz", "integrity": "sha512-Azp0Y3ytrkSOY9t9AWI5vuQEhEXogPNteUed4OycqwIa2Mvgb7jrpK9F1F9yMGabstwQyVNqt8cLGM0Gst2E9A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^3.1.2", "@graphql-codegen/visitor-plugin-common": "2.13.8", @@ -1900,6 +2092,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.0.0", "change-case-all": "1.0.15", @@ -1917,6 +2110,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -1929,13 +2123,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/introspection": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@graphql-codegen/introspection/-/introspection-2.2.1.tgz", "integrity": "sha512-083tu9rSLL0k9LrAyGt1AjGQI/O9gX3w1UliaufLc3mofDSt7iV04tT9VJRuk4IoBvyPZ/8YCs5zIpmt/GexPA==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^2.6.2", "@graphql-codegen/visitor-plugin-common": "^2.12.1", @@ -1949,13 +2145,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/plugin-helpers": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-2.7.2.tgz", "integrity": "sha512-kln2AZ12uii6U59OQXdjLk5nOlh1pHis1R98cDZGFnfaiAbX9V3fxcZ1MMJkB7qFUymTALzyjZoXXdyVmPMfRg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^8.8.0", "change-case-all": "1.0.14", @@ -1973,6 +2171,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz", "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.4.0" }, @@ -1985,6 +2184,7 @@ "resolved": "https://registry.npmjs.org/change-case-all/-/change-case-all-1.0.14.tgz", "integrity": "sha512-CWVm2uT7dmSHdO/z1CXT/n47mWonyypzBbuCy5tN7uMg22BsfkhwT6oHmFCAk+gL1LOOxhdbB9SZz3J1KTY3gA==", "dev": true, + "license": "MIT", "dependencies": { "change-case": "^4.1.2", "is-lower-case": "^2.0.2", @@ -2002,13 +2202,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/schema-ast": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/@graphql-codegen/schema-ast/-/schema-ast-2.6.1.tgz", "integrity": "sha512-5TNW3b1IHJjCh07D2yQNGDQzUpUl2AD+GVe1Dzjqyx/d2Fn0TPMxLsHsKPS4Plg4saO8FK/QO70wLsP7fdbQ1w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^3.1.2", "@graphql-tools/utils": "^9.0.0", @@ -2023,6 +2225,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.0.0", "change-case-all": "1.0.15", @@ -2040,6 +2243,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2052,13 +2256,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/typescript": { "version": "2.8.8", "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript/-/typescript-2.8.8.tgz", "integrity": "sha512-A0oUi3Oy6+DormOlrTC4orxT9OBZkIglhbJBcDmk34jAKKUgesukXRd4yOhmTrnbchpXz2T8IAOFB3FWIaK4Rw==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^3.1.2", "@graphql-codegen/schema-ast": "^2.6.1", @@ -2075,6 +2281,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/typescript-resolvers/-/typescript-resolvers-2.7.13.tgz", "integrity": "sha512-ZIXiUw86ctNYQe41RAwadhSMe0koNvomxNRK+ZYlWQn1gplpc3jcdgI+BrdJbBWK/6VBYKZzrayJHr1VsHfYJQ==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^3.1.2", "@graphql-codegen/typescript": "^2.8.8", @@ -2092,6 +2299,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.0.0", "change-case-all": "1.0.15", @@ -2109,6 +2317,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2121,13 +2330,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/typescript/node_modules/@graphql-codegen/plugin-helpers": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.0.0", "change-case-all": "1.0.15", @@ -2145,6 +2356,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2157,13 +2369,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-codegen/visitor-plugin-common": { "version": "2.13.8", "resolved": "https://registry.npmjs.org/@graphql-codegen/visitor-plugin-common/-/visitor-plugin-common-2.13.8.tgz", "integrity": "sha512-IQWu99YV4wt8hGxIbBQPtqRuaWZhkQRG2IZKbMoSvh0vGeWb3dB0n0hSgKaOOxDY+tljtOf9MTcUYvJslQucMQ==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-codegen/plugin-helpers": "^3.1.2", "@graphql-tools/optimize": "^1.3.0", @@ -2185,6 +2399,7 @@ "resolved": "https://registry.npmjs.org/@graphql-codegen/plugin-helpers/-/plugin-helpers-3.1.2.tgz", "integrity": "sha512-emOQiHyIliVOIjKVKdsI5MXj312zmRDwmHpyUTZMjfpvxq/UVAHUJIVdVf+lnjjrI+LXBTgMlTWTgHQfmICxjg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.0.0", "change-case-all": "1.0.15", @@ -2202,6 +2417,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2214,13 +2430,15 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.1.tgz", "integrity": "sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/@graphql-tools/apollo-engine-loader": { "version": "7.3.26", "resolved": "https://registry.npmjs.org/@graphql-tools/apollo-engine-loader/-/apollo-engine-loader-7.3.26.tgz", "integrity": "sha512-h1vfhdJFjnCYn9b5EY1Z91JTF0KB3hHVJNQIsiUV2mpQXZdeOXQoaWeYEKaiI5R6kwBw5PP9B0fv3jfUIG8LyQ==", "dev": true, + "license": "MIT", "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/utils": "^9.2.1", @@ -2236,6 +2454,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2249,6 +2468,7 @@ "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", "dev": true, + "license": "MIT", "dependencies": { "@peculiar/webcrypto": "^1.4.0", "@whatwg-node/node-fetch": "^0.3.6", @@ -2258,28 +2478,18 @@ } }, "node_modules/@graphql-tools/batch-execute": { - "version": "8.5.22", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.5.22.tgz", - "integrity": "sha512-hcV1JaY6NJQFQEwCKrYhpfLK8frSXDbtNMoTur98u10Cmecy1zrqNKSqhEyGetpgHxaJRqszGzKeI3RuroDN6A==", - "dev": true, + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.4.tgz", + "integrity": "sha512-kkebDLXgDrep5Y0gK1RN3DMUlLqNhg60OAz0lTCqrYeja6DshxLtLkj+zV4mVbBA4mQOEoBmw6g1LZs3dA84/w==", + "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/utils": "^10.0.13", "dataloader": "^2.2.2", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-tools/batch-execute/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dev": true, - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" @@ -2290,6 +2500,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/code-file-loader/-/code-file-loader-7.3.23.tgz", "integrity": "sha512-8Wt1rTtyTEs0p47uzsPJ1vAtfAx0jmxPifiNdmo9EOCuUPyQGEbMaik/YkqZ7QUFIEYEQu+Vgfo8tElwOPtx5Q==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/graphql-tag-pluck": "7.5.2", "@graphql-tools/utils": "^9.2.1", @@ -2306,6 +2517,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2315,63 +2527,40 @@ } }, "node_modules/@graphql-tools/delegate": { - "version": "9.0.35", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-9.0.35.tgz", - "integrity": "sha512-jwPu8NJbzRRMqi4Vp/5QX1vIUeUPpWmlQpOkXQD2r1X45YsVceyUUBnktCrlJlDB4jPRVy7JQGwmYo3KFiOBMA==", - "dev": true, - "dependencies": { - "@graphql-tools/batch-execute": "^8.5.22", - "@graphql-tools/executor": "^0.0.20", - "@graphql-tools/schema": "^9.0.19", - "@graphql-tools/utils": "^9.2.1", + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.0.11.tgz", + "integrity": "sha512-+sKeecdIVXhFB/66e5yjeKYZ3Lpn52yNG637ElVhciuLGgFc153rC6l6zcuNd9yx5wMrNx35U/h3HsMIEI3xNw==", + "license": "MIT", + "dependencies": { + "@graphql-tools/batch-execute": "^9.0.4", + "@graphql-tools/executor": "^1.2.1", + "@graphql-tools/schema": "^10.0.4", + "@graphql-tools/utils": "^10.2.1", "dataloader": "^2.2.2", - "tslib": "^2.5.0", - "value-or-promise": "^1.0.12" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/schema": { - "version": "9.0.19", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", - "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", - "dev": true, - "dependencies": { - "@graphql-tools/merge": "^8.4.1", - "@graphql-tools/utils": "^9.2.1", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "tslib": "^2.5.0" }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-tools/delegate/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dev": true, - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@graphql-tools/executor": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-0.0.20.tgz", - "integrity": "sha512-GdvNc4vszmfeGvUqlcaH1FjBoguvMYzxAfT6tDd4/LgwymepHhinqLNA5otqwVLW+JETcDaK7xGENzFomuE6TA==", - "dev": true, + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.7.tgz", + "integrity": "sha512-oyIw69QA+PuS/g7ttZZeEpIPS5CCGiIYitGtNxaChuiK7NPb7FD1dwOEXyekQt9/2FOEqZoYNpRY0NFfx/tO9Q==", + "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/utils": "^10.1.1", "@graphql-typed-document-node/core": "3.2.0", "@repeaterjs/repeater": "^3.0.4", "tslib": "^2.4.0", "value-or-promise": "^1.0.12" }, + "engines": { + "node": ">=16.0.0" + }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } @@ -2381,6 +2570,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/executor-graphql-ws/-/executor-graphql-ws-0.0.14.tgz", "integrity": "sha512-P2nlkAsPZKLIXImFhj0YTtny5NQVGSsKnhi7PzXiaHSXc6KkzqbWZHKvikD4PObanqg+7IO58rKFpGXP7eeO+w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.2.1", "@repeaterjs/repeater": "3.0.4", @@ -2399,6 +2589,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2407,11 +2598,19 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/executor-graphql-ws/node_modules/@repeaterjs/repeater": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz", + "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==", + "dev": true, + "license": "MIT" + }, "node_modules/@graphql-tools/executor-graphql-ws/node_modules/ws": { "version": "8.13.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -2433,6 +2632,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/executor-http/-/executor-http-0.1.10.tgz", "integrity": "sha512-hnAfbKv0/lb9s31LhWzawQ5hghBfHS+gYWtqxME6Rl0Aufq9GltiiLBcl7OVVOnkLF0KhwgbYP1mB5VKmgTGpg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.2.1", "@repeaterjs/repeater": "^3.0.4", @@ -2452,6 +2652,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2465,6 +2666,7 @@ "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", "dev": true, + "license": "MIT", "dependencies": { "@peculiar/webcrypto": "^1.4.0", "@whatwg-node/node-fetch": "^0.3.6", @@ -2478,6 +2680,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/executor-legacy-ws/-/executor-legacy-ws-0.0.11.tgz", "integrity": "sha512-4ai+NnxlNfvIQ4c70hWFvOZlSUN8lt7yc+ZsrwtNFbFPH/EroIzFMapAxM9zwyv9bH38AdO3TQxZ5zNxgBdvUw==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.2.1", "@types/ws": "^8.0.0", @@ -2494,6 +2697,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2507,6 +2711,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz", "integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -2523,24 +2728,12 @@ } } }, - "node_modules/@graphql-tools/executor/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dev": true, - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/@graphql-tools/git-loader": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/@graphql-tools/git-loader/-/git-loader-7.3.0.tgz", "integrity": "sha512-gcGAK+u16eHkwsMYqqghZbmDquh8QaO24Scsxq+cVR+vx1ekRlsEiXvu+yXVDbZdcJ6PBIbeLcQbEu+xhDLmvQ==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/graphql-tag-pluck": "7.5.2", "@graphql-tools/utils": "^9.2.1", @@ -2558,6 +2751,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2571,6 +2765,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/github-loader/-/github-loader-7.3.28.tgz", "integrity": "sha512-OK92Lf9pmxPQvjUNv05b3tnVhw0JRfPqOf15jZjyQ8BfdEUrJoP32b4dRQQem/wyRL24KY4wOfArJNqzpsbwCA==", "dev": true, + "license": "MIT", "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/executor-http": "^0.1.9", @@ -2589,6 +2784,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2602,6 +2798,7 @@ "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", "dev": true, + "license": "MIT", "dependencies": { "@peculiar/webcrypto": "^1.4.0", "@whatwg-node/node-fetch": "^0.3.6", @@ -2615,6 +2812,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-file-loader/-/graphql-file-loader-7.5.17.tgz", "integrity": "sha512-hVwwxPf41zOYgm4gdaZILCYnKB9Zap7Ys9OhY1hbwuAuC4MMNY9GpUjoTU3CQc3zUiPoYStyRtUGkHSJZ3HxBw==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/import": "6.7.18", "@graphql-tools/utils": "^9.2.1", @@ -2631,6 +2829,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2644,6 +2843,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/graphql-tag-pluck/-/graphql-tag-pluck-7.5.2.tgz", "integrity": "sha512-RW+H8FqOOLQw0BPXaahYepVSRjuOHw+7IL8Opaa5G5uYGOBxoXR7DceyQ7BcpMgktAOOmpDNQ2WtcboChOJSRA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.16.8", "@babel/plugin-syntax-import-assertions": "^7.20.0", @@ -2661,6 +2861,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2674,6 +2875,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/import/-/import-6.7.18.tgz", "integrity": "sha512-XQDdyZTp+FYmT7as3xRWH/x8dx0QZA2WZqfMF5EWb36a0PiH7WwlRQYIdyYXj8YCLpiWkeBXgBRHmMnwEYR8iQ==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.2.1", "resolve-from": "5.0.0", @@ -2688,6 +2890,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2701,6 +2904,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/json-file-loader/-/json-file-loader-7.4.18.tgz", "integrity": "sha512-AJ1b6Y1wiVgkwsxT5dELXhIVUPs/u3VZ8/0/oOtpcoyO/vAeM5rOvvWegzicOOnQw8G45fgBRMkkRfeuwVt6+w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/utils": "^9.2.1", "globby": "^11.0.3", @@ -2716,6 +2920,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2729,6 +2934,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/load/-/load-7.8.14.tgz", "integrity": "sha512-ASQvP+snHMYm+FhIaLxxFgVdRaM0vrN9wW2BKInQpktwWTXVyk+yP5nQUCEGmn0RTdlPKrffBaigxepkEAJPrg==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/schema": "^9.0.18", "@graphql-tools/utils": "^9.2.1", @@ -2739,11 +2945,26 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, + "node_modules/@graphql-tools/load/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@graphql-tools/load/node_modules/@graphql-tools/schema": { "version": "9.0.19", "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/merge": "^8.4.1", "@graphql-tools/utils": "^9.2.1", @@ -2759,6 +2980,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2768,24 +2990,16 @@ } }, "node_modules/@graphql-tools/merge": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", - "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.4.tgz", + "integrity": "sha512-MivbDLUQ+4Q8G/Hp/9V72hbn810IJDEZQ57F01sHnlrrijyadibfVhaQfW/pNH+9T/l8ySZpaR/DpL5i+ruZ+g==", + "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^9.2.1", + "@graphql-tools/utils": "^10.0.13", "tslib": "^2.4.0" }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", - "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" @@ -2796,6 +3010,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/optimize/-/optimize-1.4.0.tgz", "integrity": "sha512-dJs/2XvZp+wgHH8T5J2TqptT9/6uVzIYvA6uFACha+ufvdMBedkfR4b4GbT8jAKLRARiqRTxy3dctnwkTM2tdw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.4.0" }, @@ -2808,6 +3023,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/prisma-loader/-/prisma-loader-7.2.72.tgz", "integrity": "sha512-0a7uV7Fky6yDqd0tI9+XMuvgIo6GAqiVzzzFV4OSLry4AwiQlI3igYseBV7ZVOGhedOTqj/URxjpiv07hRcwag==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/url-loader": "^7.17.18", "@graphql-tools/utils": "^9.2.1", @@ -2837,6 +3053,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" @@ -2850,6 +3067,7 @@ "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", "dev": true, + "license": "MIT", "dependencies": { "@peculiar/webcrypto": "^1.4.0", "@whatwg-node/node-fetch": "^0.3.6", @@ -2858,70 +3076,135 @@ "web-streams-polyfill": "^3.2.1" } }, - "node_modules/@graphql-tools/prisma-loader/node_modules/dotenv": { - "version": "16.3.1", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", - "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=12" + "node": ">=8" }, "funding": { - "url": "https://github.com/motdotla/dotenv?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@graphql-tools/relay-operation-optimizer": { - "version": "6.5.18", - "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.18.tgz", - "integrity": "sha512-mc5VPyTeV+LwiM+DNvoDQfPqwQYhPV/cl5jOBjTgSniyaq8/86aODfMkrE2OduhQ5E00hqrkuL2Fdrgk0w1QJg==", + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT", "dependencies": { - "@ardatan/relay-compiler": "12.0.0", - "@graphql-tools/utils": "^9.2.1", - "tslib": "^2.4.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/@graphql-tools/relay-operation-optimizer/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT", "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" + "color-name": "~1.1.4" }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + "engines": { + "node": ">=7.0.0" } }, - "node_modules/@graphql-tools/schema": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.0.tgz", - "integrity": "sha512-kf3qOXMFcMs2f/S8Y3A8fm/2w+GaHAkfr3Gnhh2LOug/JgpY/ywgFVxO3jOeSpSEdoYcDKLcXVjMigNbY4AdQg==", - "dependencies": { - "@graphql-tools/merge": "^9.0.0", - "@graphql-tools/utils": "^10.0.0", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" - }, + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT" + }, + "node_modules/@graphql-tools/prisma-loader/node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=16.0.0" + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-tools/prisma-loader/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@graphql-tools/relay-operation-optimizer": { + "version": "6.5.18", + "resolved": "https://registry.npmjs.org/@graphql-tools/relay-operation-optimizer/-/relay-operation-optimizer-6.5.18.tgz", + "integrity": "sha512-mc5VPyTeV+LwiM+DNvoDQfPqwQYhPV/cl5jOBjTgSniyaq8/86aODfMkrE2OduhQ5E00hqrkuL2Fdrgk0w1QJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ardatan/relay-compiler": "12.0.0", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/schema/node_modules/@graphql-tools/merge": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-9.0.0.tgz", - "integrity": "sha512-J7/xqjkGTTwOJmaJQJ2C+VDBDOWJL3lKrHJN4yMaRLAJH3PosB7GiPRaSDZdErs0+F77sH2MKs2haMMkywzx7Q==", + "node_modules/@graphql-tools/relay-operation-optimizer/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "license": "MIT", "dependencies": { - "@graphql-tools/utils": "^10.0.0", + "@graphql-typed-document-node/core": "^3.1.1", "tslib": "^2.4.0" }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/schema": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-10.0.4.tgz", + "integrity": "sha512-HuIwqbKxPaJujox25Ra4qwz0uQzlpsaBOzO6CVfzB/MemZdd+Gib8AIvfhQArK0YIN40aDran/yi+E5Xf0mQww==", + "license": "MIT", + "dependencies": { + "@graphql-tools/merge": "^9.0.3", + "@graphql-tools/utils": "^10.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, "engines": { "node": ">=16.0.0" }, @@ -2934,6 +3217,7 @@ "resolved": "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.17.18.tgz", "integrity": "sha512-ear0CiyTj04jCVAxi7TvgbnGDIN2HgqzXzwsfcqiVg9cvjT40NcMlZ2P1lZDgqMkZ9oyLTV8Bw6j+SyG6A+xPw==", "dev": true, + "license": "MIT", "dependencies": { "@ardatan/sync-fetch": "^0.0.1", "@graphql-tools/delegate": "^9.0.31", @@ -2953,69 +3237,78 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/utils": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", - "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/batch-execute": { + "version": "8.5.22", + "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-8.5.22.tgz", + "integrity": "sha512-hcV1JaY6NJQFQEwCKrYhpfLK8frSXDbtNMoTur98u10Cmecy1zrqNKSqhEyGetpgHxaJRqszGzKeI3RuroDN6A==", "dev": true, + "license": "MIT", "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "tslib": "^2.4.0" + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", - "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/delegate": { + "version": "9.0.35", + "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-9.0.35.tgz", + "integrity": "sha512-jwPu8NJbzRRMqi4Vp/5QX1vIUeUPpWmlQpOkXQD2r1X45YsVceyUUBnktCrlJlDB4jPRVy7JQGwmYo3KFiOBMA==", "dev": true, + "license": "MIT", "dependencies": { - "@peculiar/webcrypto": "^1.4.0", - "@whatwg-node/node-fetch": "^0.3.6", - "busboy": "^1.6.0", - "urlpattern-polyfill": "^8.0.0", - "web-streams-polyfill": "^3.2.1" + "@graphql-tools/batch-execute": "^8.5.22", + "@graphql-tools/executor": "^0.0.20", + "@graphql-tools/schema": "^9.0.19", + "@graphql-tools/utils": "^9.2.1", + "dataloader": "^2.2.2", + "tslib": "^2.5.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/utils": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.0.7.tgz", - "integrity": "sha512-KOdeMj6Hd/MENDaqPbws3YJl3wVy0DeYnL7PyUms5Skyf7uzI9INynDwPMhLXfSb0/ph6BXTwMd5zBtWbF8tBQ==", + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/executor": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-0.0.20.tgz", + "integrity": "sha512-GdvNc4vszmfeGvUqlcaH1FjBoguvMYzxAfT6tDd4/LgwymepHhinqLNA5otqwVLW+JETcDaK7xGENzFomuE6TA==", + "dev": true, + "license": "MIT", "dependencies": { - "@graphql-typed-document-node/core": "^3.1.1", - "dset": "^3.1.2", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.0.0" + "@graphql-tools/utils": "^9.2.1", + "@graphql-typed-document-node/core": "3.2.0", + "@repeaterjs/repeater": "^3.0.4", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/wrap": { - "version": "9.4.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-9.4.2.tgz", - "integrity": "sha512-DFcd9r51lmcEKn0JW43CWkkI2D6T9XI1juW/Yo86i04v43O9w2/k4/nx2XTJv4Yv+iXwUw7Ok81PGltwGJSDSA==", + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", "dev": true, + "license": "MIT", "dependencies": { - "@graphql-tools/delegate": "^9.0.31", - "@graphql-tools/schema": "^9.0.18", "@graphql-tools/utils": "^9.2.1", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" + "tslib": "^2.4.0" }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/wrap/node_modules/@graphql-tools/schema": { + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/schema": { "version": "9.0.19", "resolved": "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.19.tgz", "integrity": "sha512-oBRPoNBtCkk0zbUsyP4GaIzCt8C0aCI4ycIRUL67KK5pOHljKLBBtGT+Jr6hkzA74C8Gco8bpZPe7aWFjiaK2w==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/merge": "^8.4.1", "@graphql-tools/utils": "^9.2.1", @@ -3026,15 +3319,84 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, - "node_modules/@graphql-tools/wrap/node_modules/@graphql-tools/utils": { + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/utils": { "version": "9.2.1", "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@graphql-tools/wrap": { + "version": "9.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-9.4.2.tgz", + "integrity": "sha512-DFcd9r51lmcEKn0JW43CWkkI2D6T9XI1juW/Yo86i04v43O9w2/k4/nx2XTJv4Yv+iXwUw7Ok81PGltwGJSDSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/delegate": "^9.0.31", + "@graphql-tools/schema": "^9.0.18", + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/url-loader/node_modules/@whatwg-node/fetch": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.8.8.tgz", + "integrity": "sha512-CdcjGC2vdKhc13KKxgsc6/616BQ7ooDIgPeTuAiE8qfCnS0mGzcfCOoZXypQSz73nxI+GWc7ZReIAVhxoE1KCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@peculiar/webcrypto": "^1.4.0", + "@whatwg-node/node-fetch": "^0.3.6", + "busboy": "^1.6.0", + "urlpattern-polyfill": "^8.0.0", + "web-streams-polyfill": "^3.2.1" + } + }, + "node_modules/@graphql-tools/utils": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-10.2.2.tgz", + "integrity": "sha512-ueoplzHIgFfxhFrF4Mf/niU/tYHuO6Uekm2nCYU72qpI+7Hn9dA2/o5XOBvFXDk27Lp5VSvQY5WfmRbqwVxaYQ==", + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.1.1", + "cross-inspect": "1.0.0", + "dset": "^3.1.2", "tslib": "^2.4.0" }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@graphql-tools/wrap": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.5.tgz", + "integrity": "sha512-Cbr5aYjr3HkwdPvetZp1cpDWTGdD1Owgsb3z/ClzhmrboiK86EnQDxDvOJiQkDCPWE9lNBwj8Y4HfxroY0D9DQ==", + "license": "MIT", + "dependencies": { + "@graphql-tools/delegate": "^10.0.4", + "@graphql-tools/schema": "^10.0.3", + "@graphql-tools/utils": "^10.1.1", + "tslib": "^2.4.0", + "value-or-promise": "^1.0.12" + }, + "engines": { + "node": ">=16.0.0" + }, "peerDependencies": { "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } @@ -3043,29 +3405,46 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "license": "MIT", "peerDependencies": { "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -3075,22 +3454,26 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/@iarna/toml": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, + "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -3107,6 +3490,7 @@ "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, + "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } @@ -3116,6 +3500,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -3129,6 +3514,7 @@ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -3142,6 +3528,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -3154,6 +3541,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -3169,6 +3557,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -3181,6 +3570,7 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -3190,6 +3580,7 @@ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -3202,11 +3593,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/console/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/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, + "license": "MIT", + "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/@jest/console/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/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, + "license": "MIT" + }, + "node_modules/@jest/console/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/core": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -3250,42 +3718,87 @@ } }, "node_modules/@jest/core/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@jest/core/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/@jest/core/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/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, + "license": "MIT" + }, + "node_modules/@jest/core/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, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/@jest/core/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/@jest/core/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -3301,6 +3814,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, + "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -3314,6 +3828,7 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -3326,6 +3841,7 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -3343,6 +3859,7 @@ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -3358,6 +3875,7 @@ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, + "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -3396,11 +3914,88 @@ } } }, + "node_modules/@jest/reporters/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/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, + "license": "MIT", + "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/@jest/reporters/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/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, + "license": "MIT" + }, + "node_modules/@jest/reporters/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/schemas": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, + "license": "MIT", "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -3413,6 +4008,7 @@ "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.18", "callsites": "^3.0.0", @@ -3427,6 +4023,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -3442,6 +4039,7 @@ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -3457,6 +4055,7 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -3478,11 +4077,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/transform/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/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, + "license": "MIT", + "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/@jest/transform/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/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, + "license": "MIT" + }, + "node_modules/@jest/transform/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/types": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -3495,39 +4171,119 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/@jest/types/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/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, + "license": "MIT", + "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/@jest/types/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/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, + "license": "MIT" + }, + "node_modules/@jest/types/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@josephg/resolvable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@josephg/resolvable/-/resolvable-1.0.1.tgz", - "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==" + "integrity": "sha512-CtzORUwWTTOTqfVtHaKRJ0I1kNQd1bpn3sUh8I3nJDVY+5/M/Oe1DnEWzPQvqq/xPIIkzzzIP7mfCoAjFRvDhg==", + "license": "ISC" }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -3536,22 +4292,25 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.20", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", - "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@mongodb-js/saslprep": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.0.tgz", - "integrity": "sha512-Xfijy7HvfzzqiOAhAepF4SGN5e9leLkMvg/OPOF97XemjfVCYN/oWa75wnkc6mltMSTwY+XlbhWgUOJmkFspSw==", + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.7.tgz", + "integrity": "sha512-dCHW/oEX0KJ4NjDULBo3JiOaK5+6axtpBbS+ao2ZInoAL9/YRQLhXzSNAFz7hP4nzLkIqsfYAK/PDE3+XHny0Q==", + "license": "MIT", "dependencies": { "sparse-bitfield": "^3.0.3" } @@ -3561,6 +4320,7 @@ "resolved": "https://registry.npmjs.org/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz", "integrity": "sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==", "dev": true, + "license": "MIT", "dependencies": { "eslint-scope": "5.1.1" } @@ -3570,6 +4330,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -3583,6 +4344,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -3592,6 +4354,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -3605,6 +4368,7 @@ "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.8.tgz", "integrity": "sha512-ULB1XqHKx1WBU/tTFIA+uARuRoBVZ4pNdOA878RDrRbBfBGcSzi5HBkdScC6ZbHn8z7L8gmKCgPC1LHRrP46tA==", "dev": true, + "license": "MIT", "dependencies": { "asn1js": "^3.0.5", "pvtsutils": "^1.3.5", @@ -3616,6 +4380,7 @@ "resolved": "https://registry.npmjs.org/@peculiar/json-schema/-/json-schema-1.1.12.tgz", "integrity": "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -3624,16 +4389,17 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.3.tgz", - "integrity": "sha512-VtaY4spKTdN5LjJ04im/d/joXuvLbQdgy5Z4DXF4MFZhQ+MTrejbNMkfZBp1Bs3O5+bFqnJgyGdPuZQflvIa5A==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.5.0", - "webcrypto-core": "^1.7.7" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" }, "engines": { "node": ">=10.12.0" @@ -3642,27 +4408,32 @@ "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/base64": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/eventemitter": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/fetch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" @@ -3671,40 +4442,47 @@ "node_modules/@protobufjs/float": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/path": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/pool": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" }, "node_modules/@redis/bloom": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@redis/client": { - "version": "1.5.14", - "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.14.tgz", - "integrity": "sha512-YGn0GqsRBFUQxklhY7v562VMOP0DcmlrHHs3IV1mFE3cbxe31IITUkqhBcIhVSI/2JqtWAJXg5mjV4aU+zD0HA==", + "version": "1.5.16", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.16.tgz", + "integrity": "sha512-X1a3xQ5kEMvTib5fBrHKh6Y+pXbeKXqziYuxOUo1ojQNECg4M5Etd1qqyhMap+lFUOAh8S7UYevgJHOm4A+NOg==", + "license": "MIT", "dependencies": { "cluster-key-slot": "1.1.2", "generic-pool": "3.9.0", @@ -3714,15 +4492,11 @@ "node": ">=14" } }, - "node_modules/@redis/client/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/@redis/graph": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.1.tgz", "integrity": "sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -3731,6 +4505,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.6.tgz", "integrity": "sha512-rcZO3bfQbm2zPRpqo82XbW8zg4G/w4W3tI7X8Mqleq9goQjAGLL7q/1n1ZX4dXEAmORVZ4s1+uKLaUOg7LrUhw==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -3739,6 +4514,7 @@ "version": "1.1.6", "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.6.tgz", "integrity": "sha512-mZXCxbTYKBQ3M2lZnEddwEAks0Kc7nauire8q20oA0oA/LoA+E/b5Y5KZn232ztPb1FkIGqo12vh3Lf+Vw5iTw==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } @@ -3747,26 +4523,30 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.5.tgz", "integrity": "sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg==", + "license": "MIT", "peerDependencies": { "@redis/client": "^1.0.0" } }, "node_modules/@repeaterjs/repeater": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.4.tgz", - "integrity": "sha512-AW8PKd6iX3vAZ0vA43nOUOnbq/X5ihgU+mSXXqunMkeQADGiqw/PY0JNeYtD5sr0PAy51YPgAPbDoeapv9r8WA==" + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@repeaterjs/repeater/-/repeater-3.0.6.tgz", + "integrity": "sha512-Javneu5lsuhwNCryN+pXH93VPQ8g0dBX7wItHFgYiwQmzE1sVdg5tWHiOgHywzL2W21XQopa7IwIEnNbmeUJYA==", + "license": "MIT" }, "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sinonjs/commons": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", - "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } @@ -3776,39 +4556,45 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } }, "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/babel__core": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.3.tgz", - "integrity": "sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -3818,63 +4604,80 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.6.tgz", - "integrity": "sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.3.tgz", - "integrity": "sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, + "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__traverse": { - "version": "7.20.3", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.3.tgz", - "integrity": "sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/body-parser": { - "version": "1.19.4", - "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.4.tgz", - "integrity": "sha512-N7UDG0/xiPQa2D/XrVJXjkWbpqHCd2sBaB32ggRF2l83RhPfamgKGF8gwwqyksS95qUS5ZYF9aF+lLPRlwI2UA==", + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" } }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/connect": { - "version": "3.4.37", - "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.37.tgz", - "integrity": "sha512-zBUSRqkfZ59OcwXon4HVxhx5oWCJmc0OtBTK05M+p0dYjgN6iTwIL2T/WbsQZrEsdnwaF9cWQ+azOnpPvIqY3Q==", + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/cors": { - "version": "2.8.15", - "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.15.tgz", - "integrity": "sha512-n91JxbNLD8eQIuXDIChAN1tCKNWCEgpceU9b7ZMbFA+P+Q4yIeh80jizFLEvolRPc1ES0VdwFlGv+kJTSirogw==", + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/express": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.20.tgz", - "integrity": "sha512-rOaqlkgEvOW495xErXMsmyX3WKBInbhG5eqojXYi3cGUaLoRDlXa5d52fkfWZT963AZ3v2eZ4MbKE6WpDAGVsw==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -3883,9 +4686,10 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.39", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.39.tgz", - "integrity": "sha512-BiEUfAiGCOllomsRAZOiMFP7LAnrifHpt56pc4Z7l9K6ACyN06Ns1JLMBxwkfLOjJRlSf06NwWsT7yzfpaVpyQ==", + "version": "4.19.5", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.5.tgz", + "integrity": "sha512-y6W03tvrACO72aijJ5uF02FRq5cgDR9lUxddQ8vyF+GvmjJQqbzDcJngEjURc+ZsG31VI3hODNZJ2URj86pzmg==", + "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -3894,19 +4698,21 @@ } }, "node_modules/@types/express-session": { - "version": "1.17.9", - "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.9.tgz", - "integrity": "sha512-yIqficLlTPdloeEPhOVenpOUWILkdaXHUWhTOqFGx9JoSuTgeatNjb97k8VvJehbTk0kUSUAHy5r27PXMga89Q==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-27JdDRgor6PoYlURY+Y5kCakqp5ulC0kmf7y+QwaY+hv9jEFuQOThgkjyA53RP3jmKuBsH5GR6qEfFmvb8mwOA==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/graceful-fs": { - "version": "4.1.8", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.8.tgz", - "integrity": "sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } @@ -3916,35 +4722,40 @@ "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.46.tgz", "integrity": "sha512-gGp1XVSYFRbKT0nl8nLwst6JvwcB7wGAGVkvKja2LKz3tJuTcgmo2TklQ0kUY/t8sOM94IdvBcfgGAYbJsk3tw==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/http-errors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.3.tgz", - "integrity": "sha512-pP0P/9BnCj1OVvQR2lF41EkDG/lWWnDyA203b/4Fmi2eTyORnBtcDoKDwjWQthELrBvWkMOrvSOnZ8OVlW6tXA==" + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "license": "MIT" }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ==", - "dev": true + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.2.tgz", - "integrity": "sha512-8toY6FgdltSdONav1XtUHl4LN1yTmLza+EuDazb/fEmRNCwjyqNVIQWs2IfC74IqjHkREs/nQ2FWq5kZU9IC0w==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.3.tgz", - "integrity": "sha512-1nESsePMBlf0RPRffLZi5ujYh7IH1BWL4y9pr+Bn3cJBdxz+RTP8bUFljLz9HvzhhOSWKdyBZ4DIivdL6rvgZg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -3954,88 +4765,270 @@ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-25.2.3.tgz", "integrity": "sha512-JXc1nK/tXHiDhV55dvfzqtmP4S3sy3T3ouV2tkViZgxY/zeUkcpQcQPGRlgF4KmWzWW5oiWYSZwtCB+2RsE4Fw==", "dev": true, + "license": "MIT", "dependencies": { "jest-diff": "^25.2.1", "pretty-format": "^25.2.1" } }, + "node_modules/@types/jest/node_modules/@jest/types": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", + "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^15.0.0", + "chalk": "^3.0.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/@types/jest/node_modules/@types/istanbul-reports": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", + "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest/node_modules/@types/yargs": { + "version": "15.0.19", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.19.tgz", + "integrity": "sha512-2XUaGVmyQjgyAZldf0D0c14vvo/yv0MhQBSTJcejMMaitsn3nxCB6TmH4G0ZQf+uxROOa9mpanoSm8h6SG/1ZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/jest/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@types/jest/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@types/jest/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, + "license": "MIT" + }, + "node_modules/@types/jest/node_modules/diff-sequences": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", + "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/@types/jest/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@types/jest/node_modules/jest-diff": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", + "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^3.0.0", + "diff-sequences": "^25.2.6", + "jest-get-type": "^25.2.6", + "pretty-format": "^25.5.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/@types/jest/node_modules/jest-get-type": { + "version": "25.2.6", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", + "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/@types/jest/node_modules/pretty-format": { + "version": "25.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", + "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^25.5.0", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^16.12.0" + }, + "engines": { + "node": ">= 8.3" + } + }, + "node_modules/@types/jest/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jest/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@types/js-yaml": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.8.tgz", - "integrity": "sha512-m6jnPk1VhlYRiLFm3f8X9Uep761f+CK8mHyS65LutH2OhmBF0BeMEjHgg05usH8PLZMWWc/BUR9RPmkvpWnyRA==", - "dev": true + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.9.tgz", + "integrity": "sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", - "dev": true + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" }, "node_modules/@types/json-stable-stringify": { - "version": "1.0.35", - "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.35.tgz", - "integrity": "sha512-zlCWqsRBI0+ANN7dzGeDFJ4CHaVFTLqBNRS11GjR2mHCW6XxNtnMxhQzBKMzfsnjI8oI+kWq2vBwinyQpZVSsg==", - "dev": true + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/@types/json-stable-stringify/-/json-stable-stringify-1.0.36.tgz", + "integrity": "sha512-b7bq23s4fgBB76n34m2b3RBf6M369B0Z9uRR8aHTMd8kZISRkmDEpPD8hhpYvDFzr3bJCPES96cm3Q6qRNDbQw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.14.200", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.200.tgz", - "integrity": "sha512-YI/M/4HRImtNf3pJgbF+W6FrXovqj+T+/HpENLTooK9PnkacBsDpeP3IpHab40CClUfhNmdM2WTNP2sa2dni5Q==", - "dev": true + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", - "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==", + "license": "MIT" }, "node_modules/@types/mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.4.tgz", - "integrity": "sha512-1Gjee59G25MrQGk8bsNvC6fxNiRgUlGn2wlhGf95a59DrprnnHk80FIMMFG9XHMdrfsuA119ht06QPDXA1Z7tw==" + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "license": "MIT" }, "node_modules/@types/node": { "version": "13.13.52", "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.52.tgz", - "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==" + "integrity": "sha512-s3nugnZumCC//n4moGGe6tkNMyYEdaDBitVjwPxXmR5lnMG5dHePinH2EdxkG3Rh1ghFHHixAG4NJhpJW1rthQ==", + "license": "MIT" }, "node_modules/@types/node-fetch": { - "version": "2.6.7", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.7.tgz", - "integrity": "sha512-lX17GZVpJ/fuCjguZ5b3TjEbSENxmEk1B2z02yoXSK9WMEWRivhdSY73wWMn6bpcCDAOh6qAdktpKHIlkDk2lg==", + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", + "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "license": "MIT", "dependencies": { "@types/node": "*", "form-data": "^4.0.0" } }, "node_modules/@types/oauth": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/@types/oauth/-/oauth-0.9.3.tgz", - "integrity": "sha512-avZiwxSz/WS6EaEjhchzXKgWtlGGYGnEVJoHuQuDLHf7gIW1Gmm9eIxOMuJ6umQNNKZkJ3Uy+C/rLzEvL3I8Sw==", + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@types/oauth/-/oauth-0.9.5.tgz", + "integrity": "sha512-+oQ3C2Zx6ambINOcdIARF5Z3Tu3x//HipE889/fqo3sgpQZbe9c6ExdQFtN6qlhpR7p83lTZfPJt0tCAW29dog==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/parse-json": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.1.tgz", - "integrity": "sha512-3YmXzzPAdOTVljVMkTMBdBEvlOLg2cDQaDhnnhT3nT9uDbnJzjWhKlzb+desT12Y7tGqaN6d+AbozcKzyL36Ng==", - "dev": true + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/passport": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.14.tgz", - "integrity": "sha512-D6p2ygR2S7Cq5PO7iUaEIQu/5WrM0tONu6Lxgk0C9r3lafQIlVpWCo3V/KI9To3OqHBxcfQaOeK+8AvwW5RYmw==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/@types/passport/-/passport-1.0.16.tgz", + "integrity": "sha512-FD0qD5hbPWQzaM0wHUnJ/T0BBCJBxCeemtnCwc/ThhTg3x9jfrAcRUmj5Dopza+MfFS9acTe3wk7rcVnRIp/0A==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*" } }, "node_modules/@types/passport-google-oauth20": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/passport-google-oauth20/-/passport-google-oauth20-2.0.13.tgz", - "integrity": "sha512-idIhUp1RyBqk8cgApCHvqIvk09QVZv83hQJ/39VonIHYZkBps8p0AfB9INtPee3iuittdFx9J+i35pdZBgCqUQ==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@types/passport-google-oauth20/-/passport-google-oauth20-2.0.16.tgz", + "integrity": "sha512-ayXK2CJ7uVieqhYOc6k/pIr5pcQxOLB6kBev+QUGS7oEZeTgIs1odDobXRqgfBPvXzl0wXCQHftV5220czZCPA==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*", "@types/passport": "*", @@ -4043,10 +5036,11 @@ } }, "node_modules/@types/passport-oauth2": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@types/passport-oauth2/-/passport-oauth2-1.4.14.tgz", - "integrity": "sha512-wZBvnRwqdvm35l1Jn9ebYm2Q7UtxYIdBu1PjoKXMoxJytniVjXxYJmrlDXn5fMZROWbJbnEnp1XSDANqtvMdGQ==", + "version": "1.4.17", + "resolved": "https://registry.npmjs.org/@types/passport-oauth2/-/passport-oauth2-1.4.17.tgz", + "integrity": "sha512-ODiAHvso6JcWJ6ZkHHroVp05EHGhqQN533PtFNBkg8Fy5mERDqsr030AX81M0D69ZcaMvhF92SRckEk2B0HYYg==", "dev": true, + "license": "MIT", "dependencies": { "@types/express": "*", "@types/oauth": "*", @@ -4054,101 +5048,114 @@ } }, "node_modules/@types/qs": { - "version": "6.9.9", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.9.tgz", - "integrity": "sha512-wYLxw35euwqGvTDx6zfY1vokBFnsK0HNrzc6xNHchxfO2hpuRg74GbkEW7e3sSmPvj0TjCDT1VCa6OtHXnubsg==" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "license": "MIT" }, "node_modules/@types/range-parser": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.6.tgz", - "integrity": "sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "license": "MIT" }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", - "dev": true + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true, + "license": "MIT" }, "node_modules/@types/send": { - "version": "0.17.3", - "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.3.tgz", - "integrity": "sha512-/7fKxvKUoETxjFUsuFlPB9YndePpxxRAOfGC/yJdc9kTjTeP5kRCTzfnE8kPUKCeyiyIZu0YQ76s50hCedI1ug==", + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" } }, "node_modules/@types/serve-static": { - "version": "1.15.4", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.4.tgz", - "integrity": "sha512-aqqNfs1XTF0HDrFdlY//+SGUxmdSUbjeRXb5iaZc3x0/vMbYmdw9qvOgHWOyyLFxSSRnUuP5+724zBgfw8/WAw==", + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "license": "MIT", "dependencies": { "@types/http-errors": "*", - "@types/mime": "*", - "@types/node": "*" + "@types/node": "*", + "@types/send": "*" } }, "node_modules/@types/stack-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.2.tgz", - "integrity": "sha512-g7CK9nHdwjK2n0ymT2CW698FuWJRIx+RP6embAzZ2Qi8/ilIrA1Imt2LVSeHUzKvpoi7BhmmQcXz95eS0f2JXw==", - "dev": true + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/strip-json-comments": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@types/webidl-conversions": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.2.tgz", - "integrity": "sha512-uNv6b/uGRLlCVmelat2rA8bcVd3k/42mV2EmjhPh6JLkd35T5bgwR/t6xy7a9MWhd9sixIeBUzhBenvk3NO+DQ==" + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "license": "MIT" }, "node_modules/@types/whatwg-url": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", - "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "version": "11.0.5", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-11.0.5.tgz", + "integrity": "sha512-coYR071JRaHa+xoEvvYqvnIHaVqaYrLPbsufM9BF63HkwI5Lgmy2QR8Q5K/lYDYo5AK82wOvSOS0UsLTpTG7uQ==", + "license": "MIT", "dependencies": { - "@types/node": "*", "@types/webidl-conversions": "*" } }, "node_modules/@types/ws": { - "version": "8.5.8", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.8.tgz", - "integrity": "sha512-flUksGIQCnJd6sZ1l5dqCEG/ksaoAg/eUwiLAGTJQcfgvZJKF++Ta4bJA6A5aPSJmsr+xlseHn4KLgVlNnvPTg==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*" } }, "node_modules/@types/yargs": { - "version": "17.0.29", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.29.tgz", - "integrity": "sha512-nacjqA3ee9zRF/++a3FUY1suHTFKZeHba2n8WeDw9cCVdmzmHpIxyzOJBcpHvvEmS8E9KqWlSnWHUkOrkhWcvA==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, + "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.2", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.2.tgz", - "integrity": "sha512-5qcvofLPbfjmBfKaLfj/+f+Sbd6pN4zl7w7VSVI5uz7m9QZTuB2aZAa2uo1wHFBNN2x6g/SoTkXmd8mQnQF2Cw==", - "dev": true + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -4178,26 +5185,12 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4205,17 +5198,12 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -4243,6 +5231,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0" @@ -4260,6 +5249,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/typescript-estree": "5.62.0", "@typescript-eslint/utils": "5.62.0", @@ -4287,6 +5277,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -4300,6 +5291,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "@typescript-eslint/types": "5.62.0", "@typescript-eslint/visitor-keys": "5.62.0", @@ -4322,26 +5314,12 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4349,17 +5327,12 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", @@ -4381,26 +5354,12 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -4408,17 +5367,12 @@ "node": ">=10" } }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { "version": "5.62.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, + "license": "MIT", "dependencies": { "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" @@ -4431,23 +5385,39 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/@whatwg-node/events": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/@whatwg-node/events/-/events-0.0.3.tgz", "integrity": "sha512-IqnKIDWfXBJkvy/k6tzskWTc2NK3LcqHlb+KHGCrjOCH4jfQckRX0NAiIcC/vIqQkzLYw2r2CTSwAxcrtcD6lA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@whatwg-node/fetch": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@whatwg-node/fetch/-/fetch-0.3.2.tgz", "integrity": "sha512-Bs5zAWQs0tXsLa4mRmLw7Psps1EN78vPtgcLpw3qPY8s6UYPUM67zFZ9cy+7tZ64PXhfwzxJn+m7RH2Lq48RNQ==", "dev": true, + "license": "MIT", "dependencies": { "@peculiar/webcrypto": "^1.4.0", "abort-controller": "^3.0.0", @@ -4465,6 +5435,7 @@ "resolved": "https://registry.npmjs.org/@whatwg-node/node-fetch/-/node-fetch-0.3.6.tgz", "integrity": "sha512-w9wKgDO4C95qnXZRwZTfCmLWqyRnooGjcIwG0wADWjw9/HN0p7dtvtgSvItZtUyNteEvgTrd8QojNEqV6DAGTA==", "dev": true, + "license": "MIT", "dependencies": { "@whatwg-node/events": "^0.0.3", "busboy": "^1.6.0", @@ -4478,6 +5449,7 @@ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", "dev": true, + "license": "MIT", "dependencies": { "event-target-shim": "^5.0.0" }, @@ -4489,6 +5461,7 @@ "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==", + "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -4498,10 +5471,11 @@ } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -4514,24 +5488,30 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.3", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.3.tgz", + "integrity": "sha512-MxXdReSRhGO7VlFe1bRG/oI7/mdLV9B9JJT0N8vZOhF7gFRR5l3M8W9G8JxmKV+JC5mGqJ0QvqfSOLsCPa4nUw==", "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, "engines": { "node": ">=0.4.0" } }, "node_modules/agent-base": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", - "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", "dev": true, + "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -4544,6 +5524,7 @@ "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, + "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -4557,6 +5538,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4573,6 +5555,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, + "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -4588,23 +5571,22 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/anymatch": { @@ -4612,6 +5594,7 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, + "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -4624,24 +5607,28 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "dev": true, + "license": "Python-2.0" }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4650,13 +5637,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/asn1js": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", "integrity": "sha512-FVnvrKJwpt9LP2lAMl8qZswRNm3T4q9CON+bxldk2iwk3FFpuwhx2FfinyitizWHsVYyaY+y5JzDR0rCMV5yTQ==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "pvtsutils": "^1.3.2", "pvutils": "^1.1.3", @@ -4671,6 +5660,7 @@ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -4679,6 +5669,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.3.3.tgz", "integrity": "sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw==", + "license": "MIT", "dependencies": { "retry": "0.13.1" } @@ -4686,13 +5677,15 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" }, "node_modules/auto-bind": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-4.0.0.tgz", "integrity": "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -4701,11 +5694,12 @@ } }, "node_modules/axios": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", - "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.0", + "follow-redirects": "^1.15.6", "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } @@ -4715,6 +5709,7 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -4731,11 +5726,88 @@ "@babel/core": "^7.8.0" } }, + "node_modules/babel-jest/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/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, + "license": "MIT", + "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/babel-jest/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/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, + "license": "MIT" + }, + "node_modules/babel-jest/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -4752,6 +5824,7 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -4768,6 +5841,7 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -4782,13 +5856,15 @@ "version": "7.0.0-beta.0", "resolved": "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-7.0.0-beta.0.tgz", "integrity": "sha512-Xj9XuRuz3nTSbaTXWv3itLOcxyF4oPD8douBBmj7U9BBC6nEBYfyOJYQMf/8PJAFotC62UY5dFfIGEPr7WswzQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -4812,6 +5888,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz", "integrity": "sha512-9ywCsCvo1ojrw0b+XYk7aFvTH6D9064t0RIL1rtMf3nsa02Xw41MS7sZw216Im35xj/UY0PDBQsa1brUDDF1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@babel/plugin-proposal-class-properties": "^7.0.0", "@babel/plugin-proposal-object-rest-spread": "^7.0.0", @@ -4850,6 +5927,7 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, + "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -4865,7 +5943,8 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/base64-js": { "version": "1.5.1", @@ -4885,23 +5964,29 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/base64url": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/base64url/-/base64url-3.0.1.tgz", "integrity": "sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==", + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bl": { @@ -4909,6 +5994,7 @@ "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, + "license": "MIT", "dependencies": { "buffer": "^5.5.0", "inherits": "^2.0.4", @@ -4919,6 +6005,7 @@ "version": "1.20.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -4942,6 +6029,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4949,39 +6037,43 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/bowser": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.9.0.tgz", - "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==" + "integrity": "sha512-2ld76tuLBNFekRgmJfT2+3j5MIrP6bFict8WAIT3beq+srz1gcKNAdNKMqHqauQt63NmAa88HfP1/Ypa9Er3HA==", + "license": "MIT" }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", "dev": true, "funding": [ { @@ -4997,11 +6089,12 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" }, "bin": { "browserslist": "cli.js" @@ -5015,6 +6108,7 @@ "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", "dev": true, + "license": "MIT", "dependencies": { "fast-json-stable-stringify": "2.x" }, @@ -5027,14 +6121,16 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } }, "node_modules/bson": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/bson/-/bson-6.2.0.tgz", - "integrity": "sha512-ID1cI+7bazPDyL9wYy9GaQ8gEEohWvcUl/Yf0dIdutJxnmInEEyCsb4awy/OiBfall7zBA179Pahi3vCdFze3Q==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/bson/-/bson-6.7.0.tgz", + "integrity": "sha512-w2IquM5mYzYZv6rs3uN2DZTOBe2a0zXLj53TGDqwF4l6Sz/XsISrisXOJihArF9+BZ6Cq/GjVht7Sjfmri7ytQ==", + "license": "Apache-2.0", "engines": { "node": ">=16.20.1" } @@ -5058,6 +6154,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -5067,7 +6164,8 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/busboy": { "version": "1.6.0", @@ -5085,18 +6183,25 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/call-bind": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", - "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.1", - "set-function-length": "^1.1.1" + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5107,6 +6212,7 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5116,6 +6222,7 @@ "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, + "license": "MIT", "dependencies": { "pascal-case": "^3.1.2", "tslib": "^2.0.3" @@ -5126,6 +6233,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5133,12 +6241,13 @@ "node_modules/camelize": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", - "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==" + "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==", + "license": "MIT" }, "node_modules/caniuse-lite": { - "version": "1.0.30001553", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001553.tgz", - "integrity": "sha512-N0ttd6TrFfuqKNi+pMgWJTb9qrdJu4JSpgPFLe/lrD19ugC6fZgF0pUewRowDwzdDnb9V41mFcdlYgl/PyKf4A==", + "version": "1.0.30001636", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz", + "integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==", "dev": true, "funding": [ { @@ -5153,13 +6262,15 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ] + ], + "license": "CC-BY-4.0" }, "node_modules/capital-case": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -5167,19 +6278,18 @@ } }, "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=4" } }, "node_modules/change-case": { @@ -5187,6 +6297,7 @@ "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", "dev": true, + "license": "MIT", "dependencies": { "camel-case": "^4.1.2", "capital-case": "^1.0.4", @@ -5207,6 +6318,7 @@ "resolved": "https://registry.npmjs.org/change-case-all/-/change-case-all-1.0.15.tgz", "integrity": "sha512-3+GIFhk3sNuvFAJKU46o26OdzudQlPNBCu1ZQi3cMeMHhty1bhDxu2WrEilVNYaGvqUtR1VSigFcJOiS13dRhQ==", "dev": true, + "license": "MIT", "dependencies": { "change-case": "^4.1.2", "is-lower-case": "^2.0.2", @@ -5225,6 +6337,7 @@ "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -5233,19 +6346,15 @@ "version": "0.7.0", "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], + "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -5258,10 +6367,26 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -5273,21 +6398,24 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], + "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true, + "license": "MIT" }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5297,6 +6425,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^3.1.0" }, @@ -5305,10 +6434,11 @@ } }, "node_modules/cli-spinners": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.1.tgz", - "integrity": "sha512-jHgecW0pxkonBJdrKsqxgRX9AcG+u/5k0Q7WPDfi8AogLAdwxEkyYYNWwZ5GvVFoFx2uiY1eNcSK00fh+1+FyQ==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -5321,6 +6451,7 @@ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^3.0.0", "string-width": "^4.2.0" @@ -5337,6 +6468,7 @@ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", "dev": true, + "license": "ISC", "engines": { "node": ">= 10" } @@ -5346,6 +6478,7 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -5355,11 +6488,48 @@ "node": ">=12" } }, + "node_modules/cliui/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/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, + "license": "MIT" + }, "node_modules/cliui/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -5377,6 +6547,7 @@ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8" } @@ -5385,6 +6556,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "license": "Apache-2.0", "engines": { "node": ">=0.10.0" } @@ -5394,6 +6566,7 @@ "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, + "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -5403,36 +6576,38 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true + "dev": true, + "license": "MIT" }, "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==", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "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 + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -5445,20 +6620,83 @@ "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz", "integrity": "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/compression/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/connect-redis": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-7.1.1.tgz", "integrity": "sha512-M+z7alnCJiuzKa8/1qAYdGUXHYfDnLolOGAUjOioB07pP39qxjG+X9ibsud7qUBc4jMV5Mcy3ugGv8eFcgamJQ==", + "license": "MIT", "engines": { "node": ">=16" }, @@ -5471,6 +6709,7 @@ "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -5481,6 +6720,7 @@ "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -5492,6 +6732,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz", "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -5500,6 +6741,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5508,12 +6750,14 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -5521,12 +6765,14 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" }, "node_modules/cors": { "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -5540,6 +6786,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", "dev": true, + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -5556,6 +6803,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig-toml-loader/-/cosmiconfig-toml-loader-1.0.0.tgz", "integrity": "sha512-H/2gurFWVi7xXvCyvsWRLCMekl4tITJcX0QEsDMpzxtuxDyM59xLatYNg4s/k9AA/HdtCYfj2su8mgA0GSDLDA==", "dev": true, + "license": "MIT", "dependencies": { "@iarna/toml": "^2.2.5" } @@ -5565,6 +6813,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig-typescript-loader/-/cosmiconfig-typescript-loader-4.1.1.tgz", "integrity": "sha512-9DHpa379Gp0o0Zefii35fcmuuin6q92FnLDffzdZ0l9tVd3nEobG3O+MZ06+kuBvFTSVScvNb/oHA13Nd4iipg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12", "npm": ">=6" @@ -5581,6 +6830,7 @@ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -5597,30 +6847,121 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "node_modules/cross-fetch": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", - "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", - "dev": true, - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/create-jest/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, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/create-jest/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, + "license": "MIT", + "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/create-jest/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/create-jest/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, + "license": "MIT" + }, + "node_modules/create-jest/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/create-jest/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-inspect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cross-inspect/-/cross-inspect-1.0.0.tgz", + "integrity": "sha512-4PFfn4b5ZN6FMNGSZlyb7wUhuN8wvj8t/VQHZdM4JsDcruGJ8L2kf9zao98QIrBPFCpdk27qst/AGTl7pL3ypQ==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { "node": ">= 8" @@ -5629,23 +6970,27 @@ "node_modules/dasherize": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz", - "integrity": "sha512-APql/TZ6FdLEpf2z7/X2a2zyqK8juYtqaSVqxw9mYoQ64CXkfU15AeLh8pUszT8+fnYjgm6t0aIYpWKJbnLkuA==" + "integrity": "sha512-APql/TZ6FdLEpf2z7/X2a2zyqK8juYtqaSVqxw9mYoQ64CXkfU15AeLh8pUszT8+fnYjgm6t0aIYpWKJbnLkuA==", + "license": "MIT" }, "node_modules/dataloader": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.2.2.tgz", - "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==" + "integrity": "sha512-8YnDaaf7N3k/q5HnTJVuzSyLETjoZjVmHc4AeKAzOvKHEFQKcn64OKBfzHYtE9zGjctNM7V9I0MfnUVLpi7M5g==", + "license": "MIT" }, "node_modules/debounce": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz", "integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -5663,15 +7008,17 @@ "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, + "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -5685,13 +7032,15 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5701,6 +7050,7 @@ "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, + "license": "MIT", "dependencies": { "clone": "^1.0.2" }, @@ -5709,22 +7059,27 @@ } }, "node_modules/define-data-property": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", - "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.1", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -5733,6 +7088,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5742,6 +7098,7 @@ "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz", "integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.6.0" } @@ -5750,6 +7107,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -5760,6 +7118,7 @@ "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5769,6 +7128,7 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -5778,17 +7138,19 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, "node_modules/diff-sequences": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz", - "integrity": "sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg==", + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 8.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/dir-glob": { @@ -5796,6 +7158,7 @@ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, @@ -5808,6 +7171,7 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -5819,6 +7183,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz", "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -5828,6 +7193,7 @@ "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -5837,14 +7203,16 @@ "version": "8.6.0", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.6.0.tgz", "integrity": "sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==", + "license": "BSD-2-Clause", "engines": { "node": ">=10" } }, "node_modules/dset": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.2.tgz", - "integrity": "sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz", + "integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==", + "license": "MIT", "engines": { "node": ">=4" } @@ -5854,6 +7222,7 @@ "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, + "license": "MIT", "dependencies": { "xtend": "^4.0.0" } @@ -5861,19 +7230,22 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.4.563", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.563.tgz", - "integrity": "sha512-dg5gj5qOgfZNkPNeyKBZQAQitIQ/xwfIDmEQJHCbXaD9ebTZxwJXUsDYcBlAvZGZLi+/354l35J1wkmP6CqYaw==", - "dev": true + "version": "1.4.811", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.811.tgz", + "integrity": "sha512-CDyzcJ5XW78SHzsIOdn27z8J4ist8eaFLhdto2hSMSJQgsiwvbv2fbizcKUICryw1Wii1TI/FEkvzvJsR3awrA==", + "dev": true, + "license": "ISC" }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5885,12 +7257,14 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -5900,15 +7274,38 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, + "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -5916,31 +7313,31 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -5990,6 +7387,7 @@ "resolved": "https://registry.npmjs.org/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz", "integrity": "sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A==", "dev": true, + "license": "MIT", "dependencies": { "eslint-rule-composer": "^0.3.0" }, @@ -6011,6 +7409,7 @@ "resolved": "https://registry.npmjs.org/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz", "integrity": "sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==", "dev": true, + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -6020,6 +7419,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -6029,15 +7429,79 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">=10" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "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/eslint/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/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, + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint/node_modules/eslint-scope": { @@ -6045,6 +7509,7 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -6056,40 +7521,79 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "node_modules/eslint/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { - "type-fest": "^0.20.2" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=8" + "node": "*" + } + }, + "node_modules/eslint/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8" } }, "node_modules/eslint/node_modules/type-fest": { @@ -6097,6 +7601,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -6109,6 +7614,7 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -6121,12 +7627,26 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, @@ -6139,6 +7659,7 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -6151,6 +7672,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -6160,6 +7682,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -6172,6 +7695,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -6181,6 +7705,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -6190,6 +7715,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -6198,6 +7724,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6206,13 +7733,15 @@ "version": "0.0.3", "resolved": "https://registry.npmjs.org/event-target-polyfill/-/event-target-polyfill-0.0.3.tgz", "integrity": "sha512-ZMc6UuvmbinrCk4RzGyVmRyIsAyxMRlp4CqSrcQRO8Dy0A9ldbiRy5kdtBj4OtP7EClGdqGfIqo9JmOClMsGLQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -6222,6 +7751,7 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, + "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -6254,6 +7784,7 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -6266,16 +7797,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -6307,12 +7839,13 @@ } }, "node_modules/express-session": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.3.tgz", - "integrity": "sha512-4+otWXlShYlG1Ma+2Jnn+xgKUZTMJ5QD3YvfilX3AcocOAbIkVylSWEklzALe/+Pu4qV6TYBj5GwOBFfdKqLBw==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.0.tgz", + "integrity": "sha512-m93QLWr0ju+rOwApSsyso838LQwgfs44QtOP/WBiwtAgPIo/SAh1a5c6nn2BR6mFNZehTpqKDESzP+fRHVbxwQ==", + "license": "MIT", "dependencies": { - "cookie": "0.4.2", - "cookie-signature": "1.0.6", + "cookie": "0.6.0", + "cookie-signature": "1.0.7", "debug": "2.6.9", "depd": "~2.0.0", "on-headers": "~1.0.2", @@ -6324,18 +7857,17 @@ "node": ">= 0.8.0" } }, - "node_modules/express-session/node_modules/cookie": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", - "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", - "engines": { - "node": ">= 0.6" - } + "node_modules/express-session/node_modules/cookie-signature": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.7.tgz", + "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==", + "license": "MIT" }, "node_modules/express-session/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6343,35 +7875,14 @@ "node_modules/express-session/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", - "dependencies": { - "bytes": "3.1.2", - "content-type": "~1.0.4", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.11.0", - "raw-body": "2.5.1", - "type-is": "~1.6.18", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6379,27 +7890,15 @@ "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" - }, - "node_modules/express/node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", - "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - }, - "engines": { - "node": ">= 0.8" - } + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/external-editor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", "dev": true, + "license": "MIT", "dependencies": { "chardet": "^0.7.0", "iconv-lite": "^0.4.24", @@ -6414,6 +7913,7 @@ "resolved": "https://registry.npmjs.org/extract-files/-/extract-files-11.0.0.tgz", "integrity": "sha512-FuoE1qtbJ4bBVvv94CC7s0oTnKUGvQs+Rjf1L2SJFfS+HTVVjhPFtehPdQ0JiGPqVNfSSZvL5yzHHQq2Z4WNhQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.20 || >= 14.13" }, @@ -6425,19 +7925,22 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -6449,23 +7952,39 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-querystring": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", "dev": true, + "license": "MIT", "dependencies": { "fast-decode-uri-component": "^1.0.1" } @@ -6475,21 +7994,17 @@ "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz", "integrity": "sha512-5jOCVXADYNuRkKFzNJ0dCCewsZiYo0dz8QNYljkOpFC6r2U4OBmKtvm/Tsuh4w1YYdDqDb31a8TVhBJ2OJKdqQ==", "dev": true, + "license": "MIT", "dependencies": { "punycode": "^1.3.2" } }, - "node_modules/fast-url-parser/node_modules/punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", - "dev": true - }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, + "license": "ISC", "dependencies": { "reusify": "^1.0.4" } @@ -6499,6 +8014,7 @@ "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, + "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -6508,6 +8024,7 @@ "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-3.0.5.tgz", "integrity": "sha512-ztsSx77JBtkuMrEypfhgc3cI0+0h+svqeie7xHbh1k/IKdcydnvadp/mUaGgjAOXQmQSxsqgaRhS3q9fy+1kxg==", "dev": true, + "license": "MIT", "dependencies": { "cross-fetch": "^3.1.5", "fbjs-css-vars": "^1.0.0", @@ -6522,12 +8039,14 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/fbjs-css-vars/-/fbjs-css-vars-1.0.2.tgz", "integrity": "sha512-b2XGFAFdWZWg0phtAWLHCk836A1Xann+I+Dgd3Gk64MHKZO44FfoD1KxyvbSh0qZsIoXQGGlVztIY+oitJPpRQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/feature-policy": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz", "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -6537,6 +8056,7 @@ "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -6547,20 +8067,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/figures/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, + "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -6569,10 +8081,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -6584,6 +8097,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -6601,6 +8115,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6608,13 +8123,15 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -6627,35 +8144,38 @@ } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, + "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.3", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", - "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", "funding": [ { "type": "individual", "url": "https://github.com/sponsors/RubenVerborgh" } ], + "license": "MIT", "engines": { "node": ">=4.0" }, @@ -6669,6 +8189,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -6682,13 +8203,15 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.9.0.tgz", "integrity": "sha512-rahaRMkN8P8d/tgK/BLPX+WBVM27NbvdXBxqQujBtkDAIFspaRqN7Od7lfdGQA6KAD+f82fYCLBq1ipvcu8qLw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", "dev": true, + "license": "MIT", "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "4.0.0-beta.3" @@ -6702,6 +8225,7 @@ "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", "dev": true, + "license": "MIT", "engines": { "node": ">= 14" } @@ -6710,6 +8234,7 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6718,6 +8243,7 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6726,7 +8252,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", @@ -6734,6 +8261,7 @@ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -6746,6 +8274,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6754,6 +8283,7 @@ "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -6763,6 +8293,7 @@ "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -6772,20 +8303,26 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, + "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-intrinsic": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", - "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", "dependencies": { + "es-errors": "^1.3.0", "function-bind": "^1.1.2", "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6795,6 +8332,7 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -6804,6 +8342,7 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -6815,7 +8354,9 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -6832,15 +8373,29 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, "node_modules/globals": { @@ -6848,6 +8403,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -6857,6 +8413,7 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -6876,6 +8433,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -6887,18 +8445,21 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/graphql": { - "version": "16.8.1", - "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", - "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "version": "16.9.0", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.9.0.tgz", + "integrity": "sha512-GGTKBX4SD7Wdb8mqeDLni2oaRGYQWjWHGKPQ24ZMnUtKfcsVoiv4uX8+LJr1K6U5VW2Lu1BwJnj7uiori0YtRw==", + "license": "MIT", "engines": { "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" } @@ -6908,6 +8469,7 @@ "resolved": "https://registry.npmjs.org/graphql-config/-/graphql-config-4.3.6.tgz", "integrity": "sha512-i7mAPwc0LAZPnYu2bI8B6yXU5820Wy/ArvmOseDLZIu0OU1UTULEuexHo6ZcHXeT9NvGGaUPQZm8NV3z79YydA==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-tools/graphql-file-loader": "^7.3.7", "@graphql-tools/json-file-loader": "^7.3.7", @@ -6930,11 +8492,40 @@ "graphql": "^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" } }, + "node_modules/graphql-config/node_modules/@graphql-tools/merge": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.4.2.tgz", + "integrity": "sha512-XbrHAaj8yDuINph+sAfuq3QCZ/tKblrTLOpirK0+CAgNlZUCHs0Fa+xtMUURgwCVThLle1AF7svJCxFizygLsw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-tools/utils": "^9.2.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/graphql-config/node_modules/@graphql-tools/merge/node_modules/@graphql-tools/utils": { + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-9.2.1.tgz", + "integrity": "sha512-WUw506Ql6xzmOORlriNrD6Ugx+HjVgYxt9KCXD9mHAak+eaXSwuGGPyE60hy9xaDEoXKBsG7SkG69ybitaVl6A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "tslib": "^2.4.0" + }, + "peerDependencies": { + "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/graphql-config/node_modules/@graphql-tools/utils": { "version": "8.13.1", "resolved": "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.13.1.tgz", "integrity": "sha512-qIh9yYpdUFmctVqovwMdheVNJqFh+DQNWIhX87FJStfXYnmweBUDATok9fWPleKeFwxnW8IapKmY8m8toJEkAw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.4.0" }, @@ -6947,6 +8538,7 @@ "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz", "integrity": "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==", "dev": true, + "license": "MIT", "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.2.1", @@ -6958,22 +8550,11 @@ "node": ">=10" } }, - "node_modules/graphql-config/node_modules/minimatch": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", - "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/graphql-modules": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/graphql-modules/-/graphql-modules-2.2.0.tgz", - "integrity": "sha512-iWFyqP+jZqlwPkM4zVI0A/GDgQErxCTZeiz/jVv0MNzKut+ZEV6Dx8TlLhHd6VLqrqHZmib4NybG5Me8E03jDg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/graphql-modules/-/graphql-modules-2.3.0.tgz", + "integrity": "sha512-CcrjUjMYHy3zelnffldhR3h6t4ndCVJEzdqBAv/mp4ZGEA/izirOKZB2lnRwpXNqOtVwIz2O/E1Cg/UH8dFNaQ==", + "license": "MIT", "dependencies": { "@graphql-tools/schema": "^10.0.0", "@graphql-tools/wrap": "^10.0.0", @@ -6984,83 +8565,12 @@ "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/graphql-modules/node_modules/@graphql-tools/batch-execute": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/@graphql-tools/batch-execute/-/batch-execute-9.0.2.tgz", - "integrity": "sha512-Y2uwdZI6ZnatopD/SYfZ1eGuQFI7OU2KGZ2/B/7G9ISmgMl5K+ZZWz/PfIEXeiHirIDhyk54s4uka5rj2xwKqQ==", - "dependencies": { - "@graphql-tools/utils": "^10.0.5", - "dataloader": "^2.2.2", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/graphql-modules/node_modules/@graphql-tools/delegate": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/@graphql-tools/delegate/-/delegate-10.0.3.tgz", - "integrity": "sha512-Jor9oazZ07zuWkykD3OOhT/2XD74Zm6Ar0ENZMk75MDD51wB2UWUIMljtHxbJhV5A6UBC2v8x6iY0xdCGiIlyw==", - "dependencies": { - "@graphql-tools/batch-execute": "^9.0.1", - "@graphql-tools/executor": "^1.0.0", - "@graphql-tools/schema": "^10.0.0", - "@graphql-tools/utils": "^10.0.5", - "dataloader": "^2.2.2", - "tslib": "^2.5.0" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/graphql-modules/node_modules/@graphql-tools/executor": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@graphql-tools/executor/-/executor-1.2.0.tgz", - "integrity": "sha512-SKlIcMA71Dha5JnEWlw4XxcaJ+YupuXg0QCZgl2TOLFz4SkGCwU/geAsJvUJFwK2RbVLpQv/UMq67lOaBuwDtg==", - "dependencies": { - "@graphql-tools/utils": "^10.0.0", - "@graphql-typed-document-node/core": "3.2.0", - "@repeaterjs/repeater": "^3.0.4", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, - "node_modules/graphql-modules/node_modules/@graphql-tools/wrap": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@graphql-tools/wrap/-/wrap-10.0.1.tgz", - "integrity": "sha512-Cw6hVrKGM2OKBXeuAGltgy4tzuqQE0Nt7t/uAqnuokSXZhMHXJUb124Bnvxc2gPZn5chfJSDafDe4Cp8ZAVJgg==", - "dependencies": { - "@graphql-tools/delegate": "^10.0.3", - "@graphql-tools/schema": "^10.0.0", - "@graphql-tools/utils": "^10.0.0", - "tslib": "^2.4.0", - "value-or-promise": "^1.0.12" - }, - "engines": { - "node": ">=16.0.0" - }, - "peerDependencies": { - "graphql": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" - } - }, "node_modules/graphql-request": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", "dev": true, + "license": "MIT", "dependencies": { "@graphql-typed-document-node/core": "^3.2.0", "cross-fetch": "^3.1.5" @@ -7074,6 +8584,7 @@ "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.1.0" }, @@ -7088,6 +8599,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/graphql-type-json/-/graphql-type-json-0.3.2.tgz", "integrity": "sha512-J+vjof74oMlCWXSvt0DOf2APEdZOCdubEvGDUAlqH//VBYcOYsGgRW7Xzorr44LvkjiuvecWc8fChxuZZbChtg==", + "license": "MIT", "peerDependencies": { "graphql": ">=0.8.0" } @@ -7097,6 +8609,7 @@ "resolved": "https://registry.npmjs.org/graphql-ws/-/graphql-ws-5.12.1.tgz", "integrity": "sha512-umt4f5NnMK46ChM2coO36PTFhHouBrK9stWWBczERguwYrGnPNxJ9dimU6IyOBfOkC6Izhkg4H8+F51W/8CYDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7105,29 +8618,32 @@ } }, "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==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/has-property-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", - "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.2" + "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", - "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7139,6 +8655,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -7147,9 +8664,10 @@ } }, "node_modules/hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -7162,6 +8680,7 @@ "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", "dev": true, + "license": "MIT", "dependencies": { "capital-case": "^1.0.4", "tslib": "^2.0.3" @@ -7171,6 +8690,7 @@ "version": "3.23.3", "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.23.3.tgz", "integrity": "sha512-U3MeYdzPJQhtvqAVBPntVgAvNSOJyagwZwyKsFdyRa8TV3pOKVFljalPOCxbw5Wwf2kncGhmP0qHjyazIdNdSA==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "dont-sniff-mimetype": "1.1.0", @@ -7192,6 +8712,7 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz", "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -7200,6 +8721,7 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.10.0.tgz", "integrity": "sha512-Rz953ZNEFk8sT2XvewXkYN0Ho4GEZdjAZy4stjiEQV3eN7GDxg1QKmYggH7otDyIA7uGA6XnUMVSgeJwbR5X+w==", + "license": "MIT", "dependencies": { "bowser": "2.9.0", "camelize": "1.0.0", @@ -7214,6 +8736,7 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz", "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -7221,12 +8744,14 @@ "node_modules/hpkp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz", - "integrity": "sha512-TaZpC6cO/k3DFsjfzz1LnOobbVSq+J+7WpJxrVtN4L+8+BPQj8iBDRB2Dx49613N+e7/+ZSQ9ra+xZm7Blf4wg==" + "integrity": "sha512-TaZpC6cO/k3DFsjfzz1LnOobbVSq+J+7WpJxrVtN4L+8+BPQj8iBDRB2Dx49613N+e7/+ZSQ9ra+xZm7Blf4wg==", + "license": "MIT" }, "node_modules/hsts": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz", "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0" }, @@ -7238,12 +8763,14 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -7260,6 +8787,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-6.1.1.tgz", "integrity": "sha512-JRCz+4Whs6yrrIoIlrH+ZTmhrRwtMnmOHsHn8GFEn9O2sVfSE+DAZ3oyyGIKF8tjJEeSJmP89j7aTjVsSqsU0g==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -7273,6 +8801,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-6.2.1.tgz", "integrity": "sha512-ONsE3+yfZF2caH5+bJlcddtWqNI3Gvs5A38+ngvljxaBiRXRswym2c7yf8UAeFpRFKjFNHIFEHqR/OLAWJzyiA==", "dev": true, + "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -7286,6 +8815,7 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -7294,6 +8824,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -7319,13 +8850,15 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "BSD-3-Clause" }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -7335,6 +8868,7 @@ "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz", "integrity": "sha512-AizQPcaofEtO11RZhPPHBOJRdo/20MKQF9mBLnVkBoyHi1/zXK8fzVdnEpSV9gxqtnh6Qomfp3F0xT5qP/vThw==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.8.0" } @@ -7344,6 +8878,7 @@ "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7360,6 +8895,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -7369,6 +8905,7 @@ "resolved": "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz", "integrity": "sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.2" }, @@ -7381,6 +8918,7 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, + "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -7400,6 +8938,7 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -7409,6 +8948,7 @@ "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7417,7 +8957,9 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -7426,13 +8968,15 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, "node_modules/inquirer": { "version": "8.2.6", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.6.tgz", "integrity": "sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.2.1", "chalk": "^4.1.1", @@ -7454,33 +8998,126 @@ "node": ">=12.0.0" } }, - "node_modules/invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "node_modules/inquirer/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, + "license": "MIT", "dependencies": { - "loose-envify": "^1.0.0" - } - }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "color-convert": "^2.0.1" + }, "engines": { - "node": ">= 0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/is-absolute": { - "version": "1.0.0", + "node_modules/inquirer/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, + "license": "MIT", + "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/inquirer/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/inquirer/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, + "license": "MIT" + }, + "node_modules/inquirer/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inquirer/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", "dev": true, + "license": "MIT", "dependencies": { "is-relative": "^1.0.0", "is-windows": "^1.0.1" @@ -7493,13 +9130,15 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, + "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -7508,12 +9147,16 @@ } }, "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz", + "integrity": "sha512-a5dFJih5ZLYlRtDc0dZWP7RiKr6xIKzmn/oAYCDvdLThadVgyJwlaoQPmRtMSpz+rk0OGAgIu+TcM9HUF0fk1A==", "dev": true, + "license": "MIT", "dependencies": { - "hasown": "^2.0.0" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -7524,6 +9167,7 @@ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7533,6 +9177,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7542,6 +9187,7 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -7551,6 +9197,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -7563,6 +9210,7 @@ "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7572,6 +9220,7 @@ "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-2.0.2.tgz", "integrity": "sha512-bVcMJy4X5Og6VZfdOZstSexlEy20Sr0k/p/b2IlQJlfdKAQuMpiv5w2Ccxb8sKdRUNAG1PnHVHjFSdRDVS6NlQ==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -7581,6 +9230,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -7590,6 +9240,7 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -7599,6 +9250,7 @@ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, + "license": "MIT", "dependencies": { "is-unc-path": "^1.0.0" }, @@ -7611,6 +9263,7 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -7623,6 +9276,7 @@ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", "dev": true, + "license": "MIT", "dependencies": { "unc-path-regex": "^0.1.2" }, @@ -7635,6 +9289,7 @@ "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -7647,6 +9302,7 @@ "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-2.0.2.tgz", "integrity": "sha512-44pxmxAvnnAOwBg4tHPnkfvgjPwbc5QIsSstNU+YcJ1ovxVzCWpSGosPJOZh/a1tdl81fbgnLc9LLv+x2ywbPQ==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -7656,43 +9312,55 @@ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/isomorphic-ws": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-5.0.0.tgz", "integrity": "sha512-muId7Zzn9ywDsyXgTIafTry2sV3nySZeUDe6YedVd1Hvuuep5AsIlqK+XefWpYTyJG5e503F2xIuT2lcU6rCSw==", "dev": true, + "license": "MIT", "peerDependencies": { "ws": "*" } }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=8" } }, "node_modules/istanbul-lib-instrument": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz", - "integrity": "sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", "istanbul-lib-coverage": "^3.2.0", "semver": "^7.5.4" }, @@ -7700,26 +9368,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -7727,17 +9381,12 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-instrument/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -7747,11 +9396,35 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-report/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -7762,10 +9435,11 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -7779,6 +9453,7 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -7805,6 +9480,7 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, + "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -7819,6 +9495,7 @@ "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -7846,42 +9523,87 @@ } }, "node_modules/jest-circus/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-circus/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-circus/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/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, + "license": "MIT" + }, + "node_modules/jest-circus/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, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jest-circus/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-circus/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest-cli": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", "dev": true, + "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/test-result": "^29.7.0", @@ -7910,11 +9632,88 @@ } } }, + "node_modules/jest-cli/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/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, + "license": "MIT", + "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/jest-cli/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/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, + "license": "MIT" + }, + "node_modules/jest-cli/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-config": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -7956,72 +9755,171 @@ } }, "node_modules/jest-config/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-config/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-config/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/jest-config/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-config/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, + "license": "MIT" + }, + "node_modules/jest-config/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest-diff": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz", - "integrity": "sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A==", + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, + "license": "MIT", "dependencies": { - "chalk": "^3.0.0", - "diff-sequences": "^25.2.6", - "jest-get-type": "^25.2.6", - "pretty-format": "^25.5.0" + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 8.3" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/jest-diff/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "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/jest-diff/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/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, + "license": "MIT" + }, + "node_modules/jest-diff/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, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/jest-diff/node_modules/jest-get-type": { - "version": "25.2.6", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz", - "integrity": "sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig==", + "node_modules/jest-diff/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 8.3" + "node": ">=8" } }, "node_modules/jest-docblock": { @@ -8029,6 +9927,7 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, + "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -8041,6 +9940,7 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -8053,42 +9953,87 @@ } }, "node_modules/jest-each/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-each/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-each/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/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, + "license": "MIT" + }, + "node_modules/jest-each/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, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jest-each/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-each/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest-environment-node": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -8106,6 +10051,7 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -8115,6 +10061,7 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -8140,6 +10087,7 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, + "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -8148,43 +10096,12 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-leak-detector/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/jest-leak-detector/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-leak-detector/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-matcher-utils": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -8196,66 +10113,87 @@ } }, "node_modules/jest-matcher-utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-matcher-utils/node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/jest-matcher-utils/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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-matcher-utils/node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/jest-matcher-utils/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-matcher-utils/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, + "license": "MIT" + }, + "node_modules/jest-matcher-utils/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/jest-matcher-utils/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, "node_modules/jest-message-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -8272,42 +10210,87 @@ } }, "node_modules/jest-message-util/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-message-util/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-message-util/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-message-util/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/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, + "license": "MIT" + }, + "node_modules/jest-message-util/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -8322,6 +10305,7 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" }, @@ -8339,6 +10323,7 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -8348,6 +10333,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -8368,6 +10354,7 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, + "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -8376,11 +10363,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-resolve/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/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, + "license": "MIT", + "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/jest-resolve/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/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, + "license": "MIT" + }, + "node_modules/jest-resolve/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runner": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -8408,11 +10472,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/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, + "license": "MIT", + "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/jest-runner/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/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, + "license": "MIT" + }, + "node_modules/jest-runner/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, + "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -8441,11 +10582,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/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, + "license": "MIT", + "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/jest-runtime/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/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, + "license": "MIT" + }, + "node_modules/jest-runtime/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, + "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -8473,109 +10691,186 @@ } }, "node_modules/jest-snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/diff-sequences": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "node_modules/jest-snapshot/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, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-snapshot/node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "node_modules/jest-snapshot/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, + "license": "MIT", "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "color-name": "~1.1.4" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/jest-snapshot/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, - "dependencies": { - "yallist": "^4.0.0" + "license": "MIT" + }, + "node_modules/jest-snapshot/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/pretty-format": { + "node_modules/jest-snapshot/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util": { "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" }, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-snapshot/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true - }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/jest-util/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, + "license": "MIT", "dependencies": { - "lru-cache": "^6.0.0" + "color-convert": "^2.0.1" }, - "bin": { - "semver": "bin/semver.js" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/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, + "license": "MIT", + "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/jest-util/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" } }, - "node_modules/jest-snapshot/node_modules/yallist": { + "node_modules/jest-util/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, + "license": "MIT" + }, + "node_modules/jest-util/node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "node_modules/jest-util/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, + "license": "MIT", "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" + "has-flag": "^4.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, "node_modules/jest-validate": { @@ -8583,6 +10878,7 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, + "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -8596,12 +10892,16 @@ } }, "node_modules/jest-validate/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -8612,6 +10912,7 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -8619,31 +10920,72 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/jest-validate/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "node_modules/jest-validate/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, + "license": "MIT", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/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, + "license": "MIT" + }, + "node_modules/jest-validate/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, + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/jest-validate/node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true + "node_modules/jest-validate/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } }, "node_modules/jest-watcher": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, + "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -8658,11 +11000,88 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-watcher/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/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, + "license": "MIT", + "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/jest-watcher/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/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, + "license": "MIT" + }, + "node_modules/jest-watcher/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, + "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -8673,11 +11092,22 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-worker/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker/node_modules/supports-color": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8689,10 +11119,11 @@ } }, "node_modules/jose": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.4.tgz", - "integrity": "sha512-W+oqK4H+r5sITxfxpSU+MMdr/YSWGvgZMQDIsNoBDGGy4i7GBPTtvFKibQzW06n3U3TqHjhvBJsirShsEJ6eeQ==", + "version": "4.15.7", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.15.7.tgz", + "integrity": "sha512-L7ioP+JAuZe8v+T5+zVI9Tx8LtU8BL7NxkyDFVMv+Qr3JW0jSoYDedLtodaXwfqMpeCyx4WXFNyu9tJt4WvC1A==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/panva" } @@ -8701,13 +11132,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -8715,11 +11148,18 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, + "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -8731,27 +11171,37 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.2.tgz", - "integrity": "sha512-eunSSaEnxV12z+Z73y/j5N37/In40GK4GmsSy+tEHJMxknvqnA7/djeYtAgW0GsWHUfg+847WJjKaEylk2y09g==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", + "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", "dev": true, + "license": "MIT", "dependencies": { - "jsonify": "^0.0.1" + "call-bind": "^1.0.5", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -8761,13 +11211,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-to-pretty-yaml": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/json-to-pretty-yaml/-/json-to-pretty-yaml-1.2.2.tgz", "integrity": "sha512-rvm6hunfCcqegwYaG5T4yKJWxc9FXFgBVrcTZ4XfSVRwa5HA/Xs+vB/Eo9treYYHCeNM0nrSUr82V/M31Urc7A==", "dev": true, + "license": "Apache-2.0", "dependencies": { "remedial": "^1.0.7", "remove-trailing-spaces": "^1.0.6" @@ -8781,6 +11233,7 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, + "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -8793,6 +11246,7 @@ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", "dev": true, + "license": "Public Domain", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8801,6 +11255,7 @@ "version": "2.5.1", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.5.1.tgz", "integrity": "sha512-7jFxRVm+jD+rkq3kY0iZDJfsO2/t4BBPeEb2qKn2lR/9KhuksYk5hxzfRYWMPV8P/x2d0kHD306YyWLzjjH+uA==", + "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } @@ -8810,6 +11265,7 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -8819,6 +11275,7 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8828,6 +11285,7 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -8837,6 +11295,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -8849,13 +11308,15 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/listr2": { "version": "4.0.5", "resolved": "https://registry.npmjs.org/listr2/-/listr2-4.0.5.tgz", "integrity": "sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==", "dev": true, + "license": "MIT", "dependencies": { "cli-truncate": "^2.1.0", "colorette": "^2.0.16", @@ -8878,11 +11339,48 @@ } } }, + "node_modules/listr2/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/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, + "license": "MIT" + }, "node_modules/listr2/node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -8900,6 +11398,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -8913,39 +11412,120 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/lodash.sortby": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/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, + "license": "MIT", + "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/log-symbols/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/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, + "license": "MIT" }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "node_modules/log-symbols/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/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, + "license": "MIT", "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "has-flag": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=8" } }, "node_modules/log-update": { @@ -8953,6 +11533,7 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^4.3.0", "cli-cursor": "^3.1.0", @@ -8966,11 +11547,48 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/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, + "license": "MIT" + }, "node_modules/log-update/node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -8984,9 +11602,10 @@ } }, "node_modules/loglevel": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.1.tgz", - "integrity": "sha512-tCRIJM51SHjAayKwC+QAg8hT8vg6z7GSgLJKGvzuPb1Wc+hLzqtuVLxp6/HzSPOozuK+8ErAhy7U/sVzw8Dgfg==", + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.9.1.tgz", + "integrity": "sha512-hP3I3kCrDIMuRwAwHltphhDM1r8i55H33GgqjXbrisuJhF4kRhW1dNuxsRklp4bXl8DSdLaNLuiL4A/LWRfxvg==", + "license": "MIT", "engines": { "node": ">= 0.6.0" }, @@ -8998,13 +11617,15 @@ "node_modules/long": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", - "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==", + "license": "Apache-2.0" }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "dev": true, + "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, @@ -9017,6 +11638,7 @@ "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -9026,6 +11648,7 @@ "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-2.0.2.tgz", "integrity": "sha512-EVm/rR94FJTZi3zefZ82fLWab+GX14LJN4HrWBcuo6Evmsl9hEfnqxgcHCKb9q+mNf6EVdsjx/qucYFIIB84pg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -9034,6 +11657,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -9043,6 +11667,7 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, + "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -9053,26 +11678,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -9080,23 +11691,19 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -9106,6 +11713,7 @@ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9114,6 +11722,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9121,24 +11730,28 @@ "node_modules/memory-pager": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", - "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==" + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "license": "MIT" }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -9148,6 +11761,7 @@ "resolved": "https://registry.npmjs.org/meros/-/meros-1.3.0.tgz", "integrity": "sha512-2BNGOimxEz5hmjUG2FwoxCt5HN7BXdaWyFqEwxPTrJzVdABtrL4TiHTcsWSFAxPQ/tOnEaQEJh3qWq71QRMY+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=13" }, @@ -9164,17 +11778,19 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", "engines": { "node": ">= 0.6" } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -9185,6 +11801,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", "bin": { "mime": "cli.js" }, @@ -9196,6 +11813,7 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9204,6 +11822,7 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -9216,20 +11835,22 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { - "node": "*" + "node": ">=10" } }, "node_modules/minimist": { @@ -9237,6 +11858,7 @@ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -9246,6 +11868,7 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, + "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -9254,13 +11877,14 @@ } }, "node_modules/mongodb": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.2.0.tgz", - "integrity": "sha512-d7OSuGjGWDZ5usZPqfvb36laQ9CPhnWkAGHT61x5P95p/8nMVeH8asloMwW6GcYFeB0Vj4CB/1wOTDG2RA9BFA==", + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.7.0.tgz", + "integrity": "sha512-TMKyHdtMcO0fYBNORiYdmM25ijsHs+Njs963r4Tro4OQZzqYigAzYQouwWRg4OIaiLRUEGUh/1UAcH5lxdSLIA==", + "license": "Apache-2.0", "dependencies": { - "@mongodb-js/saslprep": "^1.1.0", - "bson": "^6.2.0", - "mongodb-connection-string-url": "^2.6.0" + "@mongodb-js/saslprep": "^1.1.5", + "bson": "^6.7.0", + "mongodb-connection-string-url": "^3.0.0" }, "engines": { "node": ">=16.20.1" @@ -9299,22 +11923,24 @@ } }, "node_modules/mongodb-connection-string-url": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", - "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-3.0.1.tgz", + "integrity": "sha512-XqMGwRX0Lgn05TDB4PyG2h2kKO/FfWJyCzYQbIhXUxz7ETt0I/FqHjUeqj37irJ+Dl1ZtU82uYyj14u2XsZKfg==", + "license": "Apache-2.0", "dependencies": { - "@types/whatwg-url": "^8.2.1", - "whatwg-url": "^11.0.0" + "@types/whatwg-url": "^11.0.2", + "whatwg-url": "^13.0.0" } }, "node_modules/mongoose": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.6.3.tgz", - "integrity": "sha512-moYP2qWCOdWRDeBxqB/zYwQmQnTBsF5DoolX5uPyI218BkiA1ujGY27P0NTd4oWIX+LLkZPw0LDzlc/7oh1plg==", + "version": "7.7.0", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-7.7.0.tgz", + "integrity": "sha512-+HcoN/hmkB5IjAqWYA2ZAQeExGD8FNMe6L/eTYB04gqp9S2ZEngVivGkdtGrA4BYRf0suH+3rMNFW2JPOqC4Mg==", + "license": "MIT", "dependencies": { "bson": "^5.5.0", "kareem": "2.5.1", - "mongodb": "5.9.0", + "mongodb": "5.9.2", "mpath": "0.9.0", "mquery": "5.0.0", "ms": "2.1.3", @@ -9328,18 +11954,30 @@ "url": "https://opencollective.com/mongoose" } }, + "node_modules/mongoose/node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, "node_modules/mongoose/node_modules/bson": { "version": "5.5.1", "resolved": "https://registry.npmjs.org/bson/-/bson-5.5.1.tgz", "integrity": "sha512-ix0EwukN2EpC0SRWIj/7B5+A6uQMQy6KMREI9qQqvgpkV2frH63T0UDVd1SYedL6dNCmDBYB3QtXi4ISk9YT+g==", + "license": "Apache-2.0", "engines": { "node": ">=14.20.1" } }, "node_modules/mongoose/node_modules/mongodb": { - "version": "5.9.0", - "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.0.tgz", - "integrity": "sha512-g+GCMHN1CoRUA+wb1Agv0TI4YTSiWr42B5ulkiAfLLHitGK1R+PkSAf3Lr5rPZwi/3F04LiaZEW0Kxro9Fi2TA==", + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-5.9.2.tgz", + "integrity": "sha512-H60HecKO4Bc+7dhOv4sJlgvenK4fQNqqUIlXxZYQNbfEWSALGAwGoyJd/0Qwk4TttFXUOHJ2ZJQe/52ScaUwtQ==", + "license": "Apache-2.0", "dependencies": { "bson": "^5.5.0", "mongodb-connection-string-url": "^2.6.0", @@ -9376,15 +12014,61 @@ } } }, + "node_modules/mongoose/node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, "node_modules/mongoose/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==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mongoose/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mongoose/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongoose/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } }, "node_modules/mpath": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.9.0.tgz", "integrity": "sha512-ikJRQTk8hw5DEoFVxHG1Gn9T/xcjtdnOKIU1JTmGjZZlg9LST2mBLmcX3/ICIbgJydT2GOc15RnNy5mHmzfSew==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -9393,6 +12077,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/mquery/-/mquery-5.0.0.tgz", "integrity": "sha512-iQMncpmEK8R8ncT8HJGsGc9Dsp8xcgYMVSbs5jgnm1lFHTZqMJTUWTDx1LBO8+mK3tPNZWFLBghQEIOULSTHZg==", + "license": "MIT", "dependencies": { "debug": "4.x" }, @@ -9403,30 +12088,35 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" }, "node_modules/mute-stream": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/natural-compare-lite": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -9436,6 +12126,7 @@ "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, + "license": "MIT", "dependencies": { "lower-case": "^2.0.2", "tslib": "^2.0.3" @@ -9445,6 +12136,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz", "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -9452,7 +12144,8 @@ "node_modules/node-abort-controller": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", - "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==" + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "license": "MIT" }, "node_modules/node-domexception": { "version": "1.0.0", @@ -9469,6 +12162,7 @@ "url": "https://paypal.me/jimmywarting" } ], + "license": "MIT", "engines": { "node": ">=10.5.0" } @@ -9477,6 +12171,7 @@ "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", "dependencies": { "whatwg-url": "^5.0.0" }, @@ -9495,17 +12190,20 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -9515,19 +12213,22 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9537,6 +12238,7 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -9548,33 +12250,51 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/oauth": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.10.0.tgz", - "integrity": "sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==" + "integrity": "sha512-1orQ9MT1vHFGQxhuy7E/0gECD3fd2fCC+PIX+/jgmU/gI3EpRocXtmtvxCO5x3WZ443FLTLFWNDjl5MPJf9u+Q==", + "license": "MIT" }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "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==", + "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -9586,6 +12306,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9595,6 +12316,7 @@ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, + "license": "ISC", "dependencies": { "wrappy": "1" } @@ -9604,6 +12326,7 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -9615,17 +12338,18 @@ } }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -9636,6 +12360,7 @@ "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, + "license": "MIT", "dependencies": { "bl": "^4.1.0", "chalk": "^4.1.0", @@ -9654,11 +12379,88 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/ora/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/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, + "license": "MIT", + "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/ora/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/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, + "license": "MIT" + }, + "node_modules/ora/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, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/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, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9668,6 +12470,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -9683,6 +12486,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -9698,6 +12502,7 @@ "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, + "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -9713,6 +12518,7 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -9722,6 +12528,7 @@ "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9732,6 +12539,7 @@ "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -9744,6 +12552,7 @@ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", "dev": true, + "license": "MIT", "dependencies": { "is-absolute": "^1.0.0", "map-cache": "^0.2.0", @@ -9758,6 +12567,7 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, + "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -9775,6 +12585,7 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9784,6 +12595,7 @@ "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3" @@ -9793,6 +12605,7 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/passport/-/passport-0.6.0.tgz", "integrity": "sha512-0fe+p3ZnrWRW74fe8+SvCyf4a3Pb2/h7gFkQ8yTJpAO50gDzlfjZUZTO1k5Eg9kUct22OxHLqDZoKUWRHOh9ug==", + "license": "MIT", "dependencies": { "passport-strategy": "1.x.x", "pause": "0.0.1", @@ -9810,6 +12623,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", "integrity": "sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ==", + "license": "MIT", "dependencies": { "passport-oauth2": "1.x.x" }, @@ -9818,12 +12632,13 @@ } }, "node_modules/passport-oauth2": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.7.0.tgz", - "integrity": "sha512-j2gf34szdTF2Onw3+76alNnaAExlUmHvkc7cL+cmaS5NzHzDP/BvFHJruueQ9XAeNOdpI+CH+PWid8RA7KCwAQ==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.8.0.tgz", + "integrity": "sha512-cjsQbOrXIDE4P8nNb3FQRCCmJJ/utnFKEz2NX209f7KOHPoX18gF7gBzBbLLsj2/je4KrgiwLLGjf0lm9rtTBA==", + "license": "MIT", "dependencies": { "base64url": "3.x.x", - "oauth": "0.9.x", + "oauth": "0.10.x", "passport-strategy": "1.x.x", "uid2": "0.0.x", "utils-merge": "1.x.x" @@ -9849,6 +12664,7 @@ "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" @@ -9859,6 +12675,7 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9868,6 +12685,7 @@ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9877,6 +12695,7 @@ "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9885,13 +12704,15 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/path-root": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, + "license": "MIT", "dependencies": { "path-root-regex": "^0.1.0" }, @@ -9904,6 +12725,7 @@ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -9911,13 +12733,15 @@ "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": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -9928,16 +12752,18 @@ "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { "node": ">=8.6" }, @@ -9950,6 +12776,7 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 6" } @@ -9959,6 +12786,7 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, + "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -9971,6 +12799,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -9984,6 +12813,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -9996,6 +12826,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "license": "MIT", "dependencies": { "p-try": "^2.0.0" }, @@ -10005,88 +12836,56 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz", - "integrity": "sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ==", - "dev": true, - "dependencies": { - "@jest/types": "^25.5.0", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^16.12.0" - }, - "engines": { - "node": ">= 8.3" - } - }, - "node_modules/pretty-format/node_modules/@jest/types": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz", - "integrity": "sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw==", + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "license": "MIT", "dependencies": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^15.0.0", - "chalk": "^3.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">= 8.3" + "node": ">=8" } }, - "node_modules/pretty-format/node_modules/@types/istanbul-reports": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz", - "integrity": "sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" + "license": "MIT", + "engines": { + "node": ">= 0.8.0" } }, - "node_modules/pretty-format/node_modules/@types/yargs": { - "version": "15.0.17", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.17.tgz", - "integrity": "sha512-cj53I8GUcWJIgWVTSVe2L7NJAB5XWGdsoMosVvUgv1jEnMbAcsbaCzt1coUcyi8Sda5PgTWAooG8jNyDTD+CWA==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/yargs-parser": "*" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/pretty-format/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/promise": { @@ -10094,6 +12893,7 @@ "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", "dev": true, + "license": "MIT", "dependencies": { "asap": "~2.0.3" } @@ -10103,6 +12903,7 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, + "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -10115,6 +12916,7 @@ "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -10126,20 +12928,20 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "engines": { - "node": ">=6" - } + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" }, "node_modules/pure-rand": { - "version": "6.0.4", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.4.tgz", - "integrity": "sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "dev": true, "funding": [ { @@ -10150,13 +12952,15 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ] + ], + "license": "MIT" }, "node_modules/pvtsutils": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.5.tgz", "integrity": "sha512-ARvb14YB9Nm2Xi6nBq1ZX6dAM0FsJnuk+31aUp4TrcZEdKUlSqOqsxJHUPJDNE3qiIp+iUPEIeR6Je/tgV7zsA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.6.1" } @@ -10166,6 +12970,7 @@ "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.3.tgz", "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -10174,6 +12979,7 @@ "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -10202,12 +13008,14 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/ramda": { "version": "0.29.1", "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.29.1.tgz", "integrity": "sha512-OfxIeWzd4xdUNxlWhgFazxsA/nl3mS4/jGZI5n00uWOoSSFRhC1b6gl6xvmzUamgmqELraWp0J/qqVlXYPDPyA==", + "license": "MIT", "funding": { "type": "opencollective", "url": "https://opencollective.com/ramda" @@ -10217,6 +13025,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", "integrity": "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10225,6 +13034,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -10233,6 +13043,7 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -10244,16 +13055,18 @@ } }, "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true, + "license": "MIT" }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, + "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -10268,6 +13081,7 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, + "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -10276,12 +13090,16 @@ } }, "node_modules/redis": { - "version": "4.6.13", - "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.13.tgz", - "integrity": "sha512-MHgkS4B+sPjCXpf+HfdetBwbRz6vCtsceTmw1pHNYJAsYxrfpOP6dz+piJWGos8wqG7qb3vj/Rrc5qOlmInUuA==", + "version": "4.6.14", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.14.tgz", + "integrity": "sha512-GrNg/e33HtsQwNXL7kJT+iNFPSwE1IPmd7wzV3j4f2z0EYxZfZE7FVTmUysgAtqQQtg5NXF5SNLR9OdO/UHOfw==", + "license": "MIT", + "workspaces": [ + "./packages/*" + ], "dependencies": { "@redis/bloom": "1.2.0", - "@redis/client": "1.5.14", + "@redis/client": "1.5.16", "@redis/graph": "1.1.1", "@redis/json": "1.0.6", "@redis/search": "1.1.6", @@ -10292,26 +13110,30 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz", "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA==", + "license": "MIT", "engines": { "node": ">=4.0.0" } }, "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" + "version": "0.1.14", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.14.tgz", + "integrity": "sha512-ZhYeb6nRaXCfhnndflDK8qI6ZQ/YcWZCISRAWICW9XYqMUwjZM9Z0DveWX/ABN01oxSHwVxKQmxeYZSsm0jh5A==", + "license": "Apache-2.0" }, "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" }, "node_modules/relay-runtime": { "version": "12.0.0", "resolved": "https://registry.npmjs.org/relay-runtime/-/relay-runtime-12.0.0.tgz", "integrity": "sha512-QU6JKr1tMsry22DXNy9Whsq5rmvwr3LSZiiWV/9+DFpuTWvp+WFhobWMc8TC4OjKFfNhEZy7mOiqUAn5atQtug==", "dev": true, + "license": "MIT", "dependencies": { "@babel/runtime": "^7.0.0", "fbjs": "^3.0.0", @@ -10323,6 +13145,7 @@ "resolved": "https://registry.npmjs.org/remedial/-/remedial-1.0.8.tgz", "integrity": "sha512-/62tYiOe6DzS5BqVsNpH/nkGlX45C/Sp6V+NtiN6JQNS1Viay7cWkazmRkrQrdFj2eshDe96SIQNIoMxqhzBOg==", "dev": true, + "license": "(MIT OR Apache-2.0)", "engines": { "node": "*" } @@ -10331,19 +13154,22 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/remove-trailing-spaces": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/remove-trailing-spaces/-/remove-trailing-spaces-1.0.8.tgz", "integrity": "sha512-O3vsMYfWighyFbTd8hk8VaSj9UAGENxAtX+//ugIst2RMk5e03h6RoIS+0ylsFxY1gvmPuAY/PO4It+gPEeySA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -10352,13 +13178,15 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/resolve": { "version": "1.22.8", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, + "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -10376,6 +13204,7 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, + "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -10388,6 +13217,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10397,6 +13227,7 @@ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -10406,6 +13237,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -10418,6 +13250,7 @@ "version": "0.13.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "license": "MIT", "engines": { "node": ">= 4" } @@ -10427,22 +13260,26 @@ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -10458,6 +13295,7 @@ "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -10481,6 +13319,7 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } @@ -10490,6 +13329,7 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", "dev": true, + "license": "Apache-2.0", "dependencies": { "tslib": "^2.1.0" } @@ -10511,24 +13351,28 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/scuid": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/scuid/-/scuid-1.1.0.tgz", "integrity": "sha512-MuCAyrGZcTLfQoH2XoBlQ8C6bzwN88XT/0slOGz0pn8+gIP85BOAfYa44ZXQUTOwRwPU0QvgU+V+OSajl/59Xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -10537,6 +13381,7 @@ "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -10560,6 +13405,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -10567,18 +13413,21 @@ "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": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "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==" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" }, "node_modules/sentence-case": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", "dev": true, + "license": "MIT", "dependencies": { "no-case": "^3.0.4", "tslib": "^2.0.3", @@ -10589,6 +13438,7 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -10603,17 +13453,21 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/set-function-length": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", - "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", "dependencies": { - "define-data-property": "^1.1.1", - "get-intrinsic": "^1.2.1", + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.0" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -10623,17 +13477,20 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "license": "(MIT AND BSD-3-Clause)", "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -10647,6 +13504,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -10659,6 +13517,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10668,18 +13527,24 @@ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "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==", + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -10688,31 +13553,36 @@ "node_modules/sift": { "version": "16.0.1", "resolved": "https://registry.npmjs.org/sift/-/sift-16.0.1.tgz", - "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==" + "integrity": "sha512-Wv6BjQ5zbhW7VFefWusVP33T/EM0vYikCaQ2qR8yULbsilAT8/wQaXvuQ3ptGLpoKx+lihJE3y2UTgKDyyNHZQ==", + "license": "MIT" }, "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/signedsource": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/signedsource/-/signedsource-1.0.0.tgz", "integrity": "sha512-6+eerH9fEnNmi/hyM1DXcRK3pWdoMQtlkQ+ns0ntzunjKqp5i3sKCc80ym8Fib3iaYhdJUOPdhlJWj1tvge2Ww==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10722,6 +13592,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -10731,10 +13602,47 @@ "node": ">=8" } }, + "node_modules/slice-ansi/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/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, + "license": "MIT" + }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -10745,21 +13653,23 @@ "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", "dev": true, + "license": "MIT", "dependencies": { "dot-case": "^3.0.4", "tslib": "^2.0.3" } }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "license": "MIT", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -10768,6 +13678,7 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -10777,6 +13688,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -10786,6 +13698,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "license": "MIT", "dependencies": { "memory-pager": "^1.0.2" } @@ -10795,6 +13708,7 @@ "resolved": "https://registry.npmjs.org/sponge-case/-/sponge-case-1.0.1.tgz", "integrity": "sha512-dblb9Et4DAtiZ5YSUZHLl4XhH4uK80GhAZrVXdN4O2P4gQ40Wa5UIOPUHlA/nFd2PLblBZWUioLMMAVrgpoYcA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -10803,13 +13717,15 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/stack-utils": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, + "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -10822,6 +13738,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10830,6 +13747,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -10848,6 +13766,7 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "~5.2.0" } @@ -10856,13 +13775,15 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz", "integrity": "sha512-78lwMoCcn0nNu8LszbP1UA7g55OeE4v7rCeWnM5B453rnNr4aq+5it3FEYtZrSEiMvHZOZ9Jlqb0OD0M2VInqg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, + "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -10876,6 +13797,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -10890,6 +13812,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10902,6 +13825,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -10911,6 +13835,7 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -10920,6 +13845,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -10928,15 +13854,16 @@ } }, "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==", + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -10944,6 +13871,7 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -10956,6 +13884,7 @@ "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-2.0.2.tgz", "integrity": "sha512-kc6S2YS/2yXbtkSMunBtKdah4VFETZ8Oh6ONSmSd9bRxhqTrtARUCBUiWXH3xVPpvR7tz2CSnkuXVE42EcGnMw==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -10965,6 +13894,7 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, + "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -10974,23 +13904,39 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/title-case": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/title-case/-/title-case-3.0.3.tgz", "integrity": "sha512-e1zGYRvbffpcHIrnuqT0Dh+gEJtDaxDSoG4JAIpq4oDFyooziLBIiYQv0GBT4FUAnUop5uZ1hiIAj7oAF6sOCA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -11000,6 +13946,7 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, + "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, @@ -11011,13 +13958,15 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true + "dev": true, + "license": "BSD-3-Clause" }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -11027,6 +13976,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -11038,19 +13988,30 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", "engines": { "node": ">=0.6" } }, "node_modules/tr46": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", - "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "license": "MIT", "dependencies": { - "punycode": "^2.1.1" + "punycode": "^2.3.0" }, "engines": { - "node": ">=12" + "node": ">=14" + } + }, + "node_modules/tr46/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "license": "MIT", + "engines": { + "node": ">=6" } }, "node_modules/tree-kill": { @@ -11058,15 +14019,17 @@ "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, + "license": "MIT", "bin": { "tree-kill": "cli.js" } }, "node_modules/ts-jest": { - "version": "29.1.1", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", - "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "version": "29.1.5", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.5.tgz", + "integrity": "sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==", "dev": true, + "license": "MIT", "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", @@ -11081,10 +14044,11 @@ "ts-jest": "cli.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/transform": "^29.0.0", "@jest/types": "^29.0.0", "babel-jest": "^29.0.0", "jest": "^29.0.0", @@ -11094,6 +14058,9 @@ "@babel/core": { "optional": true }, + "@jest/transform": { + "optional": true + }, "@jest/types": { "optional": true }, @@ -11105,26 +14072,12 @@ } } }, - "node_modules/ts-jest/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/ts-jest/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -11132,23 +14085,19 @@ "node": ">=10" } }, - "node_modules/ts-jest/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/ts-log": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/ts-log/-/ts-log-2.2.5.tgz", "integrity": "sha512-PGcnJoTBnVGy6yYNFxWVNkdcAuAMstvutN9MgDJIV6L0oG8fB+ZNNy1T+wJzah8RPGor1mZuPQkVfXNDpy9eHA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -11192,6 +14141,7 @@ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-1.1.8.tgz", "integrity": "sha512-Q/m3vEwzYwLZKmV6/0VlFxcZzVV/xcgOt+Tx/VjaaRHyiBcFlV0541yrT09QjzzCxlDZ34OzKjrFAynlmtflEg==", "dev": true, + "license": "MIT", "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", @@ -11225,7 +14175,9 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, + "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -11238,6 +14190,7 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, + "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -11248,6 +14201,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-9.1.1.tgz", "integrity": "sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg==", "dev": true, + "license": "MIT", "dependencies": { "arg": "^4.1.0", "create-require": "^1.1.0", @@ -11274,6 +14228,7 @@ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, + "license": "MIT", "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", @@ -11286,6 +14241,7 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -11295,20 +14251,23 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", + "license": "0BSD" }, "node_modules/tsutils": { "version": "3.21.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^1.8.1" }, @@ -11323,13 +14282,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -11342,6 +14303,7 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -11351,6 +14313,7 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -11362,6 +14325,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -11371,10 +14335,11 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.2.tgz", + "integrity": "sha512-NcRtPEOsPFFWjobJEtfihkLCZCXZt/os3zf8nTxjVH3RvTSxjrCamJpbExGvYOF+tFHc3pA65qpdwPbzjohhew==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -11384,9 +14349,9 @@ } }, "node_modules/ua-parser-js": { - "version": "1.0.36", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", - "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz", + "integrity": "sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==", "dev": true, "funding": [ { @@ -11402,6 +14367,7 @@ "url": "https://github.com/sponsors/faisalman" } ], + "license": "MIT", "engines": { "node": "*" } @@ -11410,6 +14376,7 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "license": "MIT", "dependencies": { "random-bytes": "~1.0.0" }, @@ -11420,22 +14387,25 @@ "node_modules/uid2": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", - "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==" + "integrity": "sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA==", + "license": "MIT" }, "node_modules/unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/undici": { - "version": "5.26.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.26.4.tgz", - "integrity": "sha512-OG+QOf0fTLtazL9P9X7yqWxQ+Z0395Wk6DSkyTxtaq3wQEjIroVe7Y4asCX/vcCxYpNGMnwz8F0qbRYUoaQVMw==", + "version": "5.28.4", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", + "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", "dev": true, + "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -11448,6 +14418,7 @@ "resolved": "https://registry.npmjs.org/unixify/-/unixify-1.0.0.tgz", "integrity": "sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==", "dev": true, + "license": "MIT", "dependencies": { "normalize-path": "^2.1.1" }, @@ -11460,6 +14431,7 @@ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", "integrity": "sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w==", "dev": true, + "license": "MIT", "dependencies": { "remove-trailing-separator": "^1.0.1" }, @@ -11471,14 +14443,15 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -11494,9 +14467,10 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -11510,6 +14484,7 @@ "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -11519,6 +14494,7 @@ "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", "dev": true, + "license": "MIT", "dependencies": { "tslib": "^2.0.3" } @@ -11528,26 +14504,40 @@ "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, + "node_modules/uri-js/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/urlpattern-polyfill": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-8.0.2.tgz", "integrity": "sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -11560,6 +14550,7 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], + "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -11568,13 +14559,15 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/v8-to-istanbul": { - "version": "9.1.3", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz", - "integrity": "sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, + "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -11588,6 +14581,7 @@ "version": "1.0.12", "resolved": "https://registry.npmjs.org/value-or-promise/-/value-or-promise-1.0.12.tgz", "integrity": "sha512-Z6Uz+TYwEqE7ZN50gwn+1LCVo9ZVrpxRPOhOLnncYkY1ZzOYtrX8Fwf/rFktZ8R5mJms6EZf5TqNOMeZmnPq9Q==", + "license": "MIT", "engines": { "node": ">=12" } @@ -11596,6 +14590,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -11605,6 +14600,7 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } @@ -11614,36 +14610,40 @@ "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, + "license": "MIT", "dependencies": { "defaults": "^1.0.3" } }, "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/webcrypto-core": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.7.tgz", - "integrity": "sha512-7FjigXNsBfopEj+5DV2nhNpfic2vumtjjgPmeDKk45z+MJwXKKfhPB7118Pfzrmh4jqOMST6Ch37iPAHoImg5g==", + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.0.tgz", + "integrity": "sha512-kR1UQNH8MD42CYuLzvibfakG5Ew5seG85dMMoAM/1LqvckxaF6pUiidLuraIu4V+YCIFabYecUZAW0TuxAoaqw==", "dev": true, + "license": "MIT", "dependencies": { - "@peculiar/asn1-schema": "^2.3.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2" } }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", "engines": { "node": ">=12" } @@ -11652,20 +14652,22 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "license": "MIT", "engines": { "node": ">=12" } }, "node_modules/whatwg-url": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", - "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-13.0.0.tgz", + "integrity": "sha512-9WWbymnqj57+XEuqADHrCJ2eSXzn8WXIW/YSGaZtb2WKAInQ6CHfaUUcTyyver0p8BDg5StLQq8h1vtZuwmOig==", + "license": "MIT", "dependencies": { - "tr46": "^3.0.0", + "tr46": "^4.1.1", "webidl-conversions": "^7.0.0" }, "engines": { - "node": ">=12" + "node": ">=16" } }, "node_modules/which": { @@ -11673,6 +14675,7 @@ "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -11687,13 +14690,25 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, "node_modules/wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11703,17 +14718,55 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/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, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/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, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/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, + "license": "MIT" + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -11723,10 +14776,11 @@ } }, "node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=10.0.0" }, @@ -11747,6 +14801,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz", "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg==", + "license": "MIT", "engines": { "node": ">=4.0.0" } @@ -11756,6 +14811,7 @@ "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.4" } @@ -11765,21 +14821,23 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" }, "node_modules/yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", "dev": true, + "license": "ISC", "engines": { "node": ">= 6" } @@ -11788,13 +14846,15 @@ "version": "0.0.43", "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "dev": true + "dev": true, + "license": "Apache-2.0" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, + "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -11813,6 +14873,7 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, + "license": "ISC", "engines": { "node": ">=12" } @@ -11822,6 +14883,7 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -11831,6 +14893,7 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/backend/package.json b/backend/package.json index 42f316253..a05d883a9 100644 --- a/backend/package.json +++ b/backend/package.json @@ -31,6 +31,7 @@ "@graphql-codegen/introspection": "2.2.1", "@graphql-codegen/typescript": "^2.7.4", "@graphql-codegen/typescript-resolvers": "^2.7.4", + "@types/compression": "^1.7.5", "@types/cors": "^2.8.12", "@types/express-session": "^1.17.6", "@types/helmet": "0.0.46", @@ -54,6 +55,7 @@ "@graphql-tools/schema": "^10.0.0", "@graphql-tools/utils": "^10.0.7", "axios": "^1.5.1", + "compression": "^1.7.4", "connect-redis": "^7.1.1", "cors": "^2.8.5", "dotenv": "^8.2.0", diff --git a/backend/src/bootstrap/loaders/apollo.ts b/backend/src/bootstrap/loaders/apollo.ts index cc92f8c07..e69c6f3a8 100644 --- a/backend/src/bootstrap/loaders/apollo.ts +++ b/backend/src/bootstrap/loaders/apollo.ts @@ -4,7 +4,7 @@ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin import { ApolloServerPluginCacheControl } from '@apollo/server/plugin/cacheControl'; import { KeyValueCache, KeyValueCacheSetOptions } from '@apollo/utils.keyvaluecache'; import responseCachePlugin from '@apollo/server-plugin-response-cache'; -import { RedisClientType, createClient } from 'redis'; +import { RedisClientType } from 'redis'; class RedisCache implements KeyValueCache { client: RedisClientType; diff --git a/backend/src/bootstrap/loaders/express.ts b/backend/src/bootstrap/loaders/express.ts index e4946d7e1..54c492192 100644 --- a/backend/src/bootstrap/loaders/express.ts +++ b/backend/src/bootstrap/loaders/express.ts @@ -3,12 +3,15 @@ import cors from "cors"; import helmet from "helmet"; import type { ApolloServer } from "@apollo/server"; import { expressMiddleware } from "@apollo/server/express4"; +import compression from "compression"; import { RedisClientType } from "redis"; import passportLoader from "./passport"; import { config } from "../../config"; export default async (app: Application, server: ApolloServer, redis: RedisClientType) => { + app.use(compression()); + // Body parser only needed during POST on the graphQL path app.use(json()); diff --git a/backend/src/bootstrap/loaders/passport.ts b/backend/src/bootstrap/loaders/passport.ts index 35e8ecd8a..6d2296cad 100644 --- a/backend/src/bootstrap/loaders/passport.ts +++ b/backend/src/bootstrap/loaders/passport.ts @@ -20,61 +20,109 @@ const LOGOUT_ROUTE = "/logout"; // route need to be added as authorized origins/redirect uris in google cloud console const LOGIN_REDIRECT = config.backendPath + "/login/redirect"; - -const SUCCESS_REDIRECT = config.backendPath + config.graphqlPath; +const SUCCESS_REDIRECT = "/"; const FAILURE_REDIRECT = config.backendPath + "/fail"; -const SCOPE = ['profile', 'email'] +const SCOPE = ["profile", "email"]; -const CACHE_PREFIX = 'user-session:' +const CACHE_PREFIX = "user-session:"; export default async (app: Application, redis: RedisClientType) => { // init - app.use(session({ - secret: config.SESSION_SECRET, - name: 'sessionId', - resave: false, - saveUninitialized: false, - cookie: { - secure: !config.isDev, - httpOnly: true, - maxAge: 1000 * 60 * 60, // 1 hour - sameSite: 'lax', - }, - store: new RedisStore({ - client: redis, - prefix: CACHE_PREFIX, - }), - rolling: true, - })); + app.use( + session({ + secret: config.SESSION_SECRET, + name: "sessionId", + resave: false, + saveUninitialized: false, + cookie: { + secure: !config.isDev, + httpOnly: true, + maxAge: 1000 * 60 * 60, // 1 hour + sameSite: "lax", + }, + store: new RedisStore({ + client: redis, + prefix: CACHE_PREFIX, + }), + rolling: true, + }) + ); app.use(passport.initialize()); app.use(passport.session()); // routes app.get(LOGIN_ROUTE, (req, res, next) => { - // check if user is already logged in - if (req.isAuthenticated()) { - res.redirect(SUCCESS_REDIRECT); - } else { - next(); + const authenticated = req.isAuthenticated(); + + const { redirect_uri: redirectURI } = req.query; + + const parsedRedirectURI = + typeof redirectURI === "string" && redirectURI.startsWith("/") + ? redirectURI + : null; + + if (authenticated) { + res.redirect(parsedRedirectURI ?? SUCCESS_REDIRECT); + + return; + } + + const authenticator = passport.authenticate("google", { + scope: SCOPE, + accessType: "offline", + prompt: "consent", + state: parsedRedirectURI + ? Buffer.from( + JSON.stringify({ redirectURI: parsedRedirectURI }) + ).toString("base64") + : undefined, + }); + + authenticator(req, res, next); + }); + app.get( + LOGIN_REDIRECT_ROUTE, + passport.authenticate("google", { + failureRedirect: FAILURE_REDIRECT, + }), + (req, res) => { + const { state } = req.query; + + let parsedRedirectURI; + + try { + const { redirectURI } = JSON.parse( + Buffer.from(state as string, "base64").toString() + ); + + parsedRedirectURI = + typeof redirectURI === "string" && redirectURI.startsWith("/") + ? redirectURI + : undefined; + } catch { + // Do nothing + } + + res.redirect(parsedRedirectURI ?? SUCCESS_REDIRECT); } - }, passport.authenticate('google', { - scope: SCOPE, - accessType: 'offline', - prompt: 'consent', - })); - app.get(LOGIN_REDIRECT_ROUTE, passport.authenticate('google', { - failureRedirect: FAILURE_REDIRECT, - // failureMessage: "failed", - successRedirect: SUCCESS_REDIRECT, - })); - app.post(LOGOUT_ROUTE, (req, res) => { + ); + app.get(LOGOUT_ROUTE, (req, res) => { req.logout((err) => { if (err) { res.redirect(FAILURE_REDIRECT); - } else { - res.redirect(SUCCESS_REDIRECT); + + return; } + + const { redirect_uri: redirectURI } = req.query; + + const parsedRedirectURI = + typeof redirectURI === "string" && redirectURI.startsWith("/") + ? redirectURI + : null; + + res.redirect(parsedRedirectURI ?? SUCCESS_REDIRECT); }); }); @@ -85,36 +133,39 @@ export default async (app: Application, redis: RedisClientType) => { passport.deserializeUser((user: any, done) => { done(null, user); }); - passport.use(new GoogleStrategy.Strategy({ - clientID: config.GOOGLE_CLIENT_ID, - clientSecret: config.GOOGLE_CLIENT_SECRET, - callbackURL: LOGIN_REDIRECT, - scope: SCOPE, - state: true, - }, async (accessToken, refreshToken, profile, done) => { - const email = profile.emails?.[0].value; - - // null check for type safety - if (!email) { - return done(null, false, { message: 'No email found' }); - } + passport.use( + new GoogleStrategy.Strategy( + { + clientID: config.GOOGLE_CLIENT_ID, + clientSecret: config.GOOGLE_CLIENT_SECRET, + callbackURL: LOGIN_REDIRECT, + }, + async (accessToken, refreshToken, profile, done) => { + const email = profile.emails?.[0].value; - let user = await UserModel.findOne({ email }); - - if (!user) { - user = new UserModel({ - email, - google_id: profile.id, - username: profile.displayName, - first_name: profile.name?.givenName || '', - last_name: profile.name?.familyName || '', - // refresh_token: refreshToken, <-------------- currently not needed. - }); - } + // null check for type safety + if (!email) { + return done(null, false, { message: "No email found" }); + } - user.last_login = new Date(); - const doc = await user.save(); + let user = await UserModel.findOne({ email }); - done(null, doc); - })); -} + if (!user) { + user = new UserModel({ + email, + google_id: profile.id, + username: profile.displayName, + first_name: profile.name?.givenName || "", + last_name: profile.name?.familyName || "", + // refresh_token: refreshToken, <-------------- currently not needed. + }); + } + + user.last_login = new Date(); + const doc = await user.save(); + + done(null, doc); + } + ) + ); +}; diff --git a/backend/src/generated-types/graphql.ts b/backend/src/generated-types/graphql.ts index 41cc72cd9..e5f3a438a 100644 --- a/backend/src/generated-types/graphql.ts +++ b/backend/src/generated-types/graphql.ts @@ -17,73 +17,128 @@ export type Scalars = { JSONObject: any; }; +export type AcademicCareer = + /** Graduate */ + | 'GRAD' + /** UC Extension */ + | 'UCBX' + /** Undergraduate */ + | 'UGRD'; + export type CacheControlScope = | 'PRIVATE' | 'PUBLIC'; -export type CatalogClass = { - __typename?: 'CatalogClass'; - description?: Maybe; - enrollCount: Scalars['Int']; - enrollMax: Scalars['Int']; - lastUpdated: Scalars['ISODate']; - number: Scalars['String']; - title?: Maybe; - unitsMax: Scalars['Float']; - unitsMin: Scalars['Float']; -}; - -export type CatalogItem = { - __typename?: 'CatalogItem'; - classes: Array>; - description: Scalars['String']; - gradeAverage?: Maybe; - lastUpdated: Scalars['ISODate']; - number: Scalars['String']; - subject: Scalars['String']; - title: Scalars['String']; -}; - /** Data for a specific class in a specific semester. There may be more than one Class for a given Course in a given semester. */ export type Class = { __typename?: 'Class'; course: Course; description?: Maybe; - enrollCount: Scalars['Int']; - enrollMax: Scalars['Int']; + finalExam: ClassFinalExam; + gradingBasis: ClassGradingBasis; lastUpdated: Scalars['ISODate']; number: Scalars['String']; primarySection: Section; raw: Scalars['JSONObject']; - sections: Array>; + sections: Array
; semester: Semester; - session: Scalars['String']; - status: Scalars['String']; + session: Session; title?: Maybe; unitsMax: Scalars['Float']; unitsMin: Scalars['Float']; - waitlistCount: Scalars['Int']; - waitlistMax: Scalars['Int']; year: Scalars['Int']; }; +export type ClassFinalExam = + /** Alernate Method */ + | 'A' + /** Common Final */ + | 'C' + /** No */ + | 'N' + /** Yes */ + | 'Y'; + +export type ClassGradingBasis = + /** Multi-Term Course: Not Graded */ + | 'BMT' + /** Elective Satisfactory/Unsat */ + | 'ESU' + /** Graded */ + | 'GRD' + /** Instructor Option */ + | 'IOP' + /** Student Option */ + | 'OPT' + /** Pass/Not Pass */ + | 'PNP' + /** Satisfactory/Unsatisfactory */ + | 'SUS'; + +export type Component = + /** Clinic */ + | 'CLN' + /** Colloquium */ + | 'COL' + /** Discussion */ + | 'DIS' + /** Field Work */ + | 'FLD' + /** Directed Group Study */ + | 'GRP' + /** Independent Study */ + | 'IND' + /** Internship */ + | 'INT' + /** Laboratory */ + | 'LAB' + /** Lecture */ + | 'LEC' + /** Practicum */ + | 'PRA' + /** Reading */ + | 'REA' + /** Recitation */ + | 'REC' + /** Seminar */ + | 'SEM' + /** Session */ + | 'SES' + /** Self-paced */ + | 'SLF' + /** Studio */ + | 'STD' + /** Supplementary */ + | 'SUP' + /** Tutorial */ + | 'TUT' + /** Voluntary */ + | 'VOL' + /** Web-Based Discussion */ + | 'WBD' + /** Web-Based Lecture */ + | 'WBL' + /** Workshop */ + | 'WOR'; + /** Info shared between Classes within and across semesters. */ export type Course = { __typename?: 'Course'; - classes: Array>; - crossListing?: Maybe>>; + academicCareer: AcademicCareer; + classes: Array; + crossListing: Array; description: Scalars['String']; + finalExam?: Maybe; fromDate: Scalars['String']; gradeAverage?: Maybe; - gradingBasis: Scalars['String']; + gradingBasis: CourseGradingBasis; lastUpdated: Scalars['ISODate']; - level: Scalars['String']; number: Scalars['String']; - prereqs?: Maybe; raw: Scalars['JSONObject']; - sections: Array>; + requiredCourses: Array; + requirements?: Maybe; + sections: Array
; subject: Scalars['String']; - subjectName: Scalars['String']; title: Scalars['String']; toDate: Scalars['String']; }; @@ -101,6 +156,25 @@ export type CourseSectionsArgs = { term?: InputMaybe; }; +export type CourseFinalExam = + /** Alternative method of final assessment */ + | 'A' + /** Common Final Exam */ + | 'C' + /** To be decided by the instructor when the class is offered */ + | 'D' + /** No final exam */ + | 'N' + /** Written final exam conducted during the scheduled final exam period */ + | 'Y'; + +export type CourseGradingBasis = + | 'completedNotation' + | 'graded' + | 'letter' + | 'passFail' + | 'satisfactory'; + export type CourseListItem = { __typename?: 'CourseListItem'; number: Scalars['String']; @@ -134,6 +208,15 @@ export type EnrollmentDay = { waitlistMax: Scalars['Int']; }; +export type Exam = { + __typename?: 'Exam'; + date: Scalars['String']; + endTime: Scalars['String']; + final: Scalars['Boolean']; + location: Scalars['String']; + startTime: Scalars['String']; +}; + export type Grade = { __typename?: 'Grade'; average?: Maybe; @@ -148,8 +231,19 @@ export type GradeDistributionItem = { export type Instructor = { __typename?: 'Instructor'; - familyName: Scalars['String']; - givenName: Scalars['String']; + familyName?: Maybe; + givenName?: Maybe; +}; + +export type Meeting = { + __typename?: 'Meeting'; + days?: Maybe>; + endDate: Scalars['String']; + endTime: Scalars['String']; + instructors: Array; + location?: Maybe; + startDate: Scalars['String']; + startTime: Scalars['String']; }; export type Mutation = { @@ -202,7 +296,7 @@ export type Query = { * * Used primarily in the catalog page. */ - catalog?: Maybe>>; + catalog?: Maybe>; class?: Maybe; course?: Maybe; /** @@ -210,7 +304,7 @@ export type Query = { * * Useful for searching for courses. */ - courseList?: Maybe>>; + courseList?: Maybe>; grade?: Maybe; /** @deprecated test */ ping: Scalars['String']; @@ -270,6 +364,13 @@ export type QuerySectionArgs = { term: TermInput; }; +export type Reservation = { + __typename?: 'Reservation'; + enrollCount: Scalars['Int']; + enrollMax: Scalars['Int']; + group: Scalars['String']; +}; + export type Schedule = { __typename?: 'Schedule'; /** The ObjectID associated with the schedule record */ @@ -299,28 +400,27 @@ export type ScheduleInput = { term: TermInput; }; -/** Sections are each associated with one Class. */ +/** Sections are each associated with one Class. */ export type Section = { __typename?: 'Section'; ccn: Scalars['Int']; class: Class; + component: Component; course: Course; - dateEnd?: Maybe; - dateStart?: Maybe; - days?: Maybe>; + endDate: Scalars['String']; enrollCount: Scalars['Int']; enrollMax: Scalars['Int']; - enrollmentHistory?: Maybe>>; - instructors?: Maybe>>; - kind: Scalars['String']; + enrollmentHistory?: Maybe>; + exams: Array; lastUpdated: Scalars['ISODate']; - location?: Maybe; - notes?: Maybe; + meetings: Array; number: Scalars['String']; + online: Scalars['Boolean']; + open: Scalars['Boolean']; primary: Scalars['Boolean']; raw: Scalars['JSONObject']; - timeEnd?: Maybe; - timeStart?: Maybe; + reservations?: Maybe>; + startDate: Scalars['String']; waitlistCount: Scalars['Int']; waitlistMax: Scalars['Int']; }; @@ -344,7 +444,26 @@ export type SelectedCourseInput = { export type Semester = | 'Fall' | 'Spring' - | 'Summer'; + | 'Summer' + | 'Winter'; + +export type Session = + /** Session A */ + | 'A' + /** Session B */ + | 'B' + /** Session C */ + | 'C' + /** Session D */ + | 'D' + /** Session E */ + | 'E' + /** Session F */ + | 'F' + /** Regular Academic Session */ + | 'R' + /** 12-Week Summer Session */ + | 'S'; /** The combination of year and season that corresponds to a specific term. Both year and season/semester are required. */ export type TermInput = { @@ -457,16 +576,21 @@ export type DirectiveResolverFn; CacheControlScope: CacheControlScope; - CatalogClass: ResolverTypeWrapper; - CatalogItem: ResolverTypeWrapper; Class: ResolverTypeWrapper; + ClassFinalExam: ClassFinalExam; + ClassGradingBasis: ClassGradingBasis; + Component: Component; Course: ResolverTypeWrapper; + CourseFinalExam: CourseFinalExam; + CourseGradingBasis: CourseGradingBasis; CourseListItem: ResolverTypeWrapper; CustomEvent: ResolverTypeWrapper; CustomEventInput: CustomEventInput; EnrollmentDay: ResolverTypeWrapper; + Exam: ResolverTypeWrapper; Float: ResolverTypeWrapper; Grade: ResolverTypeWrapper; GradeDistributionItem: ResolverTypeWrapper; @@ -476,14 +600,17 @@ export type ResolversTypes = { Int: ResolverTypeWrapper; JSON: ResolverTypeWrapper; JSONObject: ResolverTypeWrapper; + Meeting: ResolverTypeWrapper; Mutation: ResolverTypeWrapper<{}>; Query: ResolverTypeWrapper<{}>; + Reservation: ResolverTypeWrapper; Schedule: ResolverTypeWrapper; ScheduleInput: ScheduleInput; Section: ResolverTypeWrapper
; SelectedCourse: ResolverTypeWrapper; SelectedCourseInput: SelectedCourseInput; Semester: Semester; + Session: Session; String: ResolverTypeWrapper; TermInput: TermInput; TermOutput: ResolverTypeWrapper; @@ -494,14 +621,13 @@ export type ResolversTypes = { /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = { Boolean: Scalars['Boolean']; - CatalogClass: CatalogClass; - CatalogItem: CatalogItem; Class: Class; Course: Course; CourseListItem: CourseListItem; CustomEvent: CustomEvent; CustomEventInput: CustomEventInput; EnrollmentDay: EnrollmentDay; + Exam: Exam; Float: Scalars['Float']; Grade: Grade; GradeDistributionItem: GradeDistributionItem; @@ -511,8 +637,10 @@ export type ResolversParentTypes = { Int: Scalars['Int']; JSON: Scalars['JSON']; JSONObject: Scalars['JSONObject']; + Meeting: Meeting; Mutation: {}; Query: {}; + Reservation: Reservation; Schedule: Schedule; ScheduleInput: ScheduleInput; Section: Section; @@ -537,66 +665,41 @@ export type CacheControlDirectiveArgs = { export type CacheControlDirectiveResolver = DirectiveResolverFn; -export type CatalogClassResolvers = { - description?: Resolver, ParentType, ContextType>; - enrollCount?: Resolver; - enrollMax?: Resolver; - lastUpdated?: Resolver; - number?: Resolver; - title?: Resolver, ParentType, ContextType>; - unitsMax?: Resolver; - unitsMin?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - -export type CatalogItemResolvers = { - classes?: Resolver>, ParentType, ContextType>; - description?: Resolver; - gradeAverage?: Resolver, ParentType, ContextType>; - lastUpdated?: Resolver; - number?: Resolver; - subject?: Resolver; - title?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}; - export type ClassResolvers = { course?: Resolver; description?: Resolver, ParentType, ContextType>; - enrollCount?: Resolver; - enrollMax?: Resolver; + finalExam?: Resolver; + gradingBasis?: Resolver; lastUpdated?: Resolver; number?: Resolver; primarySection?: Resolver; raw?: Resolver; - sections?: Resolver>, ParentType, ContextType>; + sections?: Resolver, ParentType, ContextType>; semester?: Resolver; - session?: Resolver; - status?: Resolver; + session?: Resolver; title?: Resolver, ParentType, ContextType>; unitsMax?: Resolver; unitsMin?: Resolver; - waitlistCount?: Resolver; - waitlistMax?: Resolver; year?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }; export type CourseResolvers = { - classes?: Resolver>, ParentType, ContextType, Partial>; - crossListing?: Resolver>>, ParentType, ContextType>; + academicCareer?: Resolver; + classes?: Resolver, ParentType, ContextType, Partial>; + crossListing?: Resolver, ParentType, ContextType>; description?: Resolver; + finalExam?: Resolver, ParentType, ContextType>; fromDate?: Resolver; gradeAverage?: Resolver, ParentType, ContextType>; - gradingBasis?: Resolver; + gradingBasis?: Resolver; lastUpdated?: Resolver; - level?: Resolver; number?: Resolver; - prereqs?: Resolver, ParentType, ContextType>; raw?: Resolver; - sections?: Resolver>, ParentType, ContextType, Partial>; + requiredCourses?: Resolver, ParentType, ContextType>; + requirements?: Resolver, ParentType, ContextType>; + sections?: Resolver, ParentType, ContextType, Partial>; subject?: Resolver; - subjectName?: Resolver; title?: Resolver; toDate?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -626,6 +729,15 @@ export type EnrollmentDayResolvers; }; +export type ExamResolvers = { + date?: Resolver; + endTime?: Resolver; + final?: Resolver; + location?: Resolver; + startTime?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type GradeResolvers = { average?: Resolver, ParentType, ContextType>; distribution?: Resolver>>, ParentType, ContextType>; @@ -643,8 +755,8 @@ export interface IsoDateScalarConfig extends GraphQLScalarTypeConfig = { - familyName?: Resolver; - givenName?: Resolver; + familyName?: Resolver, ParentType, ContextType>; + givenName?: Resolver, ParentType, ContextType>; __isTypeOf?: IsTypeOfResolverFn; }; @@ -656,6 +768,17 @@ export interface JsonObjectScalarConfig extends GraphQLScalarTypeConfig = { + days?: Resolver>, ParentType, ContextType>; + endDate?: Resolver; + endTime?: Resolver; + instructors?: Resolver, ParentType, ContextType>; + location?: Resolver, ParentType, ContextType>; + startDate?: Resolver; + startTime?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type MutationResolvers = { createNewSchedule?: Resolver, ParentType, ContextType, RequireFields>; deleteUser?: Resolver, ParentType, ContextType>; @@ -666,10 +789,10 @@ export type MutationResolvers = { - catalog?: Resolver>>, ParentType, ContextType, RequireFields>; + catalog?: Resolver>, ParentType, ContextType, RequireFields>; class?: Resolver, ParentType, ContextType, RequireFields>; course?: Resolver, ParentType, ContextType, RequireFields>; - courseList?: Resolver>>, ParentType, ContextType>; + courseList?: Resolver>, ParentType, ContextType>; grade?: Resolver, ParentType, ContextType, RequireFields>; ping?: Resolver; scheduleByID?: Resolver, ParentType, ContextType, RequireFields>; @@ -678,6 +801,13 @@ export type QueryResolvers, ParentType, ContextType>; }; +export type ReservationResolvers = { + enrollCount?: Resolver; + enrollMax?: Resolver; + group?: Resolver; + __isTypeOf?: IsTypeOfResolverFn; +}; + export type ScheduleResolvers = { _id?: Resolver, ParentType, ContextType>; courses?: Resolver>, ParentType, ContextType>; @@ -694,23 +824,22 @@ export type ScheduleResolvers = { ccn?: Resolver; class?: Resolver; + component?: Resolver; course?: Resolver; - dateEnd?: Resolver, ParentType, ContextType>; - dateStart?: Resolver, ParentType, ContextType>; - days?: Resolver>, ParentType, ContextType>; + endDate?: Resolver; enrollCount?: Resolver; enrollMax?: Resolver; - enrollmentHistory?: Resolver>>, ParentType, ContextType>; - instructors?: Resolver>>, ParentType, ContextType>; - kind?: Resolver; + enrollmentHistory?: Resolver>, ParentType, ContextType>; + exams?: Resolver, ParentType, ContextType>; lastUpdated?: Resolver; - location?: Resolver, ParentType, ContextType>; - notes?: Resolver, ParentType, ContextType>; + meetings?: Resolver, ParentType, ContextType>; number?: Resolver; + online?: Resolver; + open?: Resolver; primary?: Resolver; raw?: Resolver; - timeEnd?: Resolver, ParentType, ContextType>; - timeStart?: Resolver, ParentType, ContextType>; + reservations?: Resolver>, ParentType, ContextType>; + startDate?: Resolver; waitlistCount?: Resolver; waitlistMax?: Resolver; __isTypeOf?: IsTypeOfResolverFn; @@ -747,21 +876,22 @@ export type UserResolvers = { - CatalogClass?: CatalogClassResolvers; - CatalogItem?: CatalogItemResolvers; Class?: ClassResolvers; Course?: CourseResolvers; CourseListItem?: CourseListItemResolvers; CustomEvent?: CustomEventResolvers; EnrollmentDay?: EnrollmentDayResolvers; + Exam?: ExamResolvers; Grade?: GradeResolvers; GradeDistributionItem?: GradeDistributionItemResolvers; ISODate?: GraphQLScalarType; Instructor?: InstructorResolvers; JSON?: GraphQLScalarType; JSONObject?: GraphQLScalarType; + Meeting?: MeetingResolvers; Mutation?: MutationResolvers; Query?: QueryResolvers; + Reservation?: ReservationResolvers; Schedule?: ScheduleResolvers; Section?: SectionResolvers; SelectedCourse?: SelectedCourseResolvers; diff --git a/backend/src/models/semester.ts b/backend/src/models/semester.ts index a3864309f..a2819349e 100644 --- a/backend/src/models/semester.ts +++ b/backend/src/models/semester.ts @@ -2,7 +2,7 @@ import { schemaOptions } from './common'; import mongoose, { Schema, InferSchemaType } from 'mongoose'; const semesterSchemaObject = { - term: { type: String, enum: ['Fall', 'Spring', 'Summer'], required: true }, + term: { type: String, enum: ['Fall', 'Spring', 'Summer', 'Winter'], required: true }, year: { type: Number, required: true }, active: { type: Boolean, required: true }, // TODO: add other semester-specific info diff --git a/backend/src/modules/catalog/controller.ts b/backend/src/modules/catalog/controller.ts index e9247a9d6..c2e944e6d 100644 --- a/backend/src/modules/catalog/controller.ts +++ b/backend/src/modules/catalog/controller.ts @@ -1,5 +1,5 @@ -import { CatalogItem, TermInput } from "../../generated-types/graphql"; -import { ClassModel, ClassType } from "../../models/class"; +import { Course, TermInput } from "../../generated-types/graphql"; +import { ClassModel } from "../../models/class"; import { getTermStartMonth, termToString } from "../../utils/term"; import { GradeModel, GradeType } from "../../models/grade"; import { getAverage } from "../grade/controller"; @@ -10,260 +10,497 @@ import { getCourseKey, getCsCourseId } from "../../utils/course"; import { isNil } from "lodash"; import { GraphQLResolveInfo } from "graphql"; import { getChildren } from "../../utils/graphql"; +import { performance } from "perf_hooks"; function matchCsCourseId(id: any) { - return { - $elemMatch: { - type: "cs-course-id", - id, - }, - } + return { + $elemMatch: { + type: "cs-course-id", + id, + }, + }; } -export async function getCatalog(term: TermInput, info: GraphQLResolveInfo): Promise { - const classes = await ClassModel - .find({ - "session.term.name": termToString(term), - "aggregateEnrollmentStatus.maxEnroll": { $gt: 0 }, - }) - .lean() +export async function getCatalog( + term: TermInput, + info: GraphQLResolveInfo +): Promise { + const start = performance.now(); - if (classes.length === 0) { - return null - } + const classes = await ClassModel.find({ + "session.term.name": termToString(term), + // "aggregateEnrollmentStatus.maxEnroll": { $gt: 0 }, + anyPrintInScheduleOfClasses: true, + }).lean(); + + const clTime = performance.now(); + console.log("Classes query time: ", clTime - start); - const csCourseIds = new Set(classes.map(c => getCsCourseId(c.course as CourseType))) - const courses = await CourseModel - .find( - { - identifiers: matchCsCourseId({ $in: Array.from(csCourseIds) }), - /* + if (classes.length === 0) { + return null; + } + + const csCourseIds = new Set( + classes.map((c) => getCsCourseId(c.course as CourseType)) + ); + + const courses = await CourseModel.find({ + identifiers: matchCsCourseId({ $in: Array.from(csCourseIds) }), + /* The SIS toDate is unreliable so we can only filter by fromDate and then sort to find the most recent course. */ - fromDate: { $lte: getTermStartMonth(term) }, - }, - { - _updatedAt: 1, - _updated: 1, - identifiers: 1, - title: 1, - description: 1, - classSubjectArea: 1, - catalogNumber: 1 - } - ) - .sort({ - "classSubjectArea.code": 1, - "catalogNumber.formatted": 1, - fromDate: -1 - }) - .lean() - - /* Map grades to course keys for easy lookup */ - const gradesMap: { [key: string]: GradeType[] } = {} - courses.forEach(c => gradesMap[getCourseKey(c)] = []) - - const children = getChildren(info) - - if (children.includes("gradeAverage")) { - const grades = await GradeModel.find( - { - /* + // fromDate: { $lte: getTermStartMonth(term) }, + }) + .sort({ + "classSubjectArea.code": 1, + "catalogNumber.formatted": 1, + fromDate: -1, + }) + .lean(); + + const coTime = performance.now(); + console.log("Courses query time: ", coTime - clTime); + + /* Map grades to course keys for easy lookup */ + const gradesMap: { [key: string]: GradeType[] } = {}; + courses.forEach((c) => (gradesMap[getCourseKey(c)] = [])); + + const children = getChildren(info); + + if (children.includes("gradeAverage")) { + const grades = await GradeModel.find( + { + /* No filters because an appropriately large filter is actually significantly slower than no filter. */ - }, - { - CourseSubjectShortNm: 1, - CourseNumber: 1, - GradeNm: 1, - EnrollmentCnt: 1 - } - ).lean() - - for (const g of grades) { - const key = `${g.CourseSubjectShortNm as string} ${g.CourseNumber as string}` - if (key in gradesMap) { - gradesMap[key].push(g) - } - } + }, + { + CourseSubjectShortNm: 1, + CourseNumber: 1, + GradeNm: 1, + EnrollmentCnt: 1, + } + ).lean(); + + for (const g of grades) { + const key = `${g.CourseSubjectShortNm as string} ${ + g.CourseNumber as string + }`; + if (key in gradesMap) { + gradesMap[key].push(g); + } } + } + + const grTime = performance.now(); + console.log("Grades query time: ", grTime - coTime); + + const sections = await SectionModel.find({ + "class.course.identifiers": matchCsCourseId({ + $in: Array.from(csCourseIds), + }), + "class.session.term.name": termToString(term), + "association.primary": true, + }).lean(); + + const seTime = performance.now(); + console.log("Sections query time: ", seTime - grTime); - const catalog: any = {} - for (const c of courses) { - const key = getCourseKey(c) - const id = getCsCourseId(c) + const catalog: any = {}; - // skip duplicates - if (id in catalog) - continue + for (const c of courses) { + const key = getCourseKey(c); + const id = getCsCourseId(c); - catalog[id] = { - ...formatCourse(c, term), - classes: [], - gradeAverage: await getAverage(gradesMap[key]), - } + // skip duplicates + if (id in catalog) continue; + + catalog[id] = { + ...formatCourse(c, term), + classes: [], + gradeAverage: getAverage(gradesMap[key]), + }; + } + + for (const c of classes) { + const id = getCsCourseId(c.course as CourseType); + + if (!(id in catalog)) { + // throw new Error(`Class ${c.course?.subjectArea?.code} ${c.course?.catalogNumber?.formatted}` + // + ` has a course id ${id} that doesn't exist for the ${term.semester} ${term.year} term.`) + + // TODO(production): log + continue; } - for (const c of classes) { - const id = getCsCourseId(c.course as CourseType) + catalog[id].classes.push(formatClass(c)); + } + + for (const s of sections) { + if (!s.class) continue; + + const id = getCsCourseId(s.class.course as CourseType); + + if (!(id in catalog)) { + // throw new Error(`Section ${s.class.course?.subjectArea?.code} ${s.class.course?.catalogNumber?.formatted}` + // + ` has a course id ${id} that doesn't exist for the ${term.semester} ${term.year} term.`) + + // TODO(production): log + continue; + } + + const index = catalog[id].classes.findIndex( + (c: any) => c.number === s.class?.number + ); + + if (index === -1) continue; + + const primarySection = formatSection(s); + + if (!primarySection.ccn) continue; - if (!(id in catalog)) { - // throw new Error(`Class ${c.course?.subjectArea?.code} ${c.course?.catalogNumber?.formatted}` - // + ` has a course id ${id} that doesn't exist for the ${term.semester} ${term.year} term.`) + catalog[id].classes[index].primarySection = primarySection; + } - // TODO(production): log - continue; - } + for (const id in catalog) { + catalog[id].classes = catalog[id].classes.filter( + (c: any) => c.primarySection?.ccn + ); - catalog[id].classes.push(formatClass(c)) + if (catalog[id].classes.length === 0) { + delete catalog[id]; } + } - return Object.values(catalog) + const end = performance.now(); + console.log("Total time: ", end - start); + + return Object.values(catalog); } -export function getClass(subject: string, courseNumber: string, term: TermInput, classNumber: string) { - return ClassModel - .findOne({ - "course.subjectArea.code": subject, - "course.catalogNumber.formatted": courseNumber, - "session.term.name": termToString(term), - "number": classNumber, - }) - .lean() - .then(formatClass) +export function getClass( + subject: string, + courseNumber: string, + term: TermInput, + classNumber: string +) { + return ClassModel.findOne({ + "course.subjectArea.code": subject, + "course.catalogNumber.formatted": courseNumber, + "session.term.name": termToString(term), + number: classNumber, + }) + .lean() + .then(formatClass); } export function getClassById(id: string, term: TermInput, classNumber: string) { - return ClassModel - .findOne({ - "course.identifiers": matchCsCourseId(id), - "session.term.name": termToString(term), - "number": classNumber, - }) - .lean() - .then(formatClass) + return ClassModel.findOne({ + "course.identifiers": matchCsCourseId(id), + "session.term.name": termToString(term), + number: classNumber, + }) + .lean() + .then(formatClass); } -export function getPrimarySection(id: string, term: TermInput, classNumber: string) { - return SectionModel - .findOne({ - "class.course.identifiers": matchCsCourseId(id), - "class.session.term.name": termToString(term), - "class.number": classNumber, - "association.primary": true - }) - .lean() - .then(formatSection) +export function getPrimarySection( + id: string, + term: TermInput, + classNumber: string +) { + return SectionModel.findOne({ + "class.course.identifiers": matchCsCourseId(id), + "class.session.term.name": termToString(term), + "class.number": classNumber, + "association.primary": true, + }) + .lean() + .then(formatSection); } -export function getClassSections(id: string, term: TermInput, classNumber: string) { - return SectionModel - .find({ - "class.course.identifiers": matchCsCourseId(id), - "class.session.term.name": termToString(term), - "class.number": classNumber - }) - .lean() - .then(s => s.map(formatSection)) +export function getClassSections( + id: string, + term: TermInput, + classNumber: string +) { + // for associated sections with a lecture. Lecture assumed to be of form 00x + return SectionModel.find({ + "class.course.identifiers": matchCsCourseId(id), + "class.session.term.name": termToString(term), + $or: [ + { + "class.number": { + $regex: new RegExp("^" + classNumber[classNumber.length - 1]), + }, + }, + { "class.number": "999" }, + ], + }) + .lean() + .then((s) => s.map(formatSection)); } -export function getCourse(subject: string, courseNumber: string, term?: TermInput | null) { - const filter: any = { - "classSubjectArea.code": subject, - "catalogNumber.formatted": courseNumber +async function getCourseFromFilter( + filter: any, + term?: TermInput | null, + info?: GraphQLResolveInfo | null +) { + const course = await CourseModel.findOne(filter) + .sort({ fromDate: -1 }) + .lean() + .then((c) => formatCourse(c, term)); + + if (info && getChildren(info).includes("gradeAverage")) { + const grades: GradeType[] = []; + const gradesQuery = await GradeModel.find( + { + CourseSubjectShortNm: + course.raw.classSubjectArea?.description ?? + course.raw.subjectArea?.description, + CourseNumber: course.raw.catalogNumber?.formatted, + }, + { GradeNm: 1, EnrollmentCnt: 1 } + ); + for (const grade of gradesQuery) { + grades.push(grade); } + course.gradeAverage = await getAverage(grades); + } - if (!isNil(term)) { - filter.fromDate = { $lte: getTermStartMonth(term) } - } + return course; +} - return CourseModel - .findOne(filter) - .sort({ fromDate: -1 }) - .lean() - .then(c => formatCourse(c, term)) +export function getCourse( + subject: string, + courseNumber: string, + term?: TermInput | null, + info?: GraphQLResolveInfo +) { + const filter: any = { + "classSubjectArea.code": subject, + "catalogNumber.formatted": courseNumber, + }; + + if (!isNil(term)) { + filter.fromDate = { $lte: getTermStartMonth(term) }; + } + + return getCourseFromFilter(filter, term, info); } export function getCourseById(id: string, term?: TermInput | null) { - const filter: any = { - identifiers: matchCsCourseId(id) - } + const filter: any = { + identifiers: matchCsCourseId(id), + }; - if (!isNil(term)) { - filter.fromDate = { $lte: getTermStartMonth(term) } - } + if (!isNil(term)) { + filter.fromDate = { $lte: getTermStartMonth(term) }; + } - return CourseModel - .findOne(filter) - .sort({ fromDate: -1 }) - .lean() - .then(c => formatCourse(c, term)) + return getCourseFromFilter(filter, term); } export function getCourseClasses(id: string, term?: TermInput | null) { + const filter: any = { + "course.identifiers": matchCsCourseId(id), + }; + + if (!isNil(term)) { + filter["session.term.name"] = termToString(term); + } + + return ClassModel.find(filter) + .lean() + .then((c) => c.map(formatClass)); +} + +export function getCourseSections(id: string, term?: TermInput | null) { + const filter: any = { + "class.course.identifiers": matchCsCourseId(id), + }; + + if (!isNil(term)) { + filter["class.session.term.name"] = termToString(term); + } + return SectionModel.find(filter) + .lean() + .then((s) => s.map(formatSection)); +} + +export function getRequiredCourses(csCourseIds: string[]) { + return csCourseIds.map((csCourseId) => + CourseModel.findOne({ + identifiers: matchCsCourseId(csCourseId), + /* + The SIS toDate is unreliable so we can only + filter by fromDate and then sort to find the + most recent course. + */ + // fromDate: { $lte: getTermStartMonth(term) }, + }) + .lean() + .then(formatCourse) + ); +} + +export function getCrossListing( + displayNames: string[], + term?: TermInput | null +) { + return displayNames.map((name) => { const filter: any = { - "course.identifiers": matchCsCourseId(id) - } + displayName: name, + }; if (!isNil(term)) { - filter["session.term.name"] = termToString(term) + filter.fromDate = { $lte: getTermStartMonth(term) }; } - return ClassModel - .find(filter) - .lean() - .then(c => c.map(formatClass)) + return CourseModel.findOne(filter) + .sort({ fromDate: -1 }) + .lean() + .then((c) => formatCourse(c, term)); + }); } -export function getCrossListings(displayNames: string[], term?: TermInput | null) { - return displayNames.map(name => { - const filter: any = { - displayName: name - } - - if (!isNil(term)) { - filter.fromDate = { $lte: getTermStartMonth(term) } - } - - return CourseModel - .findOne(filter) - .sort({ fromDate: -1 }) - .lean() - .then(c => formatCourse(c, term)) - }) +export function getSection( + subject: string, + courseNumber: string, + term: TermInput, + classNumber: string, + sectionNumber: string +) { + return SectionModel.findOne({ + "class.course.subjectArea.code": subject, + "class.course.catalogNumber.formatted": courseNumber, + "class.session.term.name": termToString(term), + "class.number": classNumber, + number: sectionNumber, + }) + .lean() + .then(formatSection); } -export function getSection(subject: string, courseNumber: string, term: TermInput, classNumber: string, sectionNumber: string) { - return SectionModel - .findOne({ - "class.course.subjectArea.code": subject, - "class.course.catalogNumber.formatted": courseNumber, - "class.session.term.name": termToString(term), - "class.number": classNumber, - "number": sectionNumber - }) - .lean() - .then(formatSection) +export function getSectionById( + id: string, + term: TermInput, + classNumber: string, + sectionNumber: string +) { + return SectionModel.findOne({ + "class.course.identifiers": matchCsCourseId(id), + "class.session.term.name": termToString(term), + "class.number": classNumber, + number: sectionNumber, + }) + .lean() + .then(formatSection); } -export function getSectionById(id: string, term: TermInput, classNumber: string, sectionNumber: string) { - return SectionModel - .findOne({ - "class.course.identifiers": matchCsCourseId(id), - "class.session.term.name": termToString(term), - "class.number": classNumber, - "number": sectionNumber - }) - .lean() - .then(formatSection) -} +export async function getCourseList( + info: GraphQLResolveInfo +): Promise { + const start = performance.now(); + + let courses = await CourseModel.aggregate([ + { + $match: { + printInCatalog: true, + "status.code": "ACTIVE", + "catalogNumber.prefix": "", + }, + }, + { + $sort: { + "classSubjectArea.code": 1, + "catalogNumber.formatted": 1, + fromDate: -1, + }, + }, + { + $group: { + _id: "$displayName", + document: { $first: "$$ROOT" }, + }, + }, + { + $replaceRoot: { newRoot: "$document" }, + }, + ]); + + const csDisplayNames = courses.map((c) => c.displayName); + + const coTime = performance.now(); + console.log("Courses query time: ", coTime - start); + + const classes = await ClassModel.find({ + "course.displayName": { + $in: csDisplayNames, + }, + anyPrintInScheduleOfClasses: true, + }).lean(); + + courses = courses.reduce((acc, c) => { + const cl = classes + .filter( + (cl) => getCsCourseId(cl.course as CourseType) === getCsCourseId(c) + ) + .map(formatClass); + + if (cl.length === 0) return acc; + + acc.push({ + ...formatCourse(c), + classes: cl, + }); + + return acc; + }, []); + + const clTime = performance.now(); + console.log("Classes query time: ", clTime - coTime); + + /* Map grades to course keys for easy lookup */ + const gradesMap: { [key: string]: GradeType[] } = {}; + courses.forEach((c) => (gradesMap[getCourseKey(c)] = [])); + + const children = getChildren(info); + + if (children.includes("gradeAverage")) { + const grades = await GradeModel.find( + { + /* + No filters because an appropriately large filter + is actually significantly slower than no filter. + */ + }, + { + CourseSubjectShortNm: 1, + CourseNumber: 1, + GradeNm: 1, + EnrollmentCnt: 1, + } + ).lean(); + + for (const g of grades) { + const key = `${g.CourseSubjectShortNm as string} ${ + g.CourseNumber as string + }`; + if (key in gradesMap) { + gradesMap[key].push(g); + } + } + } + + const grTime = performance.now(); + console.log("Grades query time: ", grTime - clTime); -export function getCourseList(): any { - return CourseModel.aggregate() - .group({ _id: { subject: "$classSubjectArea.code", number: "$catalogNumber.formatted" } }) - .sort({ "_id.subject": 1, "_id.number": 1 }) - .project({ _id: 0, subject: "$_id.subject", number: "$_id.number" }) + return courses.map((c) => ({ + ...c, + gradeAverage: getAverage(gradesMap[getCourseKey(c)]), + })); } diff --git a/backend/src/modules/catalog/formatter.ts b/backend/src/modules/catalog/formatter.ts index 486e41b3f..94da607d3 100644 --- a/backend/src/modules/catalog/formatter.ts +++ b/backend/src/modules/catalog/formatter.ts @@ -6,134 +6,181 @@ import { getCsCourseId } from "../../utils/course"; import { stringToTerm } from "../../utils/term"; export function formatMetadata(data: any) { - return { - lastUpdated: (!data._updated) ? data._updatedAt as Date : data._updated as Date, - raw: data, - } + return { + lastUpdated: !data._updated + ? (data._updatedAt as Date) + : (data._updated as Date), + raw: data, + }; } export function formatClass(cls: ClassType | null): any { - if (cls == null) return null - - const term = stringToTerm(cls.session?.term?.name as string) - const id = getCsCourseId(cls.course as CourseType) - - return { - course: { - id, - term - }, - primarySection: { - id, - term, - classNumber: cls.number, - }, - sections: { - id, - term, - classNumber: cls.number, - }, - - description: cls.classDescription, - enrollCount: cls.aggregateEnrollmentStatus?.enrolledCount as number, - enrollMax: cls.aggregateEnrollmentStatus?.maxEnroll as number, - number: cls.number as string, - semester: term.semester, - session: cls.session?.name as string, - status: cls.status?.description as string, - title: cls.classTitle, - unitsMax: cls.allowedUnits?.maximum as number, - unitsMin: cls.allowedUnits?.minimum as number, - waitlistCount: cls.aggregateEnrollmentStatus?.waitlistedCount as number, - waitlistMax: cls.aggregateEnrollmentStatus?.maxWaitlist as number, - year: term.year, - - ...formatMetadata(cls), - } + if (cls == null) return null; + + const term = stringToTerm(cls.session?.term?.name as string); + const id = getCsCourseId(cls.course as CourseType); + + return { + course: { + id, + term, + }, + + primarySection: { + id, + term, + classNumber: cls.number, + }, + + sections: { + id, + term, + classNumber: cls.number, + }, + + description: cls.classDescription, + number: cls.number as string, + semester: term.semester, + gradingBasis: cls.gradingBasis?.description as string, + finalExam: cls.finalExam?.code as string, + session: cls.session?.id as string, + title: cls.classTitle, + unitsMax: cls.allowedUnits?.maximum as number, + unitsMin: cls.allowedUnits?.minimum as number, + year: term.year, + + ...formatMetadata(cls), + }; } export function formatSection(section: SectionType | null): any { - if (section == null) return null - - const term = stringToTerm(section.class?.session?.term?.name as string) - - /* All of the section data we have only have one meeting time so this is safe to do */ - const meeting = section.meetings != undefined ? section.meetings[0] : null; - const instructors = meeting?.assignedInstructors?. - filter(i => (i.printInScheduleOfClasses && i.instructor?.names != undefined)). - map(i => { - // Primary name has precedence over preferred name - let nameInfo = i.instructor?.names?.find(n => n.type?.code === "PRI") - if (nameInfo == undefined) { - nameInfo = i.instructor?.names?.find(n => n.type?.code === "PRF") - } - - return { givenName: nameInfo?.givenName, familyName: nameInfo?.familyName } - }); - - const id = getCsCourseId(section.class?.course as CourseType) - - return { - class: { - id, - term, - classNumber: section.class?.number, - }, - course: { - id, - term - }, - - ccn: section.id as number, - dateEnd: meeting?.endDate, - dateStart: meeting?.startDate, - days: meeting != null ? [ - meeting.meetsSunday, - meeting.meetsMonday, - meeting.meetsTuesday, - meeting.meetsWednesday, - meeting.meetsThursday, - meeting.meetsFriday, - meeting.meetsSaturday - ] as boolean[] : null, - enrollCount: section.enrollmentStatus?.enrolledCount as number, - enrollMax: section.enrollmentStatus?.maxEnroll as number, - instructors, - kind: section.component?.description as string, - location: meeting?.location?.description, - notes: section.sectionAttributes?.find(a => a.attribute?.code === "NOTE")?.value?.formalDescription, - number: section.number as string, - primary: section.association?.primary as boolean, - timeEnd: meeting?.endTime as string, - timeStart: meeting?.startTime as string, - waitlistCount: section.enrollmentStatus?.waitlistedCount as number, - waitlistMax: section.enrollmentStatus?.maxWaitlist as number, - - ...formatMetadata(section), - } + if (section == null) return null; + + const term = stringToTerm(section.class?.session?.term?.name as string); + + const id = getCsCourseId(section.class?.course as CourseType); + + return { + class: { + id, + term, + classNumber: section.class?.number, + }, + + course: { + id, + term, + }, + + ccn: section.id as number, + number: section.number as string, + primary: section.association?.primary as boolean, + + component: section.component?.code as string, + + endDate: section?.endDate?.toISOString() as string, + startDate: section?.startDate?.toISOString() as string, + + meetings: section.meetings?.map((m) => ({ + days: [ + m.meetsSunday, + m.meetsMonday, + m.meetsTuesday, + m.meetsWednesday, + m.meetsThursday, + m.meetsFriday, + m.meetsSaturday, + ], + + endDate: m.endDate?.toISOString() as string, + endTime: m.endTime, + location: m.location?.description, + startDate: m.startDate?.toISOString() as string, + startTime: m.startTime, + + instructors: m?.assignedInstructors + ?.filter( + (i) => i.printInScheduleOfClasses && i.instructor?.names != undefined + ) + .map((i) => { + // Primary name has precedence over preferred name + let nameInfo = i.instructor?.names?.find( + (n) => n.type?.code === "PRI" + ); + if (nameInfo == undefined) { + nameInfo = i.instructor?.names?.find((n) => n.type?.code === "PRF"); + } + + return { + givenName: nameInfo?.givenName as string, + familyName: nameInfo?.familyName as string, + }; + }), + })), + + exams: section.exams?.map((e) => ({ + date: e.date, + endTime: e.endTime, + location: e.location?.description as string, + startTime: e.startTime, + + // FIN: Final, MID: Midterm + final: e.type?.code === "FIN", + })), + + // P: In-Person Instruction, O: Online + online: section.instructionMode?.code === "O", + + // O: Open, C: Closed + open: section.enrollmentStatus?.status?.code === "O", + + enrollCount: section.enrollmentStatus?.enrolledCount as number, + enrollMax: section.enrollmentStatus?.maxEnroll as number, + waitlistCount: section.enrollmentStatus?.waitlistedCount as number, + waitlistMax: section.enrollmentStatus?.maxWaitlist as number, + + reservations: section.enrollmentStatus?.seatReservations?.map((sr) => ({ + group: sr.requirementGroup?.description as string, + enrollCount: sr.enrolledCount as number, + enrollMax: sr.maxEnroll as number, + })), + + ...formatMetadata(section), + }; } -export function formatCourse(course: CourseType | null, term?: TermInput | null): any { - if (course == null) return null - - return { - classes: getCsCourseId(course), - crossListing: { - displayNames: course.crossListing?.courses, - term - }, - - description: course.description as string, - fromDate: course.fromDate, - gradingBasis: course.gradingBasis?.description as string, - level: course.academicCareer?.description as string, - number: course.catalogNumber?.formatted as string, - prereqs: course.preparation?.requiredText, - subject: course.classSubjectArea?.code as string, - subjectName: course.classSubjectArea?.description as string, - title: course.title as string, - toDate: course.toDate, - - ...formatMetadata(course), - } -} \ No newline at end of file +export function formatCourse( + course: CourseType | null, + term?: TermInput | null +): any { + if (course == null) return null; + + return { + classes: getCsCourseId(course), + + crossListing: { + displayNames: course.crossListing?.courses, + term, + }, + + requiredCourses: Array.isArray(course.preparation?.requiredCourses) + ? course.preparation?.requiredCourses.map((c) => + getCsCourseId(c as CourseType) + ) + : [], + + requirements: course.preparation?.requiredText, + description: course.description as string, + primaryComponent: course.primaryInstructionMethod?.code as string, + fromDate: course.fromDate, + finalExam: course.finalExam?.description as string, + gradingBasis: course.gradingBasis?.description as string, + academicCareer: course.academicCareer?.code as string, + number: course.catalogNumber?.formatted as string, + subject: course.classSubjectArea?.code as string, + title: course.title as string, + toDate: course.toDate, + + ...formatMetadata(course), + }; +} diff --git a/backend/src/modules/catalog/generated-types/module-types.ts b/backend/src/modules/catalog/generated-types/module-types.ts index 12f453f1c..7f83a8a8e 100644 --- a/backend/src/modules/catalog/generated-types/module-types.ts +++ b/backend/src/modules/catalog/generated-types/module-types.ts @@ -3,38 +3,58 @@ import * as gm from "graphql-modules"; export namespace CatalogModule { interface DefinedFields { Query: 'course' | 'class' | 'section' | 'catalog' | 'courseList'; - Course: 'classes' | 'crossListing' | 'sections' | 'description' | 'fromDate' | 'gradeAverage' | 'gradingBasis' | 'level' | 'number' | 'prereqs' | 'subject' | 'subjectName' | 'title' | 'toDate' | 'raw' | 'lastUpdated'; - Class: 'course' | 'primarySection' | 'sections' | 'description' | 'enrollCount' | 'enrollMax' | 'number' | 'semester' | 'session' | 'status' | 'title' | 'unitsMax' | 'unitsMin' | 'waitlistCount' | 'waitlistMax' | 'year' | 'raw' | 'lastUpdated'; - Section: 'class' | 'course' | 'enrollmentHistory' | 'ccn' | 'dateEnd' | 'dateStart' | 'days' | 'enrollCount' | 'enrollMax' | 'instructors' | 'kind' | 'location' | 'notes' | 'number' | 'primary' | 'timeEnd' | 'timeStart' | 'waitlistCount' | 'waitlistMax' | 'raw' | 'lastUpdated'; + Course: 'classes' | 'crossListing' | 'sections' | 'requiredCourses' | 'requirements' | 'description' | 'fromDate' | 'gradeAverage' | 'gradingBasis' | 'finalExam' | 'academicCareer' | 'number' | 'subject' | 'title' | 'toDate' | 'raw' | 'lastUpdated'; + Class: 'course' | 'primarySection' | 'sections' | 'session' | 'gradingBasis' | 'finalExam' | 'description' | 'title' | 'number' | 'semester' | 'year' | 'unitsMax' | 'unitsMin' | 'raw' | 'lastUpdated'; + Section: 'class' | 'course' | 'enrollmentHistory' | 'ccn' | 'number' | 'primary' | 'component' | 'meetings' | 'exams' | 'startDate' | 'endDate' | 'online' | 'open' | 'reservations' | 'enrollCount' | 'waitlistCount' | 'enrollMax' | 'waitlistMax' | 'raw' | 'lastUpdated'; + Reservation: 'enrollCount' | 'enrollMax' | 'group'; + Meeting: 'days' | 'startTime' | 'endTime' | 'startDate' | 'endDate' | 'location' | 'instructors'; + Exam: 'date' | 'startTime' | 'endTime' | 'location' | 'final'; Instructor: 'familyName' | 'givenName'; EnrollmentDay: 'enrollCount' | 'enrollMax' | 'waitlistCount' | 'waitlistMax'; - CatalogItem: 'subject' | 'number' | 'title' | 'description' | 'classes' | 'gradeAverage' | 'lastUpdated'; - CatalogClass: 'number' | 'title' | 'description' | 'enrollCount' | 'enrollMax' | 'unitsMax' | 'unitsMin' | 'lastUpdated'; CourseListItem: 'subject' | 'number'; }; + interface DefinedEnumValues { + AcademicCareer: 'UGRD' | 'GRAD' | 'UCBX'; + CourseFinalExam: 'D' | 'N' | 'A' | 'C' | 'Y'; + CourseGradingBasis: 'completedNotation' | 'passFail' | 'letter' | 'satisfactory' | 'graded'; + ClassFinalExam: 'Y' | 'N' | 'A' | 'C'; + ClassGradingBasis: 'ESU' | 'SUS' | 'OPT' | 'PNP' | 'BMT' | 'GRD' | 'IOP'; + Session: 'R' | 'S' | 'A' | 'B' | 'C' | 'D' | 'E' | 'F'; + Component: 'WOR' | 'WBD' | 'CLN' | 'PRA' | 'GRP' | 'DIS' | 'VOL' | 'TUT' | 'FLD' | 'LEC' | 'SUP' | 'LAB' | 'SES' | 'STD' | 'SLF' | 'COL' | 'WBL' | 'IND' | 'INT' | 'REA' | 'REC' | 'SEM'; + }; + export type Query = Pick; export type Course = Pick; export type TermInput = Types.TermInput; export type Class = Pick; export type Section = Pick; - export type CatalogItem = Pick; - export type CourseListItem = Pick; + export type CourseGradingBasis = DefinedEnumValues['CourseGradingBasis']; + export type CourseFinalExam = DefinedEnumValues['CourseFinalExam']; + export type AcademicCareer = DefinedEnumValues['AcademicCareer']; export type JSONObject = Types.JsonObject; export type ISODate = Types.IsoDate; + export type Session = DefinedEnumValues['Session']; + export type ClassGradingBasis = DefinedEnumValues['ClassGradingBasis']; + export type ClassFinalExam = DefinedEnumValues['ClassFinalExam']; export type Semester = Types.Semester; export type EnrollmentDay = Pick; + export type Component = DefinedEnumValues['Component']; + export type Meeting = Pick; + export type Exam = Pick; + export type Reservation = Pick; export type Instructor = Pick; - export type CatalogClass = Pick; + export type CourseListItem = Pick; export type QueryResolvers = Pick; export type CourseResolvers = Pick; export type ClassResolvers = Pick; export type SectionResolvers = Pick; + export type ReservationResolvers = Pick; + export type MeetingResolvers = Pick; + export type ExamResolvers = Pick; export type InstructorResolvers = Pick; export type EnrollmentDayResolvers = Pick; - export type CatalogItemResolvers = Pick; - export type CatalogClassResolvers = Pick; export type CourseListItemResolvers = Pick; export interface Resolvers { @@ -42,10 +62,11 @@ export namespace CatalogModule { Course?: CourseResolvers; Class?: ClassResolvers; Section?: SectionResolvers; + Reservation?: ReservationResolvers; + Meeting?: MeetingResolvers; + Exam?: ExamResolvers; Instructor?: InstructorResolvers; EnrollmentDay?: EnrollmentDayResolvers; - CatalogItem?: CatalogItemResolvers; - CatalogClass?: CatalogClassResolvers; CourseListItem?: CourseListItemResolvers; }; @@ -66,15 +87,16 @@ export namespace CatalogModule { classes?: gm.Middleware[]; crossListing?: gm.Middleware[]; sections?: gm.Middleware[]; + requiredCourses?: gm.Middleware[]; + requirements?: gm.Middleware[]; description?: gm.Middleware[]; fromDate?: gm.Middleware[]; gradeAverage?: gm.Middleware[]; gradingBasis?: gm.Middleware[]; - level?: gm.Middleware[]; + finalExam?: gm.Middleware[]; + academicCareer?: gm.Middleware[]; number?: gm.Middleware[]; - prereqs?: gm.Middleware[]; subject?: gm.Middleware[]; - subjectName?: gm.Middleware[]; title?: gm.Middleware[]; toDate?: gm.Middleware[]; raw?: gm.Middleware[]; @@ -85,19 +107,16 @@ export namespace CatalogModule { course?: gm.Middleware[]; primarySection?: gm.Middleware[]; sections?: gm.Middleware[]; + session?: gm.Middleware[]; + gradingBasis?: gm.Middleware[]; + finalExam?: gm.Middleware[]; description?: gm.Middleware[]; - enrollCount?: gm.Middleware[]; - enrollMax?: gm.Middleware[]; + title?: gm.Middleware[]; number?: gm.Middleware[]; semester?: gm.Middleware[]; - session?: gm.Middleware[]; - status?: gm.Middleware[]; - title?: gm.Middleware[]; + year?: gm.Middleware[]; unitsMax?: gm.Middleware[]; unitsMin?: gm.Middleware[]; - waitlistCount?: gm.Middleware[]; - waitlistMax?: gm.Middleware[]; - year?: gm.Middleware[]; raw?: gm.Middleware[]; lastUpdated?: gm.Middleware[]; }; @@ -107,24 +126,47 @@ export namespace CatalogModule { course?: gm.Middleware[]; enrollmentHistory?: gm.Middleware[]; ccn?: gm.Middleware[]; - dateEnd?: gm.Middleware[]; - dateStart?: gm.Middleware[]; - days?: gm.Middleware[]; - enrollCount?: gm.Middleware[]; - enrollMax?: gm.Middleware[]; - instructors?: gm.Middleware[]; - kind?: gm.Middleware[]; - location?: gm.Middleware[]; - notes?: gm.Middleware[]; number?: gm.Middleware[]; primary?: gm.Middleware[]; - timeEnd?: gm.Middleware[]; - timeStart?: gm.Middleware[]; + component?: gm.Middleware[]; + meetings?: gm.Middleware[]; + exams?: gm.Middleware[]; + startDate?: gm.Middleware[]; + endDate?: gm.Middleware[]; + online?: gm.Middleware[]; + open?: gm.Middleware[]; + reservations?: gm.Middleware[]; + enrollCount?: gm.Middleware[]; waitlistCount?: gm.Middleware[]; + enrollMax?: gm.Middleware[]; waitlistMax?: gm.Middleware[]; raw?: gm.Middleware[]; lastUpdated?: gm.Middleware[]; }; + Reservation?: { + '*'?: gm.Middleware[]; + enrollCount?: gm.Middleware[]; + enrollMax?: gm.Middleware[]; + group?: gm.Middleware[]; + }; + Meeting?: { + '*'?: gm.Middleware[]; + days?: gm.Middleware[]; + startTime?: gm.Middleware[]; + endTime?: gm.Middleware[]; + startDate?: gm.Middleware[]; + endDate?: gm.Middleware[]; + location?: gm.Middleware[]; + instructors?: gm.Middleware[]; + }; + Exam?: { + '*'?: gm.Middleware[]; + date?: gm.Middleware[]; + startTime?: gm.Middleware[]; + endTime?: gm.Middleware[]; + location?: gm.Middleware[]; + final?: gm.Middleware[]; + }; Instructor?: { '*'?: gm.Middleware[]; familyName?: gm.Middleware[]; @@ -137,27 +179,6 @@ export namespace CatalogModule { waitlistCount?: gm.Middleware[]; waitlistMax?: gm.Middleware[]; }; - CatalogItem?: { - '*'?: gm.Middleware[]; - subject?: gm.Middleware[]; - number?: gm.Middleware[]; - title?: gm.Middleware[]; - description?: gm.Middleware[]; - classes?: gm.Middleware[]; - gradeAverage?: gm.Middleware[]; - lastUpdated?: gm.Middleware[]; - }; - CatalogClass?: { - '*'?: gm.Middleware[]; - number?: gm.Middleware[]; - title?: gm.Middleware[]; - description?: gm.Middleware[]; - enrollCount?: gm.Middleware[]; - enrollMax?: gm.Middleware[]; - unitsMax?: gm.Middleware[]; - unitsMin?: gm.Middleware[]; - lastUpdated?: gm.Middleware[]; - }; CourseListItem?: { '*'?: gm.Middleware[]; subject?: gm.Middleware[]; diff --git a/backend/src/modules/catalog/resolver.ts b/backend/src/modules/catalog/resolver.ts index c46593a8d..39a038f9a 100644 --- a/backend/src/modules/catalog/resolver.ts +++ b/backend/src/modules/catalog/resolver.ts @@ -1,56 +1,119 @@ import { CatalogModule } from "./generated-types/module-types"; -import { getCatalog, getClass, getClassById, getClassSections, getCourse, getCourseById, getCourseClasses, getCourseList, getCrossListings, getPrimarySection, getSection } from "./controller" +import { + getCatalog, + getClass, + getClassById, + getClassSections, + getCourse, + getCourseById, + getCourseClasses, + getCourseList, + getCourseSections, + getCrossListing, + getPrimarySection, + getRequiredCourses, + getSection, +} from "./controller"; const resolvers: CatalogModule.Resolvers = { - Query: { - catalog: (_, args, __, info) => getCatalog(args.term, info), - course: (_, args) => getCourse(args.subject, args.courseNumber, args.term), - class: (_, args) => getClass(args.subject, args.courseNumber, args.term, args.classNumber), - section: (_, args) => getSection(args.subject, args.courseNumber, args.term, args.classNumber, args.sectionNumber), - courseList: getCourseList, - }, + Query: { + catalog: (_, args, __, info) => getCatalog(args.term, info), + course: (_, args, __, info) => + getCourse(args.subject, args.courseNumber, args.term, info), + class: (_, args) => + getClass(args.subject, args.courseNumber, args.term, args.classNumber), + section: (_, args) => + getSection( + args.subject, + args.courseNumber, + args.term, + args.classNumber, + args.sectionNumber + ), + courseList: (_, __, ___, info) => getCourseList(info), + }, - /* + /* TODO: Figure out how to better type the parent objects. Apollo likes to assume they are the GraphQL types, but they are actually the information from formatter.ts that is then used to get the GraphQL types. */ - Class: { - course: (parent) => { - const c = parent.course as any - return getCourseById(c.id, c.term) - }, - sections: (parent) => { - const s = parent.sections as any - return getClassSections(s.id, s.term, s.classNumber) - }, - primarySection: (parent) => { - const s = parent.primarySection as any - return getPrimarySection(s.id, s.term, s.classNumber) - }, - }, - - Section: { - class: (parent) => { - const c = parent.class as any - return getClassById(c.id, c.term, c.classNumber) - }, - course: (parent) => { - const c = parent.course as any - return getCourseById(c.id, c.term) - } - }, - - Course: { - classes: (parent, { term }) => { - const c = parent.classes as any - return getCourseClasses(c, term) - }, - crossListing: (parent) => { - const cl = parent.crossListing as any - return getCrossListings(cl.displayNames, cl.term) - } - } -} - -export default resolvers; \ No newline at end of file + Class: { + course: (parent) => { + const c = parent.course as any; + return getCourseById(c.id, c.term); + }, + sections: (parent) => { + const s = parent.sections as any; + return getClassSections(s.id, s.term, s.classNumber); + }, + primarySection: (parent) => { + const s = parent.primarySection as any; + if (!s.term) return parent.primarySection; + return getPrimarySection(s.id, s.term, s.classNumber); + }, + }, + + Section: { + class: (parent) => { + const c = parent.class as any; + return getClassById(c.id, c.term, c.classNumber); + }, + course: (parent) => { + const c = parent.course as any; + return getCourseById(c.id, c.term); + }, + }, + + Course: { + classes: (parent, { term }) => { + const c = parent.classes as any; + if (typeof c !== "string") return parent.classes; + return getCourseClasses(c, term); + }, + crossListing: (parent) => { + const cl = parent.crossListing as any; + return getCrossListing(cl.displayNames, cl.term); + }, + sections: (parent, { term }) => { + const c = parent.classes as any; + return getCourseSections(c, term); + }, + requiredCourses: (parent) => { + const rc = parent.requiredCourses as any; + return getRequiredCourses(rc); + }, + }, + + // @ts-expect-error - Not sure how to type this + Session: { + R: "1", + S: "12W", + A: "6W1", + B: "10W", + C: "8W", + D: "6W2", + E: "3W1", + F: "3W2", + }, + + CourseFinalExam: { + D: "To be decided by the instructor when the class is offered", + N: "No final exam", + A: "Alternative method of final assessment", + C: "Common Final Exam", + Y: "Written final exam conducted during the scheduled final exam period", + }, + + ClassGradingBasis: { + ESU: "Elective Satisfactory/Unsat", + SUS: "Satisfactory/Unsatisfactory", + OPT: "Student Option", + PNP: "Pass/Not Pass", + BMT: "Multi-Term Course: Not Graded", + GRD: "Graded", + IOP: "Instructor Option", + }, +}; + +export default resolvers; diff --git a/backend/src/modules/catalog/typedefs/catalog.ts b/backend/src/modules/catalog/typedefs/catalog.ts index c37859582..11980164b 100644 --- a/backend/src/modules/catalog/typedefs/catalog.ts +++ b/backend/src/modules/catalog/typedefs/catalog.ts @@ -1,142 +1,319 @@ import { gql } from "graphql-tag"; export default gql` -type Query { + type Query { course(subject: String!, courseNumber: String!, term: TermInput): Course - class(subject: String!, courseNumber: String!, term: TermInput!, classNumber: String!): Class - section(subject: String!, courseNumber: String!, term: TermInput!, classNumber: String!, sectionNumber: String!): Section + class( + subject: String! + courseNumber: String! + term: TermInput! + classNumber: String! + ): Class + section( + subject: String! + courseNumber: String! + term: TermInput! + classNumber: String! + sectionNumber: String! + ): Section """ - Get info about all courses and their corresponding classes for a given semester. - + Get info about all courses and their corresponding classes for a given semester. + Used primarily in the catalog page. """ - catalog(term: TermInput!): [CatalogItem] + catalog(term: TermInput!): [Course!] """ - Get a list of all course names across all semesters. - + Get a list of all course names across all semesters. + Useful for searching for courses. """ - courseList: [CourseListItem] -} + courseList: [Course!] + } -""" -Info shared between Classes within and across semesters. -""" -type Course @cacheControl(maxAge: 1) { - classes(term: TermInput): [Class]! - crossListing: [Course] - sections(term: TermInput, primary: Boolean): [Section]! + """ + Info shared between Classes within and across semesters. + """ + type Course { + classes(term: TermInput): [Class!]! + crossListing: [Course!]! + sections(term: TermInput, primary: Boolean): [Section!]! + requiredCourses: [Course!]! + requirements: String description: String! fromDate: String! gradeAverage: Float - gradingBasis: String! - level: String! + gradingBasis: CourseGradingBasis! + finalExam: CourseFinalExam + academicCareer: AcademicCareer! number: String! - prereqs: String subject: String! - subjectName: String! title: String! toDate: String! - + raw: JSONObject! lastUpdated: ISODate! -} + } + + enum AcademicCareer { + "Undergraduate" + UGRD + + "Graduate" + GRAD + + "UC Extension" + UCBX + } + + enum CourseFinalExam { + "To be decided by the instructor when the class is offered" + D + + "No final exam" + N + + "Alternative method of final assessment" + A + + "Common Final Exam" + C + + "Written final exam conducted during the scheduled final exam period" + Y + } -""" -Data for a specific class in a specific semester. There may be more than one Class for a given Course in a given semester. -""" -type Class @cacheControl(maxAge: 1) { + enum CourseGradingBasis { + completedNotation + passFail + letter + satisfactory + graded + } + + """ + Data for a specific class in a specific semester. There may be more than one Class for a given Course in a given semester. + """ + type Class { course: Course! primarySection: Section! - sections: [Section]! + sections: [Section!]! + session: Session! + gradingBasis: ClassGradingBasis! + finalExam: ClassFinalExam! description: String - enrollCount: Int! - enrollMax: Int! + title: String number: String! semester: Semester! - session: String! - status: String! - title: String + year: Int! unitsMax: Float! unitsMin: Float! - waitlistCount: Int! - waitlistMax: Int! - year: Int! - + raw: JSONObject! lastUpdated: ISODate! -} + } + + enum ClassFinalExam { + "Yes" + Y -""" -Sections are each associated with one Class. -""" -type Section @cacheControl(maxAge: 1) { + "No" + N + + "Alernate Method" + A + + "Common Final" + C + } + + enum ClassGradingBasis { + "Elective Satisfactory/Unsat" + ESU + + "Satisfactory/Unsatisfactory" + SUS + + "Student Option" + OPT + + "Pass/Not Pass" + PNP + + "Multi-Term Course: Not Graded" + BMT + + "Graded" + GRD + + "Instructor Option" + IOP + } + + enum Session { + "Regular Academic Session" + R + + "12-Week Summer Session" + S + + "Session A" + A + + "Session B" + B + + "Session C" + C + + "Session D" + D + + "Session E" + E + + "Session F" + F + } + + """ + Sections are each associated with one Class. + """ + type Section { class: Class! course: Course! - enrollmentHistory: [EnrollmentDay] + enrollmentHistory: [EnrollmentDay!] ccn: Int! - dateEnd: String - dateStart: String - days: [Boolean!] - enrollCount: Int! - enrollMax: Int! - instructors: [Instructor] - kind: String! - location: String - notes: String number: String! primary: Boolean! - timeEnd: String - timeStart: String + + component: Component! + meetings: [Meeting!]! + exams: [Exam!]! + startDate: String! + endDate: String! + online: Boolean! + open: Boolean! + reservations: [Reservation!] + enrollCount: Int! waitlistCount: Int! + enrollMax: Int! waitlistMax: Int! raw: JSONObject! lastUpdated: ISODate! -} + } + + enum Component { + "Workshop" + WOR + + "Web-Based Discussion" + WBD + + "Clinic" + CLN + + "Practicum" + PRA + + "Directed Group Study" + GRP + + "Discussion" + DIS + + "Voluntary" + VOL + + "Tutorial" + TUT + + "Field Work" + FLD + + "Lecture" + LEC + + "Supplementary" + SUP + + "Laboratory" + LAB + + "Session" + SES + + "Studio" + STD + + "Self-paced" + SLF + + "Colloquium" + COL + + "Web-Based Lecture" + WBL + + "Independent Study" + IND + + "Internship" + INT -type Instructor @cacheControl(maxAge: 1) { - familyName: String! - givenName: String! -} + "Reading" + REA -type EnrollmentDay @cacheControl(maxAge: 1) { + "Recitation" + REC + + "Seminar" + SEM + } + + type Reservation { enrollCount: Int! enrollMax: Int! - waitlistCount: Int! - waitlistMax: Int! -} + group: String! + } -type CatalogItem @cacheControl(maxAge: 1) { - subject: String! - number: String! - title: String! - description: String! - classes: [CatalogClass]! - gradeAverage: Float + type Meeting { + days: [Boolean!] + startTime: String! + endTime: String! + startDate: String! + endDate: String! + location: String + instructors: [Instructor!]! + } - lastUpdated: ISODate! -} + type Exam { + date: String! + startTime: String! + endTime: String! + location: String! + final: Boolean! + } -type CatalogClass @cacheControl(maxAge: 1) { - number: String! - title: String - description: String + type Instructor { + familyName: String + givenName: String + } + + type EnrollmentDay { enrollCount: Int! enrollMax: Int! - unitsMax: Float! - unitsMin: Float! - - lastUpdated: ISODate! -} + waitlistCount: Int! + waitlistMax: Int! + } -type CourseListItem @cacheControl(maxAge: 1) { + type CourseListItem { subject: String! number: String! -} -`; \ No newline at end of file + } +`; diff --git a/backend/src/modules/common/generated-types/module-types.ts b/backend/src/modules/common/generated-types/module-types.ts index a406fc96c..d50833402 100644 --- a/backend/src/modules/common/generated-types/module-types.ts +++ b/backend/src/modules/common/generated-types/module-types.ts @@ -7,7 +7,7 @@ export namespace CommonModule { interface DefinedEnumValues { CacheControlScope: 'PUBLIC' | 'PRIVATE'; - Semester: 'Fall' | 'Spring' | 'Summer'; + Semester: 'Fall' | 'Spring' | 'Summer' | 'Winter'; }; interface DefinedInputFields { diff --git a/backend/src/modules/common/typedefs/common.ts b/backend/src/modules/common/typedefs/common.ts index 64d6acdb9..fc5ba0541 100644 --- a/backend/src/modules/common/typedefs/common.ts +++ b/backend/src/modules/common/typedefs/common.ts @@ -31,6 +31,7 @@ enum Semester { Fall Spring Summer + Winter } type Query { diff --git a/backend/src/modules/grade/controller.ts b/backend/src/modules/grade/controller.ts index 1284100c7..b4ee01cfe 100644 --- a/backend/src/modules/grade/controller.ts +++ b/backend/src/modules/grade/controller.ts @@ -3,92 +3,104 @@ import { TermInput } from "../../generated-types/graphql"; import { omitBy, isNil } from "lodash"; const calanswersToLetter: { [key: string]: string } = { - "A+": "A+", - "A": "A", - "A-": "A-", - "B+": "B+", - "B": "B", - "B-": "B-", - "C+": "C+", - "C": "C", - "C-": "C-", - "D+": "D+", - "D": "D", - "D-": "D-", - "F": "F", - "Pass": "P", - "Not Pass": "NP", -} + "A+": "A+", + A: "A", + "A-": "A-", + "B+": "B+", + B: "B", + "B-": "B-", + "C+": "C+", + C: "C", + "C-": "C-", + "D+": "D+", + D: "D", + "D-": "D-", + F: "F", + Pass: "P", + "Not Pass": "NP", +}; const letterWeights: { [key: string]: number } = { - "A+": 4.0, - "A": 4.0, - "A-": 3.7, - "B+": 3.3, - "B": 3.0, - "B-": 2.7, - "C+": 2.3, - "C": 2.0, - "C-": 1.7, - "D+": 1.3, - "D": 1.0, - "D-": 0.7, - "F": 0 -} + "A+": 4.0, + A: 4.0, + "A-": 3.7, + "B+": 3.3, + B: 3.0, + "B-": 2.7, + "C+": 2.3, + C: 2.0, + "C-": 1.7, + "D+": 1.3, + D: 1.0, + "D-": 0.7, + F: 0, +}; -export async function getCombinedGrades(subject: string, courseNum: string, sectionNum?: string | null, term?: TermInput | null) { - const filter = omitBy({ - "CourseSubjectShortNm": subject, - "CourseNumber": courseNum, - "SectionNbr": sectionNum, - "term.year": term?.year, - "term.semester": term?.semester, - }, isNil) +export async function getCombinedGrades( + subject: string, + courseNum: string, + sectionNum?: string | null, + term?: TermInput | null +) { + const filter = omitBy( + { + CourseSubjectShortNm: subject, + CourseNumber: courseNum, + SectionNbr: sectionNum, + "term.year": term?.year, + "term.semester": term?.semester, + }, + isNil + ); - const projection = { - GradeNm: 1, - EnrollmentCnt: 1 - } + const projection = { + GradeNm: 1, + EnrollmentCnt: 1, + }; - const grades = await GradeModel.find(filter, projection).lean() + const grades = await GradeModel.find(filter, projection).lean(); - return { - average: await getAverage(grades), - distribution: await getDistribution(grades), - } + return { + average: await getAverage(grades), + distribution: await getDistribution(grades), + }; } export async function getDistribution(grades: GradeType[]) { - // distribution is a map of letter -> count - const distribution: { [key: string]: number } = Object.values(calanswersToLetter) - .reduce((acc, letter) => ({ ...acc, [letter]: 0 }), {}); + // distribution is a map of letter -> count + const distribution: { [key: string]: number } = Object.values( + calanswersToLetter + ).reduce((acc, letter) => ({ ...acc, [letter]: 0 }), {}); - for (const g of grades) { - const name = g.GradeNm as string; - const count = g.EnrollmentCnt as number; + for (const g of grades) { + const name = g.GradeNm as string; + const count = g.EnrollmentCnt as number; - if (name in calanswersToLetter) { - const letter = calanswersToLetter[name]; - distribution[letter] += count; - } + if (name in calanswersToLetter) { + const letter = calanswersToLetter[name]; + distribution[letter] += count; } + } - return Object.entries(distribution).map(([letter, count]) => ({ letter, count })); + return Object.entries(distribution).map(([letter, count]) => ({ + letter, + count, + })); } -export async function getAverage(grades: GradeType[]) { - let total = 0 - let totalWeighted = 0 +export function getAverage(grades: GradeType[]) { + let total = 0; + let totalWeighted = 0; - for (const g of grades) { - const name = g.GradeNm as string; - const count = g.EnrollmentCnt as number; + for (const g of grades) { + const name = g.GradeNm as string; + const count = g.EnrollmentCnt as number; - if (name in letterWeights) { - total += count; - totalWeighted += count * letterWeights[name]; - } + if (name in letterWeights) { + total += count; + totalWeighted += count * letterWeights[name]; } + } - return total > 0 ? totalWeighted / total : null; + return total > 0 ? totalWeighted / total : null; } diff --git a/backend/src/scripts/update-catalog.ts b/backend/src/scripts/update-catalog.ts index 8ef97e903..7de48c726 100644 --- a/backend/src/scripts/update-catalog.ts +++ b/backend/src/scripts/update-catalog.ts @@ -1,183 +1,225 @@ -import mongooseLoader from '../bootstrap/loaders/mongoose'; -import { CourseModel, CourseType } from '../models/course'; -import { SemesterModel, SemesterType } from '../models/semester'; +import mongooseLoader from "../bootstrap/loaders/mongoose"; +import { CourseModel, CourseType } from "../models/course"; +import { SemesterModel, SemesterType } from "../models/semester"; import { config } from "../config"; -import axios, { AxiosResponse } from 'axios'; -import { SISResponse } from '../utils/sis'; -import { MongooseBulkWriteOptions } from 'mongoose'; -import { ClassModel, ClassType } from '../models/class'; -import { SectionModel, SectionType } from '../models/section'; +import axios, { AxiosResponse } from "axios"; +import { SISResponse } from "../utils/sis"; +import { MongooseBulkWriteOptions } from "mongoose"; +import { ClassModel, ClassType } from "../models/class"; +import { SectionModel, SectionType } from "../models/section"; -const SIS_COURSE_URL = 'https://gateway.api.berkeley.edu/sis/v4/courses'; -const SIS_CLASS_URL = 'https://gateway.api.berkeley.edu/sis/v1/classes'; -const SIS_SECTION_URL = 'https://gateway.api.berkeley.edu/sis/v1/classes/sections'; +const SIS_COURSE_URL = "https://gateway.api.berkeley.edu/sis/v4/courses"; +const SIS_CLASS_URL = "https://gateway.api.berkeley.edu/sis/v1/classes"; +const SIS_SECTION_URL = + "https://gateway.api.berkeley.edu/sis/v1/classes/sections"; const semToTermId = (s: SemesterType) => { - // term-id is computed by dropping the century digit of the year, then adding the term code - const termMap: { [key: string] : number} = {'Fall': 8, 'Spring': 2, 'Summer': 5} - return `${Math.floor(s.year / 1000)}${s.year % 100}${termMap[s.term]}` -} - -const queryPages = async (url: string, params: any, headers: any, field: string, retries: number = 3) => { - let page = 1 - const values: T[] = [] - - console.log("Querying SIS API pages...") - console.log(`URL: ${url}`) - console.log(`Params: ${JSON.stringify(params)}`) - console.log(`Headers: ${JSON.stringify(headers)}`) - while (true) { - let resp: AxiosResponse>; - - try { - resp = await axios.get(url, { params: { 'page-number': page, ...params}, headers }); - } catch (err) { - if (axios.isAxiosError(err) && err.response?.status === 404) { - break; - } else { - console.log(`Unexpected err querying SIS API. Error: ${err}.`) - - if (retries > 0) { - retries--; - console.log(`Retrying...`) - continue; - } else { - console.log(`Too many errors querying SIS API for courses. Terminating update...`) - throw err; - } - } - } - - values.push(...resp.data.apiResponse.response[field]); - page++; - } - - console.log(`Completed querying SIS API. Received ${values.length} objects in ${page - 1} pages.`) - - return values; -} + // term-id is computed by dropping the century digit of the year, then adding the term code + const termMap: { [key: string]: number } = { + Fall: 8, + Spring: 2, + Summer: 5, + Winter: 11, + }; + return `${Math.floor(s.year / 1000)}${s.year % 100}${termMap[s.term]}`; +}; + +const queryPages = async ( + url: string, + params: any, + headers: any, + field: string, + retries: number = 3 +) => { + let page = 1; + const values: T[] = []; + + console.log("Querying SIS API pages..."); + console.log(`URL: ${url}`); + console.log(`Params: ${JSON.stringify(params)}`); + console.log(`Headers: ${JSON.stringify(headers)}`); + while (true) { + let resp: AxiosResponse>; -const updateCourses = async () => { - const headers = { - 'app_id': config.sis.COURSE_APP_ID, - 'app_key': config.sis.COURSE_APP_KEY, - } - const params = { - 'status-code': 'ACTIVE', - 'page-size': 100, + try { + resp = await axios.get(url, { + params: { "page-number": page, ...params }, + headers, + }); + } catch (err) { + if (axios.isAxiosError(err) && err.response?.status === 404) { + break; + } else { + console.log(`Unexpected err querying SIS API. Error: ${err}.`); + + if (retries > 0) { + retries--; + console.log(`Retrying...`); + continue; + } else { + console.log( + `Too many errors querying SIS API for courses. Terminating update...` + ); + throw err; + } + } } - const courses = await queryPages(SIS_COURSE_URL, params, headers, 'courses'); + values.push(...resp.data.apiResponse.response[field]); + page++; + } - console.log("Updating database with new course data...") - - const bulkOps = courses.map(c => ({ - replaceOne: { - filter: { classDisplayName: c.classDisplayName }, - replacement: c, - upsert: true, - } - })); + console.log( + `Completed querying SIS API. Received ${values.length} objects in ${ + page - 1 + } pages.` + ); - const options = { } as MongooseBulkWriteOptions; + return values; +}; - const res = await CourseModel.bulkWrite(bulkOps, options); - - console.log(`Completed updating database with new course data. Created ${res.upsertedCount} and updated ${res.modifiedCount} course objects.`) -} +const updateCourses = async () => { + const headers = { + app_id: config.sis.COURSE_APP_ID, + app_key: config.sis.COURSE_APP_KEY, + }; + + const params = { + "status-code": "ACTIVE", + "page-size": 100, + }; + + const courses = await queryPages( + SIS_COURSE_URL, + params, + headers, + "courses" + ); + + console.log("Updating database with new course data..."); + + const bulkOps = courses.map((c) => ({ + replaceOne: { + filter: { classDisplayName: c.classDisplayName }, + replacement: c, + upsert: true, + }, + })); + + const options = {} as MongooseBulkWriteOptions; + + const res = await CourseModel.bulkWrite(bulkOps, options); + + console.log( + `Completed updating database with new course data. Created ${res.upsertedCount} and updated ${res.modifiedCount} course objects.` + ); +}; const updateClasses = async () => { - const headers = { - 'app_id': config.sis.CLASS_APP_ID, - 'app_key': config.sis.CLASS_APP_KEY, - } - - const activeSemesters = await SemesterModel.find({ active: true }).lean(); - const classes: ClassType[] = []; - - for (const s of activeSemesters) { - console.log(`Updating classses for ${s.term} ${s.year}...`) - - const params = { - 'term-id': semToTermId(s), - 'page-size': 100, - } + const headers = { + app_id: config.sis.CLASS_APP_ID, + app_key: config.sis.CLASS_APP_KEY, + }; - const semesterClasses = await queryPages(SIS_CLASS_URL, params, headers, 'classes'); - classes.push(...semesterClasses); - } - - console.log("Updating database with new class data...") - const bulkOps = classes.map(c => ({ - replaceOne: { - filter: { displayName: c.displayName }, - replacement: c, - upsert: true, - } - })); + const activeSemesters = await SemesterModel.find({ active: true }).lean(); + const classes: ClassType[] = []; - const options = { } as MongooseBulkWriteOptions; + for (const s of activeSemesters) { + console.log(`Updating classses for ${s.term} ${s.year}...`); - const res = await ClassModel.bulkWrite(bulkOps, options); - - console.log(`Completed updating database with new class data. Created ${res.upsertedCount} and updated ${res.modifiedCount} class objects.`) -} + const params = { + "term-id": semToTermId(s), + "page-size": 100, + }; + + const semesterClasses = await queryPages( + SIS_CLASS_URL, + params, + headers, + "classes" + ); + classes.push(...semesterClasses); + } + + console.log("Updating database with new class data..."); + const bulkOps = classes.map((c) => ({ + replaceOne: { + filter: { displayName: c.displayName }, + replacement: c, + upsert: true, + }, + })); + + const options = {} as MongooseBulkWriteOptions; + + const res = await ClassModel.bulkWrite(bulkOps, options); + + console.log( + `Completed updating database with new class data. Created ${res.upsertedCount} and updated ${res.modifiedCount} class objects.` + ); +}; const updateSections = async () => { - const headers = { - 'app_id': config.sis.CLASS_APP_ID, - 'app_key': config.sis.CLASS_APP_KEY, - } - - const activeSemesters = await SemesterModel.find({ active: true }).lean(); - const sections: SectionType[] = []; - - for (const s of activeSemesters) { - console.log(`Updating sections for ${s.term} ${s.year}...`) - - const params = { - 'term-id': semToTermId(s), - 'page-size': 100, - } + const headers = { + app_id: config.sis.CLASS_APP_ID, + app_key: config.sis.CLASS_APP_KEY, + }; - const semesterClasses = await queryPages(SIS_SECTION_URL, params, headers, 'classSections'); - sections.push(...semesterClasses); - } - - console.log("Updating database with new section data...") - const bulkOps = sections.map(s => ({ - replaceOne: { - filter: { displayName: s.displayName }, - replacement: s, - upsert: true, - } - })); - - const options = { } as MongooseBulkWriteOptions; - - const res = await SectionModel.bulkWrite(bulkOps, options); + const activeSemesters = await SemesterModel.find({ active: true }).lean(); + const sections: SectionType[] = []; - console.log(`Completed updating database with new section data. Created ${res.upsertedCount} and updated ${res.modifiedCount} section objects.`) + for (const s of activeSemesters) { + console.log(`Updating sections for ${s.term} ${s.year}...`); -} + const params = { + "term-id": semToTermId(s), + "page-size": 100, + }; + + const semesterClasses = await queryPages( + SIS_SECTION_URL, + params, + headers, + "classSections" + ); + sections.push(...semesterClasses); + } + + console.log("Updating database with new section data..."); + const bulkOps = sections.map((s) => ({ + replaceOne: { + filter: { displayName: s.displayName }, + replacement: s, + upsert: true, + }, + })); + + const options = {} as MongooseBulkWriteOptions; + + const res = await SectionModel.bulkWrite(bulkOps, options); + + console.log( + `Completed updating database with new section data. Created ${res.upsertedCount} and updated ${res.modifiedCount} section objects.` + ); +}; (async () => { - try { - await mongooseLoader(); + try { + await mongooseLoader(); - console.log("\n=== UPDATE COURSES ===") - await updateCourses(); + console.log("\n=== UPDATE COURSES ==="); + await updateCourses(); - console.log("\n=== UPDATE CLASSES ===") - await updateClasses(); + console.log("\n=== UPDATE CLASSES ==="); + await updateClasses(); - console.log("\n=== UPDATE SECTIONS ===") - await updateSections(); - } catch (err) { - console.error(err); - process.exit(1); - } + console.log("\n=== UPDATE SECTIONS ==="); + await updateSections(); + } catch (err) { + console.error(err); + process.exit(1); + } - process.exit(0); -})(); \ No newline at end of file + process.exit(0); +})(); diff --git a/backend/src/utils/term.ts b/backend/src/utils/term.ts index 0e07459ef..90f97ffb1 100644 --- a/backend/src/utils/term.ts +++ b/backend/src/utils/term.ts @@ -21,6 +21,7 @@ export function getTermStartMonth(term: TermInput) { "Fall": `${term.year}-08-31`, "Spring": `${term.year}-01-31`, "Summer": `${term.year}-05-31`, + "Winter": `${term.year}-11-30`, } return startDates[term.semester]; diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs new file mode 100644 index 000000000..9e6b0116c --- /dev/null +++ b/frontend/.eslintrc.cjs @@ -0,0 +1,15 @@ +module.exports = { + root: true, + env: { browser: true, es2020: true }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:react-hooks/recommended' + ], + ignorePatterns: ['dist', '.eslintrc.cjs'], + parser: '@typescript-eslint/parser', + plugins: ['react-refresh'], + rules: { + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }] + } +}; diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js deleted file mode 100644 index 92bafc4d2..000000000 --- a/frontend/.eslintrc.js +++ /dev/null @@ -1,32 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaFeatures: { - jsx: true - }, - ecmaVersion: 12, - sourceType: 'module' - }, - extends: [ - 'eslint:recommended', - 'plugin:react/recommended', - 'plugin:react-hooks/recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react/jsx-runtime', - 'prettier' - ], - plugins: ['react'], - rules: { - 'no-labels': 'off', - 'no-console': 'warn', - 'react/prop-types': 'off', - 'indent': [2, 'tab', { SwitchCase: 1, VariableDeclarator: 1 }], - '@typescript-eslint/no-unused-vars': ['warn', { varsIgnorePattern: '^_' }] - }, - ignorePatterns: ['build', '**/*.js', '**/*.json', 'node_modules'], - settings: { - react: { - version: 'detect' - } - } -}; diff --git a/frontend/.gitignore b/frontend/.gitignore index 823223b84..5494d6a0c 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -1,4 +1,4 @@ -build/ +dist/ node_modules/ tmpaddon @@ -7,6 +7,3 @@ tmpaddon .vscode/* !.vscode/launch.json -stats.html - -src/assets/scss/berkeleytime.css diff --git a/frontend/.graphqlrc.yml b/frontend/.graphqlrc.yml deleted file mode 100644 index 84b8ef558..000000000 --- a/frontend/.graphqlrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -schema: - - ./schema.graphql -documents: 'src/**/*.{graphql,js,ts,jsx,tsx}' diff --git a/frontend/.prettierignore b/frontend/.prettierignore deleted file mode 100644 index cff85d3bf..000000000 --- a/frontend/.prettierignore +++ /dev/null @@ -1 +0,0 @@ -_colors.scss diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 000000000..a8c0bd6e2 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,31 @@ +{ + "arrowParens": "always", + "bracketSpacing": true, + "endOfLine": "lf", + "htmlWhitespaceSensitivity": "css", + "insertPragma": false, + "singleAttributePerLine": false, + "bracketSameLine": false, + "jsxSingleQuote": false, + "printWidth": 80, + "proseWrap": "preserve", + "quoteProps": "as-needed", + "requirePragma": false, + "semi": true, + "singleQuote": false, + "tabWidth": 2, + "trailingComma": "es5", + "useTabs": false, + "importOrder": [ + "^react$", + "", + "^@/(.*)$", + "^[../]", + "^[./]" + ], + "importOrderSeparation": true, + "importOrderSortSpecifiers": true, + "plugins": [ + "@trivago/prettier-plugin-sort-imports" + ] +} diff --git a/frontend/.prettierrc.js b/frontend/.prettierrc.js deleted file mode 100644 index 43491e5e7..000000000 --- a/frontend/.prettierrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - useTabs: true, - printWidth: 100, - singleQuote: true, - trailingComma: 'none', - bracketSameLine: false, - semi: true, - tabWidth: 2, - quoteProps: 'consistent' -}; diff --git a/frontend/Dockerfile b/frontend/Dockerfile index c3c211e5c..29e06bb0f 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,13 +1,13 @@ -FROM node:14-slim@sha256:4402144207a33ba95cb1119be593b9a9699721ad46e15acd32a0b5ca8784a527 AS dev +FROM node:20 AS dev RUN mkdir /frontend WORKDIR /frontend COPY package.json . RUN npm install COPY . . -ENTRYPOINT npm start +ENTRYPOINT npm run dev FROM dev AS prod RUN npm install -g serve RUN npm run build RUN rm -rf node_modules -ENTRYPOINT npm run prod +ENTRYPOINT npm run start diff --git a/frontend/codegen.yml b/frontend/codegen.yml deleted file mode 100644 index 98666c910..000000000 --- a/frontend/codegen.yml +++ /dev/null @@ -1,33 +0,0 @@ -overwrite: true -schema: - - ./schema.graphql -documents: - - 'src/**/*.graphql' -watchConfig: - usePolling: true - interval: 1000 -generates: - src/graphql/index.ts: - plugins: - - typescript - - typescript-operations - - typescript-react-apollo - - add: - content: > - /* eslint-disable */ - /** - * - * THIS FILE IS AUTOGENERATED, DO NOT EDIT IT! - * - * instead, edit one of the `.graphql` files in this project and run - * - * npm run graphql-codegen - * - * for this file to be re-created - */ - config: - maybeValue: T # Assert non-nullable - avoidOptionals: true - nonOptionalTypename: true - skipTypename: false - defaultScalarType: 'unknown' diff --git a/frontend/frontend.rst b/frontend/frontend.rst deleted file mode 100644 index 4faba6251..000000000 --- a/frontend/frontend.rst +++ /dev/null @@ -1,5 +0,0 @@ -Frontend -********* - -.. toctree:: - :caption: Contents: diff --git a/frontend/index.html b/frontend/index.html new file mode 100644 index 000000000..01d6b7aa2 --- /dev/null +++ b/frontend/index.html @@ -0,0 +1,17 @@ + + + + + + + + + + + Berkeleytime + + +
+ + + diff --git a/frontend/package.json b/frontend/package.json index c4fbfcd01..14f85ed7e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,86 +1,54 @@ { "name": "berkeleytime", - "version": "1.0.0", + "version": "0.0.0", "private": true, - "description": "Berkeleytime Frontend", - "main": "index.js", - "keywords": [], - "author": "", - "license": "UNLICENSED", + "type": "module", "scripts": { - "codegen": "graphql-codegen --config codegen.yml", - "build:js": "vite build --emptyOutDir", - "watch:js": "vite", - "watch:codegen": "graphql-codegen --config codegen.yml --watch", - "start": "npm-run-all codegen -p watch:*", - "build": "npm-run-all codegen -p build:*", - "lint": "eslint ./**/* --fix --ext .jsx --ext .tsx --ext .scss", - "prod": "serve -s build -p 3000" + "dev": "vite", + "build": "tsc && vite build", + "lint": "eslint --ext .tsx,.ts src/ --report-unused-disable-directives", + "start": "serve -s dist -p 3000" }, "dependencies": { - "@apollo/client": "^3.2.5", - "axios": "^1.2.6", - "bootstrap": "^4.5.2", - "color": "^3.1.3", - "date-fns": "^2.21.1", - "graphql": "^15.4.0", - "iconoir-react": "^6.4.0", - "object-hash": "^3.0.0", - "react": "^18.0.0", - "react-bootstrap": "^1.3.0", - "react-cool-dimensions": "^3.0.0", - "react-dom": "^18.0.0", - "react-ga": "^3.3.1", - "react-ios-switch": "^0.1.19", - "react-loading-skeleton": "^3.1.1", - "react-markdown": "^8.0.5", - "react-redux": "^7.2.0", - "react-router": "^5.0.1", - "react-router-dom": "^5.0.1", - "react-select": "^5.7.0", - "react-tooltip": "^5.7.2", - "react-window": "^1.8.5", - "recharts": "^2.3.2", - "redux": "^4.0.4", - "redux-thunk": "^2.3.0" + "@apollo/client": "^3.10.5", + "@floating-ui/dom": "^1.6.5", + "@mapbox/mapbox-gl-directions": "^4.3.1", + "@radix-ui/react-checkbox": "^1.0.4", + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-hover-card": "^1.0.7", + "@radix-ui/react-radio-group": "^1.1.3", + "@radix-ui/react-scroll-area": "^1.0.5", + "@radix-ui/react-select": "^2.0.0", + "@radix-ui/react-tooltip": "^1.0.7", + "@shopify/draggable": "^1.1.3", + "@tanstack/react-virtual": "^3.5.1", + "classnames": "^2.5.1", + "fuse.js": "^7.0.0", + "graphql": "^16.8.2", + "iconoir-react": "^7.7.0", + "mapbox-gl": "^3.4.0", + "moment": "^2.30.1", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "react-router-dom": "^6.23.1", + "recharts": "^2.12.7" }, "devDependencies": { - "@babel/eslint-parser": "^7.19.1", - "@graphql-codegen/add": "^4.0.0", - "@graphql-codegen/cli": "3.0.0", - "@graphql-codegen/near-operation-file-preset": "^2.5.0", - "@graphql-codegen/typed-document-node": "^3.0.0", - "@graphql-codegen/typescript": "3.0.0", - "@graphql-codegen/typescript-operations": "^3.0.0", - "@graphql-codegen/typescript-react-apollo": "3.3.7", - "@graphql-codegen/typescript-rtk-query": "^2.4.0", - "@graphql-typed-document-node/core": "^3.1.1", - "@types/color": "^3.0.1", - "@types/node": "^14.6.1", - "@types/react": "^18.0.27", - "@types/react-dom": "^18.0.10", - "@types/react-redux": "^7.1.9", - "@types/react-router-dom": "^5.1.5", - "@types/react-select": "^3.0.27", - "@types/react-window": "^1.8.2", - "@types/recharts": "^1.8.15", - "@typescript-eslint/eslint-plugin": "^5.48.0", - "@typescript-eslint/parser": "^5.48.0", - "@vitejs/plugin-react-swc": "^3.0.0", - "eslint": "^8.31.0", - "eslint-config-prettier": "^8.6.0", - "eslint-plugin-jsx-a11y": "^6.3.0", - "eslint-plugin-react": "^7.32.0", - "eslint-plugin-react-hooks": "^4.6.0", - "npm-run-all": "^4.1.5", - "prettier": "^2.2.0", - "rollup-plugin-visualizer": "^5.9.0", - "sass": "^1.50.1", - "serve": "^14.2.0", - "typescript": "^4.9.5", - "vite": "^4.0.4", - "vite-plugin-html": "^3.2.0", - "vite-plugin-svgr": "^2.4.0", - "vite-tsconfig-paths": "^4.0.5" + "@trivago/prettier-plugin-sort-imports": "^4.3.0", + "@types/mapbox-gl": "^3.1.0", + "@types/node": "^20.14.2", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", + "@vitejs/plugin-react": "^4.3.1", + "eslint": "^8.57.0", + "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.7", + "prettier": "^3.3.2", + "sass": "^1.77.5", + "serve": "^14.2.3", + "typescript": "^5.4.5", + "vite": "^5.3.1" } } diff --git a/frontend/public/geojson/campus.geojson b/frontend/public/geojson/campus.geojson new file mode 100644 index 000000000..cd2d41dd8 --- /dev/null +++ b/frontend/public/geojson/campus.geojson @@ -0,0 +1,612 @@ +{ + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {}, + "geometry": { + "coordinates": [ + [ + [ + -122.25233936184476, + 37.86960944156671 + ], + [ + -122.252337422598, + 37.86968215708505 + ], + [ + -122.25235972384161, + 37.86982758792344 + ], + [ + -122.25239075165935, + 37.86995005577522 + ], + [ + -122.25241645142373, + 37.870043854766266 + ], + [ + -122.25244263114467, + 37.8701188661294 + ], + [ + -122.25249558011436, + 37.870263959551096 + ], + [ + -122.25254309145993, + 37.870383365001416 + ], + [ + -122.25266230842968, + 37.87062845670471 + ], + [ + -122.25272650982454, + 37.870774236941244 + ], + [ + -122.25275947688021, + 37.870934973889874 + ], + [ + -122.25278372709457, + 37.87110303625275 + ], + [ + -122.2527871507256, + 37.871315983356155 + ], + [ + -122.25278690087251, + 37.87142683974592 + ], + [ + -122.25279059540784, + 37.87147253047549 + ], + [ + -122.25280660506087, + 37.871537664020565 + ], + [ + -122.25283554558786, + 37.8716402249331 + ], + [ + -122.25288430163148, + 37.87179302153223 + ], + [ + -122.25300437871154, + 37.871942361430555 + ], + [ + -122.25315413330472, + 37.87208024791062 + ], + [ + -122.25326250634174, + 37.87215753259184 + ], + [ + -122.2534392413748, + 37.872289089911945 + ], + [ + -122.25369327398631, + 37.87247985750666 + ], + [ + -122.25376347015799, + 37.872529436099626 + ], + [ + -122.253910289627, + 37.872636292109874 + ], + [ + -122.25394253049413, + 37.87265785642758 + ], + [ + -122.25408477010487, + 37.87273902900786 + ], + [ + -122.25411494214354, + 37.87275409696187 + ], + [ + -122.25429712559372, + 37.87282876041688 + ], + [ + -122.25441596648076, + 37.872893406700584 + ], + [ + -122.25449313953968, + 37.87293474471399 + ], + [ + -122.25458611867936, + 37.87299939090468 + ], + [ + -122.25470372805472, + 37.873097575235974 + ], + [ + -122.25484324347346, + 37.87323210168215 + ], + [ + -122.25494439941036, + 37.87333543667445 + ], + [ + -122.2550336840147, + 37.87342584362159 + ], + [ + -122.25512187424519, + 37.873512711066 + ], + [ + -122.25517729227553, + 37.873528264919486 + ], + [ + -122.2553184831308, + 37.87365421840147 + ], + [ + -122.2553972998848, + 37.87375191580384 + ], + [ + -122.2555553491108, + 37.873945903639466 + ], + [ + -122.25560514783385, + 37.87407076641021 + ], + [ + -122.25560576358951, + 37.87411159496057 + ], + [ + -122.25602072145944, + 37.8746151943878 + ], + [ + -122.25613738661002, + 37.874750004572945 + ], + [ + -122.25625864627527, + 37.874852768791754 + ], + [ + -122.25642674763365, + 37.87496601815502 + ], + [ + -122.25651959818845, + 37.87504244758763 + ], + [ + -122.25661588185903, + 37.87514368101898 + ], + [ + -122.25671501855771, + 37.87528657876378 + ], + [ + -122.25680548780298, + 37.875435784444576 + ], + [ + -122.2568381228653, + 37.87550383075438 + ], + [ + -122.25737220400174, + 37.87543037910869 + ], + [ + -122.25780541522607, + 37.875378079950096 + ], + [ + -122.2581984860895, + 37.875328336788456 + ], + [ + -122.25845054638968, + 37.875294116744826 + ], + [ + -122.25876867778402, + 37.875251995206895 + ], + [ + -122.25922069245087, + 37.87519421878386 + ], + [ + -122.25955500344404, + 37.875153759097984 + ], + [ + -122.25987421174636, + 37.87510957827169 + ], + [ + -122.26007865834642, + 37.87508207753305 + ], + [ + -122.26024306516948, + 37.87504319371247 + ], + [ + -122.26069667445331, + 37.874987297708344 + ], + [ + -122.26081065176747, + 37.87497356366633 + ], + [ + -122.2609762901022, + 37.874914751793 + ], + [ + -122.2614422996489, + 37.874855385856975 + ], + [ + -122.26206195032826, + 37.87477692340127 + ], + [ + -122.2624271409097, + 37.87473094279311 + ], + [ + -122.26281468182924, + 37.87468038564566 + ], + [ + -122.26315932307057, + 37.87463733115874 + ], + [ + -122.26362752087122, + 37.87457780931413 + ], + [ + -122.26375128856151, + 37.87456128329961 + ], + [ + -122.2639261632346, + 37.87457197642206 + ], + [ + -122.264117047561, + 37.874525801563095 + ], + [ + -122.26414766416737, + 37.87451901183222 + ], + [ + -122.26443214338916, + 37.8744256899149 + ], + [ + -122.26463134826994, + 37.87434451323365 + ], + [ + -122.26467589082353, + 37.87432973418001 + ], + [ + -122.26493389254196, + 37.874293766279294 + ], + [ + -122.26531723732158, + 37.87424081320731 + ], + [ + -122.26572295195447, + 37.87419211142539 + ], + [ + -122.26608132277082, + 37.87414836623293 + ], + [ + -122.26613642906283, + 37.874144655871504 + ], + [ + -122.26626142750858, + 37.87413590690237 + ], + [ + -122.26627374262657, + 37.874133962687 + ], + [ + -122.26619985191954, + 37.87407660830621 + ], + [ + -122.26618076348686, + 37.87395315041975 + ], + [ + -122.26615600008947, + 37.87374793727798 + ], + [ + -122.2661315548244, + 37.873561207549365 + ], + [ + -122.26610710955933, + 37.87337447782075 + ], + [ + -122.26606824017925, + 37.87301342150939 + ], + [ + -122.26602684228128, + 37.87266324527806 + ], + [ + -122.26601155479977, + 37.87254084695806 + ], + [ + -122.26600833956522, + 37.872482644367466 + ], + [ + -122.26600477444234, + 37.872458514400996 + ], + [ + -122.2659986787443, + 37.872386442428635 + ], + [ + -122.26599574626522, + 37.872357817938095 + ], + [ + -122.2659814261998, + 37.87224729239772 + ], + [ + -122.2659629083677, + 37.87210115076131 + ], + [ + -122.26594384347477, + 37.87195616628634 + ], + [ + -122.26591845214459, + 37.87172328752212 + ], + [ + -122.26585484670002, + 37.87112260421783 + ], + [ + -122.26579421334036, + 37.8706110750866 + ], + [ + -122.265794910126, + 37.87054938950661 + ], + [ + -122.26575662141639, + 37.87022644888975 + ], + [ + -122.26575828165525, + 37.87017642214872 + ], + [ + -122.26572790488399, + 37.86993321417789 + ], + [ + -122.26572311879538, + 37.8698479760245 + ], + [ + -122.26571833270677, + 37.86974866075874 + ], + [ + -122.26574775108227, + 37.869624560631905 + ], + [ + -122.26578064079783, + 37.86955613226104 + ], + [ + -122.26582132635929, + 37.8694900251061 + ], + [ + -122.26601539418186, + 37.86915239148087 + ], + [ + -122.26611646821031, + 37.8689771960196 + ], + [ + -122.26615690493128, + 37.86890713965598 + ], + [ + -122.26618522130052, + 37.868795621886306 + ], + [ + -122.26616817832787, + 37.86873212372869 + ], + [ + -122.26607481437932, + 37.868518581778225 + ], + [ + -122.26600187164269, + 37.86835918665301 + ], + [ + -122.26595934009875, + 37.86825716369174 + ], + [ + -122.26595423479566, + 37.86822050445798 + ], + [ + -122.26590320073701, + 37.86815911837685 + ], + [ + -122.26585748312144, + 37.868074206027394 + ], + [ + -122.26578614290652, + 37.86799028796635 + ], + [ + -122.26573633238881, + 37.86796347850223 + ], + [ + -122.26565688554724, + 37.86794210031823 + ], + [ + -122.2654434370846, + 37.8679409793663 + ], + [ + -122.2652623095597, + 37.86796696814409 + ], + [ + -122.26442184715064, + 37.86807537294557 + ], + [ + -122.2637452756259, + 37.86817227732192 + ], + [ + -122.26306646102545, + 37.86826385600699 + ], + [ + -122.262427708641, + 37.86833818404452 + ], + [ + -122.26227334487223, + 37.8683435097967 + ], + [ + -122.26187132376562, + 37.86838333668726 + ], + [ + -122.2616572887386, + 37.868414113996394 + ], + [ + -122.26145557871435, + 37.868426627569214 + ], + [ + -122.26088126114529, + 37.868501886533934 + ], + [ + -122.26061959649843, + 37.86852801566544 + ], + [ + -122.25997916180721, + 37.86862027178944 + ], + [ + -122.25926252806666, + 37.868709988485236 + ], + [ + -122.25909723823816, + 37.86872897111115 + ], + [ + -122.25834922526408, + 37.86882845593595 + ], + [ + -122.25684105688666, + 37.8690205632727 + ], + [ + -122.25591299242652, + 37.86914087239033 + ], + [ + -122.25539732942917, + 37.86920831521433 + ], + [ + -122.25482471072381, + 37.86928345285854 + ], + [ + -122.25412617713565, + 37.86937515697852 + ], + [ + -122.25323276949021, + 37.869492299272615 + ], + [ + -122.25233936184476, + 37.86960944156671 + ] + ] + ], + "type": "Polygon" + } + } + ] +} \ No newline at end of file diff --git a/frontend/public/images/lower-left-grid.svg b/frontend/public/images/lower-left-grid.svg new file mode 100644 index 000000000..0eb3154fe --- /dev/null +++ b/frontend/public/images/lower-left-grid.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/images/upper-right-grid.svg b/frontend/public/images/upper-right-grid.svg new file mode 100644 index 000000000..58e572c52 --- /dev/null +++ b/frontend/public/images/upper-right-grid.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/positions.md b/frontend/public/positions.md deleted file mode 100644 index 038867729..000000000 --- a/frontend/public/positions.md +++ /dev/null @@ -1,105 +0,0 @@ -We're a group of student volunteers at UC Berkeley that work on projects like Berkeleytime (course discovery site), Berkeley Mobile (campus resource mobile app), Beehive (research matching website), and the API team (degree requirements API). We love seeing applicants who are passionate about helping students, are great at working in groups, and are constantly eager to learn. - ---- - -### Frontend Engineer - -**Teams:** Berkeleytime, Beehive - -Our frontend engineers create the interface that users see and interact with, working with designers to implement new features and improvements. - -**We are looking for...** - -- Experience working with React -- Experience working with basic frontend, eg HTML / CSS / JS - ---- - -### Backend Engineer - -**Teams:** Berkeleytime, Berkeley Mobile, Beehive, API Team - -Berkeleytime: Our engineers design, implement, and iterate on our product Django core backend API service and learn to use industry standard tools and practices. We prefer experience in technologies like git, MongoDB, REST APIs / HTTP, Django, and PostgreSQL. - -Berkeley Mobile: Berkeley Mobile's backend team develops and maintains the backend of our mobile app. We are at the forefront of creating new features and support for the app. We work with cloud technologies and primarily develop in Python. - -Beehive: Beehive was built with Rails4 and our backend engineers are developing new features including improvements to infrastructure, notifications, data monitoring and analytics. We prefer experience with Ruby on Rails. - -API Team: Our backend engineers will be building the API infrastructure and functionality. We prefer experience databases such as SQL, MongoDB, etc. and the design and development of REST APIs. - -**We are looking for...** - -- Experience with one or more general purpose programming languages including but not limited to: Python, Java, C++ -- (Bonus) Software development experience in cloud technologies such as Google Cloud Platform, Amazon Web Services, Microsoft Azure, Docker, Apache, etc. - ---- - -### Infrastructure Engineer - -**Teams:** Berkeleytime, Berkeley Mobile, Beehive, API Team - -The infrastructure engineer is a special position on the backend team that focuses on development specific to our core infrastructure. Infrastructure engineers are not as product or feature driven as the other backend engineers, but rather work systems and projects that support our compute, networking, and deployment. If you are interested in low level work or distributed systems work, this may be the right position for you. - -**We are looking for...** - -- Experience with one or more general purpose programming languages including but not limited to: Python, Java, C++ -- Experience in technologies like PostgreSQL, Docker, and Kubernetes. -- (Bonus) Experience with Redis, Elasticsearch / Kibana, Nginx, and Linux / UNIX - ---- - -### iOS Engineer - -**Teams:** Berkeley Mobile - -Our frontend iOS team is dedicated to building and improving Berkeley Mobile on iOS platforms by developing new features and addressing issues to improve the functionality and usability of the app. - -As an iOS developer, you will identify and address areas of improvement in the user interface and functionality of the app in weekly 1-2 hour hack sessions during 2-week long sprints. - -**We are looking for...** - -- Experience with Objective-C or Swift -- Experience developing for Apple platforms (Xcode, UIKit, Cocoa Touch, etc.) - ---- - -### Android Engineer - -**Teams:** Berkeley Mobile - -The Berkeley Mobile Android team aims to enrich campus life by creating visible and impactful features for students. The tools we use include Java, Firebase, and Google Maps SDK. As an Android developer, you will refine your software engineering skills while designing, implementing, and testing features on the Android app that directly impact students. - -**We are looking for...** - -- Java proficiency -- (Preferred) Android development experience -- (Preferred) Software engineering experience - ---- - -### Product Designer - -**Teams:** Berkeley Mobile, Berkeleytime, and Beehive - -As a product designer, you will collaborate with design and engineering teams to cook up new and exciting features, organize and execute user research studies, and support the current design lead on existing projects. - -**We are looking for...** - -- Experience with design tools like Figma, Adobe XD, Sketch, and Illustrator -- Design generalists: experience working across the spectrum of design, including user - research, visual design, and prototyping in both web and mobile mediums -- Experience collaborating with engineers to deliver on real-life projects - ---- - -### Marketing Associate - -**Teams:** Berkeley Mobile, Berkeleytime, and Beehive - -As a marketing associate, you will be promoting our products to gain more active users and building our brand. - -**We are looking for...** - -- Great communication skills -- Experience with designing advertisements and online marketing campaigns -- (Bonus) Experience with tools such as Adobe Sketch, Illustrator diff --git a/frontend/public/stf_guide.md b/frontend/public/stf_guide.md deleted file mode 100644 index 651214dcc..000000000 --- a/frontend/public/stf_guide.md +++ /dev/null @@ -1,7 +0,0 @@ -### How are we affiliated with the STF? - -Since 2015, Berkeleytime has largely been funded by the Student Tech Fund (STF). Although our entire team is composed of unpaid volunteers 🙋, we have relied on our grant to fund web hosting, user research, and a reliable backend uptime. Instead of begging you for money à la Wikipedia style 💸, we've focused on launching a number of new features like Berkeleytime on mobile, user profiles, and an improved search experience. - -Aside from funding Berkeleytime, the STF has funded a number of [widely recognized services and projects](https://techfund.berkeley.edu/impact/funded-projects/grantee-project-profiles) such as access to ZoomPro, the Adobe Suite, and the Student Technology Equity Program (STEP). - -We just wanted to add this note and show our appreciation for all of the work the STF has done in the background. You can learn more about the renewal of the fund [here](https://techfund.berkeley.edu/renewal-ballot). diff --git a/frontend/schema.graphql b/frontend/schema.graphql index ef41b828f..2d58ce8f2 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -1,879 +1,634 @@ -type BerkeleytimeUserType { - id: ID! - user: UserType! - major: String! - savedClasses: [CourseType] - emailClassUpdate: Boolean - emailGradeUpdate: Boolean - emailEnrollmentOpening: Boolean - emailBerkeleytimeUpdate: Boolean - schedules(before: String, after: String, first: Int, last: Int): ScheduleTypeConnection! -} - -type CourseType implements Node { - """ - The ID of the object. - """ - id: ID! - title: String! - department: String! - abbreviation: String! - courseNumber: String! - description: String! - units: String - crossListing( - before: String - after: String - first: Int - last: Int - title: String - department: String - abbreviation: String - courseNumber: String - description: String - units: String - crossListing: [ID] - prerequisites: String - gradeAverage: Float - letterAverage: String - hasEnrollment: Boolean - enrolled: Int - enrolledMax: Int - enrolledPercentage: Float - waitlisted: Int - openSeats: Int - lastUpdated: DateTime - hasGrades: Boolean - inPlaylists: String - idIn: String - ): CourseTypeConnection! - prerequisites: String! - gradeAverage: Float - letterAverage: String! - hasEnrollment: Boolean! - enrolled: Int! - enrolledMax: Int! - enrolledPercentage: Float! - waitlisted: Int! - openSeats: Int! - lastUpdated: DateTime! - sectionSet( - before: String - after: String - first: Int - last: Int - course: ID - abbreviation: String - courseNumber: String - year: String - semester: String - courseTitle: String - sectionNumber: String - ccn: String - kind: String - isPrimary: Boolean - associatedSections: [ID] - days: String - startTime: DateTime - endTime: DateTime - finalDay: String - finalEnd: DateTime - finalStart: DateTime - instructor: String - disabled: Boolean - locationName: String - instructionMode: String - lastUpdated: DateTime - enrolled: Int - enrolledMax: Int - waitlisted: Int - waitlistedMax: Int - ): SectionTypeConnection! - gradeSet( - before: String - after: String - first: Int - last: Int - course: ID - semester: String - year: String - abbreviation: String - courseNumber: String - sectionNumber: String - instructor: String - gradedTotal: Int - average: Float - ): GradeTypeConnection! - playlistSet( - before: String - after: String - first: Int - last: Int - category: String - name: String - semester: String - year: String - courses: [ID] - ): PlaylistTypeConnection! - berkeleytimeuserSet: [BerkeleytimeUserType!]! - schedulerSections( - before: String - after: String - first: Int - last: Int - ): SectionSelectionTypeConnection! -} - -type CourseTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [CourseTypeEdge]! -} - -""" -A Relay edge containing a `CourseType` and its cursor. -""" -type CourseTypeEdge { - """ - The item at the end of the edge - """ - node: CourseType - - """ - A cursor for use in pagination - """ - cursor: String! -} - -type CreateSchedule { - schedule: ScheduleType -} +directive @cacheControl( + maxAge: Int + scope: CacheControlScope + inheritMaxAge: Boolean +) on FIELD_DEFINITION | OBJECT | INTERFACE | UNION -""" -The `Date` scalar type represents a Date -value as specified by -[iso8601](https://en.wikipedia.org/wiki/ISO_8601). -""" -scalar Date +directive @auth on OBJECT | FIELD_DEFINITION """ -The `DateTime` scalar type represents a DateTime -value as specified by -[iso8601](https://en.wikipedia.org/wiki/ISO_8601). +User account info. """ -scalar DateTime - -type DeleteUser { - success: Boolean +type User { + email: String! + username: String! + first_name: String! + last_name: String! + major: [String!]! + last_login: String! + date_joined: String! + is_staff: Boolean! + is_active: Boolean! + email_class_update: Boolean! + email_grade_update: Boolean! + email_enrollment_opening: Boolean! + email_berkeleytime_update: Boolean! } """ -Proxy for enrollment object. Using this instead of -a DjangoObjectType gives us higher flexibility of the data. +User input type for mutations. """ -type EnrollmentData { - day: Int - dateCreated: Date - enrolled: Int - enrolledMax: Int - enrolledPercent: Float - waitlisted: Int - waitlistedMax: Int - waitlistedPercent: Float +input UserInput { + username: String + first_name: String + last_name: String + major: [String!] + email_class_update: Boolean + email_grade_update: Boolean + email_enrollment_opening: Boolean + email_berkeleytime_update: Boolean } -""" -The return format of both queries -""" -type EnrollmentInfo { - course: CourseType - section: [SectionType] - telebears: TelebearData - data: [EnrollmentData] - enrolledMax: Int - enrolledPercentMax: Float - enrolledScaleMax: Int - waitlistedMax: Int - waitlistedPercentMax: Float - waitlistedScaleMax: Int +type Query { + """ + Query for user info. + """ + user: User + grade( + subject: String! + courseNum: String! + classNum: String + term: TermInput + ): Grade + course(subject: String!, courseNumber: String!, term: TermInput): Course + class( + subject: String! + courseNumber: String! + term: TermInput! + classNumber: String! + ): Class + section( + subject: String! + courseNumber: String! + term: TermInput! + classNumber: String! + sectionNumber: String! + ): Section + + """ + Get info about all courses and their corresponding classes for a given semester. + + Used primarily in the catalog page. + """ + catalog(term: TermInput!): [Course!] + + """ + Get a list of all course names across all semesters. + + Useful for searching for courses. + """ + courseList: [Course!] + ping: String! @deprecated(reason: "test") + + """ + Takes in a user's email and returns all the schedules they created. + """ + schedulesByUser(created_by: String!): [Schedule] + + """ + Takes in a schedule's ObjectID and returns a specific schedule. + """ + scheduleByID(id: String!): Schedule } -type FormConfigType { - field: JSONString -} +type Mutation { + """ + Mutate user info. + """ + updateUserInfo(newUserInfo: UserInput!): User + + """ + Delete user account. + """ + deleteUser: User + + """ + Takes in a schedule's ObjectID, deletes the schedule with that ID, and returns the ID. + """ + removeScheduleByID(id: ID!): ID + + """ + Takes in schedule fields, creates a new schedule record in the database, and returns the schedule. + """ + createNewSchedule(main_schedule: ScheduleInput!): Schedule + + """ + Takes in schedule fields, finds the schedule record in the database corresponding to the provided ID, updates the record, and returns the updated schedule. + """ + editExistingSchedule(id: ID!, main_schedule: ScheduleInput!): Schedule + + """ + For the schedule specified by the ID, modifies the courses field and returns the updated schedule. + """ + setSelectedClasses(id: ID!, courses: [SelectedCourseInput!]!): Schedule +} + +type Grade { + average: Float + distribution: [GradeDistributionItem] +} + +type GradeDistributionItem { + letter: String! + count: Int! +} + +""" +Info shared between Classes within and across semesters. +""" +type Course { + classes(term: TermInput): [Class!]! + crossListing: [Course!]! + sections(term: TermInput, primary: Boolean): [Section!]! + requiredCourses: [Course!]! + requirements: String + description: String! + fromDate: String! + gradeAverage: Float + gradingBasis: CourseGradingBasis! + finalExam: CourseFinalExam! + academicCareer: AcademicCareer! + number: String! + subject: String! + title: String! + toDate: String! + raw: JSONObject! + lastUpdated: ISODate! +} + +enum AcademicCareer { + """ + Undergraduate + """ + UGRD + + """ + Graduate + """ + GRAD + + """ + UC Extension + """ + UCBX +} + +enum CourseFinalExam { + """ + To be decided by the instructor when the class is offered + """ + D + + """ + No final exam + """ + N + + """ + Alternative method of final assessment + """ + A + + """ + Common Final Exam + """ + C + + """ + Written final exam conducted during the scheduled final exam period + """ + Y +} + +enum CourseGradingBasis { + completedNotation + passFail + letter + satisfactory + graded +} + +""" +Data for a specific class in a specific semester. There may be more than one Class for a given Course in a given semester. +""" +type Class { + course: Course! + primarySection: Section! + sections: [Section!]! + session: Session! + gradingBasis: ClassGradingBasis! + finalExam: ClassFinalExam! + description: String + title: String + number: String! + semester: Semester! + year: Int! + unitsMax: Float! + unitsMin: Float! + raw: JSONObject! + lastUpdated: ISODate! +} + +enum ClassFinalExam { + """ + Yes + """ + Y + + """ + No + """ + N + + """ + Alernate Method + """ + A +} + +enum ClassGradingBasis { + """ + Elective Satisfactory/Unsat + """ + ESU + + """ + Satisfactory/Unsatisfactory + """ + SUS + + """ + Student Option + """ + OPT + + """ + Pass/Not Pass + """ + PNP + + """ + Multi-Term Course: Not Graded + """ + BMT + + """ + Graded + """ + GRD + + """ + Instructor Option + """ + IOP +} + +enum Session { + """ + Regular Academic Session + """ + R + + """ + 12-Week Summer Session + """ + S + + """ + Session A + """ + A + + """ + Session B + """ + B + + """ + Session C + """ + C + + """ + Session D + """ + D + + """ + Session E + """ + E + + """ + Session F + """ + F +} + +""" +Sections are each associated with one Class. +""" +type Section { + class: Class! + course: Course! + enrollmentHistory: [EnrollmentDay!] + ccn: Int! + number: String! + primary: Boolean! + component: Component! + meetings: [Meeting!]! + exams: [Exam!]! + startDate: String! + endDate: String! + online: Boolean! + open: Boolean! + reservations: [Reservation!] + enrollCount: Int! + waitlistCount: Int! + enrollMax: Int! + waitlistMax: Int! + raw: JSONObject! + lastUpdated: ISODate! +} + +enum Component { + """ + Workshop + """ + WOR + + """ + Web-Based Discussion + """ + WBD + + """ + Clinic + """ + CLN + + """ + Practicum + """ + PRA + + """ + Directed Group Study + """ + GRP + + """ + Discussion + """ + DIS + + """ + Voluntary + """ + VOL + + """ + Tutorial + """ + TUT + + """ + Field Work + """ + FLD + + """ + Lecture + """ + LEC + + """ + Supplementary + """ + SUP + + """ + Laboratory + """ + LAB + + """ + Session + """ + SES + + """ + Studio + """ + STD -""" -The `GenericScalar` scalar type represents a generic -GraphQL scalar value that could be: -String, Boolean, Int, Float, List or Object. -""" -scalar GenericScalar - -type GradeType implements Node { - """ - The ID of the object. - """ - id: ID! - course: CourseType! - semester: String! - year: String! - abbreviation: String! - courseNumber: String! - sectionNumber: String! - instructor: String! - instructors: [String!]! - gradedTotal: Int! - average: Float! - distribution: [LetterGradeType] - sectionGpa: Float - sectionLetter: String - denominator: Int -} - -type GradeTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [GradeTypeEdge]! -} + """ + Self-paced + """ + SLF -""" -A Relay edge containing a `GradeType` and its cursor. -""" -type GradeTypeEdge { - """ - The item at the end of the edge - """ - node: GradeType + """ + Colloquium + """ + COL - """ - A cursor for use in pagination - """ - cursor: String! -} + """ + Web-Based Lecture + """ + WBL -""" -Allows use of a JSON String for input / output from the GraphQL schema. + """ + Independent Study + """ + IND -Use of this type is *not recommended* as you lose the benefits of having a defined, static -schema (one of the key benefits of GraphQL). -""" -scalar JSONString + """ + Internship + """ + INT -type LetterGradeType { - letter: String - numerator: Int - percent: Float - percentileHigh: Float - percentileLow: Float -} + """ + Reading + """ + REA + + """ + Recitation + """ + REC -type Logout { - success: Boolean + """ + Seminar + """ + SEM } -type Mutation { - createSchedule( - name: String - public: Boolean = false - selectedSections: [SectionSelectionInput] - semester: String - timeblocks: [TimeBlockInput] - totalUnits: String - year: String - ): CreateSchedule - updateSchedule( - name: String - public: Boolean - scheduleId: ID - selectedSections: [SectionSelectionInput] - timeblocks: [TimeBlockInput] - totalUnits: String - ): UpdateSchedule - removeSchedule(scheduleId: ID): RemoveSchedule - updateUser( - emailBerkeleytimeUpdate: Boolean - emailClassUpdate: Boolean - emailEnrollmentOpening: Boolean - emailGradeUpdate: Boolean - major: String - ): UpdateUser - saveClass(classId: ID): SaveClass - removeClass(classId: ID): RemoveClass - - """ - Login mutation using graphql_jwt - """ - login(tokenId: String): ObtainJSONWebToken - logout: Logout - verifyToken(token: String): Verify - refreshToken(token: String): Refresh - deleteUser: DeleteUser +type Reservation { + enrollCount: Int! + enrollMax: Int! + group: String! } -""" -An object with an ID -""" -interface Node { - """ - The ID of the object. - """ - id: ID! +type Meeting { + days: [Boolean!] + startTime: String! + endTime: String! + startDate: String! + endDate: String! + location: String! + instructors: [Instructor!]! } -""" -Login mutation using graphql_jwt -""" -type ObtainJSONWebToken { - payload: GenericScalar! - refreshExpiresIn: Int! - user: BerkeleytimeUserType - newUser: Boolean +type Exam { + date: String! + startTime: String! + endTime: String! + location: String! + final: Boolean! } -""" -The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. -""" -type PageInfo { - """ - When paginating forwards, are there more items? - """ - hasNextPage: Boolean! - - """ - When paginating backwards, are there more items? - """ - hasPreviousPage: Boolean! - - """ - When paginating backwards, the cursor to continue. - """ - startCursor: String - - """ - When paginating forwards, the cursor to continue. - """ - endCursor: String -} - -type PlaylistType implements Node { - """ - The ID of the object. - """ - id: ID! - category: String! - name: String! - semester: String! - year: String! - courses( - before: String - after: String - first: Int - last: Int - title: String - department: String - abbreviation: String - courseNumber: String - description: String - units: String - crossListing: [ID] - prerequisites: String - gradeAverage: Float - letterAverage: String - hasEnrollment: Boolean - enrolled: Int - enrolledMax: Int - enrolledPercentage: Float - waitlisted: Int - openSeats: Int - lastUpdated: DateTime - hasGrades: Boolean - inPlaylists: String - idIn: String - ): CourseTypeConnection! -} - -type PlaylistTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [PlaylistTypeEdge]! +type Instructor { + familyName: String + givenName: String } -""" -A Relay edge containing a `PlaylistType` and its cursor. -""" -type PlaylistTypeEdge { - """ - The item at the end of the edge - """ - node: PlaylistType +type EnrollmentDay { + enrollCount: Int! + enrollMax: Int! + waitlistCount: Int! + waitlistMax: Int! +} - """ - A cursor for use in pagination - """ - cursor: String! +type CourseListItem { + subject: String! + number: String! } -type Query { - schedules: [ScheduleType] - schedule(id: ID): ScheduleType - user: BerkeleytimeUserType - allPlaylists( - before: String - after: String - first: Int - last: Int - category: String - name: String - semester: String - year: String - courses: [ID] - ): PlaylistTypeConnection - - """ - The ID of the object - """ - playlist(id: ID!): PlaylistType - allGrades( - before: String - after: String - first: Int - last: Int - course: ID - semester: String - year: String - abbreviation: String - courseNumber: String - sectionNumber: String - instructor: String - gradedTotal: Int - average: Float - ): GradeTypeConnection - - """ - The ID of the object - """ - grade(id: ID!): GradeType - formConfig: FormConfigType - courseEnrollmentBySection(sectionId: ID): EnrollmentInfo - courseEnrollmentBySemester(courseId: ID, semester: String, year: Int): EnrollmentInfo - - """ - The ID of the object - """ - course(id: ID!): CourseType - allCourses( - before: String - after: String - first: Int - last: Int - title: String - department: String - abbreviation: String - courseNumber: String - description: String - units: String - crossListing: [ID] - prerequisites: String - gradeAverage: Float - letterAverage: String - hasEnrollment: Boolean - enrolled: Int - enrolledMax: Int - enrolledPercentage: Float - waitlisted: Int - openSeats: Int - lastUpdated: DateTime - hasGrades: Boolean - inPlaylists: String - idIn: String - ): CourseTypeConnection - - """ - The ID of the object - """ - section(id: ID!): SectionType - allSections( - before: String - after: String - first: Int - last: Int - course: ID - abbreviation: String - courseNumber: String - year: String - semester: String - courseTitle: String - sectionNumber: String - ccn: String - kind: String - isPrimary: Boolean - associatedSections: [ID] - days: String - startTime: DateTime - endTime: DateTime - finalDay: String - finalEnd: DateTime - finalStart: DateTime - instructor: String - disabled: Boolean - locationName: String - instructionMode: String - lastUpdated: DateTime - enrolled: Int - enrolledMax: Int - waitlisted: Int - waitlistedMax: Int - ): SectionTypeConnection - ping: String -} - -type Refresh { - payload: GenericScalar! - refreshExpiresIn: Int! -} - -type RemoveClass { - user: BerkeleytimeUserType -} - -type RemoveSchedule { - schedule: ScheduleType -} - -type SaveClass { - user: BerkeleytimeUserType -} - -type ScheduleType implements Node { - """ - The ID of the object. - """ - id: ID! - user: BerkeleytimeUserType! - name: String! - year: String! - semester: String! - dateCreated: DateTime! - dateModified: DateTime! - totalUnits: String! - public: Boolean! - selectedSections( - before: String - after: String - first: Int - last: Int - ): SectionSelectionTypeConnection! - timeblocks(before: String, after: String, first: Int, last: Int): TimeBlockTypeConnection! -} - -type ScheduleTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [ScheduleTypeEdge]! +enum CacheControlScope { + PUBLIC + PRIVATE } """ -A Relay edge containing a `ScheduleType` and its cursor. +The `JSON` scalar type represents JSON values as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ -type ScheduleTypeEdge { - """ - The item at the end of the edge - """ - node: ScheduleType - - """ - A cursor for use in pagination - """ - cursor: String! -} - -input SectionSelectionInput { - course: ID! - primary: ID - secondary: [ID] -} - -type SectionSelectionType implements Node { - """ - The ID of the object. - """ - id: ID! - schedule: ScheduleType! - course: CourseType! - primary: SectionType - secondary( - before: String - after: String - first: Int - last: Int - course: ID - abbreviation: String - courseNumber: String - year: String - semester: String - courseTitle: String - sectionNumber: String - ccn: String - kind: String - isPrimary: Boolean - associatedSections: [ID] - days: String - startTime: DateTime - endTime: DateTime - finalDay: String - finalEnd: DateTime - finalStart: DateTime - instructor: String - disabled: Boolean - locationName: String - instructionMode: String - lastUpdated: DateTime - enrolled: Int - enrolledMax: Int - waitlisted: Int - waitlistedMax: Int - ): SectionTypeConnection! -} - -type SectionSelectionTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [SectionSelectionTypeEdge]! -} +scalar JSON """ -A Relay edge containing a `SectionSelectionType` and its cursor. +The `JSONObject` scalar type represents JSON objects as specified by [ECMA-404](http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf). """ -type SectionSelectionTypeEdge { - """ - The item at the end of the edge - """ - node: SectionSelectionType - - """ - A cursor for use in pagination - """ - cursor: String! -} - -type SectionType implements Node { - """ - The ID of the object. - """ - id: ID! - course: CourseType! - abbreviation: String! - courseNumber: String! - year: String! - semester: String! - courseTitle: String! - sectionNumber: String! - ccn: String! - kind: String! - isPrimary: Boolean! - associatedSections( - before: String - after: String - first: Int - last: Int - course: ID - abbreviation: String - courseNumber: String - year: String - semester: String - courseTitle: String - sectionNumber: String - ccn: String - kind: String - isPrimary: Boolean - associatedSections: [ID] - days: String - startTime: DateTime - endTime: DateTime - finalDay: String - finalEnd: DateTime - finalStart: DateTime - instructor: String - disabled: Boolean - locationName: String - instructionMode: String - lastUpdated: DateTime - enrolled: Int - enrolledMax: Int - waitlisted: Int - waitlistedMax: Int - ): SectionTypeConnection! - days: String! - startTime: DateTime - endTime: DateTime - finalDay: String! - finalEnd: DateTime - finalStart: DateTime - instructor: String! - disabled: Boolean! - locationName: String! - instructionMode: String! - lastUpdated: DateTime! - enrolled: Int - enrolledMax: Int - waitlisted: Int - waitlistedMax: Int - schedulerPrimarySections( - before: String - after: String - first: Int - last: Int - ): SectionSelectionTypeConnection! - schedulerSecondarySections( - before: String - after: String - first: Int - last: Int - ): SectionSelectionTypeConnection! - wordDays: String -} - -type SectionTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! - - """ - Contains the nodes in this connection. - """ - edges: [SectionTypeEdge]! -} +scalar JSONObject """ -A Relay edge containing a `SectionType` and its cursor. +ISODate custom scalar type """ -type SectionTypeEdge { - """ - The item at the end of the edge - """ - node: SectionType - - """ - A cursor for use in pagination - """ - cursor: String! -} +scalar ISODate """ -Telebears JSON +The combination of year and season that corresponds to a specific term. Both year and season/semester are required. """ -type TelebearData { - phase1Start: Date - phase1End: Date - phase2Start: Date - phase2End: Date - adjStart: Date +input TermInput { + year: Int! + semester: Semester! } -""" -The `Time` scalar type represents a Time value as -specified by -[iso8601](https://en.wikipedia.org/wiki/ISO_8601). -""" -scalar Time +enum Semester { + Fall + Spring + Summer + Winter +} -input TimeBlockInput { - name: String! - startTime: Time! - endTime: Time! - days: String! +type TermOutput { + year: Int! + semester: String! } -type TimeBlockType implements Node { - """ - The ID of the object. - """ - id: ID! - name: String! - startTime: Time! - endTime: Time! - days: String! - schedule: ScheduleType! +input CustomEventInput { + start_time: String! + end_time: String! + title: String + location: String + description: String + days_of_week: String } -type TimeBlockTypeConnection { - """ - Pagination data for this connection. - """ - pageInfo: PageInfo! +input SelectedCourseInput { + class_ID: String! + primary_section_ID: String + secondary_section_IDs: [String!] +} - """ - Contains the nodes in this connection. - """ - edges: [TimeBlockTypeEdge]! +input ScheduleInput { + name: String + created_by: String! + courses: [SelectedCourseInput!] + is_public: Boolean + term: TermInput! + custom_events: [CustomEventInput!] } -""" -A Relay edge containing a `TimeBlockType` and its cursor. -""" -type TimeBlockTypeEdge { - """ - The item at the end of the edge - """ - node: TimeBlockType +type Schedule { + """ + The ObjectID associated with the schedule record + """ + _id: ID - """ - A cursor for use in pagination - """ - cursor: String! -} + """ + The name of the schedule, such as "Oski's Fall schedule <3" + """ + name: String -type UpdateSchedule { - schedule: ScheduleType -} + """ + Identifier (probably email) for the user who created the schedule (such as oski@bereley.edu). + """ + created_by: String! + + """ + Term corresponding to the schedule, such as "Fall 1986" + """ + term: TermOutput! -type UpdateUser { - user: BerkeleytimeUserType + """ + Whether the user would like the schedule to be viewable by others. + """ + is_public: Boolean! + + """ + Courses, see the SelectedCourse type below + """ + courses: [SelectedCourse!] + + """ + Custom events, such as club meetings, that the user has added to their schedule. + """ + custom_events: [CustomEvent!] + created: String! + revised: String! } -type UserType { - id: ID! +type SelectedCourse { + """ + Identifiers (probably cs-course-ids) for the classes the user has added to their schedule. + """ + class_ID: String! + + """ + Identifiers (probably the "003" in "2022 Spring STAT 97 003") for the primary sections (typically lectures) the user has added to their schedule. + """ + primary_section_ID: String - """ - Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. - """ - username: String! - firstName: String! - lastName: String! - email: String! + """ + Identifiers (probably the "103" in "103 DIS") for the secondary sections (typically discussions) the user has added to their schedule. + """ + secondary_section_IDs: [String!] } -type Verify { - payload: GenericScalar! +type CustomEvent { + start_time: String! + end_time: String! + title: String + location: String + description: String + days_of_week: String } diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx new file mode 100644 index 000000000..b4d9fd96e --- /dev/null +++ b/frontend/src/App.tsx @@ -0,0 +1,92 @@ +import * as Tooltip from "@radix-ui/react-tooltip"; +import { IconoirProvider } from "iconoir-react"; +import { RouterProvider, createBrowserRouter } from "react-router-dom"; + +import About from "@/app/About"; +import Catalog from "@/app/Catalog"; +import Discover from "@/app/Discover"; +import Landing from "@/app/Landing"; +import Plan from "@/app/Plan"; +import Compare from "@/app/Schedule/Compare"; +import Manage from "@/app/Schedule/Manage"; +import Schedules from "@/app/Schedules"; +import Layout from "@/components/Layout"; + +import Schedule from "./app/Schedule"; + +const router = createBrowserRouter([ + { + element: , + children: [ + { + element: , + index: true, + }, + { + element: , + path: "explore", + }, + ], + }, + { + element: , + children: [ + { + element: , + path: "about", + }, + ], + }, + { + element: , + children: [ + { + element: , + path: "schedules/:scheduleId", + children: [ + { + element: , + index: true, + }, + { + element: , + path: "compare/:comparedScheduleId?", + }, + ], + }, + ], + }, + { + element: , + children: [ + { + element: , + path: "catalog/:year?/:semester?/:subject?/:courseNumber?/:classNumber?", + }, + { + element: , + path: "schedules", + }, + { + element: , + path: "plan", + }, + ], + }, +]); + +export default function App() { + return ( + + + + + + ); +} diff --git a/frontend/src/Berkeleytime.tsx b/frontend/src/Berkeleytime.tsx deleted file mode 100644 index 9c420fd41..000000000 --- a/frontend/src/Berkeleytime.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { memo, useEffect } from 'react'; -import { useDispatch } from 'react-redux'; -import { openBanner, enterMobile, exitMobile, openLandingModal } from './redux/common/actions'; -import useDimensions from 'react-cool-dimensions'; -import easterEgg from 'utils/easterEgg'; -import Routes from './Routes'; -import { fetchEnrollContext } from 'redux/actions'; -import { IconoirProvider } from 'iconoir-react'; - -const Berkeleytime = () => { - const dispatch = useDispatch(); - const { observe } = useDimensions({ - updateOnBreakpointChange: true, - breakpoints: { mobile: 0, desktop: 768 }, - onResize: ({ currentBreakpoint }) => { - if (currentBreakpoint === 'mobile') { - dispatch(enterMobile()); - } else { - dispatch(exitMobile()); - } - } - }); - - useEffect(() => { - // Fetch enrollment context early on for catalog and enrollment page. - dispatch(fetchEnrollContext()); - - const bannerType = 'fa23catalog'; // should match value in ./redux/common/reducer.ts - if (localStorage.getItem('bt-hide-banner') !== bannerType) { - dispatch(openBanner()); - } - - const modalType = 'sp22scheduler'; // should match value in ./redux/common/reducer.ts - if (localStorage.getItem('bt-hide-landing-modal') !== modalType) { - dispatch(openLandingModal()); - } - - easterEgg(); - - const key = 'bt-spring-2021-catalog'; - if (localStorage.getItem(key) === null) { - localStorage.setItem(key, key); - } - }, [dispatch]); - - return ( -
- - - -
- ); -}; - -export default memo(Berkeleytime); diff --git a/frontend/src/Routes.tsx b/frontend/src/Routes.tsx deleted file mode 100644 index 60a18b864..000000000 --- a/frontend/src/Routes.tsx +++ /dev/null @@ -1,88 +0,0 @@ -/*eslint max-len: ["error", { "code": 180 }]*/ -import { lazy, Suspense } from 'react'; -import { Switch, Route, RouteProps, Redirect } from 'react-router-dom'; -import BTLoader from 'components/Common/BTLoader'; - -import Catalog from './app/Catalog'; -import Landing from './views/Landing'; -import Error from './views/Error/Error'; -import Layout from 'components/Common/Layout'; - -const Grades = lazy(() => import('./views/Grades/Grades')); -const Enrollment = lazy(() => import('./views/Enrollment/Enrollment')); -const About = lazy(() => import('./views/About')); -const Releases = lazy(() => import('./views/Releases/Releases')); -const Faq = lazy(() => import('./views/Faq')); -const Profile = lazy(() => import('./views/Profile/Profile')); -const Login = lazy(() => import('./views/Login/Login')); -const Logout = lazy(() => import('./views/Profile/Logout')); -const SchedulerOnboard = lazy(() => import('./views/Scheduler/SchedulerOnboard')); -const LocalScheduler = lazy(() => import('./views/Scheduler/LocalSchedulerPage')); -const RemoteScheduler = lazy(() => import('./views/Scheduler/RemoteSchedulerPage')); -const ViewSchedule = lazy(() => import('./views/Scheduler/ViewSchedule')); -const PrivacyPolicy = lazy(() => import('./views/Policies/PrivacyPolicy')); -const TermsOfService = lazy(() => import('./views/Policies/TermsOfService')); -const RedirectLink = lazy(() => import('./views/RedirectLink')); - -const routes: Array = [ - { path: '/landing', component: Landing }, - { path: '/catalog', component: Catalog, exact: false }, - { path: '/grades', component: Grades, exact: false }, - { path: '/enrollment', component: Enrollment, exact: false }, - { path: '/about', component: About }, - { path: '/releases', component: Releases }, - { path: '/faq', component: Faq }, - { path: '/profile', component: Profile }, - { path: '/oauth2callback', component: Login }, - { path: '/logout', component: Logout }, - { path: '/scheduler', component: SchedulerOnboard }, - { path: '/scheduler/new', component: LocalScheduler }, - { path: '/scheduler/:scheduleId', component: RemoteScheduler }, - { path: '/schedule/:scheduleId', component: ViewSchedule }, - { path: '/error', component: Error }, - { path: '/legal/privacy', component: PrivacyPolicy }, - { path: '/legal/terms', component: TermsOfService }, - { path: '/redirect', component: RedirectLink, exact: false } -]; - -const Routes = () => ( - - - - } - > - - - - - - - - - - - - - - {routes.map((route) => ( - - ))} - - - - - - - - -); - -export default Routes; diff --git a/frontend/src/app/About/index.tsx b/frontend/src/app/About/index.tsx new file mode 100644 index 000000000..f8a4f997c --- /dev/null +++ b/frontend/src/app/About/index.tsx @@ -0,0 +1,3 @@ +export default function About() { + return
; +} diff --git a/frontend/src/app/Catalog/Catalog.module.scss b/frontend/src/app/Catalog/Catalog.module.scss index a6a7629e3..0b6b13d10 100644 --- a/frontend/src/app/Catalog/Catalog.module.scss +++ b/frontend/src/app/Catalog/Catalog.module.scss @@ -1,26 +1,7 @@ .root { - display: grid; - grid-template-areas: 'filters list view'; - grid-template-rows: 1fr; - grid-template-columns: 0.5fr 0.5fr 1fr; - position: relative; - height: calc(100vh - 57.11px); - align-items: stretch; - overflow: hidden; - - @include media(tablet) { - grid-template-areas: - 'filters view' - 'list view'; - grid-template-rows: min-content 1fr; - grid-template-columns: 1.2fr 2fr; - } - - @include media(mobile) { - grid-template-areas: - 'filters' - 'list'; - grid-template-rows: min-content 1fr; - grid-template-columns: 1fr; - } -} + display: flex; + flex-grow: 1; + overflow: clip; + height: 0; + position: relative; +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Catalog.tsx b/frontend/src/app/Catalog/Catalog.tsx deleted file mode 100644 index dbb50dfe7..000000000 --- a/frontend/src/app/Catalog/Catalog.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { useState } from 'react'; -import { CurrentFilters, SortOption } from './types'; -import catalogService from './service'; -import styles from './Catalog.module.scss'; -import CatalogFilters from './CatalogFilters'; -import CatalogList from './CatalogList'; -import CatalogView from './CatalogView'; -import { CourseFragment } from 'graphql'; - -const { SORT_OPTIONS, INITIAL_FILTERS } = catalogService; - -const Catalog = () => { - const [currentFilters, setCurrentFilters] = useState(INITIAL_FILTERS); - const [currentCourse, setCurrentCourse] = useState(null); - const [searchQuery, setSearchQuery] = useState(''); - const [sortQuery, setSortQuery] = useState(SORT_OPTIONS[0]); - - return ( -
- - - -
- ); -}; - -export default Catalog; diff --git a/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.module.scss b/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.module.scss deleted file mode 100644 index 3de00c8fd..000000000 --- a/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.module.scss +++ /dev/null @@ -1,189 +0,0 @@ -.root { - display: flex; - flex-direction: column; - background: transparent; - overflow: hidden; - - @include media(mobile, tablet) { - display: grid; - position: relative; - border-right: 1.5px solid #eaeaea; - border-bottom: 1.5px solid #eaeaea; - grid-template-columns: 1fr; - grid-template-rows: min-content 1fr; - grid-template-areas: - 'toggle' - 'modal'; - padding-top: 0; - align-items: center; - - &[data-modal='true'] { - overflow: visible !important; - } - } -} - -.toggle { - display: none; - - @include media(mobile, tablet) { - display: flex; - width: 100%; - grid-area: toggle; - z-index: 200; - justify-content: space-between; - align-items: center; - justify-self: center; - padding: 5px 8px; - background: white; - font-size: 14px; - gap: 10px; - - div { - flex: 1; - } - - button { - font-size: 18px; - outline: none; - color: #8a8a8a; - border: none; - padding: 5px; - background: white; - border-radius: 50%; - &:active, - &:hover { - color: $bt-blue; - } - } - } -} - -.search { - @include media(mobile, tablet) { - display: none; - } -} - -.container { - height: 100%; - overflow-y: overlay; - - @include media(mobile, tablet) { - position: absolute; - grid-area: modal; - width: 100%; - top: 0; - // minus size of search bar, minus size of header - height: calc(100vh - 47px); - z-index: 50; - background: hsla(0, 0%, 0%, 0.3); - justify-content: center; - align-items: center; - - &[data-modal='false'] { - display: none; - } - - &[data-modal='true'] { - display: flex; - } - } -} - -.wrapper { - display: flex; - flex-direction: column; - gap: 12px; - background: white; - padding: 30px; - border-right: 1.5px solid #eaeaea; - height: 100%; - font-size: 14px; - overflow-y: overlay; - top: 10vh; - - @include media(mobile, tablet) { - position: absolute; - border-radius: 12px; - background: white; - width: 80%; - height: min-content; - - &[data-modal='false'] { - display: none; - } - - &[data-modal='true'] { - display: flex; - } - } -} - -.item { - display: flex; - flex-direction: column; - gap: 10px; - - p { - font-weight: 600; - } -} - -.error { - background: $bt-indicator-red; - color: $bt-white; - font-size: 14px; - padding: 10px; - border-radius: 6px; - text-align: center; -} - -.header { - margin-bottom: 20px; - display: flex; - justify-content: space-between; - flex-direction: row; - align-items: baseline; - gap: 30px; - h3 { - font-size: 20px; - line-height: 30px; - font-weight: 600; - } - - button { - color: #2f80ed; - transition: 0.5s; - border: none; - background: none; - padding: 4px 8px; - border-radius: 4px; - font-size: 16px; - &:hover { - background: hsla(0, 0%, 92.2%, 0.6196078431); - } - } -} - -.select { - [class$='-multiValue'] { - background: white; - border: 1px solid $bt-border-grey; - border-radius: 12px; - - :nth-child(2) { - border-radius: 12px; - color: hsl(0, 0%, 80%); - } - - :nth-child(2):hover { - background: $bt-button-background; - color: $bt-base-text; - } - } - - [class$='MultiValueGeneric2'] { - color: $bt-blue; - } -} diff --git a/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.tsx b/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.tsx deleted file mode 100644 index 90c4550f3..000000000 --- a/frontend/src/app/Catalog/CatalogFilters/CatalogFilters.tsx +++ /dev/null @@ -1,175 +0,0 @@ -import { Dispatch, memo, SetStateAction, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { ActionMeta } from 'react-select'; -import BTSelect from 'components/Custom/Select'; - -import catalogService from '../service'; -import { ReactComponent as SearchIcon } from 'assets/svg/common/search.svg'; -import { ReactComponent as FilterIcon } from 'assets/svg/catalog/filter.svg'; -import BTInput from 'components/Custom/Input'; -import { CurrentFilters, FilterOption, SortOption, CatalogFilterKeys, CatalogSlug } from '../types'; - -import { useGetFiltersQuery } from 'graphql'; -import BTLoader from 'components/Common/BTLoader'; -import { useHistory, useParams } from 'react-router'; - -import styles from './CatalogFilters.module.scss'; - -type CatalogFilterProps = { - currentFilters: CurrentFilters; - sortQuery: SortOption; - searchQuery: string; - setCurrentFilters: Dispatch>; - setSortQuery: Dispatch>; - setSearchQuery: Dispatch>; -}; - -const { SORT_OPTIONS, FILTER_TEMPLATE, INITIAL_FILTERS } = catalogService; - -const CatalogFilters = (props: CatalogFilterProps) => { - const { - currentFilters, - setCurrentFilters, - sortQuery, - searchQuery, - setSortQuery, - setSearchQuery - } = props; - - const { data, loading, error } = useGetFiltersQuery(); - const [isOpen, setOpen] = useState(false); - const filters = useMemo(() => catalogService.processFilterData(data), [data]); - const history = useHistory(); - const slug = useParams(); - const modalRef = useRef(null); - - const filterList = useMemo( - () => catalogService.putFilterOptions(FILTER_TEMPLATE, filters), - [filters] - ); - - useEffect(() => { - if (filterList?.semester) { - const options = filterList.semester.options as FilterOption[]; - const semester = options.find(({ label }) => label === slug?.semester) ?? null; - - setCurrentFilters((prev) => ({ - ...prev, - semester: semester ?? options[0] - })); - } - }, [filterList, setCurrentFilters, slug?.semester]); - - useEffect(() => { - const ref = modalRef; - - const listener = (event: MouseEvent | TouchEvent) => { - if (ref.current && isOpen && (event.target as HTMLDivElement)?.contains(ref.current)) - setOpen(!isOpen); - }; - - document.addEventListener('click', listener); - - return () => { - document.removeEventListener('click', listener); - }; - }, [isOpen, modalRef, setOpen]); - - const handleFilterReset = useCallback(() => { - setSortQuery(SORT_OPTIONS[0]); - setSearchQuery(''); - - if (filterList) { - const semester = filterList.semester.options[0] as FilterOption; - setCurrentFilters({ - ...INITIAL_FILTERS, - semester - }); - history.push(`/catalog/${semester.value.name}`); - } - }, [filterList, history, setCurrentFilters, setSearchQuery, setSortQuery]); - - const handleFilterChange = ( - newValue: FilterOption | readonly FilterOption[] | null, - meta: ActionMeta - ) => { - const key = meta.name as CatalogFilterKeys; - setCurrentFilters((prev) => ({ - ...prev, - [key]: newValue - })); - - // Update the url slug if semester filter changes. - if (key === 'semester') { - history.push( - `/catalog/${(newValue as FilterOption)?.value?.name}` - .concat(slug?.abbreviation ? `/${slug.abbreviation}` : '') - .concat(slug?.courseNumber ? `/${slug.courseNumber}` : '') - ); - } - }; - - return ( -
-
- setSearchQuery(e.target.value)} - type="search" - placeholder="Search for a class..." - icon={} - /> - -
-
-
-
-

Filters

- -
- setSearchQuery(e.target.value)} - type="search" - placeholder="Search for a class..." - icon={} - /> - setSortQuery(newValue as SortOption)} - /> - {filterList && - Object.entries(filterList).map(([key, filter]) => ( -
-

{filter.name}

- -
- ))} - {loading && } - {error &&
Failed to fetch catalog filters.
} -
-
-
- ); -}; - -export default memo(CatalogFilters); diff --git a/frontend/src/app/Catalog/CatalogFilters/index.ts b/frontend/src/app/Catalog/CatalogFilters/index.ts deleted file mode 100644 index 978858c71..000000000 --- a/frontend/src/app/Catalog/CatalogFilters/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import CatalogFilters from './CatalogFilters'; - -export default CatalogFilters; diff --git a/frontend/src/app/Catalog/CatalogList/CatalogList.module.scss b/frontend/src/app/Catalog/CatalogList/CatalogList.module.scss deleted file mode 100644 index 538f1592b..000000000 --- a/frontend/src/app/Catalog/CatalogList/CatalogList.module.scss +++ /dev/null @@ -1,144 +0,0 @@ -.root { - display: flex; - grid-area: list; - position: relative; - flex-direction: column; - border-right: 1.5px solid #eaeaea; - height: 100%; - overflow: hidden; -} - -.itemRoot { - display: flex; - flex-direction: row; - justify-content: space-between; - transition: all 0.15s ease-in-out; - padding: 5px 15px; - - .itemContainer { - display: grid; - grid-template-columns: 100%; - grid-template-rows: 1fr min-content; - transition: all 0.15s ease-in-out; - width: 100%; - border-radius: 8px; - padding: 8px 10px; - position: relative; - - @include media(mobile) { - border: 0.5px solid $bt-light-border-grey; - } - - &:hover { - background: $bt-off-white; - cursor: pointer; - } - } -} - -.skeleton { - padding: 0 !important; -} - -.selected { - background: $bt-off-white; -} - -.itemInfo { - display: flex; - width: 100%; - flex-direction: row; - gap: 10px; - justify-content: space-between; - - h6 { - font-size: 16px; - font-weight: bold; - } - - p { - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; /* number of lines to show */ - line-height: 1.2em; /* fallback */ - max-height: 1.2em * 2; - color: $bt-light-text; - font-size: 14px; - } -} - -.list { - overflow: overlay !important; -} - -.error { - display: flex; - padding: 30px; - height: 100%; - text-align: center; - justify-content: center; - align-items: center; - color: $bt-light-text; -} - -.itemContent { - display: grid; - grid-auto-flow: row; - justify-content:space-evenly; - h6 { - justify-self: flex-start; - } -} - -.grade { - display: flex; - justify-content: center; -} - -.A { - color: $bt-indicator-green; -} - -.B { - color: $bt-indicator-yellow; -} - -.C { - color: $bt-indicator-orange; -} - -.D { - color: $bt-indicator-squash; -} - -.F { - color: $bt-indicator-red; -} - -.itemStats { - display: flex; - flex-direction: row; - gap: 5px; - color: $bt-light-text; - - span { - font-size: 14px; - } -} - -.saveIcon { - opacity: 0.5; - transition: all 0.15s ease-in-out; - color: $bt-light-grey; - z-index: 5; - &:active { - transform: scale(0.9) !important; - } - - &:hover { - opacity: 1; - transform: scale(1.1); - } -} diff --git a/frontend/src/app/Catalog/CatalogList/CatalogList.tsx b/frontend/src/app/Catalog/CatalogList/CatalogList.tsx deleted file mode 100644 index e68c7c783..000000000 --- a/frontend/src/app/Catalog/CatalogList/CatalogList.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { FixedSizeList } from 'react-window'; -import CatalogListItem from './CatalogListItem'; -import { CourseFragment, useGetCoursesForFilterLazyQuery } from 'graphql'; -import { CurrentFilters, FilterOption, SortOption } from '../types'; -import { Dispatch, memo, SetStateAction, useEffect, useMemo } from 'react'; -import useDimensions from 'react-cool-dimensions'; - -import styles from './CatalogList.module.scss'; -import { useHistory } from 'react-router'; -import { searchCourses } from 'utils/courses/search'; -import { sortByAttribute } from 'utils/courses/sorting'; - -type CatalogListProps = { - currentFilters: CurrentFilters; - setCurrentCourse: Dispatch>; - selectedId: string | null; - searchQuery: string; - sortQuery: SortOption; -}; - -type Skeleton = { __typename: 'Skeleton'; id: number }; - -/** - * Component for course list - */ -const CatalogList = (props: CatalogListProps) => { - const { currentFilters, setCurrentCourse, selectedId, searchQuery, sortQuery } = props; - const { observe, height } = useDimensions(); - const [fetchCatalogList, { data }] = useGetCoursesForFilterLazyQuery({}); - const history = useHistory(); - - const courses = useMemo(() => { - if (!data) - return [...Array(20).keys()].map( - (key) => - ({ - __typename: 'Skeleton', - id: key - } as Skeleton) - ); - - let courses = data.allCourses.edges.map((edge) => edge.node); - courses = searchCourses(courses, searchQuery); - - //TODO: Very big problem to inspect - server is returning duplicate entries of same courses. - // Here we filter the duplicates to ensure catalog list consistency. - courses = courses.filter((v, i, a) => a.findIndex((t) => t.id === v.id) === i); - - // Inspect one case of duplication: - // console.log(courses.filter((v, i, a) => v.id === 'Q291cnNlVHlwZTo0NDc1')); - - return courses.sort(sortByAttribute(sortQuery.value)); - }, [data, searchQuery, sortQuery]); - - useEffect(() => { - const playlists = Object.values(currentFilters ?? {}) - .filter((val) => val !== null) - .map((item) => (Array.isArray(item) ? item.map((v) => v.value.id) : item?.value.id)) - .flat() - .join(','); - - if (playlists) fetchCatalogList({ variables: { playlists } }); - }, [fetchCatalogList, currentFilters]); - - const handleCourseSelect = (course: CourseFragment) => { - setCurrentCourse(course); - history.push( - `/catalog/${(currentFilters.semester as FilterOption)?.value?.name}/${course.abbreviation}/${ - course.courseNumber - }` - ); - }; - - return ( -
- {height && courses.length > 0 ? ( - courses[index]?.id} - > - {({ index, style }) => ( - - )} - - ) : ( -
There are no courses matching your filters.
- )} -
- ); -}; - -export default memo(CatalogList); diff --git a/frontend/src/app/Catalog/CatalogList/CatalogListItem.tsx b/frontend/src/app/Catalog/CatalogList/CatalogListItem.tsx deleted file mode 100644 index f5370a199..000000000 --- a/frontend/src/app/Catalog/CatalogList/CatalogListItem.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import { CourseFragment } from 'graphql'; -import { useSaveCourse, useUnsaveCourse } from 'graphql/hooks/saveCourse'; -import { useUser } from 'graphql/hooks/user'; -import { CSSProperties, memo } from 'react'; -import { areEqual } from 'react-window'; -import { ReactComponent as BookmarkSaved } from 'assets/svg/catalog/bookmark-saved.svg'; -import { ReactComponent as BookmarkUnsaved } from 'assets/svg/catalog/bookmark-unsaved.svg'; -import catalogService from '../service'; - -const { colorEnrollment, formatEnrollment } = catalogService; - -import styles from './CatalogList.module.scss'; -import Skeleton from 'react-loading-skeleton'; - -function formatUnits(units: string) { - return `${units} Unit${units === '1.0' || units === '1' ? '' : 's'}` - .replace(/.0/g, '') - .replace(/ - /, '-') - .replace(/ or /g, '-'); -} - -type CatalogListItemProps = { - data: { - course: CourseFragment | { __typename: 'Skeleton'; id: number }; - handleCourseSelect: (course: CourseFragment) => void; - isSelected: boolean; - }; - style: CSSProperties; -}; - -const CatalogListItem = ({ style, data }: CatalogListItemProps) => { - const { course, handleCourseSelect, isSelected } = data; - - const { user } = useUser(); - const saveCourse = useSaveCourse(); - const unsaveCourse = useUnsaveCourse(); - - const isSaved = user?.savedClasses?.some((savedCourse) => savedCourse?.id === course.id); - - return course.__typename === 'Skeleton' ? ( -
-
- -
-
- ) : ( -
handleCourseSelect(course)}> -
-
-
-
{`${course.abbreviation} ${course.courseNumber}`}
-

{course.title}

-
-
- {user && ( -
{ - e.stopPropagation(); - isSaved ? unsaveCourse(course) : saveCourse(course); - }} - > - {isSaved ? : } -
- )} - - {course.letterAverage !== '' ? course.letterAverage : ''} - -
-
-
- - {formatEnrollment(course.enrolledPercentage)} - - • {course.units ? formatUnits(course.units) : 'N/A'} -
-
-
- ); -}; - -export default memo(CatalogListItem, areEqual); diff --git a/frontend/src/app/Catalog/CatalogList/index.ts b/frontend/src/app/Catalog/CatalogList/index.ts deleted file mode 100644 index 7e8e5cec0..000000000 --- a/frontend/src/app/Catalog/CatalogList/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import CatalogList from './CatalogList'; - -export default CatalogList; diff --git a/frontend/src/app/Catalog/CatalogView/CatalogView.module.scss b/frontend/src/app/Catalog/CatalogView/CatalogView.module.scss deleted file mode 100644 index bb576282e..000000000 --- a/frontend/src/app/Catalog/CatalogView/CatalogView.module.scss +++ /dev/null @@ -1,260 +0,0 @@ -@-webkit-keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -.root { - display: flex; - position: relative; - grid-area: view; - flex-direction: column; - padding: 30px; - gap: 15px; - overflow-y: auto; - overflow-x: hidden; - -webkit-animation: fadeIn 0.1s; - animation: fadeIn 0.1s; - - h3 { - font-size: 24px; - font-weight: 700; - } - - h5 { - color: $bt-base-text; - font-weight: 700; - font-size: 18px; - - span { - color: $bt-blue; - } - } - - h6 { - font-size: 18px; - font-weight: 400; - color: $bt-light-text; - } - - @include media(mobile) { - background: white; - position: absolute !important; - top: 0; - height: 100%; - z-index: 300; - width: 100vw; - // Add size of fixed header. - padding-top: 30px; - &[data-modal='false'] { - display: none; - } - - [data-modal='true'] { - display: flex; - } - } -} - -.modalButton { - display: none; - @include media(mobile) { - display: flex; - justify-content: flex-start; - align-items: center; - text-align: center; - border: none; - background: none; - line-height: 20px; - color: $bt-grey-text; - gap: 10px; - padding: 0; - margin-bottom: 15px; - - &:hover { - color: #2f80ed; - } - } -} - -.description { - display: flex; - flex-direction: column; - gap: 10px; - color: $bt-grey-text; - - span { - color: $bt-blue; - margin-left: 5px; - &:hover { - cursor: pointer; - } - } - - h6 { - font-size: 16px; - font-weight: 700; - color: $bt-base-text; - } -} - -.pills { - display: block; - position: relative; - white-space: nowrap; - - div { - display: flex; - flex-direction: row; - white-space: nowrap; - position: relative; - margin: 0px -30px; - padding-left: 30px; - gap: 5px; - overflow-x: auto; - - &::-webkit-scrollbar { - display: none !important; - } - } -} - -.pill { - display: inline-block; - position: relative; - display: flex; - align-items: center; - white-space: nowrap; - height: 34px; - padding: 6px 12px; - border: 1.5px solid #eaeaea; - border-radius: 50vh !important; - background: white; - text-align: center; - color: $bt-blue; - font-size: 14px; - - &:hover { - cursor: pointer; - background-color: $bt-off-white; - } -} - -.stats { - display: flex; - flex-direction: column; - - .statLine { - display: flex; - flex-direction: row; - align-items: center; - text-align: center; - gap: 8px; - color: $bt-light-text; - - > p { - color: $bt-light-text; - margin-left: 5px; - } - - img { - width: 14px; - height: 24px; - } - - > div { - display: flex; - align-items: center; - gap: 3px; - flex-direction: row; - - img { - width: 16px !important; - } - } - } -} - -.statLink { - display: flex; - border-radius: 2px; - transition: 0.2s; - line-height: 0; - padding: 0px 5px; - - &:hover { - cursor: pointer; - opacity: 1; - background: $bt-button-background; - } -} - -.sectionRoot { - display: flex; - flex-direction: column; - gap: 10px; -} - -.sectionItem { - display: flex; - flex-direction: row; - // background: #F8F8F8; - padding: 12px 24px; - border-radius: 12px !important; - border: 1.5px solid #eaeaea; - gap: 20px; - h5 { - font-size: 16px; - margin: 0; - } - - h6 { - font-size: 14px; - span { - text-transform: capitalize; - } - } -} - -.sectionInfo { - display: flex; - gap: 5px; - flex-direction: column; - flex: 1; -} - -.sectionStats { - display: flex; - flex-direction: row; - flex-wrap: wrap; - gap: 5px; - color: $bt-light-text; - margin-top: 5px; - font-size: 14px; - text-transform: none !important; -} - -.enrolled { - display: flex; - justify-content: center; - align-items: center; - font-size: 14px; - font-weight: 600; - gap: 5px; - - img { - width: 14px; - } -} diff --git a/frontend/src/app/Catalog/CatalogView/CatalogView.tsx b/frontend/src/app/Catalog/CatalogView/CatalogView.tsx deleted file mode 100644 index d370ddbca..000000000 --- a/frontend/src/app/Catalog/CatalogView/CatalogView.tsx +++ /dev/null @@ -1,263 +0,0 @@ -import { Dispatch, memo, SetStateAction, useEffect, useMemo, useState } from 'react'; -import people from 'assets/svg/catalog/people.svg'; -import chart from 'assets/svg/catalog/chart.svg'; -import book from 'assets/svg/catalog/book.svg'; -import launch from 'assets/svg/catalog/launch.svg'; -import { ReactComponent as BackArrow } from 'assets/img/images/catalog/backarrow.svg'; -import catalogService from '../service'; -import { applyIndicatorPercent, applyIndicatorGrade, formatUnits } from 'utils/utils'; -import { CourseFragment, PlaylistType, useGetCourseForNameLazyQuery } from 'graphql'; -import { CurrentFilters } from 'app/Catalog/types'; -import { useHistory, useParams } from 'react-router'; -import { sortSections } from 'utils/sections/sort'; -import Skeleton from 'react-loading-skeleton'; -import ReadMore from './ReadMore'; - -import styles from './CatalogView.module.scss'; -import { useSelector } from 'react-redux'; -import SectionTable from './SectionTable'; - -interface CatalogViewProps { - coursePreview: CourseFragment | null; - setCurrentCourse: Dispatch>; - setCurrentFilters: Dispatch>; -} - -const skeleton = [...Array(8).keys()]; - -const CatalogView = (props: CatalogViewProps) => { - const { coursePreview, setCurrentFilters, setCurrentCourse } = props; - const { abbreviation, courseNumber, semester } = useParams<{ - abbreviation: string; - courseNumber: string; - semester: string; - }>(); - - const [course, setCourse] = useState(coursePreview); - const [isOpen, setOpen] = useState(false); - const history = useHistory(); - - const legacyId = useSelector( - (state: any) => - state.enrollment?.context?.courses?.find( - (c: any) => c.abbreviation === abbreviation && c.course_number === courseNumber - )?.id ?? null - ); - - const [getCourse, { data, loading }] = useGetCourseForNameLazyQuery({ - onCompleted: (data) => { - const course = data.allCourses.edges[0].node; - if (course) { - setCourse(course); - setOpen(true); - } - } - }); - - useEffect(() => { - if (!abbreviation || !courseNumber) { - setOpen(false); - } - }, [abbreviation, courseNumber]); - - useEffect(() => { - const [sem, year] = semester?.split(' ') ?? [null, null]; - - const variables = { - abbreviation: abbreviation ?? null, - courseNumber: courseNumber ?? null, - semester: sem?.toLowerCase() ?? null, - year: year - }; - - // Only fetch the course if every parameter has a value. - if (Object.values(variables).every((value) => value !== null)) getCourse({ variables }); - }, [getCourse, abbreviation, courseNumber, semester]); - - useEffect(() => { - const course = data?.allCourses.edges[0].node; - - if (course && course?.id === coursePreview?.id) { - setCourse(course); - setOpen(true); - } else if (coursePreview) { - setCourse(coursePreview); - setOpen(true); - } - }, [coursePreview, data]); - - const [playlists, sections] = useMemo(() => { - let playlists = null; - let sections = null; - // let semesters = null; - - if (course?.playlistSet) { - const { edges } = course.playlistSet; - playlists = catalogService.sortPills(edges.map((e) => e.node as PlaylistType)); - - // semesters = catalogService.sortSemestersByLatest( - // edges.map((e) => e.node).filter((n) => n.category === 'semester') - // ); - } - - if (course?.sectionSet) { - const { edges } = course.sectionSet; - sections = sortSections(edges.map((e) => e.node)); - } - - // return [playlists ?? skeleton, sections ?? [], semesters]; - return [playlists ?? skeleton, sections ?? null]; - }, [course]); - - const handlePill = (pillItem: PlaylistType) => { - setCurrentFilters((prev) => { - if (['haas', 'ls', 'engineering', 'university'].includes(pillItem.category)) { - const reqs = prev.requirements; - if (reqs?.find((el) => el.label === pillItem.name)) { - return prev; - } - - return { - ...prev, - requirements: [...(reqs ?? []), { label: pillItem.name, value: pillItem }] - }; - } - - return { - ...prev, - [pillItem.category]: { label: pillItem.name, value: pillItem } - }; - }); - }; - - const enrollPath = legacyId - ? `/enrollment/0-${legacyId}-${semester.replace(' ', '-')}-all` - : `/enrollment`; - - const gradePath = legacyId ? `/grades/0-${legacyId}-all-all` : `/grades`; - - return ( -
- {course && ( - <> - -

- {course.abbreviation} {course.courseNumber} -

-
{course.title}
-
-
- - Enrolled: - {course.enrolled !== -1 ? ( -
- {applyIndicatorPercent( - `${course.enrolled}/${course.enrolledMax}`, - course.enrolledPercentage - )} - - - -
- ) : ( -
N/A
- )} -
-
- - Average Grade: - {course.gradeAverage !== -1 ? ( -
- {applyIndicatorGrade(course.letterAverage, course.letterAverage)} - - - -
- ) : ( -
N/A
- )} -
-
- - {formatUnits(course?.units)} -
-
-
-
- {playlists?.map((req) => - typeof req === 'number' ? ( - - ) : ( - handlePill(req)}> - {req.name} - - ) - )} -
-
- - {course?.description ?? ''} - <> -
Prerequisites
-

- {course.prerequisites !== '' - ? course.prerequisites - : 'There is no information on the prerequisites of this course.'} -

- -
-
Class Times - {semester ?? ''}
- {sections && sections.length > 0 ? ( - - ) : !loading ? ( - There are no class times for the selected course. - ) : null} - - {/* - Redesigned catalog sections - - */} - - {/* Good feature whenever we want... -
Past Offerings
-
- {pastSemesters ? ( - pastSemesters.map((req) => ( - - )) - ) : ( - - )} -
*/} - - )} -
- ); -}; - -export default memo(CatalogView); diff --git a/frontend/src/app/Catalog/CatalogView/ReadMore.tsx b/frontend/src/app/Catalog/CatalogView/ReadMore.tsx deleted file mode 100644 index 7ad9cfedc..000000000 --- a/frontend/src/app/Catalog/CatalogView/ReadMore.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { ReactNode, useState } from 'react'; - -import styles from './CatalogView.module.scss'; - -interface Props { - // Here we specify that the component MUST take a string followed by a singular component. - children: [string, ReactNode]; -} - -// -// Handles the 'read more' button logic in the CatalogView component. -// -const ReadMore = ({ children }: Props) => { - const [isRead, setRead] = useState(false); - const [text, node] = children; - - return ( -
- {text.length > 150 ? ( -

- {isRead ? text : text.slice(0, 150) + '...'} - setRead((prev) => !prev)}>{isRead ? 'see less' : 'see more'} -

- ) : text !== '' ? ( - text - ) : ( - 'There is no description for this course.' - )} - - {(isRead || text.length < 150) && node} -
- ); -}; - -export default ReadMore; diff --git a/frontend/src/app/Catalog/CatalogView/SectionTable.tsx b/frontend/src/app/Catalog/CatalogView/SectionTable.tsx deleted file mode 100644 index f3b70bf21..000000000 --- a/frontend/src/app/Catalog/CatalogView/SectionTable.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { SectionFragment } from 'graphql'; -import { CSSProperties } from 'react'; -import { Table } from 'react-bootstrap'; - -import denero from 'assets/img/eggs/denero.png'; -import hug from 'assets/img/eggs/hug.png'; -import hilf from 'assets/img/eggs/hilf.png'; -import sahai from 'assets/img/eggs/sahai.png'; -import scott from 'assets/img/eggs/scott.png'; -import kubi from 'assets/img/eggs/kubi.png'; -import garcia from 'assets/img/eggs/garcia.png'; -import { formatSectionTime } from 'utils/sections/section'; - -const easterEggImages = new Map([ - ['DENERO J', denero], - ['HUG J', hug], - ['SAHAI A', sahai], - ['HILFINGER P', hilf], - ['SHENKER S', scott], - ['KUBIATOWICZ J', kubi], - ['GARCIA D', garcia] -]); - -function findInstructor(instr: string | null): CSSProperties { - if (instr === null) return {}; - - for (const [name, eggUrl] of easterEggImages) { - if (instr.includes(name)) { - return { - cursor: `url("${eggUrl}"), pointer` - } as CSSProperties; - } - } - - return {}; -} - -type Props = { - sections: SectionFragment[] | null; -}; - -const SectionTable = ({ sections }: Props) => { - return ( -
-
- - - - - - - - - - - - - - {sections?.map((section) => { - return ( - - - - - {section.startTime && section.endTime ? ( - - ) : ( - - )} - - - - - ); - })} - -
TypeCCNInstructorTimeLocationEnrolledWaitlist
{section.kind}{section.ccn}{section.instructor} - {section.wordDays} {formatSectionTime(section)} - {section.locationName} - {section.enrolled}/{section.enrolledMax} - {section.waitlisted}
-
-
- ); -}; - -export default SectionTable; diff --git a/frontend/src/app/Catalog/CatalogView/__new_SectionTable.tsx b/frontend/src/app/Catalog/CatalogView/__new_SectionTable.tsx deleted file mode 100644 index a33b596c1..000000000 --- a/frontend/src/app/Catalog/CatalogView/__new_SectionTable.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { SectionFragment } from 'graphql'; -import { CSSProperties } from 'react'; -import { formatSectionTime } from 'utils/sections/section'; -import catalogService from '../service'; -import Skeleton from 'react-loading-skeleton'; - -import people from 'assets/svg/catalog/people.svg'; -import denero from 'assets/img/eggs/denero.png'; -import hug from 'assets/img/eggs/hug.png'; -import hilf from 'assets/img/eggs/hilf.png'; -import sahai from 'assets/img/eggs/sahai.png'; -import scott from 'assets/img/eggs/scott.png'; -import kubi from 'assets/img/eggs/kubi.png'; -import garcia from 'assets/img/eggs/garcia.png'; - -import styles from './CatalogView.module.scss'; - -const { colorEnrollment, formatEnrollment } = catalogService; - -const easterEggImages = new Map([ - ['DENERO J', denero], - ['HUG J', hug], - ['SAHAI A', sahai], - ['HILFINGER P', hilf], - ['SHENKER S', scott], - ['KUBIATOWICZ J', kubi], - ['GARCIA D', garcia] -]); - -function findInstructor(instr: string | null): CSSProperties { - if (instr === null) return {}; - - for (const [name, eggUrl] of easterEggImages) { - if (instr.includes(name)) { - return { - cursor: `url("${eggUrl}"), pointer` - } as CSSProperties; - } - } - - return {}; -} - -type Props = { - sections: SectionFragment[] | null; -}; - -const CatalogViewSections = ({ sections }: Props) => { - if (!sections) { - return ( - - ); - } - - return ( -
- {sections.length > 0 ? ( - sections.map((section) => ( -
-
-
- {section.kind} -{' '} - {section.locationName ? section.locationName : 'Unknown Location'} -
-
- {section?.instructor?.toLowerCase() ?? 'instructor'},{' '} - {section.wordDays} {formatSectionTime(section)} -
- - - {formatEnrollment(section.enrolled / section.enrolledMax)} - - • {section.waitlisted} waitlisted - • CCN: {section.ccn} - -
-
- - {section.enrolled}/{section.enrolledMax} -
-
- )) - ) : ( -
There are no class sections for this course.
- )} -
- ); -}; - -export default CatalogViewSections; diff --git a/frontend/src/app/Catalog/CatalogView/index.ts b/frontend/src/app/Catalog/CatalogView/index.ts deleted file mode 100644 index a035bac40..000000000 --- a/frontend/src/app/Catalog/CatalogView/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import CatalogView from './CatalogView'; - -export default CatalogView; diff --git a/frontend/src/app/Catalog/Class/Class.module.scss b/frontend/src/app/Catalog/Class/Class.module.scss new file mode 100644 index 000000000..e9f19e408 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Class.module.scss @@ -0,0 +1,71 @@ +.content { + width: 128px; + background-color: red; + height: 128px; +} + +.root { + flex-grow: 1; + display: flex; + flex-direction: column; + overflow: auto; + + @media (width <= 992px) { + position: absolute; + inset: 0; + background-color: var(--background-color); + z-index: 3; + } + + .header { + padding: 24px 24px 12px; + background-color: var(--foreground-color); + + .row { + display: flex; + justify-content: space-between; + margin-bottom: 24px; + } + + .group { + display: flex; + align-items: center; + gap: 12px; + + .bookmark.active { + color: var(--blue-500); + border-color: color-mix(in srgb, currentColor 10%, transparent); + background-color: color-mix(in srgb, currentColor 10%, transparent); + } + + .like.active { + color: var(--rose-500); + border-color: color-mix(in srgb, currentColor 10%, transparent); + background-color: color-mix(in srgb, currentColor 10%, transparent); + } + } + + .heading { + font-size: 24px; + line-height: 1.25; + font-weight: 700; + color: var(--heading-color); + margin-bottom: 8px; + } + + .description { + font-size: 16px; + line-height: 1.5; + color: var(--paragraph-color); + margin-bottom: 16px; + } + } + + .menu { + display: flex; + border-bottom: 1px solid var(--border-color); + background-color: var(--foreground-color); + padding: 12px; + align-items: center; + } +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Enrollment/Enrollment.module.scss b/frontend/src/app/Catalog/Class/Enrollment/Enrollment.module.scss new file mode 100644 index 000000000..5500e3906 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Enrollment/Enrollment.module.scss @@ -0,0 +1,42 @@ +.root { + padding: 24px; + flex-grow: 1; + display: flex; + flex-direction: column; + + .legend { + display: flex; + gap: 24px; + justify-content: center; + + .label { + font-size: 14px; + line-height: 1; + color: var(--paragraph-color); + display: flex; + align-items: center; + gap: 12px; + + .icon { + width: 16px; + height: 16px; + border-radius: 4px; + background-color: currentColor; + } + + &:first-child { + color: var(--blue-500); + } + } + } + + .chart { + height: 384px; + + .label { + font-size: 12px; + color: var(--label-color); + font-weight: 400; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Enrollment/Reservations/Reservations.module.scss b/frontend/src/app/Catalog/Class/Enrollment/Reservations/Reservations.module.scss new file mode 100644 index 000000000..416d1359b --- /dev/null +++ b/frontend/src/app/Catalog/Class/Enrollment/Reservations/Reservations.module.scss @@ -0,0 +1,87 @@ +.root { + padding: 24px; + border: 1px solid var(--border-color); + background-color: var(--foreground-color); + border-radius: 8px; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.025); + flex-grow: 1; + background-color: var(--foreground-color); + + .label { + font-size: 14px; + line-height: 1; + margin-bottom: 12px; + color: var(--label-color); + } + + .groups { + display: flex; + flex-direction: column; + gap: 12px; + + .divider { + height: 1px; + background-color: var(--border-color); + } + + .group { + display: flex; + justify-content: space-between; + align-items: flex-start; + font-size: 14px; + line-height: 1.5; + gap: 24px; + color: var(--paragraph-color); + + @media (width <= 992px) { + flex-direction: column; + gap: 8px; + } + + .description { + white-space: nowrap; + transition: all 100ms ease-in-out; + } + + .title { + font-weight: 500; + transition: all 100ms ease-in-out; + + &.active { + color: var(--heading-color); + } + } + } + } + + .chart { + display: flex; + gap: 4px; + margin-bottom: 20px; + + .bar { + height: 16px; + border-radius: 2px; + overflow: hidden; + background-color: var(--button-color); + transition: all 100ms ease-in-out; + min-width: 16px; + + .progress { + height: 100%; + } + + &:first-child:last-child { + border-radius: 8px; + } + + &:first-child { + border-radius: 8px 2px 2px 8px; + } + + &:last-child { + border-radius: 2px 8px 8px 2px; + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Enrollment/Reservations/index.tsx b/frontend/src/app/Catalog/Class/Enrollment/Reservations/index.tsx new file mode 100644 index 000000000..4fae011a0 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Enrollment/Reservations/index.tsx @@ -0,0 +1,122 @@ +import { Fragment, useMemo, useState } from "react"; + +import classNames from "classnames"; + +import { IReservation } from "@/lib/api"; + +import styles from "./Reservations.module.scss"; + +const getColor = (count: number, capacity: number) => { + const percentage = count / capacity; + + return percentage >= 0.75 + ? "var(--rose-500)" + : percentage > 0.5 + ? "var(--amber-500)" + : "var(--emerald-500)"; +}; + +interface ReservationsProps { + reservations: IReservation[]; + enrollMax: number; + enrollCount: number; +} + +export default function Reservations({ + reservations, + enrollMax, + enrollCount, +}: ReservationsProps) { + const [currentReservation, setCurrentReservation] = useState( + null + ); + + const parsedReservations = useMemo(() => { + const _reservations = structuredClone(reservations); + + const [totalEnrollCount, totalEnrollMax] = reservations.reduce( + ([totalEnrollCount, totalEnrollMax], { enrollCount, enrollMax }) => [ + totalEnrollCount + enrollCount, + totalEnrollMax + enrollMax, + ], + [0, 0] + ); + + if (totalEnrollMax !== enrollMax) { + _reservations.push({ + group: "All students", + enrollCount: enrollCount - totalEnrollCount, + enrollMax: enrollMax - totalEnrollMax, + }); + } + + return _reservations.sort((a, b) => b.enrollMax - a.enrollMax); + }, [enrollCount, enrollMax, reservations]); + + return ( +
+

Reservations

+
+ {parsedReservations.map(({ enrollCount, enrollMax }, index) => { + const identifier = index + 1; + const backgroundColor = getColor(enrollCount, enrollMax); + + const opacity = + !currentReservation || identifier === currentReservation ? 1 : 0.25; + + return ( +
setCurrentReservation(identifier)} + onMouseOut={() => setCurrentReservation(null)} + style={{ + opacity, + flex: enrollMax, + }} + > +
+
+ ); + })} +
+
+ {parsedReservations.map(({ group, enrollCount, enrollMax }, index) => { + const identifier = index + 1; + const color = getColor(enrollCount, enrollMax); + + const opacity = + !currentReservation || identifier === currentReservation ? 1 : 0.25; + + return ( + + {index !== 0 &&
} +
setCurrentReservation(identifier)} + onMouseOut={() => setCurrentReservation(null)} + > +

+ {group} +

+

+ {enrollCount} / {enrollMax} +

+
+ + ); + })} +
+
+ ); +} diff --git a/frontend/src/app/Catalog/Class/Enrollment/index.tsx b/frontend/src/app/Catalog/Class/Enrollment/index.tsx new file mode 100644 index 000000000..2f1d43e75 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Enrollment/index.tsx @@ -0,0 +1,140 @@ +import { + CartesianGrid, + Line, + LineChart, + ReferenceLine, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; + +import { IClass } from "@/lib/api"; + +import styles from "./Enrollment.module.scss"; +import Reservations from "./Reservations"; + +const data = [ + { + name: "Page A", + uv: 0, + pv: 0, + amt: 1, + }, + { + name: "Page B", + uv: 2000, + pv: 2500, + amt: 2, + }, + { + name: "Page C", + uv: 2500, + pv: 2700, + amt: 3, + }, + { + name: "Page D", + uv: 2800, + pv: 2850, + amt: 4, + }, + { + name: "Page E", + uv: 2900, + pv: 3000, + amt: 5, + }, + { + name: "Page F", + uv: 3000, + pv: 3000, + amt: 6, + }, + { + name: "Page G", + uv: 3010, + pv: 3010, + amt: 7, + }, +]; + +interface EnrollmentProps { + currentClass?: IClass; +} + +export default function Enrollment({ currentClass }: EnrollmentProps) { + return ( +
+
+
+
+ Spring 2024 +
+
+
+ Average +
+
+
+ + + + + + + } + /> + value.toLocaleString()} + tickMargin={8} + label={
} + /> + + + + +
+ {currentClass && ( + + )} +
+ ); +} diff --git a/frontend/src/app/Catalog/Class/Grades/Grades.module.scss b/frontend/src/app/Catalog/Class/Grades/Grades.module.scss new file mode 100644 index 000000000..64a8a3757 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Grades/Grades.module.scss @@ -0,0 +1,4 @@ +.root { + height: 384px; + padding: 24px; +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Grades/index.tsx b/frontend/src/app/Catalog/Class/Grades/index.tsx new file mode 100644 index 000000000..48fbb0783 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Grades/index.tsx @@ -0,0 +1,68 @@ +import { + Bar, + BarChart, + CartesianGrid, + Legend, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; + +import styles from "./Grades.module.scss"; + +const data = [ + { + grade: "A", + percentage: 20, + average: 25, + }, + { + grade: "B", + percentage: 15, + average: 20, + }, + { + grade: "C", + percentage: 10, + average: 15, + }, + { + grade: "D", + percentage: 5, + average: 10, + }, + { + grade: "F", + percentage: 2.5, + average: 5, + }, + { + grade: "Pass", + percentage: 35, + average: 20, + }, + { + grade: "Not pass", + percentage: 17.5, + average: 5, + }, +]; + +export default function Grades() { + return ( +
+ + + + + + + + + + + +
+ ); +} diff --git a/frontend/src/app/Catalog/Class/Overview/Overview.module.scss b/frontend/src/app/Catalog/Class/Overview/Overview.module.scss new file mode 100644 index 000000000..0ca3579a1 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Overview/Overview.module.scss @@ -0,0 +1,16 @@ +.root { + padding: 24px; + font-size: 14px; + + .label { + margin-top: 24px; + color: var(--label-color); + line-height: 1; + } + + .description { + color: var(--paragraph-color); + margin-top: 8px; + line-height: 1.5; + } +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Overview/index.tsx b/frontend/src/app/Catalog/Class/Overview/index.tsx new file mode 100644 index 000000000..b633500e4 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Overview/index.tsx @@ -0,0 +1,30 @@ +import Details from "@/components/Details"; +import { IClass } from "@/lib/api"; + +import styles from "./Overview.module.scss"; + +interface OverviewProps { + currentClass?: IClass; +} + +export default function Overview({ currentClass }: OverviewProps) { + if (!currentClass) return null; + + return ( +
+
+

Description

+

+ {currentClass.description ?? currentClass.course.description} +

+ {currentClass.course.requirements && ( + <> +

Prerequisites

+

+ {currentClass.course.requirements} +

+ + )} +
+ ); +} diff --git a/frontend/src/app/Catalog/Class/Sections/Sections.module.scss b/frontend/src/app/Catalog/Class/Sections/Sections.module.scss new file mode 100644 index 000000000..0e21e418b --- /dev/null +++ b/frontend/src/app/Catalog/Class/Sections/Sections.module.scss @@ -0,0 +1,141 @@ +.placeholder { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + color: var(--label-color); + height: 100%; + font-size: 16px; + line-height: 1.5; + padding: 24px; + text-align: center; + + .heading { + color: var(--heading-color); + font-weight: 500; + margin-top: 24px; + } + + .paragraph { + color: var(--paragraph-color); + margin-top: 8px; + max-width: 448px; + } +} + +.root { + background-color: var(--background-color); + padding: 24px 24px 24px 12px; + display: flex; + gap: 24px; + + @media (width <= 992px) { + flex-direction: column; + } + + @media (width > 992px) { + align-items: flex-start; + } + + .view { + flex-grow: 1; + + .group { + scroll-margin-top: 24px; + + .section { + padding: 24px; + background-color: var(--foreground-color); + border-radius: 8px; + box-shadow: 0 1px 2px rgb(0 0 0 / 5%); + margin-bottom: 24px; + border: 1px solid var(--border-color); + + .header { + display: flex; + margin-bottom: 24px; + gap: 12px; + + .text { + flex-grow: 1; + + .heading { + color: var(--heading-color); + font-size: 14px; + margin-bottom: 8px; + line-height: 1; + font-weight: 500; + } + } + } + } + } + } + + .menu { + position: sticky; + top: 24px; + width: 192px; + flex-shrink: 0; + display: flex; + flex-direction: column; + gap: 8px; + + .item { + height: 32px; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: space-between; + position: relative; + gap: 12px; + padding: 0 12px; + line-height: 1; + font-size: 14px; + cursor: pointer; + + &:hover { + background-color: var(--button-hover-color); + + .component { + color: var(--heading-color); + } + } + + &:active { + background-color: var(--button-active-color); + } + + &.active .component { + color: var(--heading-color); + } + + &.active::after { + opacity: 1; + } + + &::after { + content: ""; + width: 2px; + height: 100%; + background-color: var(--blue-500); + position: absolute; + opacity: 0; + left: -12px; + transition: all 100ms ease-in-out; + } + + .component { + font-weight: 500; + color: var(--paragraph-color); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + + .count { + color: var(--label-color); + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Catalog/Class/Sections/index.tsx b/frontend/src/app/Catalog/Class/Sections/index.tsx new file mode 100644 index 000000000..e169750f2 --- /dev/null +++ b/frontend/src/app/Catalog/Class/Sections/index.tsx @@ -0,0 +1,181 @@ +import { useEffect, useMemo, useRef, useState } from "react"; + +import classNames from "classnames"; +import { FrameAltEmpty, OpenNewWindow } from "iconoir-react"; + +import CCN from "@/components/CCN"; +import Details from "@/components/Details"; +import IconButton from "@/components/IconButton"; +import LoadingIndicator from "@/components/LoadingIndicator"; +import Tooltip from "@/components/Tooltip"; +import { Component, IClass, Semester, components } from "@/lib/api"; +import { getExternalLink } from "@/lib/section"; + +import Capacity from "../../../../components/Capacity"; +import styles from "./Sections.module.scss"; + +interface SectionsProps { + currentClass?: IClass; + currentYear: number; + currentSemester: Semester; +} + +export default function Sections({ + currentClass, + currentYear, + currentSemester, +}: SectionsProps) { + const viewRef = useRef(null); + const [group, setGroup] = useState(null); + + const groups = useMemo(() => { + const sortedSections = structuredClone(currentClass?.sections ?? []).sort( + (a, b) => a.number.localeCompare(b.number) + ); + + return Object.groupBy(sortedSections, (section) => section.component); + }, [currentClass]); + + useEffect(() => { + const element = viewRef.current; + if (!element) return; + + let currentElement: HTMLElement | null = element; + + while (currentElement) { + const overflowY = window.getComputedStyle(currentElement).overflowY; + + if (overflowY === "auto") { + break; + } + + currentElement = currentElement.parentElement; + } + + if (!currentElement) return; + + const updateGroup = () => { + const view = viewRef.current; + if (!view) return; + + // element is a div that can scroll, find the child with the most pixels within the viewport + const children = Array.from(view.children) as HTMLElement[]; + + const visibleIndexes = children.map((child) => { + const rect = child.getBoundingClientRect(); + const top = Math.max(rect.top, 0); + const bottom = Math.min(rect.bottom, window.innerHeight); + + return bottom - top; + }); + + const maxVisibleIndex = visibleIndexes.reduce( + (maxIndex, visible, index) => + visible > visibleIndexes[maxIndex] ? index : maxIndex, + 0 + ); + + const group = Object.keys(groups)[maxVisibleIndex] as Component; + setGroup(group); + }; + + updateGroup(); + + currentElement.addEventListener("scroll", updateGroup); + + return () => { + currentElement.removeEventListener("scroll", updateGroup); + }; + }, [groups]); + + const handleClick = (index: number) => { + viewRef.current?.children[index].scrollIntoView({ behavior: "smooth" }); + }; + + return currentClass ? ( + currentClass.sections.length === 0 ? ( +
+ +

No associated sections

+

+ Please refer to the class syllabus or instructor for the most accurate + information regarding class attendance requirements. +

+
+ ) : ( +
+
+ {Object.keys(groups).map((component, index) => ( +
handleClick(index)} + > +

+ {components[component as Component]} +

+

+ {groups[component as Component]?.length.toLocaleString()} +

+
+ ))} +
+
+ {Object.values(groups).map((sections) => ( +
+ {sections.map((section) => ( +
+
+
+

+ {components[section.component]} {section.number} +

+ +
+ + {currentClass && ( + + + + + + + + )} +
+
+
+ ))} +
+ ))} +
+
+ ) + ) : ( +
+ +
+ ); +} diff --git a/frontend/src/app/Catalog/Class/index.tsx b/frontend/src/app/Catalog/Class/index.tsx new file mode 100644 index 000000000..a85ba5791 --- /dev/null +++ b/frontend/src/app/Catalog/Class/index.tsx @@ -0,0 +1,238 @@ +import { useMemo, useState } from "react"; + +import { useQuery } from "@apollo/client"; +import classNames from "classnames"; +import { + Bookmark, + BookmarkSolid, + CalendarPlus, + GridPlus, + Heart, + HeartSolid, + OpenInWindow, + OpenNewWindow, + Xmark, +} from "iconoir-react"; +import { Link, useSearchParams } from "react-router-dom"; + +import AverageGrade from "@/components/AverageGrade"; +import Button from "@/components/Button"; +import CCN from "@/components/CCN"; +import Capacity from "@/components/Capacity"; +import IconButton from "@/components/IconButton"; +import MenuItem from "@/components/MenuItem"; +import Tooltip from "@/components/Tooltip"; +import Units from "@/components/Units"; +import { GET_CLASS, IClass, ICourse, Semester } from "@/lib/api"; +import { getExternalLink } from "@/lib/section"; + +import styles from "./Class.module.scss"; +import Enrollment from "./Enrollment"; +import Grades from "./Grades"; +import Overview from "./Overview"; +import Sections from "./Sections"; + +const views = [ + { + text: "Overview", + Component: Overview, + }, + { + text: "Sections", + Component: Sections, + }, + { + text: "Grades", + Component: Grades, + }, + { + text: "Enrollment", + Component: Enrollment, + }, +]; + +interface ClassProps { + partialCurrentCourse: ICourse | null; + currentSemester: Semester; + currentYear: number; + currentClassNumber: string; + currentCourseNumber: string; + currentSubject: string; +} + +export default function Class({ + partialCurrentCourse, + currentSemester, + currentYear, + currentClassNumber, + currentCourseNumber, + currentSubject, +}: ClassProps) { + const [searchParams] = useSearchParams(); + const [view, setView] = useState(0); + + // TODO: Query for enrollment and grades data in the background + + const { data } = useQuery<{ class: IClass }>(GET_CLASS, { + variables: { + term: { + semester: currentSemester, + year: currentYear, + }, + subject: currentSubject, + courseNumber: currentCourseNumber, + classNumber: currentClassNumber, + }, + }); + + const partialCurrentClass = useMemo( + () => + partialCurrentCourse?.classes.find( + (class_) => class_.number === currentClassNumber + ), + [partialCurrentCourse, currentClassNumber] + ); + + const currentClass = useMemo(() => data?.class, [data]); + + const Component = useMemo(() => views[view].Component, [view]); + + const [liked, setLiked] = useState(false); + const [bookmarked, setBookmarked] = useState(false); + + return ( +
+
+
+
+ + + + + setBookmarked(!bookmarked)} + > + {bookmarked ? : } + + + + + + + + + + + + +
+
+ + + + + + {currentClass && ( + + + + + + + + )} + + + + + + + +
+
+

+ {currentSubject} {currentCourseNumber} +

+

+ {currentClass?.title ?? + partialCurrentClass.title ?? + partialCurrentCourse.title} +

+
+ + + + {currentClass && } +
+
+
+ {views.map(({ text }, index) => ( + setView(index)} + > + {text} + + ))} +
+ +
+ ); +} diff --git a/frontend/src/app/Catalog/index.ts b/frontend/src/app/Catalog/index.ts deleted file mode 100644 index ddc203ace..000000000 --- a/frontend/src/app/Catalog/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Catalog from './Catalog'; - -export default Catalog; diff --git a/frontend/src/app/Catalog/index.tsx b/frontend/src/app/Catalog/index.tsx new file mode 100644 index 000000000..5e08f5425 --- /dev/null +++ b/frontend/src/app/Catalog/index.tsx @@ -0,0 +1,75 @@ +import { useCallback, useMemo, useState } from "react"; + +import { useNavigate, useParams, useSearchParams } from "react-router-dom"; + +import Browser from "@/components/Browser"; +import { ICourse, Semester } from "@/lib/api"; + +import styles from "./Catalog.module.scss"; +import Class from "./Class"; + +export default function Catalog() { + const { + year, + semester, + subject, + courseNumber: currentCourseNumber, + classNumber: currentClassNumber, + } = useParams(); + + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + + const [partialCurrentCourse, setPartialCurrentCourse] = + useState(null); + + // TODO: Select year + const currentYear = useMemo(() => (year && parseInt(year)) || 2024, [year]); + + // TODO: Select semester + const currentSemester = useMemo( + () => + semester + ? ((semester[0].toUpperCase() + + semester.slice(1).toLowerCase()) as Semester) + : Semester.Spring, + [semester] + ); + + const currentSubject = useMemo(() => subject?.toUpperCase(), [subject]); + + const handleClick = useCallback( + (course: ICourse, number: string) => { + setPartialCurrentCourse(course); + + navigate({ + pathname: `/catalog/${currentYear}/${currentSemester}/${course.subject}/${course.number}/${number}`, + search: searchParams.toString(), + }); + }, + [navigate, currentYear, currentSemester, searchParams] + ); + + return ( +
+ + {currentClassNumber && currentCourseNumber && currentSubject ? ( + + ) : ( + <> + )} +
+ ); +} diff --git a/frontend/src/app/Catalog/service.ts b/frontend/src/app/Catalog/service.ts deleted file mode 100644 index e7cb92bb0..000000000 --- a/frontend/src/app/Catalog/service.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { FilterFragment, GetFiltersQuery, PlaylistType } from 'graphql'; -import styles from './CatalogList/CatalogList.module.scss'; - -import { - CatalogCategoryKeys, - FilterTemplate, - CatalogFilterKeys, - FilterOptions, - SortOption, - CurrentFilters -} from './types'; - -const SEMESTER_VALUES = { - spring: 0.0, - summer: 0.1, - fall: 0.2 -}; - -const SORT_OPTIONS: SortOption[] = [ - { value: 'relevance', label: 'Sort By: Relevance' }, - { value: 'average_grade', label: 'Sort By: Average Grade' }, - { value: 'department_name', label: 'Sort By: Department Name' }, - { value: 'open_seats', label: 'Sort By: Open Seats' }, - { value: 'enrolled_percentage', label: 'Sort By: Percent Enrolled' } -]; - -const INITIAL_FILTERS: CurrentFilters = { - department: null, - semester: null, - units: null, - level: null, - requirements: null -}; - -const FILTER_TEMPLATE: FilterTemplate = { - requirements: { - name: 'Requirements', - isClearable: true, - isMulti: true, - closeMenuOnSelect: false, - isSearchable: false, - options: [], - placeholder: 'Requirements...' - }, - units: { - name: 'Units', - isClearable: true, - isMulti: true, - closeMenuOnSelect: false, - isSearchable: false, - options: [], - placeholder: 'Units...' - }, - department: { - name: 'Department', - isClearable: true, - isMulti: false, - closeMenuOnSelect: true, - isSearchable: true, - options: [], - placeholder: 'Department...' - }, - level: { - name: 'Class Level', - isClearable: true, - isMulti: true, - closeMenuOnSelect: false, - isSearchable: false, - options: [], - placeholder: 'Class levels...' - }, - semester: { - name: 'Semesters', - isClearable: false, - isMulti: false, - closeMenuOnSelect: true, - isSearchable: false, - options: [], - placeholder: 'Semester...' - } -}; - -/** - * @param data The raw, unprocessed query data from the server - * @returns An object where the keys are filter categories and the values are - * a sorted array of `FilterFragments` or null if no data was passed. - */ -const processFilterData = (data?: GetFiltersQuery) => { - if (!data) return null; - - const filters = data.allPlaylists.edges - .map((edge) => edge.node) - .reduce((prev, filter) => { - const category = filter.category as CatalogCategoryKeys; - return { - ...prev, - [category]: [...(prev[category] || []), filter] - }; - }, {} as FilterOptions); - - // After organizing the data, sort each category accordingly. - Object.entries(filters).map(([key, category]) => { - switch (key as CatalogCategoryKeys) { - case 'semester': - return sortSemestersByLatest(category); - default: - return sortByName(category); - } - }); - - return filters; -}; -/** - * - * @param filterItems an empty filter template - * @param filters processed filter data - * @description Populates the `options` field of each template item with the - * appropriate filter options from the server. - * @returns a `FilterTemplate` with populated `options` - */ -const putFilterOptions = (filterItems: FilterTemplate, filters?: FilterOptions | null) => { - if (!filters) return null; - - const result = { ...filterItems }; - - const requirements: { label: string; key: CatalogCategoryKeys }[] = [ - { label: 'University Requirements', key: 'university' }, - { label: 'L&S Breadths', key: 'ls' }, - { label: 'College of Engineering', key: 'engineering' }, - { label: 'Haas Breadths', key: 'haas' } - ]; - - result['requirements'].options = requirements.map((req) => ({ - label: req.label, - options: - filters[req.key]?.map((filter) => ({ - label: filter.name, - value: filter - })) || [] - })); - - Object.entries(result) - .filter(([key]) => key !== 'requirements') - .map(([k]) => { - const key = k as CatalogFilterKeys; - result[key].options = filters[key].map((filter) => ({ - label: filter.name, - value: filter - })); - }); - - return result; -}; - -/** - * - * @param semesters - * @returns The semester filters sorted by their year and semester. - * @description Sorts all semester filters by their year and semester, - * then returns the id of the most recent one - */ -const sortSemestersByLatest = (semester: FilterOptions['semester']) => { - return semester.sort((a, b) => SemesterToValue(b) - SemesterToValue(a)); -}; - -/** - * - * @param semesterFiler - * @returns a number representing the semester in the form (year + semester) - * @description Converts the name of a semester to a number value to be compared with. Greater = more recent - */ -const SemesterToValue = (semesterFilter: FilterFragment) => { - const [semester, year] = semesterFilter.name.toLowerCase().split(' ') as [ - 'spring' | 'fall' | 'summer', - string - ]; - - return parseInt(year, 10) + SEMESTER_VALUES[semester]; -}; - -/** - * @description sorts the playlists alphabetically, and - * by putting the `units` category at the end of the list - */ -const sortPills = (playlists: PlaylistType[]) => { - const semesters = sortSemestersByLatest(playlists.filter((p) => p.category === 'semester')); - const units = sortByName(playlists.filter((p) => p.category === 'units')); - const rest = sortByName(playlists.filter((p) => !['units', 'semester'].includes(p.category))); - - return rest.concat(units, semesters.slice(0, 4) as PlaylistType[]); -}; - -export const sortByName = (arr: T) => { - return arr.sort((a, b) => a.name.localeCompare(b.name)); -}; - -function formatEnrollment(percentage: number) { - if (percentage === -1) return 'N/A'; - return `${Math.floor(percentage * 100)}% enrolled`; -} - -function colorEnrollment(percentage: number) { - if (percentage === -1) return ''; - - const pct = percentage * 100; - if (pct < 33) { - return styles.A; - } else if (pct < 67) { - return styles.C; - } else { - return styles.F; - } -} - -export default { - FILTER_TEMPLATE, - SORT_OPTIONS, - INITIAL_FILTERS, - processFilterData, - putFilterOptions, - sortByName, - sortSemestersByLatest, - sortPills, - formatEnrollment, - colorEnrollment -}; diff --git a/frontend/src/app/Catalog/types.ts b/frontend/src/app/Catalog/types.ts deleted file mode 100644 index 9d6d9e94c..000000000 --- a/frontend/src/app/Catalog/types.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { FilterFragment } from 'graphql'; -import { GroupBase } from 'react-select'; - -export type CatalogSlug = { - abbreviation?: string; - courseNumber?: string; - semester?: string; -}; - -export type CatalogCategoryKeys = - | 'department' - | 'engineering' - | 'haas' - | 'level' - | 'ls' - | 'semester' - | 'units' - | 'university' - | 'requirements'; - -export type CatalogFilterKeys = Exclude< - CatalogCategoryKeys, - 'haas' | 'ls' | 'engineering' | 'university' ->; - -export type FilterOptions = { - [category in CatalogCategoryKeys]: FilterFragment[]; -}; - -export type CurrentFilters = { - department: FilterOption | null; - level: FilterOption[] | null; - units: FilterOption[] | null; - semester: FilterOption | null; - requirements: FilterOption[] | null; -}; - -type CatalogSortKeys = - | 'relevance' - | 'average_grade' - | 'department_name' - | 'open_seats' - | 'enrolled_percentage'; - -export type SortOption = { value: CatalogSortKeys; label: string }; -export type FilterOption = { value: FilterFragment; label: string }; - -export type FilterTemplate = { - [key in CatalogFilterKeys]: { - name: string; - isClearable: boolean; - isMulti: boolean; - closeMenuOnSelect: boolean; - isSearchable: boolean; - options: (FilterOption | GroupBase)[]; - placeholder: string; - }; -}; diff --git a/frontend/src/app/Discover/Discover.module.scss b/frontend/src/app/Discover/Discover.module.scss new file mode 100644 index 000000000..d1f58ec77 --- /dev/null +++ b/frontend/src/app/Discover/Discover.module.scss @@ -0,0 +1,105 @@ +.root { + .body { + display: flex; + gap: 48px; + padding: 48px 0; + + .sideBar { + width: 288px; + flex-shrink: 0; + } + + .view { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(288px, 1fr)); + gap: 12px; + flex-grow: 1; + + .course { + border-radius: 8px; + padding: 16px; + background-color: var(--foreground-color); + border: 1px solid var(--border-color); + box-shadow: 0 1px 2px rgba(0 0 0 / 5%); + display: flex; + flex-direction: column; + + .title { + font-size: 14px; + color: var(--heading-color); + font-weight: 700; + margin-bottom: 8px; + line-height: 1; + } + + .description { + font-size: 14px; + color: var(--paragraph-color); + line-height: 1.5; + margin-bottom: 12px; + } + + .row { + display: flex; + align-items: center; + gap: 12px; + margin-top: auto; + + .badge { + font-size: 14px; + line-height: 1; + height: 32px; + display: flex; + align-items: center; + gap: 8px; + color: var(--gray-500); + background-color: var(--background-color); + padding: 0 12px; + border-radius: 16px; + } + } + } + } + } + + .header { + background: linear-gradient(to top right, var(--blue-500), var(--sky-500)); + display: flex; + flex-direction: column; + + .container { + padding: 64px 12px; + flex-grow: 1; + display: grid; + place-items: center; + + .form { + position: relative; + width: 640px; + max-width: 100%; + background-color: white; + padding: 0 16px; + border-radius: 4px; + display: flex; + align-items: center; + gap: 16px; + box-shadow: 0 4px 8px rgba(0 0 0 / 10%); + + .input:not(:placeholder-shown) + .placeholder { + display: none; + } + + .input { + color: var(--slate-900); + height: 56px; + font-size: 16px; + line-height: 1; + + &::placeholder { + color: var(--slate-500); + } + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Discover/Placeholder/Placeholder.module.scss b/frontend/src/app/Discover/Placeholder/Placeholder.module.scss new file mode 100644 index 000000000..ebf36d37f --- /dev/null +++ b/frontend/src/app/Discover/Placeholder/Placeholder.module.scss @@ -0,0 +1,10 @@ +.root { + color: var(--slate-500); + position: absolute; + top: 50%; + left: 16px; + transform: translateY(-50%); + pointer-events: none; + font-size: 16px; + line-height: 1; +} \ No newline at end of file diff --git a/frontend/src/app/Discover/Placeholder/index.tsx b/frontend/src/app/Discover/Placeholder/index.tsx new file mode 100644 index 000000000..6f55da168 --- /dev/null +++ b/frontend/src/app/Discover/Placeholder/index.tsx @@ -0,0 +1,57 @@ +import { useEffect, useRef, useState } from "react"; + +import classNames from "classnames"; + +import styles from "./Placeholder.module.scss"; + +const values = [ + "Explore courses...", + "Computational methods for science and engineering", + "Environmental policy and resource management", + "Bioinformatics and computational biology", + "Quantum mechanics and mathematical physics", + "Public health epidemiology and data analysis", +]; + +interface PlaceholderProps { + className?: string; +} + +export default function Placeholder({ className }: PlaceholderProps) { + const [text, setText] = useState(values[0]); + const positionRef = useRef(values[0].length - 1); + const indexRef = useRef(0); + + useEffect(() => { + let timeoutId: ReturnType; + + const update = () => { + let position = positionRef.current + 1; + + if (position === values[indexRef.current].length * 2) { + indexRef.current = (indexRef.current + 1) % values.length; + + position = 0; + } + + positionRef.current = position; + + const value = values[indexRef.current]; + + const end = + position > value.length ? -(position % value.length) : position; + + const _text = values[indexRef.current].slice(0, end); + + setText(_text); + + timeoutId = setTimeout(update, _text.length === value.length ? 1000 : 75); + }; + + timeoutId = setTimeout(update, 100); + + return () => clearInterval(timeoutId); + }, []); + + return

{text}

; +} diff --git a/frontend/src/app/Discover/index.tsx b/frontend/src/app/Discover/index.tsx new file mode 100644 index 000000000..ee822d8de --- /dev/null +++ b/frontend/src/app/Discover/index.tsx @@ -0,0 +1,152 @@ +import { FormEvent, useState } from "react"; + +import { useApolloClient, useQuery } from "@apollo/client"; +import { ArrowRight, Calendar } from "iconoir-react"; + +import AverageGrade from "@/components/AverageGrade"; +import Button from "@/components/Button"; +import Container from "@/components/Container"; +import Footer from "@/components/Footer"; +import NavigationBar from "@/components/NavigationBar"; +import Units from "@/components/Units"; +import { + GET_COURSE, + GET_COURSES, + GetCoursesResponse, + ICourse, + Semester, +} from "@/lib/api"; + +import styles from "./Discover.module.scss"; +import Placeholder from "./Placeholder"; + +const score = { + [Semester.Fall]: 4, + [Semester.Summer]: 3, + [Semester.Spring]: 2, + [Semester.Winter]: 1, +}; + +export default function Discover() { + const [input, setInput] = useState(""); + const [courses, setCourses] = useState([]); + const apolloClient = useApolloClient(); + + const { data } = useQuery(GET_COURSES); + + console.log(data); + + const getCourse = async (name: string) => { + const [subject, courseNumber] = name.split(" "); + + const { data } = await apolloClient.query<{ course: ICourse }>({ + query: GET_COURSE, + variables: { subject, courseNumber }, + }); + + if (!data) return; + + return data.course; + }; + + const handleSubmit = async (event: FormEvent) => { + event.preventDefault(); + + const response = await fetch( + `http://localhost:3002/query?input=${encodeURIComponent(input)}&topK=24` + ); + + if (!response.ok) return; + + const { matches } = (await response.json()) as { + matches: { id: string }[]; + }; + + const courses = await Promise.all( + matches.map(({ id: name }) => getCourse(name)) + ); + + setCourses( + courses.filter( + (course) => course && course.classes.length !== 0 + ) as ICourse[] + ); + }; + + return ( +
+
+ +
+
+ setInput(event.target.value)} + /> + + + +
+
+ +
+
+
+ {courses + .sort((a, b) => { + const getTerm = (course: ICourse) => { + return [...course.classes].sort( + (a, b) => + a.year - b.year || score[a.semester] - score[b.semester] + )[0]; + }; + + return ( + getTerm(b).year - getTerm(a).year || + score[getTerm(b).semester] - score[getTerm(a).semester] + ); + }) + .map((course) => { + const { year, semester } = [...course.classes].sort( + (a, b) => + a.year - b.year || score[a.semester] - score[b.semester] + )[0]; + + const { unitsMax, unitsMin } = course.classes.reduce( + (acc, { unitsMax, unitsMin }) => ({ + unitsMax: Math.max(acc.unitsMax, unitsMax), + unitsMin: Math.min(acc.unitsMin, unitsMin), + }), + { unitsMax: 0, unitsMin: 0 } + ); + + return ( +
+

+ {course.subject} {course.number} +

+

{course.title}

+
+ +
+ + {semester} {year} +
+ +
+
+ ); + })} +
+
+
+
+
+ ); +} diff --git a/frontend/src/app/Landing/Features/Features.module.scss b/frontend/src/app/Landing/Features/Features.module.scss new file mode 100644 index 000000000..49f4ce940 --- /dev/null +++ b/frontend/src/app/Landing/Features/Features.module.scss @@ -0,0 +1,157 @@ +.root { + padding: 96px 24px; + display: grid; + grid-template-columns: 1fr; + gap: 96px; + + @media (768px < width <= 1200px) { + grid-template-columns: 1fr 1fr; + } + + .row { + @media (width > 1200px) { + display: flex; + gap: 96px; + } + + .gallery { + flex-grow: 1; + position: relative; + + @media (width <= 1200px) { + display: none; + } + + .image { + padding: 16px; + border-radius: 8px; + border: 1px solid var(--slate-200); + background-color: white; + box-shadow: 0 4px 32px rgb(0 0 0 / 5%); + position: absolute; + } + + .graph { + bottom: 0; + left: 0; + max-width: calc(100% - 96px); + top: 50%; + transform: translateY(-50%); + } + + .enrollment1 { + top: 0; + right: 64px; + max-width: 256px; + } + + .enrollment2 { + bottom: 64px; + right: 0; + max-width: 256px; + } + + .grades1 { + top: 0; + right: 64px; + max-width: 160px; + } + + .grades2 { + bottom: 64px; + right: 0; + max-width: 160px; + } + + .calendar { + max-width: calc(100% - 96px); + top: 0; + left: 0; + } + + .schedule { + width: 100%; + max-width: 256px; + right: 0; + bottom: 0; + } + + .filters { + max-width: 256px; + top: 0; + left: 0; + } + + .courses { + max-width: 256px; + width: 100%; + left: 96px; + bottom: 0; + } + + .course { + width: calc(100% - 192px); + right: 0; + top: 64px; + } + } + + .text { + @media (width > 1200px) { + padding: 192px 0; + width: 512px; + flex-shrink: 0; + display: flex; + flex-direction: column; + justify-content: center; + } + + .link { + display: flex; + width: fit-content; + align-items: center; + gap: 8px; + color: var(--blue-500); + font-size: 16px; + font-weight: 500; + line-height: 1; + transition: all 100ms ease-in-out; + + &:hover { + color: var(--blue-600); + } + } + + .description { + font-size: 16px; + line-height: 1.5; + margin-bottom: 32px; + color: var(--slate-500); + } + + .heading { + font-size: 32px; + font-weight: 660; + font-feature-settings: 'cv05' on, 'cv13' on, 'ss07' on, 'cv12' on, 'cv06' on; + line-height: 1.25; + margin-bottom: 16px; + color: var(--slate-900); + } + + .badge { + height: 24px; + border-radius: 4px; + padding: 0 8px; + display: flex; + align-items: center; + background-color: var(--orange-500); + width: max-content; + color: white; + font-size: 14px; + font-weight: 500; + line-height: 1; + margin-bottom: 16px; + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Landing/Features/calendar.png b/frontend/src/app/Landing/Features/calendar.png new file mode 100644 index 000000000..5050d9105 Binary files /dev/null and b/frontend/src/app/Landing/Features/calendar.png differ diff --git a/frontend/src/app/Landing/Features/course.png b/frontend/src/app/Landing/Features/course.png new file mode 100644 index 000000000..4681e5296 Binary files /dev/null and b/frontend/src/app/Landing/Features/course.png differ diff --git a/frontend/src/app/Landing/Features/courses.png b/frontend/src/app/Landing/Features/courses.png new file mode 100644 index 000000000..c0b603106 Binary files /dev/null and b/frontend/src/app/Landing/Features/courses.png differ diff --git a/frontend/src/app/Landing/Features/enrollment-1.png b/frontend/src/app/Landing/Features/enrollment-1.png new file mode 100644 index 000000000..db67677b6 Binary files /dev/null and b/frontend/src/app/Landing/Features/enrollment-1.png differ diff --git a/frontend/src/app/Landing/Features/enrollment-2.png b/frontend/src/app/Landing/Features/enrollment-2.png new file mode 100644 index 000000000..bd47fbe1b Binary files /dev/null and b/frontend/src/app/Landing/Features/enrollment-2.png differ diff --git a/frontend/src/app/Landing/Features/filters.png b/frontend/src/app/Landing/Features/filters.png new file mode 100644 index 000000000..063b720ed Binary files /dev/null and b/frontend/src/app/Landing/Features/filters.png differ diff --git a/frontend/src/app/Landing/Features/grades-1.png b/frontend/src/app/Landing/Features/grades-1.png new file mode 100644 index 000000000..1562b65c6 Binary files /dev/null and b/frontend/src/app/Landing/Features/grades-1.png differ diff --git a/frontend/src/app/Landing/Features/grades-2.png b/frontend/src/app/Landing/Features/grades-2.png new file mode 100644 index 000000000..4146af70c Binary files /dev/null and b/frontend/src/app/Landing/Features/grades-2.png differ diff --git a/frontend/src/app/Landing/Features/graph-1.png b/frontend/src/app/Landing/Features/graph-1.png new file mode 100644 index 000000000..023251cbd Binary files /dev/null and b/frontend/src/app/Landing/Features/graph-1.png differ diff --git a/frontend/src/app/Landing/Features/graph-2.png b/frontend/src/app/Landing/Features/graph-2.png new file mode 100644 index 000000000..e6f6412b0 Binary files /dev/null and b/frontend/src/app/Landing/Features/graph-2.png differ diff --git a/frontend/src/app/Landing/Features/index.tsx b/frontend/src/app/Landing/Features/index.tsx new file mode 100644 index 000000000..1ad21f8be --- /dev/null +++ b/frontend/src/app/Landing/Features/index.tsx @@ -0,0 +1,133 @@ +import classNames from "classnames"; +import { ArrowRight } from "iconoir-react"; +import { Link } from "react-router-dom"; + +import Container from "@/components/Container"; + +import styles from "./Features.module.scss"; +import calendar from "./calendar.png"; +import course from "./course.png"; +import courses from "./courses.png"; +import enrollment1 from "./enrollment-1.png"; +import enrollment2 from "./enrollment-2.png"; +import filters from "./filters.png"; +import grades1 from "./grades-1.png"; +import grades2 from "./grades-2.png"; +import graph1 from "./graph-1.png"; +import graph2 from "./graph-2.png"; +import schedule from "./schedule.png"; + +export default function Features() { + return ( + +
+
+ + +
+
+
New
+

Simple schedule planning

+

+ Plan, save, and share schedules. An alternative to CalCentral, + Berkeleytime makes scheduling your semester easy and user-friendly. +

+ + Start planning + + +
+
+
+
+ + + +
+
+

Find the right classes for you

+

+ Instead of spending hours sifting through courses on the Berkeley + course catalog, instantly filter and sort courses by average grade, + number of open seats, and more. +

+ + Browse courses + + +
+
+
+
+ + + +
+
+

Get ahead of the curve

+

+ View grade distributions for classes based on the semester and + professor. Stop worrying about the A, and make informed decisions + about your schedule. +

+ + Go to Grades + + +
+
+
+
+ + + +
+
+

Secure your seat

+

+ Track enrollment for courses and sections in real-time. View + enrollment history over time and know when to enroll, and when you + can wait. +

+ + Go to Enrollment + + +
+
+
+ ); +} diff --git a/frontend/src/app/Landing/Features/schedule.png b/frontend/src/app/Landing/Features/schedule.png new file mode 100644 index 000000000..d76c16eb4 Binary files /dev/null and b/frontend/src/app/Landing/Features/schedule.png differ diff --git a/frontend/src/app/Landing/Hero/Hero.module.scss b/frontend/src/app/Landing/Hero/Hero.module.scss new file mode 100644 index 000000000..bff3391db --- /dev/null +++ b/frontend/src/app/Landing/Hero/Hero.module.scss @@ -0,0 +1,128 @@ +.root { + position: relative; + display: flex; + flex-direction: column; + overflow: hidden; + background: linear-gradient(var(--landing-gradient-angle, to top right), var(--landing-gradient-start), var(--landing-gradient-stop)); + + .wave { + position: absolute; + width: 100%; + bottom: 0px; + left: 0; + z-index: 2; + filter: drop-shadow(0 -8px 0 rgba(white, 0.1)); + } + + @media (width > 992px) { + height: 100dvh; + max-height: 992px; + } + + .container { + max-width: 1280px; + width: 100%; + flex-grow: 1; + margin: 0 auto; + padding: 0px 24px; + position: relative; + z-index: 1; + + .text { + margin: 96px 0 192px; + position: relative; + z-index: 2; + + @media (width <= 992px) { + margin-top: 64px; + } + + @media (width > 992px) { + max-width: 592px; + } + + .heading { + font-size: 48px; + margin-bottom: 16px; + color: white; + font-weight: 660; + font-feature-settings: 'cv05' on, 'cv13' on, 'ss07' on, 'cv12' on, 'cv06' on; + line-height: 1.25; + position: relative; + + @media (width <= 768px) { + font-size: 32px; + line-height: 1.5; + } + } + + .description { + font-size: 24px; + color: rgb(255 255 255 / 65%); + line-height: 1.5; + font-weight: 500; + margin-bottom: 64px; + } + + .form { + position: relative; + max-width: 448px; + background-color: white; + padding: 0 16px; + border-radius: 4px; + display: flex; + align-items: center; + gap: 16px; + box-shadow: 0 4px 8px rgba(0 0 0 / 10%); + + .input { + font-size: 16px; + color: var(--slate-900); + height: 56px; + + &::placeholder { + color: var(--slate-500); + } + } + } + } + + .clock { + position: absolute; + right: 272px; + bottom: 128px; + text-align: right; + font-size: 16px; + line-height: 1.5; + color: rgb(255 255 255 / 65%); + z-index: 1; + + @media (width <= 992px) { + display: none; + } + + p.heading { + font-weight: 500; + color: white; + margin-top: 16px; + } + + p.description { + margin-top: 4px; + } + } + + img.campanile { + position: absolute; + z-index: 1; + right: 24px; + top: 0; + + @media (width <= 992px) { + left: 50%; + transform: translateX(-50%); + opacity: 0.25; + } + } + } +} diff --git a/frontend/src/app/Landing/Hero/afternoon.svg b/frontend/src/app/Landing/Hero/afternoon.svg new file mode 100644 index 000000000..5f6fe174e --- /dev/null +++ b/frontend/src/app/Landing/Hero/afternoon.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/dawn.svg b/frontend/src/app/Landing/Hero/dawn.svg new file mode 100644 index 000000000..08c27a69a --- /dev/null +++ b/frontend/src/app/Landing/Hero/dawn.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/dusk.svg b/frontend/src/app/Landing/Hero/dusk.svg new file mode 100644 index 000000000..0e22dfda5 --- /dev/null +++ b/frontend/src/app/Landing/Hero/dusk.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/index.tsx b/frontend/src/app/Landing/Hero/index.tsx new file mode 100644 index 000000000..eabd4f23c --- /dev/null +++ b/frontend/src/app/Landing/Hero/index.tsx @@ -0,0 +1,137 @@ +import { FormEvent, useEffect, useMemo, useRef, useState } from "react"; + +import { ArrowRight, Clock } from "iconoir-react"; + +import Button from "@/components/Button"; +import NavigationBar from "@/components/NavigationBar"; + +import styles from "./Hero.module.scss"; +import afternoon from "./afternoon.svg"; +import dawn from "./dawn.svg"; +import dusk from "./dusk.svg"; +import morning from "./morning.svg"; +import sunrise from "./sunrise.svg"; +import sunset from "./sunset.svg"; +import wave from "./wave.svg"; + +// TODO: Tailwind color gradients +const steps = [ + { + colors: ["#CFADD4", "#B5B2D9"], + // gradient: ["var(--purple-400)", "var(--violet-400)"], + // color: "var(--violet-500)", + image: dawn, + }, + { + colors: ["#D3A4BF", "#EEC9C1"], + // gradient: ["var(--fuchsia-400)", "var(--purple-400)"], + // color: "var(--purple-500)", + image: sunrise, + }, + { + colors: ["#DCD6C4", "#C8DCD9"], + image: morning, + }, + { + gradient: ["var(--blue-500)", "var(--sky-500)"], + colors: ["#3b82f6", "#0ea5e9"], + image: afternoon, + }, + { + colors: ["#D25950", "#EE8A1F"], + image: sunset, + }, + { + colors: ["#10101B", "#202036"], + angle: "to bottom right", + image: dusk, + }, +]; + +export default function Hero() { + const root = useRef(null); + + // Berkeley time + const [milliseconds, setMilliseconds] = useState( + () => Date.now() - 10 * 60 * 1000 + ); + + const step = useMemo(() => { + // const date = new Date(milliseconds); + // const index = Math.floor(((date.getHours() - 0) / 24) * 6); + return steps[3]; + }, []); + + useEffect(() => { + const interval = setInterval( + () => setMilliseconds((milliseconds) => milliseconds + 1000), + 1000 + ); + + return () => clearInterval(interval); + }, []); + + useEffect(() => { + const element = root.current; + if (!element) return; + + const [start, stop] = step.gradient ?? step.colors; + const { angle } = step; + + element.style.setProperty("--landing-gradient-start", start); + element.style.setProperty("--landing-gradient-stop", stop); + + if (angle) { + element.style.setProperty("--landing-gradient-angle", angle); + return; + } + + element.style.removeProperty("--landing-gradient-angle"); + }, [step]); + + const handleSubmit = (event: FormEvent) => { + event.preventDefault(); + }; + + return ( +
+ +
+
+

+ Confidently plan and manage your schedule +

+

+ Berkeley's largest course discovery platform built and run by + students, for students +

+
+ + +
+
+
+ +

+ {new Date(milliseconds).toLocaleTimeString(undefined, { + hour: "numeric", + minute: "numeric", + second: "numeric", + })} +

+

Berkeley time

+
+ +
+ +
+ ); +} diff --git a/frontend/src/app/Landing/Hero/morning.svg b/frontend/src/app/Landing/Hero/morning.svg new file mode 100644 index 000000000..c89b37038 --- /dev/null +++ b/frontend/src/app/Landing/Hero/morning.svg @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/sunrise.svg b/frontend/src/app/Landing/Hero/sunrise.svg new file mode 100644 index 000000000..54b49af01 --- /dev/null +++ b/frontend/src/app/Landing/Hero/sunrise.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/sunset.svg b/frontend/src/app/Landing/Hero/sunset.svg new file mode 100644 index 000000000..0cbd3bfe0 --- /dev/null +++ b/frontend/src/app/Landing/Hero/sunset.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/app/Landing/Hero/wave.svg b/frontend/src/app/Landing/Hero/wave.svg new file mode 100644 index 000000000..be943d1a0 --- /dev/null +++ b/frontend/src/app/Landing/Hero/wave.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/app/Landing/Landing.module.scss b/frontend/src/app/Landing/Landing.module.scss new file mode 100644 index 000000000..01db0a138 --- /dev/null +++ b/frontend/src/app/Landing/Landing.module.scss @@ -0,0 +1,5 @@ +.root { + display: flex; + flex-direction: column; + background-color: var(--slate-50); +} diff --git a/frontend/src/app/Landing/Organization/Organization.module.scss b/frontend/src/app/Landing/Organization/Organization.module.scss new file mode 100644 index 000000000..0f648e60b --- /dev/null +++ b/frontend/src/app/Landing/Organization/Organization.module.scss @@ -0,0 +1,73 @@ +.root { + background: var(--neutral-900); + padding-top: 96px; + + .heading { + font-size: 48px; + margin-bottom: 16px; + color: white; + font-weight: 660; + font-feature-settings: 'cv05' on, 'cv13' on, 'ss07' on, 'cv12' on, 'cv06' on; + line-height: 1.25; + position: relative; + text-align: center; + + @media (width <= 768px) { + font-size: 32px; + line-height: 1.5; + } + } + + .accordion { + max-width: 512px; + margin: 64px auto; + display: flex; + flex-direction: column; + gap: 32px; + + details { + appearance: none; + + &:not(:last-child) { + padding-bottom: 32px; + border-bottom: 1px solid var(--neutral-700); + } + + &:not([open]) summary > :last-child { + display: none; + } + + &[open] summary > :nth-last-child(2) { + display: none; + } + + .content { + margin-top: 24px; + font-size: 16px; + line-height: 1.5; + color: var(--neutral-500); + } + + summary { + color: var(--neutral-500); + display: flex; + align-items: center; + justify-content: space-between; + cursor: pointer; + + &:hover .title { + color: var(--neutral-300); + } + + .title { + font-size: 24px; + font-weight: 660; + font-feature-settings: "cv05" on, "cv13" on, "ss07" on, "cv12" on, "cv06" on; + line-height: 1.25; + color: white; + transition: all 100ms ease-in-out; + } + } + } + } +} diff --git a/frontend/src/app/Landing/Organization/index.tsx b/frontend/src/app/Landing/Organization/index.tsx new file mode 100644 index 000000000..993eaebb1 --- /dev/null +++ b/frontend/src/app/Landing/Organization/index.tsx @@ -0,0 +1,58 @@ +import { Minus, Plus } from "iconoir-react"; + +import Container from "@/components/Container"; +import Footer from "@/components/Footer"; + +import styles from "./Organization.module.scss"; + +export default function Organization() { + return ( +
+ +

Get involved

+
+
+ +

Join our team

+ + +
+

+ Become part of a dynamic and innovative group dedicated to helping + students navigate Berkeley! Roles on the Berkeleytime team include + backend & frontend development, product design, user research, and + marketing. We are always looking for passionate and talented + students. +

+
+
+ +

Contribute

+ + +
+

+ Become part of a dynamic and innovative group dedicated to helping + students navigate Berkeley! Roles on the Berkeleytime team include + backend & frontend development, product design, user research, and + marketing. We are always looking for passionate and talented + students. +

+
+
+ +

Provide feedback

+ + +
+

+ Berkeleytime is an open-source project. If you are interested in + contributing to the project, check out our +

+
+
+
+
+
+ ); +} diff --git a/frontend/src/app/Landing/Organization/wave.svg b/frontend/src/app/Landing/Organization/wave.svg new file mode 100644 index 000000000..2fc1d3e40 --- /dev/null +++ b/frontend/src/app/Landing/Organization/wave.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/app/Landing/index.tsx b/frontend/src/app/Landing/index.tsx new file mode 100644 index 000000000..3fa7ce738 --- /dev/null +++ b/frontend/src/app/Landing/index.tsx @@ -0,0 +1,16 @@ +import Features from "./Features"; +import Hero from "./Hero"; +import HomeFooter from "./Organization"; +import styles from "./Landing.module.scss"; + +const Home = () => { + return ( +
+ + + +
+ ); +}; + +export default Home; diff --git a/frontend/src/app/Plan/Plan.module.scss b/frontend/src/app/Plan/Plan.module.scss new file mode 100644 index 000000000..73d4c080d --- /dev/null +++ b/frontend/src/app/Plan/Plan.module.scss @@ -0,0 +1,30 @@ +.root { + flex-grow: 1; + height: 0; + overflow: clip; + display: flex; + + .sideBar { + width: 384px; + border-right: 1px solid var(--border-color); + background-color: var(--foreground-color); + overflow: auto; + flex-shrink: 0; + } + + .view { + flex-grow: 1; + background-color: var(--background-color); + overflow-x: auto; + overflow-y: hidden; + + .body { + display: flex; + align-items: flex-start; + padding: 24px; + gap: 24px; + height: 100%; + width: max-content; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Plan/Term/Catalog/Catalog.module.scss b/frontend/src/app/Plan/Term/Catalog/Catalog.module.scss new file mode 100644 index 000000000..06968d3cf --- /dev/null +++ b/frontend/src/app/Plan/Term/Catalog/Catalog.module.scss @@ -0,0 +1,62 @@ +.overlay { + background-color: rgb(255 255 255 / 80%); + inset: 0; + position: fixed; + z-index: 988; + opacity: 0; + animation: fadeIn 250ms ease-in-out forwards; + + @media (prefers-color-scheme: dark) { + background-color: rgb(0 0 0 / 80%); + } +} + +.content { + height: 100dvh; + position: fixed; + left: 0; + top: 0; + z-index: 989; + display: flex; + flex-direction: column; + transform: translateX(-100%); + animation: slideIn 250ms ease-in-out forwards; + + @media (width <= 992px) { + width: 100%; + } + + .body { + flex-grow: 1; + height: 0; + overflow: clip; + } + + .header { + border-width: 0 1px 1px 0; + border-color: var(--border-color); + border-style: solid; + padding: 12px; + background-color: var(--foreground-color); + display: flex; + align-items: center; + flex-shrink: 0; + justify-content: space-between; + font-size: 14px; + line-height: 1; + color: var(--heading-color); + font-weight: 500; + } +} + +@keyframes fadeIn { + 100% { + opacity: 1; + } +} + +@keyframes slideIn { + 100% { + transform: translateX(0); + } +} \ No newline at end of file diff --git a/frontend/src/app/Plan/Term/Catalog/index.tsx b/frontend/src/app/Plan/Term/Catalog/index.tsx new file mode 100644 index 000000000..36115a412 --- /dev/null +++ b/frontend/src/app/Plan/Term/Catalog/index.tsx @@ -0,0 +1,73 @@ +import { ReactNode, useState } from "react"; + +import * as Dialog from "@radix-ui/react-dialog"; +import { Xmark } from "iconoir-react"; +import { useSearchParams } from "react-router-dom"; + +import Browser from "@/components/Browser"; +import IconButton from "@/components/IconButton"; +import { ICourse, Semester } from "@/lib/api"; + +import styles from "./Catalog.module.scss"; + +interface CatalogProps { + onClick: (course: ICourse, number: string) => void; + children: ReactNode; + semester: Semester; + year: number; +} + +export default function Catalog({ + onClick, + children, + semester, + year, +}: CatalogProps) { + const [open, setOpen] = useState(false); + const [searchParams, setSearchParams] = useSearchParams(); + + const handleOpenChange = (open: boolean) => { + setOpen(open); + + if (open) return; + + searchParams.delete("query"); + setSearchParams(searchParams); + }; + + const handleClick = (course: ICourse, number: string) => { + onClick(course, number); + + setOpen(false); + + searchParams.delete("query"); + setSearchParams(searchParams); + }; + + return ( + + {children} + + + +
+ Add a course to this semester + + + + + +
+
+ +
+
+
+
+ ); +} diff --git a/frontend/src/app/Plan/Term/Course/Course.module.scss b/frontend/src/app/Plan/Term/Course/Course.module.scss new file mode 100644 index 000000000..2909bf049 --- /dev/null +++ b/frontend/src/app/Plan/Term/Course/Course.module.scss @@ -0,0 +1,82 @@ +.root { + border-radius: 8px; + border: 1px solid var(--border-color); + user-select: none; + cursor: pointer; + + &:global(.draggable-mirror) { + border-color: var(--blue-500); + z-index: 999; + box-shadow: 0 4px 16px rgb(0 0 0 / 10%); + } + + &:global(.draggable-source--is-dragging) { + background-color: transparent; + box-shadow: unset; + border-style: dashed; + + .body { + visibility: hidden; + } + } + + &:not(:global(.draggable-source--is-dragging)) { + box-shadow: 0 1px 2px rgb(0 0 0 / 2.5%); + background-color: var(--foreground-color); + } + + .body { + padding: 16px; + display: flex; + gap: 12px; + + .icon { + flex-shrink: 0; + } + + .text { + flex-grow: 1; + + .title { + font-size: 14px; + font-weight: 700; + color: var(--heading-color); + line-height: 1; + margin-bottom: 8px; + } + + .description { + font-size: 14px; + color: var(--paragraph-color); + line-height: 1.5; + margin-bottom: 12px; + } + + .row { + display: flex; + gap: 12px; + align-items: center; + + .basis { + font-size: 14px; + line-height: 1; + color: var(--paragraph-color); + } + + .badge { + height: 32px; + border-radius: 16px; + display: flex; + align-items: center; + font-size: 14px; + line-height: 1; + gap: 8px; + padding: 0 12px; + user-select: none; + background-color: var(--emerald-500); + color: white; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Plan/Term/Course/index.tsx b/frontend/src/app/Plan/Term/Course/index.tsx new file mode 100644 index 000000000..973f8cb21 --- /dev/null +++ b/frontend/src/app/Plan/Term/Course/index.tsx @@ -0,0 +1,36 @@ +import classNames from "classnames"; +import { Book } from "iconoir-react"; + +import AverageGrade from "@/components/AverageGrade"; +import Units from "@/components/Units"; +import { ICourse } from "@/lib/api"; + +import styles from "./Course.module.scss"; + +export default function Course({ + subject, + number, + title, + gradeAverage, +}: ICourse) { + return ( +
+
+
+

+ {subject} {number} +

+

{title}

+
+ +
+ + Major +
+ +
+
+
+
+ ); +} diff --git a/frontend/src/app/Plan/Term/Term.module.scss b/frontend/src/app/Plan/Term/Term.module.scss new file mode 100644 index 000000000..e0f844fb4 --- /dev/null +++ b/frontend/src/app/Plan/Term/Term.module.scss @@ -0,0 +1,42 @@ +.root { + width: 320px; + flex-shrink: 0; + border-radius: 8px; + overflow: auto; + height: 100%; + border: 1px solid var(--border-color); + + .header { + padding: 8px 8px 8px 16px; + background: linear-gradient(to bottom, var(--background-color) 40px, transparent); + display: flex; + align-items: center; + position: sticky; + top: 0; + + .term { + font-size: 14px; + color: var(--heading-color); + font-weight: 500; + line-height: 1; + margin-right: auto; + } + + .units { + font-size: 12px; + color: var(--label-color); + line-height: 1; + margin-right: 16px; + } + } + + .body { + display: flex; + flex-direction: column; + align-items: stretch; + min-height: 121px; + width: 100%; + gap: 8px; + padding: 0 8px 8px; + } +} \ No newline at end of file diff --git a/frontend/src/app/Plan/Term/index.tsx b/frontend/src/app/Plan/Term/index.tsx new file mode 100644 index 000000000..3456424a5 --- /dev/null +++ b/frontend/src/app/Plan/Term/index.tsx @@ -0,0 +1,49 @@ +import { forwardRef } from "react"; + +import { Plus } from "iconoir-react"; + +import IconButton from "@/components/IconButton"; +import Units from "@/components/Units"; +import { ICourse, Semester } from "@/lib/api"; + +import Catalog from "./Catalog"; +import Course from "./Course"; +import styles from "./Term.module.scss"; + +interface TermProps { + semester: Semester; + year: number; + courses: ICourse[]; + onClick: (course: ICourse) => void; +} + +const Term = forwardRef( + ({ semester, year, courses, onClick }, ref) => { + return ( +
+
+

+ {semester} {year} +

+ + {(units) =>

{units}

} +
+ + + + + +
+
+ {courses.map((course) => ( + + ))} +
+
+ ); + } +); + +Term.displayName = "Semester"; + +export default Term; diff --git a/frontend/src/app/Plan/index.tsx b/frontend/src/app/Plan/index.tsx new file mode 100644 index 000000000..b7a12a853 --- /dev/null +++ b/frontend/src/app/Plan/index.tsx @@ -0,0 +1,126 @@ +import { useEffect, useRef, useState } from "react"; + +import { Plugins, Sortable } from "@shopify/draggable"; + +import { ICourse, Semester } from "@/lib/api"; + +import styles from "./Plan.module.scss"; +import Term from "./Term"; + +const defaultTerms: { + semester: Semester; + year: number; + courses: ICourse[]; +}[] = [ + { + semester: Semester.Fall, + year: 2021, + courses: [], + }, + { + semester: Semester.Spring, + year: 2022, + courses: [], + }, + { + semester: Semester.Fall, + year: 2022, + courses: [], + }, + { + semester: Semester.Spring, + year: 2023, + courses: [], + }, + { + semester: Semester.Fall, + year: 2023, + courses: [], + }, + { + semester: Semester.Spring, + year: 2024, + courses: [], + }, + { + semester: Semester.Fall, + year: 2024, + courses: [], + }, +]; + +export default function Plan() { + const containerRefs = useRef([]); + const [terms, setTerms] = useState(defaultTerms); + + const handleClick = (course: ICourse, index: number) => { + setTerms((terms) => { + const _terms = structuredClone(terms); + _terms[index].courses.splice(0, 0, course); + return _terms; + }); + }; + + const handleRef = (index: number, element: HTMLElement | null) => { + if (element) containerRefs.current.splice(index, 0, element); + else containerRefs.current.splice(index, 1); + }; + + useEffect(() => { + const sortable = new Sortable(containerRefs.current, { + draggable: `.draggable`, + distance: 4, + mirror: { + constrainDimensions: true, + }, + plugins: [Plugins.ResizeMirror], + }); + + sortable.on("drag:stop", (event) => { + event.cancel(); + }); + + sortable.on("sortable:stop", (event) => { + const { oldIndex, newIndex, oldContainer, newContainer } = event; + + if (oldContainer === newContainer && oldIndex === newIndex) return; + + const oldContainerIndex = containerRefs.current.indexOf(oldContainer); + const newContainerIndex = containerRefs.current.indexOf(newContainer); + + setTerms((terms) => { + const _terms = structuredClone(terms); + + const course = _terms[oldContainerIndex].courses.splice(oldIndex, 1)[0]; + + _terms[newContainerIndex].courses.splice(newIndex, 0, course); + + return _terms; + }); + }); + + return () => { + sortable.destroy(); + }; + }, []); + + return ( +
+
+
+
+ {terms.map(({ semester, year, courses }, index) => ( + handleClick(course, index)} + ref={(element) => handleRef(index, element)} + /> + ))} +
+
+
+ ); +} diff --git a/frontend/src/app/Schedule/Compare/Compare.module.scss b/frontend/src/app/Schedule/Compare/Compare.module.scss new file mode 100644 index 000000000..35fa55b01 --- /dev/null +++ b/frontend/src/app/Schedule/Compare/Compare.module.scss @@ -0,0 +1,76 @@ +.root { + display: flex; + flex-direction: column; + flex-grow: 1; + + .header { + border-bottom: 1px solid var(--border-color); + display: flex; + background-color: var(--foreground-color); + + .group { + display: flex; + align-items: center; + padding: 12px; + flex: 1; + gap: 12px; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + + .paragraph { + font-size: 12px; + line-height: 1; + color: var(--paragraph-color); + } + + .heading { + font-size: 14px; + font-weight: 500; + line-height: 1; + color: var(--heading-color); + flex-grow: 1; + } + } + } + + .body { + display: flex; + flex-grow: 1; + height: 0; + + .panel { + display: flex; + flex-direction: column; + flex: 1; + width: 0; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + + .context { + display: flex; + justify-content: space-between; + height: 32px; + flex-shrink: 0; + padding: 0 12px; + align-items: center; + border-bottom: 1px solid var(--border-color); + background-color: var(--backdrop-color); + + .data { + font-size: 12px; + color: var(--paragraph-color); + line-height: 1; + } + } + + .view { + overflow: auto; + flex-grow: 1; + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Compare/index.tsx b/frontend/src/app/Schedule/Compare/index.tsx new file mode 100644 index 000000000..787b8efd4 --- /dev/null +++ b/frontend/src/app/Schedule/Compare/index.tsx @@ -0,0 +1,145 @@ +import { useEffect, useMemo, useRef, useState } from "react"; + +import { DataTransferBoth, Xmark } from "iconoir-react"; +import { Link, useOutletContext } from "react-router-dom"; + +import IconButton from "@/components/IconButton"; +import Tooltip from "@/components/Tooltip"; +import Units from "@/components/Units"; +import Week from "@/components/Week"; + +import { ScheduleContextType } from "../schedule"; +import styles from "./Compare.module.scss"; + +export default function Compare() { + const { selectedSections, classes } = useOutletContext(); + const [y, setY] = useState(null); + const leftRef = useRef(null); + const rightRef = useRef(null); + const [current, setCurrent] = useState(null); + + const [minimum, maximum] = useMemo( + () => + classes.reduce( + ([minimum, maximum], { unitsMax, unitsMin }) => [ + minimum + unitsMin, + maximum + unitsMax, + ], + [0, 0] + ), + [classes] + ); + + useEffect(() => { + if (!leftRef.current || !rightRef.current) return; + + const left = leftRef.current; + const right = rightRef.current; + + const handleScroll = (left?: boolean) => { + if (!leftRef.current || !rightRef.current) return; + + if (left) { + if (current === 1) return; + + rightRef.current.scrollTo({ + top: leftRef.current.scrollTop, + left: leftRef.current.scrollLeft, + }); + + return; + } + + if (current === 0) return; + + leftRef.current.scrollTo({ + top: rightRef.current.scrollTop, + left: rightRef.current.scrollLeft, + }); + }; + + const handleLeftScroll = () => handleScroll(true); + left.addEventListener("scroll", handleLeftScroll); + + const handleRightScroll = () => handleScroll(); + right.addEventListener("scroll", handleRightScroll); + + return () => { + right.removeEventListener("scroll", handleLeftScroll); + left.removeEventListener("scroll", handleRightScroll); + }; + }, [current]); + + return ( +
+
+
+

Untitled Spring 2024 schedule

+

Spring 2024

+
+
+

No schedule selected

+ + + + + + + + + + +
+
+
+
+
+
Spring 2024
+
+ {classes.length === 1 ? "1 class" : `${classes.length} classes`},{" "} + + {(units) => units} + +
+
+
setCurrent(0)} + onMouseLeave={() => + setCurrent((previous) => (previous === 0 ? null : previous)) + } + > + +
+
+
+
+
Spring 2024
+
+ {classes.length === 1 ? "1 class" : `${classes.length} classes`},{" "} + + {(units) => units} + +
+
+
setCurrent(1)} + onMouseLeave={() => + setCurrent((previous) => (previous === 1 ? null : previous)) + } + > + +
+
+
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/Calendar/Calendar.module.scss b/frontend/src/app/Schedule/Manage/Calendar/Calendar.module.scss new file mode 100644 index 000000000..b31016768 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/Calendar.module.scss @@ -0,0 +1,63 @@ +.root { + display: flex; + flex-direction: column; + background-color: var(--background-color); + min-width: 1080px; + + .header { + display: flex; + flex-direction: column; + border-bottom: 1px solid var(--border-color); + position: sticky; + top: 0; + z-index: 1; + font-size: 12px; + line-height: 1; + z-index: 2; + + .legend { + display: flex; + padding: 0 12px; + height: 32px; + gap: 12px; + align-items: center; + background-color: var(--backdrop-color); + border-bottom: 1px solid var(--border-color); + color: var(--paragraph-color); + + .timezone { + margin-left: auto; + } + + .category { + display: flex; + gap: 8px; + align-items: center; + } + } + + .week { + display: grid; + grid-template-columns: repeat(7, 1fr); + color: var(--label-color); + background-color: var(--background-color); + flex-grow: 1; + + .day { + height: 32px; + display: grid; + place-items: center; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + } + } + } + + .view { + display: flex; + flex-direction: column; + z-index: 1; + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/Calendar/Week/Day/Day.module.scss b/frontend/src/app/Schedule/Manage/Calendar/Week/Day/Day.module.scss new file mode 100644 index 000000000..25a77fdab --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/Week/Day/Day.module.scss @@ -0,0 +1,66 @@ +.root { + aspect-ratio: 1; + padding: 8px; + display: flex; + flex-direction: column; + font-size: 12px; + line-height: 1; + gap: 4px; + overflow: hidden; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + + .event { + display: flex; + align-items: center; + padding: 0 8px; + border-radius: 4px; + gap: 8px; + height: 24px; + white-space: nowrap; + color: white; + + &:not(.exam) { + border: 1px dashed var(--color); + } + + &.exam { + background-color: var(--color); + + .time { + color: rgb(255 255 255 / 75%); + } + + .course { + color: white; + } + } + + &.active { + opacity: 0.5; + } + + .time { + font-size: 8px; + color: var(--label-color); + } + + .course { + font-weight: 500; + text-overflow: ellipsis; + overflow: hidden; + color: var(--color); + } + } + + .date { + display: flex; + color: var(--label-color); + + .number { + margin-left: auto; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/Calendar/Week/Day/index.tsx b/frontend/src/app/Schedule/Manage/Calendar/Week/Day/index.tsx new file mode 100644 index 000000000..3d9177c0d --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/Week/Day/index.tsx @@ -0,0 +1,54 @@ +import { CSSProperties } from "react"; + +import classNames from "classnames"; + +import { getColor } from "@/lib/section"; + +import { IDay } from "../../calendar"; +import styles from "./Day.module.scss"; + +const parseTime = (time: string) => { + const [hours, minutes] = time.split(":").map(Number); + + let _time = `${hours % 12 || 12}`; + if (minutes > 0) _time += `:${minutes.toString().padStart(2, "0")}`; + _time += hours < 12 ? " AM" : " PM"; + + return _time; +}; + +interface DayProps extends IDay { + active: boolean; +} + +export default function Day({ date, events, active }: DayProps) { + return ( +
+ {active && ( +
+ {date.format("D") === "1" && date.format("MMMM")} +

{date.format("D")}

+
+ )} + {events.map((event, index) => { + const color = getColor(event.subject, event.number); + + return ( +
+
{parseTime(event.startTime)}
+
+ {event.subject} {event.number} +
+
+ ); + })} +
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/Calendar/Week/Week.module.scss b/frontend/src/app/Schedule/Manage/Calendar/Week/Week.module.scss new file mode 100644 index 000000000..8ddeeaa8f --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/Week/Week.module.scss @@ -0,0 +1,34 @@ +.root { + display: flex; + flex-direction: column; + + &:not(:first-child) { + border-top: 1px solid var(--border-color); + } + + &.dead { + background-color: var(--backdrop-color); + } + + &.finals { + background-color: var(--foreground-color); + } + + .header { + font-size: 12px; + line-height: 1; + height: 32px; + color: var(--paragraph-color); + padding: 0 12px; + display: flex; + gap: 12px; + align-items: center; + border-bottom: 1px solid var(--border-color); + } + + .body { + flex-grow: 1; + display: grid; + grid-template-columns: repeat(7, 1fr); + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/Calendar/Week/index.tsx b/frontend/src/app/Schedule/Manage/Calendar/Week/index.tsx new file mode 100644 index 000000000..3a5a3e437 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/Week/index.tsx @@ -0,0 +1,43 @@ +import classNames from "classnames"; +import { ArrowDown } from "iconoir-react"; +import moment from "moment"; + +import { IDay } from "../calendar"; +import Day from "./Day"; +import styles from "./Week.module.scss"; + +interface WeekProps { + days: IDay[]; + finals: boolean; + dead: boolean; + first: moment.Moment; + last: moment.Moment; +} + +export default function Week({ days, finals, dead, first, last }: WeekProps) { + return ( +
+ {(dead || finals) && ( +
+ + {dead ? "Reading, Review, and Recitation (RRR)" : "Finals"} week +
+ )} +
+ {days.map(({ date, events }) => ( + + ))} +
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/Calendar/calendar.ts b/frontend/src/app/Schedule/Manage/Calendar/calendar.ts new file mode 100644 index 000000000..4fbd305c6 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/calendar.ts @@ -0,0 +1,16 @@ +export interface IEvent { + subject: string; + number: string; + active?: boolean; + startTime: string; + endTime: string; + startDate: string; + endDate: string; + days?: boolean[]; + date?: string; +} + +export interface IDay { + date: moment.Moment; + events: IEvent[]; +} diff --git a/frontend/src/app/Schedule/Manage/Calendar/index.tsx b/frontend/src/app/Schedule/Manage/Calendar/index.tsx new file mode 100644 index 000000000..f41411811 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Calendar/index.tsx @@ -0,0 +1,172 @@ +import { useMemo, useState } from "react"; + +import { MinusSquareDashed, MinusSquareSolid } from "iconoir-react"; +import moment from "moment"; + +import { ISection } from "@/lib/api"; + +import styles from "./Calendar.module.scss"; +import Week from "./Week"; +import { IDay, IEvent } from "./calendar"; + +interface CalendarProps { + selectedSections: ISection[]; + currentSection: ISection | null; +} + +export default function Calendar({ + selectedSections, + currentSection, +}: CalendarProps) { + const [first] = useState(() => moment("2024-01-01")); + const [last] = useState(() => moment("2024-05-31")); + + const [start] = useState(() => { + const current = moment("2024-01-01"); + current.subtract(current.day(), "days"); + return current; + }); + + const [stop] = useState(() => { + const stop = moment("2024-05-31"); + stop.add(6 - stop.day(), "days"); + return stop; + }); + + const events = useMemo( + () => + (currentSection + ? [...selectedSections, currentSection] + : selectedSections + ).reduce((events, section) => { + const { + startDate, + endDate, + meetings, + exams, + course: { subject, number }, + ccn, + } = section; + + for (const meeting of meetings) { + const { days, startTime, endTime } = meeting; + + events.push({ + startDate, + endDate, + subject: subject, + number: number, + active: currentSection?.ccn === ccn, + days, + startTime, + endTime, + }); + } + + const filteredExams = exams.filter(function (exam, index) { + return ( + exams.findIndex( + ({ date, startTime, endTime }) => + date === exam.date && + exam.startTime === startTime && + exam.endTime === endTime + ) == index + ); + }); + + for (const exam of filteredExams) { + const { date, startTime, endTime } = exam; + + events.push({ + date, + subject: subject, + number: number, + active: currentSection?.ccn === ccn, + startTime, + endTime, + startDate, + endDate, + }); + } + + return events; + }, [] as IEvent[]), + [selectedSections, currentSection] + ); + + const weeks = useMemo(() => { + const weeks: IDay[][] = []; + + const current = moment(start); + + while (current.isSameOrBefore(stop)) { + const week = []; + + for (let i = 0; i < 7; i++) { + const day = { + date: moment(current), + events: events + .filter(({ startDate, endDate, date, days }) => + date + ? moment(parseInt(date)).isSame(current, "day") + : current.isSameOrAfter(startDate) && + current.isSameOrBefore(endDate) && + days?.[current.day()] + ) + .sort((a, b) => a.startTime.localeCompare(b.startTime)), + }; + + week.push(day); + + current.add(1, "days"); + } + + weeks.push(week); + } + + return weeks; + }, [events, start, stop]); + + return ( +
+
+
+
+ + Section +
+
+ + Exam +
+
+ All times are listed in Pacific Standard Time (PST). +
+
+
+
Sunday
+
Monday
+
Tuesday
+
Wednesday
+
Thursday
+
Friday
+
Saturday
+
+
+
+ {weeks.map((days, index) => { + return ( + + ); + })} +
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/Manage.module.scss b/frontend/src/app/Schedule/Manage/Manage.module.scss new file mode 100644 index 000000000..602e2759b --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Manage.module.scss @@ -0,0 +1,54 @@ +.root { + flex-grow: 1; + display: flex; + flex-direction: column; + + .header { + border-bottom: 1px solid var(--border-color); + background-color: var(--foreground-color); + display: flex; + padding: 12px; + position: relative; + align-items: center; + gap: 12px; + + .tabs { + display: flex; + margin-right: auto; + } + + .group { + display: flex; + align-items: center; + width: 372px; + gap: 12px; + + .separator { + border-left: 1px solid var(--border-color); + height: 24px; + } + + .heading { + font-size: 14px; + font-weight: 500; + color: var(--heading-color); + flex-grow: 1; + } + } + } + + .body { + flex-grow: 1; + display: flex; + overflow: clip; + height: 0; + + .view { + flex-grow: 1; + display: flex; + flex-direction: column; + width: 0; + overflow: auto; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/Map/Map.module.scss b/frontend/src/app/Schedule/Manage/Map/Map.module.scss new file mode 100644 index 000000000..bbc655b23 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Map/Map.module.scss @@ -0,0 +1,157 @@ +.root { + background-color: var(--background-color); + height: 100%; + position: relative; + + .container { + height: 100%; + width: 100%; + } + + .toolBar { + position: absolute; + top: 24px; + left: 24px; + z-index: 1; + padding: 12px; + border: 1px solid var(--border-color); + background-color: var(--foreground-color); + border-radius: 8px; + display: flex; + gap: 8px; + } + + .sideBar { + width: 256px; + background-color: var(--foreground-color); + border-radius: 8px; + border: 1px solid var(--border-color); + flex-shrink: 0; + padding: 16px; + position: absolute; + top: 24px; + right: 24px; + max-height: calc(100% - 48px); + overflow: auto; + + .leg { + height: 32px; + display: flex; + gap: 8px; + align-items: center; + background-color: var(--slate-100); + width: fit-content; + border-radius: 16px; + padding: 0 12px; + color: var(--paragraph-color); + margin: 24px 0; + position: relative; + + &::after { + left: 14px; + bottom: -24px; + width: 4px; + border-right: 4px dashed var(--slate-100); + height: 24px; + content: ""; + position: absolute; + } + + .value { + font-size: 14px; + line-height: 1; + + .distance { + color: var(--red-500); + } + } + } + + .waypoint { + display: flex; + gap: 12px; + color: var(--paragraph-color); + position: relative; + + &:not(:last-child)::after { + left: 14px; + top: 32px; + width: 4px; + border-right: 4px dashed var(--slate-100); + height: calc(100% - 8px); + content: ""; + position: absolute; + } + + .number { + width: 32px; + height: 32px; + border-radius: 50%; + background-color: var(--blue-500); + display: flex; + font-weight: 700; + font-size: 14px; + align-items: center; + justify-content: center; + color: white; + } + + .text { + flex-grow: 1; + font-size: 14px; + + .label { + font-size: 12px; + } + + .heading { + font-weight: 700; + color: var(--heading-color); + margin-top: 4px; + } + + .description { + margin-top: 4px; + } + } + } + } +} + +:global(.marker) { + width: 32px; + height: 32px; + border-radius: 50%; + background-color: var(--blue-500); + display: flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 700; + font-size: 14px; + + &:global(.marker-red) { + background-color: var(--red-500); + width: 8px; + height: 8px; + } +} + +:global(.tooltip) { + position: absolute; + border-radius: 4px; + padding: 12px; + background-color: var(--background-color); + width: 256px; + animation: fadeIn 100ms ease-in; + color: white; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/Map/index.tsx b/frontend/src/app/Schedule/Manage/Map/index.tsx new file mode 100644 index 000000000..48917495e --- /dev/null +++ b/frontend/src/app/Schedule/Manage/Map/index.tsx @@ -0,0 +1,325 @@ +import { useEffect, useMemo, useRef, useState } from "react"; + +// @ts-expect-error - MapboxDirections does not provide types +import MapboxDirections from "@mapbox/mapbox-gl-directions/dist/mapbox-gl-directions"; +import "@mapbox/mapbox-gl-directions/dist/mapbox-gl-directions.css"; +import { ArrowSeparateVertical, Walking, ZoomIn, ZoomOut } from "iconoir-react"; +import mapboxgl from "mapbox-gl"; +import "mapbox-gl/dist/mapbox-gl.css"; + +import Button from "@/components/Button"; +import IconButton from "@/components/IconButton"; +import usePrefersColorScheme from "@/hooks/usePrefersColorScheme"; +import { ISection } from "@/lib/api"; +import { buildings } from "@/lib/location"; + +import styles from "./Map.module.scss"; + +const TOKEN = + "pk.eyJ1IjoibWF0aGh1bGsiLCJhIjoiY2t6bTFhcDU2M2prOTJwa3VwcTJ2d2dpMiJ9.WEJWEP_qrKGXkYOgbIsaGg"; + +const MAX_ZOOM = 18; +const MIN_ZOOM = 14; +const DEFAULT_ZOOM = 15.5; +// const OFFSET: [number, number] = [-156, 0]; + +mapboxgl.accessToken = TOKEN; + +interface MapProps { + selectedSections: ISection[]; +} + +export default function Map({ selectedSections }: MapProps) { + const colorScheme = usePrefersColorScheme(); + + const containerRef = useRef(null); + const markersRef = useRef([]); + + const [zoom, setZoom] = useState(DEFAULT_ZOOM); + const [directions, setDirections] = useState(null); + const mapRef = useRef(null); + + const waypoints = useMemo( + () => + selectedSections + .filter((section) => section.meetings[0].location) + .map(({ meetings: [{ location }] }) => { + const building = location!.split(" ").slice(0, -1).join(" "); + return buildings[building].location; + }), + [selectedSections] + ); + + useEffect(() => { + if (!containerRef.current) return; + + // let destructor: (() => void) | null = null; + + const map = new mapboxgl.Map({ + container: containerRef.current, + style: + colorScheme === "dark" + ? "mapbox://styles/mathhulk/clvblbtkd005k01rd1n28b2xt" + : "mapbox://styles/mathhulk/clbznbvgs000314k8gtwa9q60", + center: [-122.2592173, 37.8721508], + zoom: DEFAULT_ZOOM, + minZoom: MIN_ZOOM, + maxZoom: MAX_ZOOM, + }); + + map.on("load", async () => { + const directions = new MapboxDirections({ + styles: [ + { + id: "directions-route-line-casing", + type: "line", + source: "directions", + layout: { + "line-cap": "round", + "line-join": "round", + }, + paint: { + "line-color": "#3b82f6", + "line-width": 4, + }, + filter: [ + "all", + ["in", "$type", "LineString"], + ["in", "route", "selected"], + ], + }, + ], + accessToken: TOKEN, + unit: "imperial", + profile: "mapbox/walking", + controls: { + inputs: false, + instructions: false, + profileSwitcher: false, + }, + interactive: false, + instructions: false, + }); + + map.addControl(directions); + + // @ts-expect-error - MapboxDirections does not provide types + directions.on("route", ({ route }) => { + console.log(route); + + for (let index = 0; index < route[0].legs.length; index++) { + const { steps } = route[0].legs[index]; + + const start = document.createElement("div"); + start.className = "marker"; + start.textContent = (index + 1).toLocaleString(); + + /*const tooltip = document.createElement("div"); + tooltip.className = "tooltip"; + tooltip.textContent = "Stop";*/ + + const originMarker = new mapboxgl.Marker(start) + .setLngLat(steps[0].maneuver.location) + .addTo(map); + + markersRef.current.push(originMarker); + + /*const showTooltip = () => { + document.body.appendChild(tooltip); + + destructor = autoUpdate( + start, + tooltip, + () => { + computePosition(start, tooltip, { + placement: "top", + middleware: [ + flip(), + offset(8), + shift({ + padding: 8, + boundary: document.getElementById("boundary") as Element, + }), + ], + }).then(({ x, y }) => { + Object.assign(tooltip.style, { + left: `${x}px`, + top: `${y}px`, + }); + }); + }, + { + animationFrame: true, + } + ); + }; + + const hideTooltip = () => { + tooltip.remove(); + + destructor?.(); + }; + + [ + ["mouseenter", showTooltip], + ["mouseleave", hideTooltip], + ["focus", showTooltip], + ["blur", hideTooltip], + ].forEach(([event, listener]) => { + start.addEventListener( + event as keyof HTMLElementEventMap, + listener as () => void + ); + });*/ + + if (index !== route[0].legs.length - 1) continue; + + const end = document.createElement("div"); + end.className = "marker"; + end.textContent = (index + 2).toLocaleString(); + + const destinationMarker = new mapboxgl.Marker(end) + .setLngLat(steps[steps.length - 1].maneuver.location) + .addTo(map); + + markersRef.current.push(destinationMarker); + } + + map.jumpTo({ center: [-122.2592173, 37.8721508] }); + + // Remove unnecessary layers + map.removeLayer("directions-route-line"); + map.removeLayer("directions-waypoint-point-casing"); + map.removeLayer("directions-waypoint-point"); + map.removeLayer("directions-origin-point"); + map.removeLayer("directions-destination-point"); + map.removeLayer("directions-origin-label"); + map.removeLayer("directions-destination-label"); + }); + + map.addSource("campus", { + type: "geojson", + data: "/geojson/campus.geojson", + }); + + map.addLayer({ + id: "campus-fill", + type: "line", + source: "campus", + layout: {}, + paint: { + "line-width": 1, + "line-color": "#3b82f6", + "line-opacity": 0.5, + "line-dasharray": [2, 2], + }, + }); + + map.addLayer({ + id: "campus-line", + type: "fill", + source: "campus", + layout: {}, + paint: { + "fill-color": "#3b82f6", + "fill-opacity": 0.05, + }, + }); + + setDirections(directions); + }); + + map.on("zoomend", () => { + setZoom(map.getZoom()); + }); + + mapRef.current = map; + + return () => { + mapRef.current?.remove(); + }; + }, [colorScheme]); + + useEffect(() => { + if (!directions) return; + + markersRef.current.forEach((marker) => marker.remove()); + + const length = directions.getWaypoints().length; + + for (let index = 0; index < length; index++) { + directions.removeWaypoint(index); + } + + if (waypoints.length < 2) return; + + directions.setOrigin(waypoints[0]); + directions.setDestination(waypoints[waypoints.length - 1]); + + for (let index = 1; index < waypoints.length - 1; index++) { + directions.addWaypoint(index, waypoints[index]); + } + }, [waypoints, directions]); + + return ( +
+
+ + mapRef.current?.zoomIn()} + > + + + mapRef.current?.zoomOut()} + > + + +
+
+
+
+
1
+
+

8:30 AM

+

STAT 154

+

Dwinelle Hall 117

+
+
+
+ +
+ 5 min. (0.5 mi.) +
+
+
+
2
+
+

8:30 AM

+

STAT 154

+

Dwinelle Hall 117

+
+
+
+ +
+ 5 min. (0.5 mi.) +
+
+
+
3
+
+

8:30 AM

+

STAT 154

+

Dwinelle Hall 117

+
+
+
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/SideBar/Catalog/Catalog.module.scss b/frontend/src/app/Schedule/Manage/SideBar/Catalog/Catalog.module.scss new file mode 100644 index 000000000..60aa65c33 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Catalog/Catalog.module.scss @@ -0,0 +1,63 @@ +.overlay { + background-color: var(--background-color); + inset: 0; + position: fixed; + z-index: 988; + opacity: 0; + animation: fadeIn 250ms ease-in-out forwards; +} + +.content { + height: 100dvh; + position: fixed; + left: 0; + top: 0; + z-index: 989; + display: flex; + flex-direction: column; + transform: translateX(-100%); + animation: slideIn 250ms ease-in-out forwards; + + @media (width <= 992px) { + width: 100%; + } + + + .body { + flex-grow: 1; + height: 0; + overflow: clip; + } + + .header { + border-width: 0 1px 1px 0; + border-color: var(--border-color); + border-style: solid; + padding: 12px; + background-color: var(--foreground-color); + display: flex; + align-items: center; + flex-shrink: 0; + justify-content: space-between; + font-size: 14px; + line-height: 1; + color: var(--heading-color); + font-weight: 500; + + @media (width <= 992px) { + border-width: 0 0 1px; + } + } +} + +@keyframes fadeIn { + to { + opacity: 0.75; + } +} + +@keyframes slideIn { + to { + transform: translateX(0); + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/SideBar/Catalog/index.tsx b/frontend/src/app/Schedule/Manage/SideBar/Catalog/index.tsx new file mode 100644 index 000000000..3c389ba93 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Catalog/index.tsx @@ -0,0 +1,68 @@ +import { useState } from "react"; + +import * as Dialog from "@radix-ui/react-dialog"; +import { Xmark } from "iconoir-react"; +import { useSearchParams } from "react-router-dom"; + +import Browser from "@/components/Browser"; +import IconButton from "@/components/IconButton"; +import { ICourse, Semester } from "@/lib/api"; + +import styles from "./Catalog.module.scss"; + +interface CatalogProps { + onClassSelect: (course: ICourse, number: string) => void; + children: JSX.Element; + semester: string; + year: number; +} + +export default function Catalog({ onClassSelect, children }: CatalogProps) { + const [open, setOpen] = useState(false); + const [searchParams, setSearchParams] = useSearchParams(); + + const handleOpenChange = (open: boolean) => { + setOpen(open); + + if (open) return; + + searchParams.delete("query"); + setSearchParams(searchParams); + }; + + const handleClassSelect = (course: ICourse, number: string) => { + onClassSelect(course, number); + + setOpen(false); + + searchParams.delete("query"); + setSearchParams(searchParams); + }; + + return ( + + {children} + + + +
+ Add a course to this schedule + + + + + +
+
+ +
+
+
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/SideBar/Class/Class.module.scss b/frontend/src/app/Schedule/Manage/SideBar/Class/Class.module.scss new file mode 100644 index 000000000..0192ffe32 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Class/Class.module.scss @@ -0,0 +1,103 @@ +.root { + display: flex; + + .border { + width: 8px; + background-color: var(--purple-500); + border-radius: 8px 0 0 8px; + } + + .body { + flex-grow: 1; + border-width: 1px 1px 1px 0; + border-radius: 0 8px 8px 0; + border-style: solid; + border-color: var(--border-color); + background-color: var(--foreground-color); + box-shadow: 0 1px 2px rgba(0 0 0 / 2.5%); + padding: 16px; + } + + .group { + border-top: 1px solid var(--border-color); + padding-top: 16px; + margin-top: 16px; + display: flex; + flex-direction: column; + gap: 16px; + + .label { + font-size: 14px; + line-height: 1; + display: flex; + color: var(--label-color); + + .component { + margin-left: 28px; + } + + .time { + margin-left: auto; + } + } + } + + .header { + display: flex; + cursor: pointer; + gap: 12px; + align-items: flex-start; + transition: all 100ms ease-in-out; + + &:hover .icon { + color: var(--heading-color); + } + + .icon { + color: var(--paragraph-color); + flex-shrink: 0; + } + + .toolBar { + display: flex; + flex-direction: column; + gap: 8px; + + .iconButton { + height: 24px; + width: 24px; + } + } + + .text { + flex-grow: 1; + font-size: 14px; + + .heading { + font-weight: 700; + color: var(--heading-color); + margin-bottom: 8px; + line-height: 1; + } + + .description { + color: var(--paragraph-color); + line-height: 1.5; + } + + .row { + display: flex; + gap: 12px; + margin-top: 12px; + align-items: center; + line-height: 1; + + .units { + font-size: 14px; + user-select: none; + color: var(--paragraph-color); + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/SideBar/Class/Section/Section.module.scss b/frontend/src/app/Schedule/Manage/SideBar/Class/Section/Section.module.scss new file mode 100644 index 000000000..36b407377 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Class/Section/Section.module.scss @@ -0,0 +1,57 @@ +.root { + display: flex; + align-items: center; + gap: 12px; + cursor: pointer; + + &:hover .title { + color: var(--heading-color); + } + + &.active .title { + color: var(--heading-color); + } + + &.active .radioButton { + border-color: var(--blue-500); + + &::after { + opacity: 1; + background-color: var(--blue-500); + } + } + + .radioButton { + height: 16px; + width: 16px; + border-radius: 8px; + border: 1.5px solid var(--gray-400); + position: relative; + + &::after { + height: 10px; + width: 10px; + border-radius: 5px; + background-color: var(--gray-400); + content: ""; + position: absolute; + top: 1.5px; + left: 1.5px; + opacity: 0; + transition: all 100ms ease-in-out; + } + } + + .time { + margin-left: auto; + line-height: 1; + } + + .title { + font-size: 14px; + line-height: 1; + color: var(--paragraph-color); + font-weight: 500; + transition: all 100ms ease-in-out; + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/SideBar/Class/Section/index.tsx b/frontend/src/app/Schedule/Manage/SideBar/Class/Section/index.tsx new file mode 100644 index 000000000..d371e0023 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Class/Section/index.tsx @@ -0,0 +1,47 @@ +import classNames from "classnames"; + +import CCN from "@/components/CCN"; +import Time from "@/components/Time"; +import { ISection } from "@/lib/api"; + +import styles from "./Section.module.scss"; + +interface SectionProps { + onSectionSelect?: () => void; + onSectionMouseOver: () => void; + onSectionMouseOut: () => void; + active: boolean; +} + +export default function Section({ + onSectionSelect, + onSectionMouseOver, + onSectionMouseOut, + active, + ccn, + number, + meetings: [{ startTime, endTime, days }], +}: SectionProps & ISection) { + return ( +
onSectionSelect?.()} + onMouseOver={() => onSectionMouseOver()} + onMouseOut={() => onSectionMouseOut()} + > +
+

{number}

+ +
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/SideBar/Class/index.tsx b/frontend/src/app/Schedule/Manage/SideBar/Class/index.tsx new file mode 100644 index 000000000..1571aaab8 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/Class/index.tsx @@ -0,0 +1,148 @@ +import { useMemo } from "react"; + +import { ArrowSeparateVertical, ArrowUnionVertical } from "iconoir-react"; + +import AverageGrade from "@/components/AverageGrade"; +import Capacity from "@/components/Capacity"; +import Units from "@/components/Units"; +import { Component, IClass, ISection, components } from "@/lib/api"; +import { getColor } from "@/lib/section"; + +import styles from "./Class.module.scss"; +import Section from "./Section"; + +interface ClassProps { + expanded: boolean; + onExpandedChange: (expanded: boolean) => void; + selectedSections: ISection[]; + onSectionSelect: (section: ISection) => void; + onSectionMouseOver: (section: ISection) => void; + onSectionMouseOut: () => void; +} + +export default function Class({ + expanded, + onExpandedChange, + title, + course, + unitsMin, + unitsMax, + primarySection, + sections, + number, + selectedSections, + onSectionSelect, + onSectionMouseOver, + onSectionMouseOut, +}: ClassProps & IClass) { + const groups = useMemo(() => { + const sortedSections = structuredClone(sections).sort((a, b) => + a.number.localeCompare(b.number) + ); + + return Object.groupBy(sortedSections, (section) => section.component); + }, [sections]); + + // TODO: Fix temporary hack to set the class number + const handleSectionSelect = (section: ISection) => { + const clonedSection = structuredClone(section); + + // @ts-expect-error - Hack to set the class number + clonedSection.class = { number }; + + onSectionSelect(clonedSection); + }; + + const handleSectionMouseOver = (section: ISection) => { + const clonedSection = structuredClone(section); + + // @ts-expect-error - Hack to set the class number + clonedSection.class = { number }; + + onSectionMouseOver(clonedSection); + }; + + return ( +
+
+
+
onExpandedChange(!expanded)} + > +
+ {expanded ? : } +
+
+

+ {course.subject} {course.number} +

+

{title ?? course.title}

+
+ + + +
+
+
+ {expanded && ( +
+
+

+ {components[primarySection.component]} +

+

Time

+
+
selectedSection.ccn === primarySection.ccn + )} + {...primarySection} + onSectionMouseOver={() => handleSectionMouseOver(primarySection)} + onSectionMouseOut={onSectionMouseOut} + /> +
+ )} + {expanded && + Object.keys(groups).map((component) => { + const group = component as Component; + + return ( +
+
+

{components[group]}

+

Time

+
+ {groups[group]?.map((section) => { + const active = selectedSections.some( + (selectedSection) => selectedSection.ccn === section.ccn + ); + + return ( +
handleSectionMouseOver(section)} + onSectionSelect={() => handleSectionSelect(section)} + {...section} + key={section.ccn} + /> + ); + })} +
+ ); + })} +
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/SideBar/SideBar.module.scss b/frontend/src/app/Schedule/Manage/SideBar/SideBar.module.scss new file mode 100644 index 000000000..134c9f4a3 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/SideBar.module.scss @@ -0,0 +1,45 @@ +.root { + width: 384px; + border-right: 1px solid var(--border-color); + flex-shrink: 0; + background-color: var(--background-color); + overflow: auto; + padding-bottom: 12px; + + .header { + display: flex; + flex-direction: column; + gap: 12px; + padding: 12px; + position: sticky; + top: 0; + background: linear-gradient(to bottom, var(--background-color) 44px, transparent); + z-index: 2; + + .button { + height: 48px; + padding: 0 16px; + justify-content: space-between; + } + + .context { + display: flex; + justify-content: space-between; + align-items: center; + + .data { + font-size: 12px; + color: var(--paragraph-color); + line-height: 1; + } + } + } + + .body { + display: flex; + flex-direction: column; + gap: 12px; + padding: 0 12px; + z-index: 1; + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedule/Manage/SideBar/index.tsx b/frontend/src/app/Schedule/Manage/SideBar/index.tsx new file mode 100644 index 000000000..e6c843a10 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/SideBar/index.tsx @@ -0,0 +1,94 @@ +import { useMemo } from "react"; + +import { Plus } from "iconoir-react"; + +import Button from "@/components/Button"; +import Units from "@/components/Units"; +import { IClass, ICourse, ISection, Semester } from "@/lib/api"; + +import Catalog from "./Catalog"; +import Class from "./Class"; +import styles from "./SideBar.module.scss"; + +interface SideBarProps { + classes: IClass[]; + selectedSections: ISection[]; + expanded: boolean[]; + onClassSelect: (course: ICourse, number: string) => void; + onSectionSelect: (section: ISection) => void; + onSectionMouseOver: (section: ISection) => void; + onSectionMouseOut: () => void; + onExpandedChange: (index: number, expanded: boolean) => void; +} + +export default function SideBar({ + classes, + selectedSections, + onClassSelect, + expanded, + onSectionSelect, + onSectionMouseOver, + onSectionMouseOut, + onExpandedChange, +}: SideBarProps) { + const [minimum, maximum] = useMemo( + () => + classes.reduce( + ([minimum, maximum], { unitsMax, unitsMin }) => [ + minimum + unitsMin, + maximum + unitsMax, + ], + [0, 0] + ), + [classes] + ); + + return ( +
+
+
+
Spring 2024
+
+ {classes.length === 1 ? "1 class" : `${classes.length} classes`},{" "} + + {(units) => units} + +
+
+ + + +
+
+ {classes.map((class_, index) => { + const filteredSections = selectedSections.filter( + (section) => + section.course.number === class_.course.number && + section.class.number === class_.number && + section.course.subject === class_.course.subject + ); + + return ( + onExpandedChange(index, expanded)} + onSectionSelect={onSectionSelect} + onSectionMouseOver={onSectionMouseOver} + onSectionMouseOut={onSectionMouseOut} + selectedSections={filteredSections} + /> + ); + })} +
+
+ ); +} diff --git a/frontend/src/app/Schedule/Manage/index.tsx b/frontend/src/app/Schedule/Manage/index.tsx new file mode 100644 index 000000000..f6fd5f252 --- /dev/null +++ b/frontend/src/app/Schedule/Manage/index.tsx @@ -0,0 +1,259 @@ +import { useCallback, useRef, useState } from "react"; + +import { useApolloClient } from "@apollo/client"; +import { + ArrowLeft, + Copy, + Settings, + ShareIos, + ViewColumns2, +} from "iconoir-react"; +import { Link, useOutletContext } from "react-router-dom"; + +import Button from "@/components/Button"; +import IconButton from "@/components/IconButton"; +import MenuItem from "@/components/MenuItem"; +import Tooltip from "@/components/Tooltip"; +import Week from "@/components/Week"; +import { GET_CLASS, IClass, ICourse, ISection } from "@/lib/api"; +import { getY } from "@/lib/schedule"; + +import { ScheduleContextType } from "../schedule"; +import Calendar from "./Calendar"; +import styles from "./Manage.module.scss"; +import Map from "./Map"; +import SideBar from "./SideBar"; + +export default function Manage() { + const { + selectedSections, + setSelectedSections, + classes, + setClasses, + expanded, + setExpanded, + } = useOutletContext(); + + const [currentSection, setCurrentSection] = useState(null); + const apolloClient = useApolloClient(); + const [tab, setTab] = useState(0); + + // Radix and Floating UI reference the boundary by id + const bodyRef = useRef(null); + + const handleSectionSelect = useCallback( + (section: ISection) => { + // Clear the current section + setCurrentSection(null); + + setSelectedSections((selectedSections) => { + // Ignore selected sections + const ignored = selectedSections.some( + (selectedSection) => selectedSection.ccn === section.ccn + ); + + if (ignored) return selectedSections; + + return [ + ...selectedSections.filter( + (selectedSection) => + !( + selectedSection.course.subject === section.course.subject && + selectedSection.course.number === section.course.number && + selectedSection.class.number === section.class.number && + selectedSection.component == section.component + ) + ), + section, + ]; + }); + }, + [setSelectedSections, setCurrentSection] + ); + + const handleSectionMouseOver = useCallback( + (section: ISection) => { + // Jump to the section + if ( + tab === 0 && + section.meetings[0].startTime && + section.meetings[0].endTime + ) { + const top = getY(section.meetings[0].startTime); + + const offset = (getY(section.meetings[0].endTime) - top) / 2; + + bodyRef.current?.scrollTo({ + top: top + offset - bodyRef.current.clientHeight / 2, + behavior: "smooth", + }); + } + + // Ignore selected sections + if ( + selectedSections.some( + (selectedSection) => selectedSection.ccn === section.ccn + ) + ) + return; + + setCurrentSection(section); + }, + [setCurrentSection, selectedSections, tab] + ); + + const handleClassSelect = useCallback( + async (course: ICourse, number: string) => { + // Fetch the selected class + const { data } = await apolloClient.query<{ class: IClass }>({ + query: GET_CLASS, + variables: { + term: { + semester: "Spring", + year: 2024, + }, + subject: course.subject, + courseNumber: course.number, + classNumber: number, + }, + }); + + if (!data) return; + + // Move existing classes to the top rather than duplicating them + const index = classes.findIndex( + (class_) => + class_.course.subject === course.subject && + class_.course.number === course.number && + class_.number === number + ); + + setExpanded((expandedClasses) => { + const _expandedClasses = structuredClone(expandedClasses); + if (index !== -1) _expandedClasses.splice(index, 1); + return [true, ...expandedClasses]; + }); + + setClasses((classes) => { + const _classes = structuredClone(classes); + if (index !== -1) _classes.splice(index, 1); + return [data.class, ...classes]; + }); + + // Add new classes to the top expanded + if (index !== -1) return; + + const { primarySection, sections } = data.class; + + const clonedPrimarySection = structuredClone(primarySection); + + // @ts-expect-error - Hack to set the class number + clonedPrimarySection.class = { number }; + + // Add the primary section to selected sections + setSelectedSections((sections) => [...sections, clonedPrimarySection]); + + const kinds = Array.from( + new Set(sections.map((section) => section.component)) + ); + + // Add the first section of each kind to selected sections + for (const kind of kinds) { + const section = sections + .filter((section) => section.component === kind) + .sort((a, b) => a.number.localeCompare(b.number))[0]; + + const clonedSection = structuredClone(section); + + // @ts-expect-error - Hack to set the class number + clonedSection.class = { number }; + + setSelectedSections((sections) => [...sections, clonedSection]); + } + }, + [apolloClient, setClasses, classes, setSelectedSections, setExpanded] + ); + + const handleExpandedChange = (index: number, expanded: boolean) => { + setExpanded((expandedClasses) => { + const _expandedClasses = structuredClone(expandedClasses); + _expandedClasses[index] = expanded; + return _expandedClasses; + }); + }; + + return ( +
+
+
+ + + + + + + +

Untitled Spring 2024 schedule

+ + + + + +
+
+
+ setTab(0)}> + Schedule + + setTab(1)}> + Calendar + + setTab(2)}> + Map + +
+ + + + + +
+
+ setCurrentSection(null)} + /> +
+ {tab === 0 ? ( + + ) : tab === 1 ? ( + + ) : ( + + )} +
+
+
+ ); +} diff --git a/frontend/src/app/Schedule/index.tsx b/frontend/src/app/Schedule/index.tsx new file mode 100644 index 000000000..08f139889 --- /dev/null +++ b/frontend/src/app/Schedule/index.tsx @@ -0,0 +1,45 @@ +import { useState } from "react"; + +import { useQuery } from "@apollo/client"; +import { Outlet } from "react-router"; +import { useNavigate, useParams } from "react-router-dom"; + +import Boundary from "@/components/Boundary"; +import LoadingIndicator from "@/components/LoadingIndicator"; +import { GET_SCHEDULE, GetScheduleResponse, IClass, ISection } from "@/lib/api"; + +import { ScheduleContextType } from "./schedule"; + +export default function Schedule() { + const { scheduleId } = useParams(); + + const navigate = useNavigate(); + + const { data } = useQuery(GET_SCHEDULE, { + onError: () => navigate("/schedules"), + variables: { id: scheduleId }, + }); + + const [selectedSections, setSelectedSections] = useState([]); + const [classes, setClasses] = useState([]); + const [expanded, setExpanded] = useState([]); + + return data ? ( + + ) : ( + + + + ); +} diff --git a/frontend/src/app/Schedule/schedule.ts b/frontend/src/app/Schedule/schedule.ts new file mode 100644 index 000000000..394870cf0 --- /dev/null +++ b/frontend/src/app/Schedule/schedule.ts @@ -0,0 +1,12 @@ +import { Dispatch, SetStateAction } from "react"; + +import { IClass, ISection } from "@/lib/api"; + +export interface ScheduleContextType { + selectedSections: ISection[]; + setSelectedSections: Dispatch>; + classes: IClass[]; + setClasses: Dispatch>; + expanded: boolean[]; + setExpanded: Dispatch>; +} diff --git a/frontend/src/app/Schedules/Schedules.module.scss b/frontend/src/app/Schedules/Schedules.module.scss new file mode 100644 index 000000000..8b181cfe4 --- /dev/null +++ b/frontend/src/app/Schedules/Schedules.module.scss @@ -0,0 +1,38 @@ +.root { + max-width: 1280px; + width: 100%; + margin: 24px auto; + display: flex; + align-items: flex-start; + + .menu { + width: 384px; + border-right: 1px solid var(--border-color); + height: 384px; + } + + .view { + padding: 0 24px; + + .header { + display: flex; + gap: 12px; + + .icon { + height: 32px; + width: 32px; + border-radius: 16px; + background-color: var(--orange-100); + display: grid; + place-items: center; + color: var(--orange-500); + } + + .title { + font-size: 14px; + text-transform: uppercase; + color: var(--paragraph-color); + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/Schedules/index.tsx b/frontend/src/app/Schedules/index.tsx new file mode 100644 index 000000000..339551109 --- /dev/null +++ b/frontend/src/app/Schedules/index.tsx @@ -0,0 +1,112 @@ +import { Reference, gql, useMutation, useQuery } from "@apollo/client"; +import { ClockRotateRight } from "iconoir-react"; +import { Link } from "react-router-dom"; + +import Button from "@/components/Button"; +import { + AccountResponse, + CREATE_SCHEDULE, + CreateScheduleResponse, + DELETE_SCHEDULE, + GET_ACCOUNT, + GET_SCHEDULES, + GetSchedulesResponse, +} from "@/lib/api"; + +import styles from "./Schedules.module.scss"; + +export default function Schedules() { + const { data: account } = useQuery(GET_ACCOUNT); + + const { data: schedules } = useQuery(GET_SCHEDULES, { + variables: { + createdBy: account?.user.email, + }, + }); + + const [createSchedule] = useMutation( + CREATE_SCHEDULE, + { + variables: { + name: "Untitled schedule", + term: { + year: 2024, + semester: "Spring", + }, + createdBy: account?.user.email, + }, + update(cache, { data }) { + const schedule = data?.createNewSchedule; + + if (!schedule) return; + + cache.modify({ + fields: { + schedulesByUser(existingSchedules = []) { + const ref = cache.writeFragment({ + data: schedule, + fragment: gql` + fragment NewSchedule on Schedule { + _id + name + term { + year + semester + } + } + `, + }); + + return [...existingSchedules, ref]; + }, + }, + }); + }, + } + ); + + const [deleteSchedule] = useMutation(DELETE_SCHEDULE, { + update(cache, { data }) { + const id = data?.removeScheduleByID; + + if (!id) return; + + cache.modify({ + fields: { + schedulesByUser(existingSchedules = [], { readField }) { + return existingSchedules.filter( + (scheduleRef: Reference) => id !== readField("_id", scheduleRef) + ); + }, + }, + }); + }, + }); + + return ( +
+
+
+
+
+ +
+

Jump back in

+
+ + {schedules?.schedulesByUser.map((schedule) => ( +
+ {schedule.name} + +
+ ))} +
+
+ ); +} diff --git a/frontend/src/assets/img/about/2022-23/alexander_1.jpg b/frontend/src/assets/img/about/2022-23/alexander_1.jpg deleted file mode 100644 index d4e85ea13..000000000 Binary files a/frontend/src/assets/img/about/2022-23/alexander_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/carissa_1.jpg b/frontend/src/assets/img/about/2022-23/carissa_1.jpg deleted file mode 100644 index 78fd1b916..000000000 Binary files a/frontend/src/assets/img/about/2022-23/carissa_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/eric_1.jpg b/frontend/src/assets/img/about/2022-23/eric_1.jpg deleted file mode 100644 index 6993a2c9c..000000000 Binary files a/frontend/src/assets/img/about/2022-23/eric_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/eric_2.jpg b/frontend/src/assets/img/about/2022-23/eric_2.jpg deleted file mode 100644 index 1b720e701..000000000 Binary files a/frontend/src/assets/img/about/2022-23/eric_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/ethan_1.jpg b/frontend/src/assets/img/about/2022-23/ethan_1.jpg deleted file mode 100644 index 552ab44f8..000000000 Binary files a/frontend/src/assets/img/about/2022-23/ethan_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/ethan_2.jpg b/frontend/src/assets/img/about/2022-23/ethan_2.jpg deleted file mode 100644 index c23e06c49..000000000 Binary files a/frontend/src/assets/img/about/2022-23/ethan_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/henric_1.jpg b/frontend/src/assets/img/about/2022-23/henric_1.jpg deleted file mode 100644 index 6a87113d8..000000000 Binary files a/frontend/src/assets/img/about/2022-23/henric_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/henric_2.jpg b/frontend/src/assets/img/about/2022-23/henric_2.jpg deleted file mode 100644 index c9ff44fdf..000000000 Binary files a/frontend/src/assets/img/about/2022-23/henric_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/jaden_1.jpg b/frontend/src/assets/img/about/2022-23/jaden_1.jpg deleted file mode 100644 index 1279a682b..000000000 Binary files a/frontend/src/assets/img/about/2022-23/jaden_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/joanne_1.jpg b/frontend/src/assets/img/about/2022-23/joanne_1.jpg deleted file mode 100644 index a741f788e..000000000 Binary files a/frontend/src/assets/img/about/2022-23/joanne_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/joanne_2.jpg b/frontend/src/assets/img/about/2022-23/joanne_2.jpg deleted file mode 100644 index 622b3f057..000000000 Binary files a/frontend/src/assets/img/about/2022-23/joanne_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/joel_1.jpg b/frontend/src/assets/img/about/2022-23/joel_1.jpg deleted file mode 100644 index 7ad639e34..000000000 Binary files a/frontend/src/assets/img/about/2022-23/joel_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/kelly_1.jpg b/frontend/src/assets/img/about/2022-23/kelly_1.jpg deleted file mode 100644 index ba79a1f7b..000000000 Binary files a/frontend/src/assets/img/about/2022-23/kelly_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/kelly_2.jpg b/frontend/src/assets/img/about/2022-23/kelly_2.jpg deleted file mode 100644 index 5514bad29..000000000 Binary files a/frontend/src/assets/img/about/2022-23/kelly_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/kevin_1.jpg b/frontend/src/assets/img/about/2022-23/kevin_1.jpg deleted file mode 100644 index fa8c3472b..000000000 Binary files a/frontend/src/assets/img/about/2022-23/kevin_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/kevin_2.jpg b/frontend/src/assets/img/about/2022-23/kevin_2.jpg deleted file mode 100644 index 25338260a..000000000 Binary files a/frontend/src/assets/img/about/2022-23/kevin_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/levi_1.jpg b/frontend/src/assets/img/about/2022-23/levi_1.jpg deleted file mode 100644 index 18944dac5..000000000 Binary files a/frontend/src/assets/img/about/2022-23/levi_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/matthew_1.jpg b/frontend/src/assets/img/about/2022-23/matthew_1.jpg deleted file mode 100644 index e1a660ca9..000000000 Binary files a/frontend/src/assets/img/about/2022-23/matthew_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/matthew_2.jpg b/frontend/src/assets/img/about/2022-23/matthew_2.jpg deleted file mode 100644 index 4740d6875..000000000 Binary files a/frontend/src/assets/img/about/2022-23/matthew_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/max_1.jpg b/frontend/src/assets/img/about/2022-23/max_1.jpg deleted file mode 100644 index 635d4728b..000000000 Binary files a/frontend/src/assets/img/about/2022-23/max_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/michael_1.jpg b/frontend/src/assets/img/about/2022-23/michael_1.jpg deleted file mode 100644 index 6f1bf5383..000000000 Binary files a/frontend/src/assets/img/about/2022-23/michael_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/michelle_1.jpg b/frontend/src/assets/img/about/2022-23/michelle_1.jpg deleted file mode 100644 index 26f6c3221..000000000 Binary files a/frontend/src/assets/img/about/2022-23/michelle_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/michelle_2.jpg b/frontend/src/assets/img/about/2022-23/michelle_2.jpg deleted file mode 100644 index e1db0e173..000000000 Binary files a/frontend/src/assets/img/about/2022-23/michelle_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/rachel_1.jpg b/frontend/src/assets/img/about/2022-23/rachel_1.jpg deleted file mode 100644 index cab5ce0e4..000000000 Binary files a/frontend/src/assets/img/about/2022-23/rachel_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/william_1.jpg b/frontend/src/assets/img/about/2022-23/william_1.jpg deleted file mode 100644 index 5542795f4..000000000 Binary files a/frontend/src/assets/img/about/2022-23/william_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/william_2.jpg b/frontend/src/assets/img/about/2022-23/william_2.jpg deleted file mode 100644 index ac4260aa9..000000000 Binary files a/frontend/src/assets/img/about/2022-23/william_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/zachary_1.jpg b/frontend/src/assets/img/about/2022-23/zachary_1.jpg deleted file mode 100644 index 169fa659e..000000000 Binary files a/frontend/src/assets/img/about/2022-23/zachary_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/2022-23/zachary_2.jpg b/frontend/src/assets/img/about/2022-23/zachary_2.jpg deleted file mode 100644 index 1e6c5ec49..000000000 Binary files a/frontend/src/assets/img/about/2022-23/zachary_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/ashwin.jpg b/frontend/src/assets/img/about/alumni/ashwin.jpg deleted file mode 100644 index 7d09e1fee..000000000 Binary files a/frontend/src/assets/img/about/alumni/ashwin.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/austin_1.jpg b/frontend/src/assets/img/about/alumni/austin_1.jpg deleted file mode 100644 index c9db88619..000000000 Binary files a/frontend/src/assets/img/about/alumni/austin_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/austin_2.jpg b/frontend/src/assets/img/about/alumni/austin_2.jpg deleted file mode 100644 index 33e99cb19..000000000 Binary files a/frontend/src/assets/img/about/alumni/austin_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/chris_1.jpg b/frontend/src/assets/img/about/alumni/chris_1.jpg deleted file mode 100644 index 2ff829ba5..000000000 Binary files a/frontend/src/assets/img/about/alumni/chris_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/chris_2.jpg b/frontend/src/assets/img/about/alumni/chris_2.jpg deleted file mode 100644 index 3e8917470..000000000 Binary files a/frontend/src/assets/img/about/alumni/chris_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/grace_1.jpg b/frontend/src/assets/img/about/alumni/grace_1.jpg deleted file mode 100644 index 9d36042ec..000000000 Binary files a/frontend/src/assets/img/about/alumni/grace_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/grace_2.jpg b/frontend/src/assets/img/about/alumni/grace_2.jpg deleted file mode 100644 index acfe40311..000000000 Binary files a/frontend/src/assets/img/about/alumni/grace_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/hannah_1.jpg b/frontend/src/assets/img/about/alumni/hannah_1.jpg deleted file mode 100644 index d5b6b3e39..000000000 Binary files a/frontend/src/assets/img/about/alumni/hannah_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/hannah_2.jpg b/frontend/src/assets/img/about/alumni/hannah_2.jpg deleted file mode 100644 index 3b5ff1a71..000000000 Binary files a/frontend/src/assets/img/about/alumni/hannah_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/janet_1.jpg b/frontend/src/assets/img/about/alumni/janet_1.jpg deleted file mode 100644 index 710a65b7d..000000000 Binary files a/frontend/src/assets/img/about/alumni/janet_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/janet_2.jpg b/frontend/src/assets/img/about/alumni/janet_2.jpg deleted file mode 100644 index cd69b76e6..000000000 Binary files a/frontend/src/assets/img/about/alumni/janet_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/jonathan_1.jpg b/frontend/src/assets/img/about/alumni/jonathan_1.jpg deleted file mode 100644 index fd763e96c..000000000 Binary files a/frontend/src/assets/img/about/alumni/jonathan_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/jonathan_2.jpg b/frontend/src/assets/img/about/alumni/jonathan_2.jpg deleted file mode 100644 index ee10440a5..000000000 Binary files a/frontend/src/assets/img/about/alumni/jonathan_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/junghyun_1.jpg b/frontend/src/assets/img/about/alumni/junghyun_1.jpg deleted file mode 100644 index 9c2ae6c8a..000000000 Binary files a/frontend/src/assets/img/about/alumni/junghyun_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/junghyun_2.jpg b/frontend/src/assets/img/about/alumni/junghyun_2.jpg deleted file mode 100644 index 8ea8bb415..000000000 Binary files a/frontend/src/assets/img/about/alumni/junghyun_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/kate.jpg b/frontend/src/assets/img/about/alumni/kate.jpg deleted file mode 100644 index ebd1d3681..000000000 Binary files a/frontend/src/assets/img/about/alumni/kate.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/leon_1.jpg b/frontend/src/assets/img/about/alumni/leon_1.jpg deleted file mode 100644 index 5337bf0de..000000000 Binary files a/frontend/src/assets/img/about/alumni/leon_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/leon_2.jpg b/frontend/src/assets/img/about/alumni/leon_2.jpg deleted file mode 100644 index 70ed58d27..000000000 Binary files a/frontend/src/assets/img/about/alumni/leon_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/michael_1.jpg b/frontend/src/assets/img/about/alumni/michael_1.jpg deleted file mode 100644 index 4a6541566..000000000 Binary files a/frontend/src/assets/img/about/alumni/michael_1.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/michael_2.jpg b/frontend/src/assets/img/about/alumni/michael_2.jpg deleted file mode 100755 index 379d89724..000000000 Binary files a/frontend/src/assets/img/about/alumni/michael_2.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/noah.jpg b/frontend/src/assets/img/about/alumni/noah.jpg deleted file mode 100644 index bdfd4fc5e..000000000 Binary files a/frontend/src/assets/img/about/alumni/noah.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/scott.jpg b/frontend/src/assets/img/about/alumni/scott.jpg deleted file mode 100644 index 7ccb92f62..000000000 Binary files a/frontend/src/assets/img/about/alumni/scott.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/alumni/yuxin.jpg b/frontend/src/assets/img/about/alumni/yuxin.jpg deleted file mode 100644 index c2323c5ad..000000000 Binary files a/frontend/src/assets/img/about/alumni/yuxin.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/chengdu.JPG b/frontend/src/assets/img/about/group/chengdu.JPG deleted file mode 100644 index a727ba8b6..000000000 Binary files a/frontend/src/assets/img/about/group/chengdu.JPG and /dev/null differ diff --git a/frontend/src/assets/img/about/group/christina_janet.jpg b/frontend/src/assets/img/about/group/christina_janet.jpg deleted file mode 100644 index 465decb2b..000000000 Binary files a/frontend/src/assets/img/about/group/christina_janet.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/doe.jpg b/frontend/src/assets/img/about/group/doe.jpg deleted file mode 100644 index 7e7a3993e..000000000 Binary files a/frontend/src/assets/img/about/group/doe.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/grace_janet.jpg b/frontend/src/assets/img/about/group/grace_janet.jpg deleted file mode 100644 index 675ece263..000000000 Binary files a/frontend/src/assets/img/about/group/grace_janet.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/jemma.jpg b/frontend/src/assets/img/about/group/jemma.jpg deleted file mode 100644 index d55cf943d..000000000 Binary files a/frontend/src/assets/img/about/group/jemma.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/michaels.jpg b/frontend/src/assets/img/about/group/michaels.jpg deleted file mode 100644 index d8258463c..000000000 Binary files a/frontend/src/assets/img/about/group/michaels.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/retreat.jpg b/frontend/src/assets/img/about/group/retreat.jpg deleted file mode 100644 index 161438920..000000000 Binary files a/frontend/src/assets/img/about/group/retreat.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/retreat_silly.png b/frontend/src/assets/img/about/group/retreat_silly.png deleted file mode 100644 index f7fe2c0fd..000000000 Binary files a/frontend/src/assets/img/about/group/retreat_silly.png and /dev/null differ diff --git a/frontend/src/assets/img/about/group/retreat_sp20.png b/frontend/src/assets/img/about/group/retreat_sp20.png deleted file mode 100644 index a776e9aca..000000000 Binary files a/frontend/src/assets/img/about/group/retreat_sp20.png and /dev/null differ diff --git a/frontend/src/assets/img/about/group/will.jpg b/frontend/src/assets/img/about/group/will.jpg deleted file mode 100644 index 5399822ec..000000000 Binary files a/frontend/src/assets/img/about/group/will.jpg and /dev/null differ diff --git a/frontend/src/assets/img/about/group/zoom.png b/frontend/src/assets/img/about/group/zoom.png deleted file mode 100644 index fd8b1e09d..000000000 Binary files a/frontend/src/assets/img/about/group/zoom.png and /dev/null differ diff --git a/frontend/src/assets/img/commands b/frontend/src/assets/img/commands deleted file mode 100644 index 213b256e7..000000000 --- a/frontend/src/assets/img/commands +++ /dev/null @@ -1,6 +0,0 @@ -# convert png to jpg -mogrify -format jpg *.png - -# compress jpg -# ! OVERWRITES ORIGINAL ! -jpegoptim --size=50 *.jpg diff --git a/frontend/src/assets/img/eggs/denero.png b/frontend/src/assets/img/eggs/denero.png deleted file mode 100644 index b1621bba0..000000000 Binary files a/frontend/src/assets/img/eggs/denero.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/garcia.png b/frontend/src/assets/img/eggs/garcia.png deleted file mode 100644 index b612ed3ab..000000000 Binary files a/frontend/src/assets/img/eggs/garcia.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/hilf.png b/frontend/src/assets/img/eggs/hilf.png deleted file mode 100644 index e011c0996..000000000 Binary files a/frontend/src/assets/img/eggs/hilf.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/hug.png b/frontend/src/assets/img/eggs/hug.png deleted file mode 100644 index a6c2d0470..000000000 Binary files a/frontend/src/assets/img/eggs/hug.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/kubi.png b/frontend/src/assets/img/eggs/kubi.png deleted file mode 100644 index 116d5da78..000000000 Binary files a/frontend/src/assets/img/eggs/kubi.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/sahai.png b/frontend/src/assets/img/eggs/sahai.png deleted file mode 100644 index fa05a10d9..000000000 Binary files a/frontend/src/assets/img/eggs/sahai.png and /dev/null differ diff --git a/frontend/src/assets/img/eggs/scott.png b/frontend/src/assets/img/eggs/scott.png deleted file mode 100644 index 19bfce9cd..000000000 Binary files a/frontend/src/assets/img/eggs/scott.png and /dev/null differ diff --git a/frontend/src/assets/img/images/catalog/backarrow.svg b/frontend/src/assets/img/images/catalog/backarrow.svg deleted file mode 100644 index dc2ba3b85..000000000 --- a/frontend/src/assets/img/images/catalog/backarrow.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - \ No newline at end of file diff --git a/frontend/src/assets/img/images/catalog/checked.png b/frontend/src/assets/img/images/catalog/checked.png deleted file mode 100644 index 764a19470..000000000 Binary files a/frontend/src/assets/img/images/catalog/checked.png and /dev/null differ diff --git a/frontend/src/assets/img/images/catalog/enrollment.svg b/frontend/src/assets/img/images/catalog/enrollment.svg deleted file mode 100755 index bd285c23f..000000000 --- a/frontend/src/assets/img/images/catalog/enrollment.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - diff --git a/frontend/src/assets/img/images/catalog/grade.svg b/frontend/src/assets/img/images/catalog/grade.svg deleted file mode 100755 index 59070bf61..000000000 --- a/frontend/src/assets/img/images/catalog/grade.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - diff --git a/frontend/src/assets/img/images/click.png b/frontend/src/assets/img/images/click.png deleted file mode 100644 index d0739f34c..000000000 Binary files a/frontend/src/assets/img/images/click.png and /dev/null differ diff --git a/frontend/src/assets/img/images/empty-graph.png b/frontend/src/assets/img/images/empty-graph.png deleted file mode 100644 index 9fc4de55c..000000000 Binary files a/frontend/src/assets/img/images/empty-graph.png and /dev/null differ diff --git a/frontend/src/assets/img/images/empty-sign.png b/frontend/src/assets/img/images/empty-sign.png deleted file mode 100644 index a43ddf448..000000000 Binary files a/frontend/src/assets/img/images/empty-sign.png and /dev/null differ diff --git a/frontend/src/assets/img/images/graphs/empty.svg b/frontend/src/assets/img/images/graphs/empty.svg deleted file mode 100644 index 49bcef20c..000000000 --- a/frontend/src/assets/img/images/graphs/empty.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/frontend/src/assets/img/images/graphs/info.svg b/frontend/src/assets/img/images/graphs/info.svg deleted file mode 100644 index 30472792c..000000000 --- a/frontend/src/assets/img/images/graphs/info.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/img/images/octo.jpg b/frontend/src/assets/img/images/octo.jpg deleted file mode 100644 index 19f699d6b..000000000 Binary files a/frontend/src/assets/img/images/octo.jpg and /dev/null differ diff --git a/frontend/src/assets/img/images/octoIcon.jpg b/frontend/src/assets/img/images/octoIcon.jpg deleted file mode 100644 index eb09a8e1f..000000000 Binary files a/frontend/src/assets/img/images/octoIcon.jpg and /dev/null differ diff --git a/frontend/src/assets/img/images/oski.jpg b/frontend/src/assets/img/images/oski.jpg deleted file mode 100644 index 159e1b68e..000000000 Binary files a/frontend/src/assets/img/images/oski.jpg and /dev/null differ diff --git a/frontend/src/assets/img/landing/asuc_logo.png b/frontend/src/assets/img/landing/asuc_logo.png deleted file mode 100644 index 7d2085d72..000000000 Binary files a/frontend/src/assets/img/landing/asuc_logo.png and /dev/null differ diff --git a/frontend/src/assets/img/landing/ocf_logo.png b/frontend/src/assets/img/landing/ocf_logo.png deleted file mode 100644 index 9cf4ba327..000000000 Binary files a/frontend/src/assets/img/landing/ocf_logo.png and /dev/null differ diff --git a/frontend/src/assets/img/landing/scheduler.png b/frontend/src/assets/img/landing/scheduler.png deleted file mode 100644 index f0ff06f7d..000000000 Binary files a/frontend/src/assets/img/landing/scheduler.png and /dev/null differ diff --git a/frontend/src/assets/img/landing/stf_logo.jpeg b/frontend/src/assets/img/landing/stf_logo.jpeg deleted file mode 100644 index 19653e0ed..000000000 Binary files a/frontend/src/assets/img/landing/stf_logo.jpeg and /dev/null differ diff --git a/frontend/src/assets/scss/berkeleytime.scss b/frontend/src/assets/scss/berkeleytime.scss deleted file mode 100644 index d1497758d..000000000 --- a/frontend/src/assets/scss/berkeleytime.scss +++ /dev/null @@ -1,84 +0,0 @@ -// bootstrap 4 -@import '~bootstrap/scss/bootstrap'; - -// base & themes -@import 'bt/base/responsive'; -@import 'bt/base/variables'; -@import 'bt/theming/colors'; -@import 'bt/base/typography'; -@import 'bt/theming/buttons'; -@import 'bt/theming/navbar'; -@import 'bt/theming/grades_color'; -@import 'bt/theming/enrollment_color'; - -@import 'bt/berkeleytime'; - -// common -@import 'bt/common/banner'; -@import 'bt/common/footer'; -@import 'bt/common/bt-loader'; -@import 'bt/common/input'; -@import 'bt/common/popover'; - -// landing -@import 'bt/landing/jumbotron'; -@import 'bt/landing/explore'; -@import 'bt/landing/mission'; -@import 'bt/landing/blurbs'; -@import 'bt/landing/landing_modal'; - -// Catalog -@import 'bt/catalog/description'; - -// Grades & Enrollment -@import 'bt/classcards'; -@import 'bt/graph-empty'; - -// Grades -@import 'bt/grades/grades'; -@import 'bt/grades/graph'; -@import 'bt/shared/grades_enrollment_info'; - -// Enrollment -@import 'bt/enrollment/enrollment'; - -// Scheduler -@import 'bt/scheduler/course-selector'; -@import 'bt/scheduler/course-calendar'; -@import 'bt/scheduler/calendar-card'; -@import 'bt/scheduler/course-card'; -@import 'bt/scheduler/callout'; -@import 'bt/scheduler/scheduler'; -@import 'bt/scheduler/onboard'; -@import 'bt/scheduler/schedule-modal'; -@import 'bt/scheduler/access-control'; - -// Releases -@import 'bt/releases'; - -// Faq -@import 'bt/faq'; - -@import 'bt/temporary'; -@import 'bt/dashboard'; - -// About page -@import 'bt/about/about'; -@import 'bt/about/current_and_past'; - -// Join page -@import 'bt/join'; -@import 'bt/about/position'; - -// Apply -@import 'bt/positions'; - -// Error page -@import 'bt/error/error'; - -// Profile -@import 'bt/profile/profile'; -@import 'bt/profile/account'; -@import 'bt/profile/card'; -@import 'bt/profile/support'; -@import 'bt/profile/logout'; diff --git a/frontend/src/assets/scss/bt/_berkeleytime.scss b/frontend/src/assets/scss/bt/_berkeleytime.scss deleted file mode 100644 index c5b43b2dd..000000000 --- a/frontend/src/assets/scss/bt/_berkeleytime.scss +++ /dev/null @@ -1,88 +0,0 @@ -// wrapper for bt app (excluding banner) -.app { - background-color: $bt-white; - - // we change navbar's position to absolute when the banner is open - // so the container needs to be positioned relatively - position: relative; - - // A viewport app sits under the navbar and takes up as much vertical space as the viewport - // and has a minimum height of 800px (including navbar). Viewport apps include catalog, - // grades, and enrollment. When smaller than desktop, we no longer attempt to match the - // height of the viewport b/c we change to mobile view. - .viewport-app { - // padding-top: $bt-navbar-height; - - // The reason for this, but WebKit (Chrome + Safari) won't allow child - // element's height: 100% to work if the parent has a min-height but the - // height is *not* an absolute size. - // (see https://bugs.webkit.org/show_bug.cgi?id=26559) - display: flex; - flex-direction: column; - align-items: stretch; - - min-height: $viewport-min-height; - - > div { - // Effective height: 100% - flex: 1; - - @include touch { - align-content: flex-start; - } - } - - @include touch { - height: auto; - } - } - - .fit-to-viewport { - height: 100vh; - min-height: $viewport-min-height; - - @include touch { - height: auto; - min-height: $touch-viewport-min-height; - } - } - - .under-navbar { - padding-top: $bt-navbar-height; - } -} - -::-webkit-scrollbar { - background-color: rgba(0, 0, 0, 0); - width: 14px; - height: 14px; - z-index: 999999; -} - -::-webkit-scrollbar-track { - background-color: rgba(0, 0, 0, 0); -} - -::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0); - border-radius: 16px; - border: 0px solid #fff; -} - -::-webkit-scrollbar-button { - display: none; -} - -:hover::-webkit-scrollbar-thumb { - background-color: #a0a0a5; - border: 4px solid #fff; -} - -::-webkit-scrollbar-thumb:hover { - background-color: #a0a0a5; - border: 4px solid #f4f4f4; -} - -.footer { - position: relative; -} diff --git a/frontend/src/assets/scss/bt/_classcards.scss b/frontend/src/assets/scss/bt/_classcards.scss deleted file mode 100644 index b30ae6272..000000000 --- a/frontend/src/assets/scss/bt/_classcards.scss +++ /dev/null @@ -1,119 +0,0 @@ -.class-card-list { - margin-bottom: 10px; - min-height: 150px; - - @include touch { - min-height: auto; - - > div { - display: flex; - flex-wrap: nowrap; - overflow-x: scroll; - } - } - - .class-card-column { - padding-left: 5px; - padding-right: 5px; - margin: 10px 0; - - .class-card-mobile { - display: flex; - - .class-card-mobile-column { - padding-right: 15px; - flex-direction: row; - } - } - - .class-card { - border: 1px solid $border-color; - border-radius: 5px; - padding: 15px; - height: 130px; - - @include mobile { - height: 200px; - width: 300px; - } - - display: flex; - flex-direction: column; - justify-content: space-between; - - .class-card-header { - display: flex; - flex-direction: row; - align-items: center; - - .class-card-square { - width: 16px; - height: 16px; - border-radius: 3px; - margin-right: 8px; - margin-bottom: 4px; - } - - .class-card-course { - margin-right: auto !important; - font-weight: bold; - color: $bt-base-text; - //font-size: 18px; - @include font-size-responsive-larger(18px); - } - - .class-card-remove { - color: $bt-indicator-red; - cursor: pointer; - opacity: 0.5; - padding: 2px; - transition: 0.5s; - border-radius: 4px; - - &:hover { - opacity: 1; - background: rgba(224, 185, 185, 0.4); - } - } - } - - .class-card-title, - .class-card-options { - color: $bt-grey-text; - } - - /* magic to truncate at 2 lines lol */ - .class-card-title { - //font-size: 16px; - @include font-size-responsive-larger(16px); - - /* hide text if it more than N lines */ - overflow: hidden; - /* for set '...' in absolute position */ - position: relative; - /* use this value to count block height */ - line-height: 1.2em; - /* max-height = line-height (1.2) * lines max number (3) */ - max-height: 2.4em; - /* fix problem when last visible word doesn't adjoin right side */ - text-align: left; - /* place for '...' */ - margin-right: -1em; - padding-right: 1em; - } - - .class-card-options { - //font-size: 15px; - @include font-size-responsive-larger(15px); - - @include mobile { - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 2; - -webkit-box-orient: vertical; - overflow: hidden; - } - } - } - } -} diff --git a/frontend/src/assets/scss/bt/_dashboard.scss b/frontend/src/assets/scss/bt/_dashboard.scss deleted file mode 100644 index 256a11161..000000000 --- a/frontend/src/assets/scss/bt/_dashboard.scss +++ /dev/null @@ -1,98 +0,0 @@ -/* -.dashboard-columns { - @media screen and (max-width: $tablet) { - justify-content: center; - } -} - -.dashboard-card { - height: auto; - width: 350px; - margin: 20px; - display: flex; - flex-direction: column; - justify-content: center; - - .dashboard-container { - margin: 20px 30px 20px; - display: flex; - flex-direction: column; - justify-content: space-between; - - .dashboard-profile-pic-container { - height: 200px; - margin-top: 15px; - display: flex; - flex-direction: column; - justify-content: space-around; - align-items: center; - - .dashboard-profile-pic { - height: 125px; - width: 125px; - object-fit: cover; - border-radius: 99em; - } - - .dashboard-profile-name { - font-size: 24px; - text-transform: uppercase; - font-weight: 500; - letter-spacing: 1px; - color: #616161; - } - } - - .dashboard-profile-info { - display: flex; - flex-direction: column; - justify-content: space-between; - - .dashboard-profile-info-section { - margin-top: 10px; - - h4 { - color: #616161; - } - - p { - color: #AFAFAF; - } - } - } - - .dashboard-card-title { - font-size: 20px; - color: #616161; - } - - .dashboard-schedule-list { - display: flex; - flex-direction: column; - justify-content: space-between; - margin-top: 20px; - - h5 { - color: #AFAFAF; - margin-bottom: 5px; - } - - p { - margin-top: 10px; - color: #616161; - text-transform: uppercase; - - span { - float: right; - color: #AFAFAF; - text-transform: none; - } - } - } - - .dashboard-schedule-link { - margin-top: 15px; - } - } -} -*/ diff --git a/frontend/src/assets/scss/bt/_error.scss b/frontend/src/assets/scss/bt/_error.scss deleted file mode 100644 index d1d129221..000000000 --- a/frontend/src/assets/scss/bt/_error.scss +++ /dev/null @@ -1,75 +0,0 @@ -.error { - display: flex; - flex-direction: column; - justify-content: center; - - .error-heading { - padding: 100px 0; - padding-right: 30px; - display: flex; - flex-direction: column; - align-items: baseline; - - h1 { - margin: 15px 0; - font-size: 64px; - font-weight: 500; - } - - h2 { - margin: 15px 0; - font-size: 32px; - font-weight: 500; - color: lighten($bt-grey, 10%); - } - - p { - font-size: 18px; - color: $bt-grey; - line-height: 35px; - } - - .error-buttons { - margin: 50px 0; - display: flex; - flex-direction: row; - - .error-info { - border-color: $bt-blue; - background-color: $bt-blue; - color: white; - transition: 0.3s; - - a { - color: inherit; - } - - &:hover { - background-color: white; - color: $bt-blue; - } - } - - .error-bugs { - margin-left: 20px; - border-color: $bt-light-grey; - color: $bt-light-grey; - transition: 0.3s; - - a { - color: inherit; - } - - &:hover { - background-color: $bt-light-grey; - color: white; - } - } - } - } - - .error-img { - height: 350px; - object-fit: scale-down; - } -} diff --git a/frontend/src/assets/scss/bt/_faq.scss b/frontend/src/assets/scss/bt/_faq.scss deleted file mode 100644 index c15140b53..000000000 --- a/frontend/src/assets/scss/bt/_faq.scss +++ /dev/null @@ -1,50 +0,0 @@ -.faq { - padding-top: $bt-navbar-height; - margin-bottom: 100px; - - .faq-heading { - text-align: center; - } - - .faq-row { - width: 100%; - margin-top: 10px; - border-bottom: 1px solid $bt-light-border-grey; - - .faq-question { - cursor: pointer; - - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - span { - width: 24px; - margin-left: 12px; - - text-align: center; - font-size: 24px; - font-weight: 500; - color: $bt-primary; - - -webkit-user-select: none; /* Chrome all / Safari all */ - -moz-user-select: none; /* Firefox all */ - -ms-user-select: none; /* IE 10+ */ - } - } - - .faq-answer { - padding-top: 2px; - padding-bottom: 10px; - - .collapse-text { - line-height: 1.75; - } - - a { - color: $bt-primary; - } - } - } -} diff --git a/frontend/src/assets/scss/bt/_graph-empty.scss b/frontend/src/assets/scss/bt/_graph-empty.scss deleted file mode 100644 index 6449cfff3..000000000 --- a/frontend/src/assets/scss/bt/_graph-empty.scss +++ /dev/null @@ -1,109 +0,0 @@ -.graph-empty { - // min-height: inherit; - - .opaque { - opacity: 1 !important; - } - - .graph-empty-content { - height: 0px; - position: relative; - @include responsive(bottom, 250px, 300px); - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - min-height: inherit; - - .graph-empty-image { - max-width: 4%; - } - - .graph-empty-heading { - color: $bt-light-text; - display: inline-block; - //font-size: 16px; - @include font-size-responsive-larger(16px); - font-weight: 500; - margin-top: 15px; - text-align: center; - } - } - - .grades-info { - display: flex; - flex-direction: column; - - @include mobile { - text-align: left; - //border: 1px solid $bt-border-grey; - border-radius: 8px; - padding: 20px 20px 20px 20px; - } - - .info-icon { - padding-left: 5px; - width: 25px; - } - - .info-text { - line-height: 1.6; - color: $bt-grey-text; - font-weight: lighter; - } - - .date { - font-weight: bold; - } - - .header { - display: flex; - flex-direction: row; - align-items: center; - - margin-bottom: 5px; - - .square { - background-color: $bt-border-grey; - width: 16px; - height: 16px; - border-radius: 3px; - margin-right: 8px; - margin-bottom: 4px; - } - - .course { - font-weight: bold; - color: $bt-base-text; - //font-size: 18px; - @include font-size-responsive-larger(18px); - } - } - - .title, - .info { - //font-size: 16px; - @include font-size-responsive-larger(16px); - color: $bt-border-grey; - } - - .title { - margin-bottom: 5px; - } - - .info { - margin-bottom: 30px; - } - - span { - margin-right: 5px; - } - - .course-average, - .section-average, - .percentile { - margin-bottom: 10px; - color: $bt-border-grey; - } - } -} diff --git a/frontend/src/assets/scss/bt/_join.scss b/frontend/src/assets/scss/bt/_join.scss deleted file mode 100644 index 63b112f96..000000000 --- a/frontend/src/assets/scss/bt/_join.scss +++ /dev/null @@ -1,92 +0,0 @@ -.join { - padding-top: $bt-navbar-height; - margin: 0 auto 30px auto; - display: flex; - flex-direction: column; - align-items: center; - - .releases-heading-button { - justify-content: center; - margin: 20px 0px 12px 0px; - flex-direction: row; - padding-top: 0px; - - input { - overflow: visible; - margin-right: 10px; - border: solid 1px #cfcfcf; - text-indent: 10px; - color: $bt-base-text; - border-radius: 4px; - width: 280px; - padding: 6px; - - &::placeholder { - color: $bt-light-grey; - } - - &:focus::placeholder { - color: $bt-light-border-grey; - } - } - } - - .join-pic { - width: 800px; - margin-top: 24px; - margin-bottom: 28px; - @include mobile { - width: 95%; - } - } - - .join-us { - .join-link, - a { - color: $bt-blue; - } - - > h5 { - margin-top: 50px; - text-align: center; - - font-weight: bold; - color: $bt-base-text; - font-size: 24px; - - @include mobile { - font-size: 20px; - } - } - - > p { - margin-top: 20px; - margin-bottom: 20px; - text-align: left; - font-size: 16px; - line-height: 1.75; - color: #8a8a8a; - width: 650px; - - @include mobile { - width: 330px; - } - } - - .releases-heading-button.btn-toolbar { - > input { - overflow: visible; - margin-right: 10px; - border: solid 1px #cfcfcf; - text-indent: 10px; - color: $bt-base-text; - border-radius: 4px; - width: 280px; - - &::placeholder { - color: $bt-light-grey; - } - } - } - } -} diff --git a/frontend/src/assets/scss/bt/_positions.scss b/frontend/src/assets/scss/bt/_positions.scss deleted file mode 100644 index 2e661923a..000000000 --- a/frontend/src/assets/scss/bt/_positions.scss +++ /dev/null @@ -1,93 +0,0 @@ -.positions { - margin: 0 auto 30px auto; - padding-top: $bt-navbar-height; - - display: flex; - flex-direction: column; - align-items: center; - - .positions-heading { - h2 { - font-weight: bold; - font-size: 24px; - margin-top: 50px; - margin-bottom: 30px; - text-align: center; - color: $bt-base-text; - } - } - - .positions-body { - color: $bt-grey-text; - font-size: 16px; - line-height: 175%; - text-align: left; - - strong { - color: inherit; - } - - h3 { - margin-top: 32px; - font-weight: bold; - font-size: 18px; - color: inherit; - } - - p { - margin-top: 18px; - color: inherit; - margin-bottom: 15px; - } - - a { - color: $bt-primary; - } - - ol { - margin-top: 13px; - padding-left: 0; - color: inherit; - margin-bottom: 15px; - - li { - margin-top: 5px; - } - } - - ul { - margin-top: 13px; - padding-left: 0; - list-style-type: none; - color: inherit; - margin-bottom: 15px; - - li { - text-indent: -22px; - margin-top: 5px; - } - - li:before { - content: '-'; - padding-right: 15px; - } - } - } - - .positions-bar { - height: 80px; - background-color: white; - border-top: solid 1px $bt-light-border-grey; - position: sticky; - margin-top: 30px; - position: -webkit-sticky; - width: 100%; - bottom: 0; - - .position-button { - position: absolute; - right: 0; - top: 15px; - } - } -} diff --git a/frontend/src/assets/scss/bt/_purpose-section.scss b/frontend/src/assets/scss/bt/_purpose-section.scss deleted file mode 100644 index 5035f9a32..000000000 --- a/frontend/src/assets/scss/bt/_purpose-section.scss +++ /dev/null @@ -1,88 +0,0 @@ -.purpose-section { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding-bottom: 60px; - height: 100%; - - .purpose-container { - display: flex; - flex-direction: column; - align-items: center; - height: auto; - width: 85%; - margin: auto; - - .purpose-title { - text-align: center; - font-weight: bold; - font-family: 'Open Sans'; - } - - .purpose-subheading { - text-align: center; - font-family: 'Open Sans'; - margin-top: 10px; - margin-bottom: 30px; - } - - .app-cards { - display: flex; - flex-direction: row; - justify-content: center; - margin: 0 20px; - - .app-card { - min-width: 150px; - width: 25%; - max-width: 400px; - display: flex; - flex-direction: column; - margin: 30px; - padding: 25px; - align-items: center; - border-radius: 15px; - box-shadow: 0 0 10px 1px rgba(0, 0, 0, 0.1); - - .app-icon { - width: 100%; - margin-bottom: 10px; - } - - .app-text { - min-height: 150px; - - .app-title { - margin: 15px 0; - font-family: 'Open Sans'; - font-weight: 500; - text-align: center; - } - - .app-description { - font-size: 14px; - font-family: 'Open Sans'; - text-align: center; - margin-bottom: 10px; - } - } - - .app-link { - font-family: 'Open Sans'; - color: $bt-blue; - } - } - } - } -} - -.bt-pink { - color: $bt-pink; -} -.bt-green { - color: $bt-green; -} -.bt-blue { - color: $bt-blue; -} diff --git a/frontend/src/assets/scss/bt/_releases.scss b/frontend/src/assets/scss/bt/_releases.scss deleted file mode 100644 index 49f225cb7..000000000 --- a/frontend/src/assets/scss/bt/_releases.scss +++ /dev/null @@ -1,76 +0,0 @@ -.releases { - margin: 0 auto 30px auto; - padding-top: $bt-navbar-height; - - display: flex; - flex-direction: column; - align-items: center; - - .releases-heading { - h2 { - font-weight: bold; - font-size: 24px; - margin-top: 50px; - text-align: center; - color: $bt-base-text; - } - - h3 { - font-size: 16px; - line-height: 150%; - text-align: center; - color: $bt-light-text; - margin-top: 18px; - } - - .releases-heading-button { - justify-content: center; - margin-top: 20px; - margin-bottom: 64px; - } - } - - .releases-log { - margin-bottom: 48px; - - .releases-log-date { - h3 { - font-weight: bold; - font-size: 18px; - line-height: 150%; - margin-bottom: 18px; - } - } - - .releases-log-list { - h2 { - font-weight: bold; - font-size: 16px; - line-height: 150%; - margin-bottom: 12px; - } - - ul { - font-size: 16px; - line-height: 150%; - color: $bt-grey-text; - padding-left: 0px; - margin-bottom: 16px; - list-style-position: outside; - margin-left: 28px; - } - - li { - margin: 8pt 0; - } - - a { - color: $bt-primary; - text-decoration: none; - &:hover { - text-decoration: underline; - } - } - } - } -} diff --git a/frontend/src/assets/scss/bt/_temporary.scss b/frontend/src/assets/scss/bt/_temporary.scss deleted file mode 100644 index 1bca2ff67..000000000 --- a/frontend/src/assets/scss/bt/_temporary.scss +++ /dev/null @@ -1,11 +0,0 @@ -.temporary-jumbo { - margin-top: 100px; - - h1 { - text-align: center; - font-size: 50px; - font-weight: 500; - - margin: 50vh 0; - } -} diff --git a/frontend/src/assets/scss/bt/about/_about.scss b/frontend/src/assets/scss/bt/about/_about.scss deleted file mode 100644 index f0d9b42c1..000000000 --- a/frontend/src/assets/scss/bt/about/_about.scss +++ /dev/null @@ -1,253 +0,0 @@ -.about { - padding-top: $bt-navbar-height; - - .about-our-team { - text-align: center; - - p { - color: $bt-light-text; - line-height: 1.75; - width: 500px; - - @include mobile { - width: 300px; - } - } - } - - .group { - display: flex; - justify-content: center; - width: 100%; - position: relative; - overflow: hidden; - .about-carousel { - /* Make the width of the flexbox equal the sum of the width of its items */ - display: inline-flex; - flex-direction: row; - justify-content: center; - - &.about-carousel-slide-left { - transition: transform 1s ease; - transform: translateX(-20%); - } - &.about-carousel-slide-right { - transition: transform 1s ease; - transform: translateX(20%); - } - - .about-carousel-item { - display: none; - transition: filter 1s ease, transform 1s ease; - - &.about-carousel-active { - display: block; - transform: translateX(0) scale(0.9); - filter: brightness(0.35); - } - &.about-carousel-active-prev { - @extend .about-carousel-active; - order: 0; - } - &.about-carousel-active-first { - @extend .about-carousel-active; - order: 1; - } - &.about-carousel-active-second { - @extend .about-carousel-active; - order: 2; - transform: scale(1); - filter: brightness(1); - } - &.about-carousel-active-third { - @extend .about-carousel-active; - order: 3; - } - &.about-carousel-active-next { - @extend .about-carousel-active; - order: 4; - } - &.focus-in { - transform: scale(1); - filter: brightness(1); - } - &.focus-out { - transform: scale(0.9); - filter: brightness(0.35); - } - - > img { - border-radius: 3px; - width: 100%; - height: 100%; - object-fit: cover; - } - @include desktop { - height: 400px; - width: 711px; - } - - @include sm-md { - height: 300px; - width: 533px; - } - - @include xs { - height: 200px; - width: 356px; - } - } - - // remove scroll bar - -ms-overflow-style: none; /* Internet Explorer 10+ */ - scrollbar-width: none; /* Firefox */ - } - - .about-carousel-arrow { - position: absolute; - - top: calc(50% - 24px); - - display: grid; - place-items: center; - - height: 48px; - width: 48px; - - border: none; - - border-radius: 50%; - - background-color: rgba(white, 0.75); - - transition: background-color 0.15s ease-in-out; - - color: #383838; - - &:hover { - background-color: white; - } - } - - .about-carousel-next { - @extend .about-carousel-arrow; - - right: calc(15% - 48px); - } - - .about-carousel-prev { - @extend .about-carousel-arrow; - - left: calc(15% - 48px); - } - } - - // remove scroll bar - .group::-webkit-scrollbar { - /* Safari and Chrome */ - display: none; - } - - .values { - margin-bottom: 80px; - - @include desktop { - width: 900px; - } - - @include mobile { - width: 300px; - } - - > h5 { - margin-bottom: 40px; - text-align: center; - - font-weight: bold; - font-size: 24px; - @include mobile { - font-size: 20px; - } - } - - .value-col { - margin-bottom: 20px; - - .value { - height: 100%; - padding: 0 20px; - - .value-content { - height: 100%; - border-radius: 4px; - border: solid 2px #6d6a7238; - padding: 20px 10px; - - display: flex; - flex-direction: column; - align-items: center; - - > h6 { - font-size: 18px; - font-weight: bold; - margin: 20px 0 10px; - } - - > p { - text-align: center; - width: 95%; - line-height: 1.75; - color: #8a8a8a; - } - } - } - } - } - - // should move somewhere else??? - .releases-heading-button { - justify-content: center; - margin-top: 20px; - margin-bottom: 64px; - - input { - overflow: visible; - margin-right: 10px; - border: solid 1px #cfcfcf; - text-indent: 10px; - color: $bt-base-text; - border-radius: 4px; - width: 280px; - - &::placeholder { - color: $bt-light-grey; - } - } - } - - .join-pic { - width: 800px; - margin-bottom: 28px; - @include mobile { - width: 95%; - } - } - - .nav-link { - background-color: #e1e1e16b; - } - - display: flex; - flex-direction: column; - align-items: center; - - .title { - font-weight: bold; - color: $bt-base-text; - font-size: 24px; - - @include mobile { - font-size: 30px; - } - } -} diff --git a/frontend/src/assets/scss/bt/about/_current_and_past.scss b/frontend/src/assets/scss/bt/about/_current_and_past.scss deleted file mode 100644 index 5c5151977..000000000 --- a/frontend/src/assets/scss/bt/about/_current_and_past.scss +++ /dev/null @@ -1,85 +0,0 @@ -.current-contributors, -.past-contributors { - display: flex; - flex-direction: column; - - > div { - display: grid; - grid-template-columns: repeat(4, 150px); - justify-content: center; - flex-wrap: wrap; - gap: 25px; - - @include media(mobile) { - grid-template-columns: repeat(2, 150px); - } - } -} - -.contributor-card { - display: flex; - flex-direction: column; - align-items: flex-start; - margin-bottom: 25px; - - // use width/height to enforce aspect ratio i guess - .headshot { - width: 150px; - height: 150px; - - margin-bottom: 10px; - - img { - width: 150px; - height: 150px; - - position: absolute; - object-fit: cover; - object-position: 50% 20%; - border-radius: 3px; - } - - .serious { - z-index: $z-index-serious; - transition: 0.2s; - - &:hover { - opacity: 0; - } - } - } - - .name { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - width: 100%; - margin-bottom: 3px; - - p { - // font-weight: 500; - color: $bt-grey-text; - } - - svg { - width: 22px; - height: 21px; - padding: 2px; - transition: 0.2s; - border-radius: 4px; - margin-bottom: 2px; - - &:hover { - background-color: $bt-button-background; - } - } - } - - .role { - font-size: 14px; - word-wrap: normal; - color: $bt-light-text; - } -} diff --git a/frontend/src/assets/scss/bt/about/_position.scss b/frontend/src/assets/scss/bt/about/_position.scss deleted file mode 100644 index 9086d43f4..000000000 --- a/frontend/src/assets/scss/bt/about/_position.scss +++ /dev/null @@ -1,78 +0,0 @@ -.position-card-row { - width: 800px; - - @include mobile { - width: 90%; - } -} - -.position-card-column { - padding-left: 20px; - padding-right: 20px; - margin: 20px 0; - - .position-card-mobile { - display: flex; - - .position-card-mobile-column { - padding-right: 15px; - flex-direction: row; - } - } - - .position-card { - border: 1px solid $border-color; - border-radius: 5px; - padding: 15px; - - display: flex; - flex-direction: column; - justify-content: flex-start; - - .position-card-header { - display: flex; - flex-direction: row; - align-items: center; - - .position-card-course { - margin-right: auto !important; - font-weight: bold; - color: $bt-base-text; - font-size: 18px; - } - } - - .position-card-title, - .position-card-options { - color: $bt-grey-text; - } - - /* magic to truncate at 2 lines lol */ - .position-card-title { - font-size: 16px; - line-height: 1.75; - color: #8a8a8a; - - /* for set '...' in absolute position */ - position: relative; - /* fix problem when last visible word doesn't adjoin right side */ - text-align: left; - /* place for '...' */ - margin-right: -1em; - padding-right: 1em; - margin-top: 10px; - margin-bottom: 10px; - } - - .position-card-row { - font-size: 16px; - text-align: right; - padding-right: 10px; - width: 100%; - } - - .position-card-link { - color: $bt-primary; - } - } -} diff --git a/frontend/src/assets/scss/bt/base/_responsive.scss b/frontend/src/assets/scss/bt/base/_responsive.scss deleted file mode 100644 index 72632f2a7..000000000 --- a/frontend/src/assets/scss/bt/base/_responsive.scss +++ /dev/null @@ -1,81 +0,0 @@ -// This file contains responsive mixins based on Bootstrap 4 breakpoints. -// https://getbootstrap.com/docs/4.0/layout/overview/#responsive-breakpoints - -// xs: 0-576 (mobile) (touch) -// sm: 576-768 (mobile) (touch) -// md: 768-992 (tablet) (touch) -// lg: 992-1200 (desktop) -// xl: 1200+ (widescreen) (desktop) - -$breakpoints: ( - mobile: 768px, - tablet: 1124px, -); - -@mixin media($keys...) { - @each $key in $keys { - @media (max-width: map-get($breakpoints, $key)) { - @content; - } - } -} - -@mixin mobile { - @include media-breakpoint-down(sm) { - @content; - } -} - -// between 768px and 992px, or md -@mixin tablet { - @include media-breakpoint-only(md) { - @content; - } -} - -// up to 576px, or xs -@mixin xs { - @include media-breakpoint-down(xs) { - @content; - } -} - -// between 576px and 992px -@mixin sm-md { - @include media-breakpoint-between(sm, md) { - @content; - } -} - -// mobile & tablet -// up to 992px, or xs + sm + md -@mixin touch { - @include media-breakpoint-down(md) { - @content; - } -} - -// greater than 992px, or lg + xl -@mixin desktop { - @include media-breakpoint-up(lg) { - @content; - } -} - -// greater than 1200px, or xl -@mixin widescreen { - @include media-breakpoint-up(xl) { - @content; - } -} - -// have property take on 2 different values depending on the view -@mixin responsive($property, $desktop, $touch) { - @include desktop { - #{$property}: $desktop; - } - - @include touch { - #{$property}: $touch; - } -} diff --git a/frontend/src/assets/scss/bt/base/_typography.scss b/frontend/src/assets/scss/bt/base/_typography.scss deleted file mode 100644 index 5829f793e..000000000 --- a/frontend/src/assets/scss/bt/base/_typography.scss +++ /dev/null @@ -1,90 +0,0 @@ -// This file contains some default styling for all text tags. - -body, -h1, -h2, -h3, -h4, -h5, -h6, -p, -a, -button, -td { - font-family: 'Inter', sans-serif; - font-style: normal; - font-weight: normal; - color: $bt-base-text; - margin: 0; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -a { - color: $bt-blue; - transition: color 0.2s; - - &:hover { - text-decoration: none; - } -} - -// responsively scale font sizes (replace with $responsive) -@mixin font-size-responsive($size) { - font-size: $size; - - @if $size <= 24px { - @include tablet { - font-size: $size - 2px; - } - @include mobile { - font-size: $size - 4px; - } - } @else if $size <= 25px { - @include tablet { - font-size: $size - 3px; - } - @include mobile { - font-size: $size - 5px; - } - } @else { - @include tablet { - font-size: $size - 3px; - } - @include mobile { - font-size: $size - 6px; - } - } -} - -@mixin font-size-responsive-larger($size) { - @include mobile { - font-size: $size - 2px; - } - font-size: $size; -} - -.bt-h3 { - @include font-size-responsive(26px); -} - -.bt-h6 { - @include font-size-responsive(18px); -} - -.bt-p { - @include font-size-responsive(16px); -} - -.bt-a { - @include font-size-responsive(16px); -} - -.bt-bold { - font-weight: 600; -} - -.bt-light-bold { - font-weight: 500; -} diff --git a/frontend/src/assets/scss/bt/base/_variables.scss b/frontend/src/assets/scss/bt/base/_variables.scss deleted file mode 100644 index 56c52fa3a..000000000 --- a/frontend/src/assets/scss/bt/base/_variables.scss +++ /dev/null @@ -1,19 +0,0 @@ -// This file contains some variables used throughout the stylesheets. - -// exact height of the bootstrap navbar -$bt-navbar-height: 58px; - -// height of the banner -$banner-height: $bt-navbar-height; - -// minimum supported desktop height for app that fits to viewport -$viewport-min-height: 800px; - -// minimum supported mobile height for app to -$touch-viewport-min-height: 600px; - -// variables for z indexes -$z-index-serious: 1; - -// landing -$landing-section-gap: 150px; diff --git a/frontend/src/assets/scss/bt/catalog/_description.scss b/frontend/src/assets/scss/bt/catalog/_description.scss deleted file mode 100644 index 2c84c74d3..000000000 --- a/frontend/src/assets/scss/bt/catalog/_description.scss +++ /dev/null @@ -1,233 +0,0 @@ -.catalog-description-container { - // We don't want the description container to - // make the description column giant, so we make - // it absolute to take it out of the layout flow. - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - - @include mobile { - position: relative; - } - - // (Generally) it shouldn't need to scroll but - // just in case there's some weird description - // with giant words. This prevents things from - // getting cut - overflow-y: auto; - - .loading { - height: 100%; - display: flex; - justify-content: center; - align-items: center; - } - - .catalog-results-empty { - padding: 1.5rem; - font-size: 18px; - text-align: center; - color: $bt-light-text; - } - - .catalog-description { - height: 100%; - padding: 30px 0; - - display: block; - - > *:not(section), - > section > * { - margin-bottom: 15px; - } - - > section:not(.description-section), - .description-section > div { - padding: 0 30px; - } - - h3 { - font-size: 24px; - font-weight: 700; - } - - h6 { - font-size: 18px; - font-weight: 400; - color: $bt-light-text; - } - - .stats { - display: flex; - flex-direction: column; - - .statline { - display: flex; - flex-direction: row; - - .statline-div { - display: flex; - } - - > img { - width: 14px; - margin-right: 8px; - } - - color: $bt-light-text; - - > p { - color: $bt-light-text; - margin-left: 5px; - } - - .statlink { - opacity: 0.8; - border-radius: 2px; - transition: 0.2s; - padding: 0px 4px; - line-height: 0; - padding-top: 4px; - - &:hover { - cursor: pointer; - opacity: 1; - background: $bt-button-background; - } - - img { - height: 16px; - vertical-align: bottom; - } - } - } - } - - .pill-container { - overflow-x: auto; - - &::-webkit-scrollbar { - display: none; - } - - > div { - white-space: nowrap; - display: inline-block; - } - - .pill { - display: inline-block; - margin: 0px 10px 2px 0px; - padding: 6px 12px; - white-space: nowrap; - border: 1px solid $bt-border-grey; - border-radius: 50vh; - text-align: center; - color: $bt-blue; - font-size: 14px; - transition: 200ms; - - &:hover { - cursor: pointer; - background-color: $bt-button-background; - } - } - } - - .description { - color: $bt-grey-text; - - span { - color: $bt-blue; - - &:hover { - cursor: pointer; - } - } - } - - .prereqs { - h6 { - margin-bottom: 10px; - color: $bt-grey-text; - font-weight: 700; - font-size: 1rem; - } - - span { - color: $bt-blue; - - &:hover { - cursor: pointer; - } - } - } - - h5 { - color: $bt-base-text; - font-weight: 700; - margin-top: 10px; - font-size: 18px; - } - - .table-container { - position: relative; - overflow-x: auto; - - @include mobile { - overflow-y: scroll; - } - - div { - display: inline-block; - padding: 0 30px; - } - - .table-empty { - color: $bt-light-text; - font-size: 18px; - } - - table { - max-width: 100%; - max-height: 100%; - margin-bottom: 0; - color: $bt-base-text; - font-weight: normal; - - tr { - transition: 0.2s; - &:hover { - background-color: #d4d4d442; - } - - cursor: var(--section-cursor), pointer; - } - - thead { - th { - font-weight: 700; - border-top: none; - border-bottom: none; - padding: 0.75rem; - position: sticky; - background: white; - transition: 0.2s; - top: 0; - } - } - - td { - font-weight: 400; - padding: 0.75rem; - } - } - } - } -} - -.table-container > div { - overflow-x: scroll; -} diff --git a/frontend/src/assets/scss/bt/common/_banner.scss b/frontend/src/assets/scss/bt/common/_banner.scss deleted file mode 100644 index 1f3079ad4..000000000 --- a/frontend/src/assets/scss/bt/common/_banner.scss +++ /dev/null @@ -1,50 +0,0 @@ -.banner { - .patriotic { - background: repeating-linear-gradient(to right, $bt-blue, $bt-indicator-red); - } - - min-height: $banner-height; - - background-color: $bt-off-white; - - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - - .content { - flex-grow: 1; - - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - gap: 10px; - font-size: 14px; - width: 100%; - min-height: $banner-height; - padding: 10px 5px; - - > * { - margin: 0 5px; - } - - p { - text-align: center; - } - } - - > img { - margin: 0 15px 0 5px; - padding: 6px; - width: 24px; - height: 24px; - border-radius: 4px; - transition: background-color 0.2s; - cursor: pointer; - - &:hover { - background-color: $bt-light-border-grey; - } - } -} diff --git a/frontend/src/assets/scss/bt/common/_bt-loader.scss b/frontend/src/assets/scss/bt/common/_bt-loader.scss deleted file mode 100644 index 071075f2c..000000000 --- a/frontend/src/assets/scss/bt/common/_bt-loader.scss +++ /dev/null @@ -1,82 +0,0 @@ -/** - * The MIT License (MIT) - * - * Copyright (c) 2017 David Hu - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -@keyframes bt-loader-kf { - 50% { - transform: scale(0.75); - opacity: 0.2; - } - 100% { - transform: scale(1); - opacity: 1; - } -} - -@mixin bt-loader-dot($i) { - display: inline-block; - background-color: #579eff; - width: 15px; - height: 15px; - margin: 2px; - border-radius: 100%; - animation: 0.7s if($i % 2 == 0, 0s, 0.35s) infinite linear bt-loader-kf; - animation-fill-mode: both; -} - -.bt-loader-wrapper, -.viewport-app > div.bt-loader-wrapper { - &.bt-loader--fill { - height: calc(100vh - 58px); - flex: 1 0 auto; - } - - &.bt-loader--error { - p { - font-size: 1.5rem; - } - } - - display: flex; - align-items: center; - justify-content: center; - flex-direction: column; - - p { - margin-top: 1rem; - font-size: 18px; - color: $bt-light-text; - } -} - -.bt-loader { - display: flex; - align-items: center; - justify-content: center; - - @for $i from 0 to 3 { - > :nth-child(#{$i + 1}) { - @include bt-loader-dot($i); - } - } -} diff --git a/frontend/src/assets/scss/bt/common/_footer.scss b/frontend/src/assets/scss/bt/common/_footer.scss deleted file mode 100644 index 0989dee0e..000000000 --- a/frontend/src/assets/scss/bt/common/_footer.scss +++ /dev/null @@ -1,36 +0,0 @@ -footer { - background-color: $bt-footer; - border-top: 1.5px solid $bt-light-border-grey; - - .footer-col-container { - display: flex; - justify-content: center; - - .footer-col { - display: flex; - flex-direction: column; - - h6 { - color: $bt-grey; - text-transform: uppercase; - } - - a { - color: $bt-light-grey; - - &:hover { - color: $bt-blue; - } - - .footer-new { - @include font-size-responsive(14px); - - color: $bt-white !important; - background-color: $bt-blue; - padding: 2px 4px; - border-radius: 6px; - } - } - } - } -} diff --git a/frontend/src/assets/scss/bt/common/_input.scss b/frontend/src/assets/scss/bt/common/_input.scss deleted file mode 100644 index a24d59826..000000000 --- a/frontend/src/assets/scss/bt/common/_input.scss +++ /dev/null @@ -1,69 +0,0 @@ -.bt-input { - position: relative; - - &.bt-input--icon { - input { - padding-left: 1.75rem; - } - } - - input { - width: 100%; - padding: 6px; - border: 1px solid $bt-border-grey; - box-shadow: none; - color: $bt-base-text; - font-size: 14px; - font-family: 'FontAwesome', 'Inter', sans-serif; - transition: 100ms; - border-radius: 4px; - text-indent: 6px; - - outline: none; - - &::-webkit-search-cancel-button { - -webkit-appearance: none; - background: url(../svg/common/close.svg); - width: 10px; - height: 10px; - background-size: contain; - cursor: pointer; - } - - &::placeholder { - color: $bt-light-grey; - } - - &:focus { - border: 1px solid #2684ff; - box-shadow: 0 0 0 1px #2684ff; - - + svg { - fill: #2684ff; - } - } - - &:focus { - &::placeholder { - color: $bt-base-text; - } - } - - @include mobile { - // Set the font size so no zoom in on mobile - // font-size: 16px; - } - } - - svg { - position: absolute; - width: 1rem; - height: 1rem; - left: 0.75rem; - top: 50%; - transform: translateY(-50%); - color: inherit; - fill: $bt-light-grey; - transition: 100ms; - } -} diff --git a/frontend/src/assets/scss/bt/common/_popover.scss b/frontend/src/assets/scss/bt/common/_popover.scss deleted file mode 100644 index 2ffe8f3e2..000000000 --- a/frontend/src/assets/scss/bt/common/_popover.scss +++ /dev/null @@ -1,13 +0,0 @@ -.dropdown-menu, -.popover { - box-shadow: rgba(0, 0, 0, 0) 0px 0px 0px 0px, rgba(0, 0, 0, 0) 0px 0px 0px 0px, - rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px; - - border: 1px solid $bt-light-border-grey; - - .arrow { - display: none; - } - - padding: 1rem; -} diff --git a/frontend/src/assets/scss/bt/enrollment/_enrollment.scss b/frontend/src/assets/scss/bt/enrollment/_enrollment.scss deleted file mode 100644 index 576c86c55..000000000 --- a/frontend/src/assets/scss/bt/enrollment/_enrollment.scss +++ /dev/null @@ -1,217 +0,0 @@ -.enrollment { - padding: 30px; - max-width: 100vw; - display: flex; - flex-direction: column; - - @include mobile { - padding: 10px; - } - - .enrollment-mobile-heading { - margin: 30px 0px 30px 20px; - font-size: 20px; - font-weight: 500; - } - - .recharts-surface { - @include desktop { - height: 410px; - } - } - - .enrollment-recharts-container { - height: 450px; - - .recharts-responsive-container { - position: absolute; - } - } - - .css-1myhgat-indicatorContainer { - color: $bt-light-border-grey; - transition: 0.5s; - &:hover { - color: #ababab; - } - } - - .btn-primary:disabled { - cursor: default; - } - - .graph { - margin-top: 20px; - } - - .css-yk16xz-control:hover { - cursor: pointer; - } - - .xlabel { - padding-left: 60px; - font-weight: bold; - color: $bt-light-text; - } - - .disclaimer { - .info { - width: 15px; - margin-bottom: 2px; - } - padding-left: 55px; - padding-top: 5px; - - @include mobile { - padding: 0px 10px 20px 10px; - text-align: center; - } - - p { - display: inline; - margin-left: 5px; - color: $bt-light-grey; - font-size: 14px; - - a { - color: $bt-primary; - - &:hover { - text-decoration: underline; - } - } - } - } - - g.recharts-layer.recharts-cartesian-axis.recharts-xAxis.xAxis, - g.recharts-layer.recharts-cartesian-axis.recharts-yAxis.yAxis { - opacity: 0.5; - } - .recharts-default-tooltip { - border-radius: 4px; - border: 1px solid rgb(225, 225, 225); - } - - .enrollment-search-bar { - .fast-option-selected { - color: white; - } - - > div > div { - padding-left: 5px; - padding-right: 5px; - - @include touch { - padding-top: 10px; - - .btn { - width: 100%; - } - } - } - } -} - -// EnrollmentGraph - -.enrollment-graph { - margin-top: 20px; - - @include mobile { - overflow-x: scroll; - margin: 0px 10px 0px 10px; - - .recharts-legend-wrapper { - left: 65px !important; - } - } - - .enrollment-content { - } -} - -// .enrollment-graph-card { -// box-shadow: none; -// border: none; -// -// .enrollment-graph { -// margin-top: 20px; -// padding: 15px 15px 0px 35px; -// min-height: 500px; -// -// @include mobile { -// padding: 0px 10px 0px 10px; -// text-align: center; -// overflow-x: scroll; -// } -// -// .enrollment-content { -// -// @include mobile { -// width: 500px; -// //ResponsiveContainer already sets height to 500px -// min-height: 510px; -// } -// -// .graph { -// height: 400px; -// padding: 15px 15px 15px 15px; -// } -// .graph-title { -// font-weight: bold; -// font-size: 20px; -// } -// } -// } -// } - -// EnrollmentInfoCard -.card.enrollment-card-info { - box-shadow: none; - border: none; - - .content { - padding: 0px 15px 15px 15px; - - .content { - padding: 0px 15px 15px 15px; - } - - .class-num { - font-weight: bold; - font-size: 20px; - width: fit-content; - } - - .class-info { - margin-top: 5px; - color: #8f8f8f; - } - - .class-title { - padding-top: 5px; - padding-bottom: 10px; - } - - .class-stats { - padding-bottom: 5px; - } - - .class-stat-type { - font-size: 15px; - } - - .class-adjustment-percent { - color: #ffa414; - font-size: 15px; - } - - .class-stats-left-col { - padding-left: 0px; - } - - .class-stats-name { - color: #8f8f8f; - } - } -} diff --git a/frontend/src/assets/scss/bt/error/_error.scss b/frontend/src/assets/scss/bt/error/_error.scss deleted file mode 100644 index 1cc8e5abd..000000000 --- a/frontend/src/assets/scss/bt/error/_error.scss +++ /dev/null @@ -1,55 +0,0 @@ -.viewport-app-404 { - height: 60vh; - min-height: 600px; - - @include mobile { - height: 120vh; - } -} - -.error { - display: flex; - justify-content: center; - align-items: center; - - .content { - display: flex; - flex-direction: column; - justify-content: center; - - > h1 { - margin-bottom: 20px; - font-weight: bold; - @include font-size-responsive(60px); - } - - > h3 { - color: $bt-light-text; - margin-bottom: 24px; - font-weight: bold; - @include font-size-responsive(26px); - } - - > p { - color: $bt-light-text; - margin-bottom: 20px; - @include font-size-responsive(16px); - } - } - - .img-container { - display: flex; - justify-content: center; - align-items: center; - - > img { - width: 100%; - } - - margin-bottom: 20px; - } -} - -a.btn.btn-bt-primary-inverted.btn-bt-lg { - border-width: 2px; -} diff --git a/frontend/src/assets/scss/bt/grades/_grades.scss b/frontend/src/assets/scss/bt/grades/_grades.scss deleted file mode 100644 index 44585dcad..000000000 --- a/frontend/src/assets/scss/bt/grades/_grades.scss +++ /dev/null @@ -1,162 +0,0 @@ -.grades { - padding: 30px; - max-width: 100vw; - - display: flex; - flex-direction: column; - - @include mobile { - padding: 10px; - } - - .grades-mobile-heading { - margin: 10px 0px 5px 10px; - font-size: 20px; - font-weight: 500; - } - - .css-1myhgat-indicatorContainer { - color: $bt-light-border-grey; - transition: 0.5s; - &:hover { - color: #ababab; - } - } - - .btn-primary:disabled { - cursor: default; - } - - .css-yk16xz-control:hover { - cursor: pointer; - } - - .css-10r6hld-indicatorContainer, - .css-hu2rzu-indicatorContainer { - color: $bt-light-border-grey; - transition: 0.5s; - &:hover { - color: #ababab; - } - } - - .disclaimer { - .info { - width: 15px; - margin-bottom: 2px; - } - padding-left: 55px; - padding-top: 5px; - - @include mobile { - padding: 0px 10px 20px 10px; - text-align: center; - } - - p { - display: inline; - margin-left: 5px; - color: $bt-light-grey; - font-size: 14px; - - a { - color: $bt-primary; - - &:hover { - text-decoration: underline; - } - } - } - } - - .grades-search-bar { - margin-bottom: 0; - - .fast-option-selected { - color: white; - } - - // row - > div { - // columns - > div { - padding-left: 5px; - padding-right: 5px; - - @include touch { - padding-top: 10px; - - .btn { - width: 100%; - } - } - } - } - } -} - -// GradesGraph -.grades-graph-card { - box-shadow: none; - border: none; - - .graph-content { - .graph { - padding: 15px 15px 15px 15px; - } - .graph-title { - font-weight: bold; - font-size: 20px; - } - } -} - -// GradesInfoCard -.grades-card-info { - box-shadow: none; - - .content { - padding: 0px 15px 15px 15px; - - .class-num { - font-weight: bold; - font-size: 20px; - width: fit-content; - } - - .class-info { - margin-top: 5px; - color: #8f8f8f; - } - - .class-title { - padding-top: 5px; - padding-bottom: 10px; - } - - .class-avgs { - padding: 0; - - .class-avg-stats { - padding: 0; - font-size: 15px; - font-weight: bold; - margin-bottom: 3%; - } - - .class-stats-name { - color: #8f8f8f; - } - - .class-grade { - font-size: 18px; - font-weight: bold; - } - - .class-percent { - color: gray; - font-size: 18px; - } - } - } -} diff --git a/frontend/src/assets/scss/bt/grades/_graph.scss b/frontend/src/assets/scss/bt/grades/_graph.scss deleted file mode 100644 index d8e8bc353..000000000 --- a/frontend/src/assets/scss/bt/grades/_graph.scss +++ /dev/null @@ -1,35 +0,0 @@ -.grades-graph { - margin-top: 20px; - max-width: 90vw; - - g.recharts-layer.recharts-cartesian-axis.recharts-xAxis.xAxis, - g.recharts-layer.recharts-cartesian-axis.recharts-yAxis.yAxis { - opacity: 0.5; - } - - .recharts-surface { - @include desktop { - height: 410px; - } - // don't cut off number label on widest bar in mobile view - overflow: visible; - } - - .recharts-default-tooltip, - .grades-graph-tooltip { - border-radius: 4px; - border: 1px solid rgb(225, 225, 225); - } - - .grades-graph-tooltip { - opacity: 1 !important; - background: white; - text-align: left; - padding: 12px 12px 12px 12px; - - h6 { - margin-bottom: 5px; - font-weight: bold; - } - } -} diff --git a/frontend/src/assets/scss/bt/landing/_blurbs.scss b/frontend/src/assets/scss/bt/landing/_blurbs.scss deleted file mode 100644 index 9584f7222..000000000 --- a/frontend/src/assets/scss/bt/landing/_blurbs.scss +++ /dev/null @@ -1,34 +0,0 @@ -.landing-blurbs { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - - margin-bottom: $landing-section-gap; - - .desc { - text-align: center; - width: 450px; - - @include touch { - width: 300px; - } - } - - .sponsors { - display: flex; - flex-wrap: wrap; - flex-direction: row; - justify-content: center; - - img { - height: 150px; - padding: 10px; - object-fit: scale-down; - - @include touch { - height: 100px; - } - } - } -} diff --git a/frontend/src/assets/scss/bt/landing/_explore.scss b/frontend/src/assets/scss/bt/landing/_explore.scss deleted file mode 100644 index f059de4bb..000000000 --- a/frontend/src/assets/scss/bt/landing/_explore.scss +++ /dev/null @@ -1,31 +0,0 @@ -.landing-explore { - max-width: 900px; - - @include mobile { - width: 300px; - } - - margin: 25px auto $landing-section-gap; - @extend .px-3; - - text-align: center; - - .feature { - display: flex; - flex-direction: column; - align-items: center; - - @extend .mb-5; - - img { - width: 60px; - height: 60px; - object-fit: scale-down; - } - - p { - width: 95%; - color: #8a8a8a; - } - } -} diff --git a/frontend/src/assets/scss/bt/landing/_jumbotron.scss b/frontend/src/assets/scss/bt/landing/_jumbotron.scss deleted file mode 100644 index 94c0c139d..000000000 --- a/frontend/src/assets/scss/bt/landing/_jumbotron.scss +++ /dev/null @@ -1,149 +0,0 @@ -.landing-jumbo { - height: 100vh; - min-height: $viewport-min-height; - - @include touch { - min-height: $touch-viewport-min-height; - } - - .container, - .container > .row { - // row takes up entire height of jumbotron - height: 100%; - } - - // if tablet or mobile, heading and svg will be stacked on top of each other - @include tablet { - .container > .row { - > :first-child { - // heading - height: 40%; - } - - > :last-child { - // svg - height: 60%; - } - } - } - - @include mobile { - .container > .row { - > :first-child { - // heading - height: 50%; - } - - > :last-child { - // svg - height: 50%; - } - } - } - - .heading { - height: 100%; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: baseline; - text-align: left; - - @include mobile { - // start heading right below svg - justify-content: flex-start; - padding: 20px; - } - - p { - color: $bt-grey-text; - } - } - - .animation-container { - display: flex; - flex-direction: column; - - width: 100%; - height: 100%; - - @include tablet { - padding-top: 100px; - } - - @include mobile { - padding-top: 75px; - } - - display: flex; - justify-content: center; - align-items: center; - - svg { - @keyframes updown { - from { - transform: translateY(-8px); - } - to { - transform: translateY(8px); - } - } - @keyframes updownshort { - from { - transform: translateY(-4px); - } - to { - transform: translateY(4x); - } - } - #left-float { - animation: updown 3.5s ease alternate infinite; - } - #middle-float { - animation: updown 3s ease alternate infinite; - } - #right-float { - animation: updown 4.5s ease alternate infinite; - } - #everything { - animation: updownshort 2.5s ease alternate infinite; - } - #campanile, - #hearst-building, - #evans, - #doe-library, - #hearst-pond { - animation: updownshort 2.5s ease alternate infinite; - } - #treee, - #treee-2, - #other-bush, - #ball-bush, - #tre { - animation: updownshort 2.5s ease alternate infinite; - } - } - - svg, - img { - width: 500px; - max-width: 100%; - - @include touch { - width: auto; - height: 100%; - max-width: 70%; - } - } - - .credit { - color: $bt-light-text; - @include font-size-responsive(14px); - - @include desktop { - margin-top: 5px; - } - } - } -} diff --git a/frontend/src/assets/scss/bt/landing/_landing_modal.scss b/frontend/src/assets/scss/bt/landing/_landing_modal.scss deleted file mode 100644 index 2ce300b8a..000000000 --- a/frontend/src/assets/scss/bt/landing/_landing_modal.scss +++ /dev/null @@ -1,72 +0,0 @@ -.modal.landing-modal { - flex-direction: column; - - .landing-modal-btn { - width: 350px; - align-self: center; - - @include mobile { - width: 200px; - justify-content: center; - height: 40px; - display: flex; - align-items: center; - } - } - - .landing-modal-img { - margin: auto; - width: 400px; - margin-bottom: 15px; - border-radius: 5px; - -webkit-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.2); - -moz-box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.2); - box-shadow: 0px 0px 8px 2px rgba(0, 0, 0, 0.2); - @include mobile { - width: 100%; - } - } - - .landing-modal-text { - color: $bt-light-text; - @include font-size-responsive(14px); - padding: 5px 0 20px 0; - } - - .landing-modal-subtitle { - color: $bt-primary; - } - - .landing-close-btn { - position: absolute; - right: 22px; - top: 20px; - padding: unset; - margin: unset; - img { - width: 10px; - height: 10px; - } - background: none; - border: none; - outline: none; - } - - .landing-modal-dialog { - width: 650px !important; - @include mobile { - width: 75vw !important; - } - - margin: 0 auto; - - align-self: center !important; - top: 15vh !important; - - .modal-content { - padding: 50px !important; - text-align: center !important; - border-radius: 4px !important; - } - } -} diff --git a/frontend/src/assets/scss/bt/landing/_mission.scss b/frontend/src/assets/scss/bt/landing/_mission.scss deleted file mode 100644 index cae367277..000000000 --- a/frontend/src/assets/scss/bt/landing/_mission.scss +++ /dev/null @@ -1,27 +0,0 @@ -.landing-mission { - margin-bottom: $landing-section-gap; - - img { - width: 100%; - object-fit: scale-down; - } - - .mission { - width: 100%; - height: 100%; - @extend .py-4; - - display: flex; - flex-direction: column; - justify-content: center; - align-items: baseline; - - @include mobile { - align-items: center; - } - - p { - max-width: 300px; - } - } -} diff --git a/frontend/src/assets/scss/bt/profile/_account.scss b/frontend/src/assets/scss/bt/profile/_account.scss deleted file mode 100644 index d111d3504..000000000 --- a/frontend/src/assets/scss/bt/profile/_account.scss +++ /dev/null @@ -1,65 +0,0 @@ -//Account Subview -.account-view { - .personal-edit { - position: absolute; - right: 0; - color: #2f80ed; - background-color: Transparent; - border: none; - font-weight: 500; - } - - .personal-edit:focus { - outline: none; - box-shadow: none; - } - - .major-select { - width: 300px; - margin-left: -10px; // Account for react-select padding - } - - .profile-see-more { - color: #2f80ed; - } - - .profile-card-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 12px; - margin: 1rem 0; - } -} - -.profile-row { - display: flex; - - .personal-attribute { - font-weight: 500; - color: #535353; - width: 250px; - max-width: 30%; - flex: 0 0 auto; - - .personal-value { - .p { - @include mobile { - width: 90vw; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - } - } - } - - @include xs { - .personal-attribute { - max-width: 100%; - } - flex-direction: column; - height: auto; - align-items: flex-start; - padding: 8px 0; - } -} diff --git a/frontend/src/assets/scss/bt/profile/_card.scss b/frontend/src/assets/scss/bt/profile/_card.scss deleted file mode 100644 index 0f2abbe21..000000000 --- a/frontend/src/assets/scss/bt/profile/_card.scss +++ /dev/null @@ -1,89 +0,0 @@ -.profile-card { - height: 100%; - border-radius: 8px; - padding: 8px 12px; - - cursor: pointer; - - border: 1.5px solid #e5e5e5; - - display: flex; - flex-direction: row; - justify-content: space-between; - position: relative; - - .profile-card-info { - min-width: 0; // Prevents it from growing past parent - padding-right: 12px; - display: flex; - flex-direction: column; - justify-content: space-between; - - h6 { - font-size: 14px; - line-height: 1.5; - // margin-bottom: 0.25rem; - font-weight: bold; - } - - .profile-card-info-desc { - font-size: 12px; - line-height: 1.7; - color: $bt-light-text; - // margin-bottom: 0.25rem; - font-weight: 500; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - .profile-card-info-stats { - font-size: 12px; - line-height: 1.7; - color: $bt-light-text; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - } - - .profile-card-sort { - display: flex; - align-items: center; - justify-content: center; - font-weight: 600; - - width: 2rem; - flex: 0 0 auto; - } - - .profile-card-remove { - display: none; - position: absolute; - top: 2px; - right: 3px; - } - - &:hover .profile-card-remove { - display: block; - } -} - -.profile-card-remove { - color: $bt-indicator-red; - cursor: pointer; - opacity: 0.5; - padding: 2px; - transition: opacity 0.2s ease, background 0.2s ease; - border-radius: 4px; - - svg { - width: 20px; - height: 20px; - } - - &:hover { - opacity: 1; - background: rgba(224, 185, 185, 0.1); - } -} diff --git a/frontend/src/assets/scss/bt/profile/_logout.scss b/frontend/src/assets/scss/bt/profile/_logout.scss deleted file mode 100644 index ef7da3042..000000000 --- a/frontend/src/assets/scss/bt/profile/_logout.scss +++ /dev/null @@ -1,24 +0,0 @@ -.logout, -.logout.viewport-app { - display: flex; - align-items: center; - justify-content: center; - - .logout-status { - flex: 0 0 auto; - - span { - display: block; - padding: 1.5rem; - font-size: 24px; - text-align: center; - max-width: 300px; - color: $bt-light-text; - } - } - - .bt-loader-wrapper { - display: block; - height: auto; - } -} diff --git a/frontend/src/assets/scss/bt/profile/_profile.scss b/frontend/src/assets/scss/bt/profile/_profile.scss deleted file mode 100644 index 9f02ca075..000000000 --- a/frontend/src/assets/scss/bt/profile/_profile.scss +++ /dev/null @@ -1,146 +0,0 @@ -.profile-container { - min-height: 300px; - padding: 3rem 1rem; - box-sizing: border-box; - - .profile-sidebar { - @include mobile { - overflow: scroll; - } - button { - width: 100%; - border-radius: 4px; - color: $bt-light-text; - background: #fff; - border: none; - padding: 0.5rem 1rem; - - display: flex; - align-items: center; - - margin-bottom: 12px; - - > * { - vertical-align: middle; - } - - svg, - img { - height: 18px; - width: 18px; - outline-color: $bt-light-text; - } - - span { - margin-left: 8px; - line-height: normal; - font-weight: 600; - font-size: 14px; - line-height: 18px; - white-space: nowrap; - } - - &.selected { - color: $bt-primary; - background: #f8f8f8; - } - - &:focus { - text-decoration: none; - } - - &:hover, - &:active { - text-decoration: none; - background: #f8f8f8; - cursor: pointer; - } - } - } - - h1 { - font-weight: bold; - font-size: 32px; - margin-bottom: 32px; - } - - .profile-view-container { - position: relative; - - .profile-sidebar { - position: absolute; - top: 0; - left: -150px - 32px; - width: 150px; - - @include mobile { - position: static; - display: flex; - width: 100%; - margin-bottom: 1rem; - } - } - - .profile-view { - // Prevents weird CSS margin collapse - display: flex; - flex-direction: column; - } - } - - .profile-subview { - margin-bottom: 2rem; - - .profile-subview-title { - display: flex; - position: relative; - align-items: center; - - margin-bottom: 1rem; - - h3 { - font-weight: bold; - font-size: 24px; - margin: 0; - } - - button { - background-color: Transparent; - border: none; - } - - button:focus { - outline: none; - box-shadow: none; - } - - img, - svg { - margin-left: 8px; - height: 28px; - width: 28px; - border-radius: 15px; - padding: 4px 4px 4px 4px; - - transition: all 0.25s ease; - - &:hover { - background: #fafafa; - filter: brightness(95%); - } - } - } - } -} - -.profile-row { - display: flex; - position: relative; - align-items: center; - border-bottom: 1.5px solid #ececec; - height: 50px; - - a { - cursor: pointer; - } -} diff --git a/frontend/src/assets/scss/bt/profile/_support.scss b/frontend/src/assets/scss/bt/profile/_support.scss deleted file mode 100644 index 29932ec28..000000000 --- a/frontend/src/assets/scss/bt/profile/_support.scss +++ /dev/null @@ -1,7 +0,0 @@ -.resource-text-blue { - color: #2f80ed; -} - -.resource-text-red { - color: #de5f18; -} diff --git a/frontend/src/assets/scss/bt/scheduler/_access-control.scss b/frontend/src/assets/scss/bt/scheduler/_access-control.scss deleted file mode 100644 index 079eba4aa..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_access-control.scss +++ /dev/null @@ -1,96 +0,0 @@ -.access-control-toggle { - display: block; - margin: 0; - outline: none; - border: none; - background: none; - margin: 0; - padding: 4px 4px; - - display: flex; - align-items: center; - - svg:first-child { - height: 1rem; - width: 1rem; - margin-right: 8px; - } - - span { - text-align: left; - color: $bt-black; - font-size: 0.9rem; - min-width: 100px; - } - - .access-control-toggle__expand { - height: 0.8rem; - width: 0.8rem; - } -} - -.access-control-menu { - padding: 0; - - .access-control-menu__link { - padding: 1rem; - - h4 { - font-size: 0.9rem; - color: $bt-black; - font-weight: 600; - } - - p { - font-size: 0.9rem; - color: $bt-light-text; - } - - input { - font-size: 0.9rem; - color: $bt-base-text; - display: block; - width: 100%; - border: 1px solid $bt-border-grey; - border-radius: 4px; - box-sizing: border-box; - padding: 2px 8px; - margin-top: 8px; - cursor: pointer; - } - - border-bottom: 1px solid $bt-light-border-grey; - } - - .dropdown-item { - display: flex; - align-items: center; - - &:hover { - background: $bt-off-white; - } - - padding: 12px 1rem; - line-height: 1.2; - - .access-control-menu__name { - font-size: 0.85rem; - color: $bt-base-text; - font-weight: 500; - } - - .access-control-menu__desc { - font-size: 0.85rem; - color: $bt-light-text; - } - - svg { - height: 1rem; - width: 1rem; - } - - > div:not(:first-child) { - flex: 1; - } - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_calendar-card.scss b/frontend/src/assets/scss/bt/scheduler/_calendar-card.scss deleted file mode 100644 index 64172e8b0..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_calendar-card.scss +++ /dev/null @@ -1,90 +0,0 @@ -.calendar-course-card { - &:not(.calendar-course-card--preview) { - cursor: pointer; - } - - &.calendar-course-card--preview { - // color: var(--mixed-text) !important; - opacity: 0.5; - } -} - -.course-card-popover { - font-size: 0.9rem; - - .course-card-popover-square { - position: absolute; - border: 4px; - left: 0; - width: 16px; - height: 16px; - border-radius: 3px; - margin-right: 8px; - } - - .btn { - position: absolute; - right: -8px; - top: -10px; - } - - > * { - padding-left: 1.5rem; - position: relative; - } - - h4 { - font-size: 1em; - line-height: 1rem; - font-weight: 600; - margin-right: 4rem; - } - - > p { - margin-top: 0.3em; - line-height: 1.5; - color: $bt-light-text; - font-size: 0.8rem; - } -} - -.calendar-card { - width: 100%; - height: 100%; - - line-height: 1.5; - - padding: 0.5rem 1rem; - border-radius: 4px; - - box-shadow: 0 0 0 2px #fff; - - color: $bt-white-text; - - .calendar-card__title { - font-size: 13px; - font-weight: 500; - overflow: hidden; - text-overflow: ellipsis; - display: block; - display: -webkit-box; - -webkit-line-clamp: 1; // Duplicated for fallback - -webkit-line-clamp: var(--calendar-card-lines, 1); - -webkit-box-orient: vertical; - line-height: 1.2; - margin-bottom: 1px; - } - - .calendar-card__description { - margin: 0; - font-size: 10px; - color: inherit; - line-height: inherit; - overflow: hidden; - text-overflow: ellipsis; - display: -webkit-box; - -webkit-line-clamp: 3; - -webkit-box-orient: vertical; - line-height: 1.2; - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_callout.scss b/frontend/src/assets/scss/bt/scheduler/_callout.scss deleted file mode 100644 index 1cc768a58..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_callout.scss +++ /dev/null @@ -1,28 +0,0 @@ -.callout { - display: flex; - - font-size: 12px; - - &.callout--state-default { - color: $bt-indicator-blue; - } - - &.callout--state-error { - color: $bt-indicator-red; - } - - svg { - width: 1em; - height: 1em; - margin-right: 4px; - margin-top: 0.25em; - } - - p { - flex: 1; - margin: 0; - color: currentColor; - line-height: 1.5; - font-size: inherit; - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_course-calendar.scss b/frontend/src/assets/scss/bt/scheduler/_course-calendar.scss deleted file mode 100644 index 11fffe8d3..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_course-calendar.scss +++ /dev/null @@ -1,73 +0,0 @@ -.course-calendar { - width: 100%; - height: 100%; - - $calendar-border: 1px solid rgba(0, 0, 0, 0.04); - - .course-calendar__time { - box-sizing: border-box; - width: 90px; - flex: 0 0 auto; - - > div { - padding: 0 16px; - font-size: 14px; - color: $bt-light-text; - font-weight: 600; - text-align: right; - - > span { - display: block; - transform: translateY(-50%); - } - } - } - - .course-calendar__header { - height: 40px; - line-height: 40px; - vertical-align: middle; - font-size: 18px; - color: $bt-base-text; - text-align: center; - font-weight: bold; - border-bottom: $calendar-border; - } - - .course-calendar__content { - display: flex; - .course-calendar__week { - flex: 1; - display: flex; - box-sizing: border-box; - } - } - - .course-calendar__body { - .course-calendar__time, - .course-calendar__day { - padding: 4px 4px; - box-sizing: border-box; - } - - .course-calendar__day > div { - position: relative; - } - } - - .course-card__positioner { - position: absolute; - right: 0; - background: #fff; - border-radius: 4px; - } - - .course-calendar__day { - position: relative; - flex: 1; - border-left: $calendar-border; - &:last-child { - border-right: $calendar-border; - } - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_course-card.scss b/frontend/src/assets/scss/bt/scheduler/_course-card.scss deleted file mode 100644 index a642a78b1..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_course-card.scss +++ /dev/null @@ -1,166 +0,0 @@ -.course-card { - border: 1px solid #e5e5e5; - border-radius: 8px; - - padding: 1rem 1.5rem; - - margin-top: 1rem; - - overflow: hidden; - position: relative; - - .course-card-description { - padding-left: 1.5rem; - } - - &::before { - content: ''; - position: absolute; - left: 0; - top: 0; - bottom: 0; - width: 6px; - background: var(--card-color); - } - - section > * { - margin-bottom: 2px; - } - - section.course-card--disabled { - opacity: 0.5; - } - - section + section { - margin-top: 1rem; - } - - h4 { - font-size: 1rem; - font-weight: 700; - color: $bt-base-text; - line-height: 1.5; - - > .custom-checkbox { - display: flex; - flex-direction: row; - align-items: center; - - label { - flex: 1; - } - } - } - - p { - font-size: 14px; - color: $bt-light-text; - } - - .course-card-scroll { - padding-left: 4px; - margin: 0.5rem 0; - } - - .section-label { - color: $bt-light-text; - font-size: 14px; - font-weight: 400; - margin-left: 4px; - - .section-label-box { - display: inline-block; - height: 1em; - width: 1em; - border-radius: 4px; - margin-right: 0.5em; - margin-bottom: -1.5px; - } - } -} - -.scheduler-course { - + .scheduler-course { - margin-top: 1rem; - border-top: 1px solid $bt-light-border-grey; - padding-top: 1rem; - } - - .scheduler-status { - display: flex; - align-items: center; - justify-content: center; - padding: 1.5rem; - font-size: 18px; - text-align: center; - color: $bt-light-text; - } - - .scheduler-course-header { - display: flex; - flex-direction: row; - align-items: center; - margin: 0; - margin-top: 2px; - - position: relative; - padding-left: 16px + 8px; - - .scheduler-course-square { - position: absolute; - left: 0; - width: 16px; - height: 16px; - border-radius: 3px; - margin-right: 8px; - } - - .scheduler-course-title { - margin-right: auto !important; - font-weight: bold; - color: $bt-base-text; - font-size: 1rem; - line-height: 1rem; - } - - .scheduler-course-name { - margin-right: auto !important; - color: $bt-light-text; - font-size: 0.85rem; - line-height: 1.8; - } - - .scheduler-course-icon { - width: 24px; - height: 24px; - display: flex; - justify-content: center; - align-items: center; - cursor: pointer; - - opacity: 0.5; - transition: 0.5s; - - &:hover { - opacity: 1; - } - } - - .scheduler-course-expand { - svg { - transition: 0.2s ease all; - } - } - - .scheduler-course-remove { - color: $bt-indicator-red; - padding: 2px; - border-radius: 4px; - - &:hover { - opacity: 1; - background: rgba(224, 185, 185, 0.4); - } - } - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_course-selector.scss b/frontend/src/assets/scss/bt/scheduler/_course-selector.scss deleted file mode 100644 index 68cfc6da0..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_course-selector.scss +++ /dev/null @@ -1,22 +0,0 @@ -.course-selector { - padding: 32px; - box-sizing: border-box; - - h2 { - font-weight: 700; - font-size: 20px; - } - - p { - color: $bt-light-text; - font-size: 16px; - } - - > * { - margin-bottom: 1em; - } - - .react-select-virtualized { - z-index: 10; - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_onboard.scss b/frontend/src/assets/scss/bt/scheduler/_onboard.scss deleted file mode 100644 index cef169242..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_onboard.scss +++ /dev/null @@ -1,218 +0,0 @@ -.onboard { - .scheduler-heading { - font-weight: bold; - font-size: 20px; - text-align: center; - } - - .welcome { - padding: 5rem 1rem; - text-align: center; - - .scheduler-title { - font-weight: bold; - font-size: 2rem; - margin-bottom: 1rem; - color: $bt-base-text; - text-align: center; - } - - .prompt { - margin-bottom: 2rem; - font-weight: 400; - font-size: 18px; - color: $bt-light-text; - text-align: center; - } - - .bt-btn-primary { - width: 100px; - font-weight: 600; - } - - .saved-schedules { - margin-top: 3rem; - - .scheduler-heading { - text-align: initial; - } - - .profile-card-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); - gap: 12px; - margin: 1rem 0; - text-align: initial !important; - } - } - } - - .select-classes { - min-height: 710px; - padding: 5rem 1rem; - - .prompt { - margin-top: 18px; - color: $bt-light-text; - font-weight: 500; - font-size: 16px; - text-align: center; - } - - .course-selector { - padding: 32px 32px 18px 32px; - } - - .profile-card-grid { - .profile-card-row { - margin-bottom: 10px; - display: flex; - - .add-class { - height: fit-content; - margin-top: 14px; - margin-right: 10px; - padding: 0; - font-size: 32px; - color: $bt-blue; - text-decoration: none; - - &:hover { - cursor: pointer; - } - } - - .profile-card { - width: 81%; - - &:hover { - cursor: default; - } - } - } - } - - .selected-classes { - margin: 30px 15px 75px 15px; - - .profile-card { - width: 81%; - margin: auto auto 10px auto; - - .profile-card-grade { - margin-right: 18px; - } - - &:hover { - cursor: default; - } - } - } - - .continue { - position: absolute; - bottom: 0; - right: 20%; - } - } - - .time-preferences { - .data-row { - display: flex; - align-items: center; - padding: 12px 0; - - + .data-row { - border-top: 1px solid $bt-light-border-grey; - } - - > :first-child { - font-weight: 500; - color: #535353; - width: 100px; - flex: 0 0 auto; - - + * { - font-weight: 400; - color: $bt-base-text; - flex: 1; - - display: flex; - justify-content: space-between; - align-items: center; - } - } - } - - .blocks { - margin-top: 4rem; - margin-bottom: 4rem; - - .blocks-grid { - margin: 1rem 0; - - display: grid; - grid-template-columns: repeat(auto-fit, minmax(150px, 200px)); - gap: 12px; - - .block { - padding: 8px; - border: 1px solid $bt-light-border-grey; - border-radius: 6px; - - .block__title { - font-weight: 700; - font-size: 0.9rem; - color: $bt-base-text; - } - - .block__desc { - font-weight: 600; - font-size: 0.8rem; - color: $bt-light-text; - } - } - } - - .blocks__placeholder { - display: flex; - flex-direction: column; - align-items: center; - text-align: center; - - svg { - margin: 1rem 0; - } - - p { - color: $bt-light-text; - line-height: 1.5; - font-weight: 600; - width: 200px; - } - } - } - - .small-caps { - text-transform: uppercase; - color: $bt-light-text; - font-weight: 600; - letter-spacing: 1px; - } - - .inline-select { - display: inline-block; - width: 115px; - } - - .select { - width: 100%; - } - - .continue { - position: absolute; - bottom: 4rem; - right: 5%; - } - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_schedule-modal.scss b/frontend/src/assets/scss/bt/scheduler/_schedule-modal.scss deleted file mode 100644 index cedf323bc..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_schedule-modal.scss +++ /dev/null @@ -1,25 +0,0 @@ -.schedule-modal { - .modal-dialog { - max-width: 1024px; - } - - .modal-content { - overflow-x: auto; - - .schedule-modal-content { - min-width: 600px; - padding: 1rem; - padding-right: 2rem; - - input { - text-align: center; - } - - .scheduler-header { - margin-left: 1rem; - margin-bottom: 1rem; - padding-right: 0; - } - } - } -} diff --git a/frontend/src/assets/scss/bt/scheduler/_scheduler.scss b/frontend/src/assets/scss/bt/scheduler/_scheduler.scss deleted file mode 100644 index 95a0ea47e..000000000 --- a/frontend/src/assets/scss/bt/scheduler/_scheduler.scss +++ /dev/null @@ -1,106 +0,0 @@ -.scheduler, -.scheduler.viewport-app { - // I suggest completely overhauling the SCSS lol - @media screen and (min-width: 992px) { - > .row > div { - box-sizing: border-box; - position: relative; - - > .course-selector { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - overflow-y: auto; - } - } - } - - .mobile { - margin-bottom: 2rem; - font-weight: 400; - font-size: 18px; - color: #8a8a8a; - text-align: center; - } - - // Force auto-sizing - &.scheduler { - min-height: 0; - } - - .scheduler-units { - font-size: 16px; - font-weight: 500; - color: $bt-base-text; - flex: 1; - } - - &.schedule-standalone-content { - .scheduler-header input { - text-align: center; - } - } - - .scheduler-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-left: 72px; - padding: 1rem; - - > div { - display: flex; - align-items: center; - } - - > *:not(:last-child) { - margin-right: 1rem; - } - - > span, - > * > span { - font-size: 0.9rem; - &:not(.callout) { - color: $bt-light-text; - } - - &.scheduler-header-strong { - color: $bt-base-text; - font-weight: 500; - } - } - - .scheduler-name-input { - box-shadow: none; - border: none; - appearance: none; - border-radius: 0; - font-size: 1.2rem; - margin: 0; - padding: 0 4px; - font-weight: 500; - border-bottom: 1px solid $bt-border-grey; - background: none; - - &:focus { - border-radius: 0; - outline: none; - border-color: #2684ff; - box-shadow: 0 1px 0px 0px #2684ff; - } - } - } - - .scheduler__status { - min-height: 600px; - display: flex; - align-items: center; - justify-content: center; - padding: 1.5rem; - font-size: 18px; - text-align: center; - color: $bt-light-text; - } -} diff --git a/frontend/src/assets/scss/bt/shared/_grades_enrollment_info.scss b/frontend/src/assets/scss/bt/shared/_grades_enrollment_info.scss deleted file mode 100644 index 2f5f94022..000000000 --- a/frontend/src/assets/scss/bt/shared/_grades_enrollment_info.scss +++ /dev/null @@ -1,86 +0,0 @@ -.grades-info, -.enrollment-info { - display: flex; - flex-direction: column; - - .info-icon { - padding-left: 5px; - width: 25px; - } - .opaque { - opacity: 1 !important; - } - - .info-text { - opacity: 1 !important; - line-height: 1.6; - color: $bt-grey-text; - font-weight: lighter; - } - - .header { - display: flex; - flex-direction: row; - align-items: center; - - margin-bottom: 5px; - - .square { - width: 16px; - height: 16px; - border-radius: 3px; - margin-right: 8px; - margin-bottom: 4px; - } - - .course { - font-weight: bold; - color: $bt-base-text; - font-size: 18px; - } - } - - .title, - .info { - font-size: 16px; - color: $bt-grey-text; - } - - .title { - margin-bottom: 5px; - } - - .info { - margin-bottom: 30px; - } - - h6 { - font-size: 16px; - font-weight: bold; - margin-bottom: 5px; - } - - .stat-section { - .date { - font-weight: bold; - padding-bottom: 5px; - } - .text { - padding-right: 8px; - } - .waitlisted-stat { - margin-top: 5px; - margin-bottom: 20px; - } - } - - span { - margin-right: 5px; - } - - .course-average, - .section-average, - .percentile { - margin-bottom: 10px; - } -} diff --git a/frontend/src/assets/scss/bt/theming/_buttons.scss b/frontend/src/assets/scss/bt/theming/_buttons.scss deleted file mode 100644 index 44445275b..000000000 --- a/frontend/src/assets/scss/bt/theming/_buttons.scss +++ /dev/null @@ -1,109 +0,0 @@ -// This file includes additional variants and sizes for Bootstrap buttons. -// https://react-bootstrap.github.io/getting-started/theming/ - -// custom BsPrefix for buttons -.bt-btn { - @extend .btn; - - @include font-size-responsive(16px); -} - -.bt-btn-sm { - @extend .btn-sm; - - @include font-size-responsive(14px); -} - -@mixin bt-variant($color, $background, $border, $hover) { - color: $color; - background-color: $background; - border-color: $border; - - &:hover { - color: $color; - background-color: $hover; - cursor: pointer; - } -} - -.bt-btn-primary { - @include bt-variant($bt-white, $bt-primary, $bt-primary, $bt-primary-background); -} - -.bt-btn-inverted { - @include bt-variant($bt-primary, $bt-white, $bt-border-grey, $bt-button-background); -} - -.btn-bt-red-inverted { - color: $bt-indicator-red; - background-color: $bt-white; - border-color: $bt-border-grey; - border-width: 2px; - - transition: 0.2s; - - &:hover { - color: $bt-indicator-red; - background-color: $bt-button-background; - border-color: $bt-border-grey; - } - - a { - color: inherit; - } -} - -.btn-bt-blue-inverted { - color: $bt-indicator-blue; - background-color: $bt-white; - border-color: $bt-border-grey; - border-width: 2px; - - transition: 0.2s; - - &:hover { - color: $bt-indicator-blue; - background-color: $bt-button-background; - border-color: $bt-border-grey; - } - - a { - color: inherit; - } -} - -.btn-bt-lg { - font-size: 18px; - line-height: 1.5; - border-radius: 0.3rem; - - @include mobile { - font-size: 1rem; - } -} - -.btn-bt-md { - font-size: 16px; - line-height: 1.5; - border-width: 2px; - border-radius: 0.3rem; -} - -.btn-bt-border { - height: 35px; - background-color: $bt-white; - font-size: 16px; - border: 0.5px solid $bt-light-border-grey; - box-sizing: border-box; - border-radius: 4px; -} - -.as-link { - background: none !important; - border: none; - padding: 0 !important; - text-decoration: none; - &:hover { - text-decoration: underline; - } -} diff --git a/frontend/src/assets/scss/bt/theming/_colors.scss b/frontend/src/assets/scss/bt/theming/_colors.scss deleted file mode 100644 index c63f1da44..000000000 --- a/frontend/src/assets/scss/bt/theming/_colors.scss +++ /dev/null @@ -1,53 +0,0 @@ -$bt-white: #FFFFFF; -$bt-off-white: #F8F8F8; -$bt-light-border-grey: #EAEAEA; -$bt-border-grey: #C7C7C7; -$bt-light-grey: #A0A0A0; -$bt-grey: #5C5C5C; -$bt-black: #000000; -$bt-button-background: #8e9fc81c; -$bt-primary-background: #0069d9; - -$bt-footer: #FFFFFF; - -$bt-blue: #2F80ED; -$bt-green: #18DE83; -$bt-pink: #F85386; -$bt-yellow: #FFFF00; - -$bt-indicator-red: #FC7676; -$bt-indicator-squash: #DE5F18; -$bt-indicator-orange: #FFA414; -$bt-indicator-yellow: #ECD71C; -$bt-indicator-green: #18DE83; -$bt-indicator-blue: #2F80ED; - -// text colors -$bt-white-text: #FFFFFF; -$bt-light-text: #8A8A8A; -$bt-grey-text: #535353; -$bt-base-text: #383838; - -$bt-primary: #2F80ED; - - - -.bt-indicator-red { - color: $bt-indicator-red !important; -} - -.bt-indicator-orange { - color: $bt-indicator-orange !important; -} - -.bt-indicator-yellow { - color: $bt-indicator-yellow !important; -} - -.bt-indicator-green { - color: $bt-indicator-green !important; -} - -.bt-light-text { - color: $bt-light-text !important; -} diff --git a/frontend/src/assets/scss/bt/theming/_enrollment_color.scss b/frontend/src/assets/scss/bt/theming/_enrollment_color.scss deleted file mode 100644 index 541db5d52..000000000 --- a/frontend/src/assets/scss/bt/theming/_enrollment_color.scss +++ /dev/null @@ -1,11 +0,0 @@ -.enrollment-first-third { - color: $bt-indicator-green !important; -} - -.enrollment-second-third { - color: $bt-indicator-orange !important; -} - -.enrollment-last-third { - color: $bt-indicator-red !important; -} diff --git a/frontend/src/assets/scss/bt/theming/_grades_color.scss b/frontend/src/assets/scss/bt/theming/_grades_color.scss deleted file mode 100644 index 5e1b4f1a3..000000000 --- a/frontend/src/assets/scss/bt/theming/_grades_color.scss +++ /dev/null @@ -1,19 +0,0 @@ -.grade-A { - color: $bt-indicator-green; -} - -.grade-B { - color: $bt-indicator-yellow; -} - -.grade-C { - color: $bt-indicator-orange; -} - -.grade-D { - color: $bt-indicator-squash; -} - -.grade-F { - color: $bt-indicator-red; -} diff --git a/frontend/src/assets/scss/bt/theming/_navbar.scss b/frontend/src/assets/scss/bt/theming/_navbar.scss deleted file mode 100644 index 82fbcfe4e..000000000 --- a/frontend/src/assets/scss/bt/theming/_navbar.scss +++ /dev/null @@ -1,65 +0,0 @@ -nav { - border-bottom: 1.5px solid $bt-light-border-grey; - - .navbar-brand { - padding: 4px 8px; // just enough top down padding to not increase navbar height - - @include touch { - padding: 0; - } - } - - .nav-link { - color: $bt-base-text !important; - - &.is-new { - position: relative; - &::after { - content: 'New!'; - display: inline-block; - text-transform: uppercase; - font-size: 8px; - font-weight: 600; - color: $bt-white; - background: $bt-primary; - padding: 2px 4px; - border-radius: 2px; - line-height: 1; - - margin-left: 4px; - transform: translateY(-2px); - } - } - } - - // log in button - .navbar-nav .bt-btn { - @extend .bt-bold; - font-size: 1rem; - width: fit-content; - } - - // don't change color on hover when collapsed - @include desktop { - .navbar-brand, - .navbar-nav .nav-link { - transition: 0.2s; - border-radius: 6px; - - &:hover { - background-color: $bt-button-background; - color: $bt-primary !important; - - @include touch { - background: none; - color: $bt-base-text; - } - } - } - - // log in button - .navbar-nav .bt-btn { - margin-left: 0.5rem; - } - } -} diff --git a/frontend/src/assets/svg/catalog/book.svg b/frontend/src/assets/svg/catalog/book.svg deleted file mode 100644 index 8f11f63d8..000000000 --- a/frontend/src/assets/svg/catalog/book.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/catalog/bookmark-saved.svg b/frontend/src/assets/svg/catalog/bookmark-saved.svg deleted file mode 100644 index ffc4efe55..000000000 --- a/frontend/src/assets/svg/catalog/bookmark-saved.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/catalog/bookmark-unsaved.svg b/frontend/src/assets/svg/catalog/bookmark-unsaved.svg deleted file mode 100644 index f4dd999a3..000000000 --- a/frontend/src/assets/svg/catalog/bookmark-unsaved.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/catalog/chart.svg b/frontend/src/assets/svg/catalog/chart.svg deleted file mode 100644 index e71f3e71a..000000000 --- a/frontend/src/assets/svg/catalog/chart.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/catalog/filter.svg b/frontend/src/assets/svg/catalog/filter.svg deleted file mode 100644 index 09ffb8c3a..000000000 --- a/frontend/src/assets/svg/catalog/filter.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/svg/catalog/launch.svg b/frontend/src/assets/svg/catalog/launch.svg deleted file mode 100644 index 00f7a93fe..000000000 --- a/frontend/src/assets/svg/catalog/launch.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/catalog/people.svg b/frontend/src/assets/svg/catalog/people.svg deleted file mode 100644 index cd9a5b16c..000000000 --- a/frontend/src/assets/svg/catalog/people.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/common/close.svg b/frontend/src/assets/svg/common/close.svg deleted file mode 100644 index bcd4e9cf0..000000000 --- a/frontend/src/assets/svg/common/close.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/frontend/src/assets/svg/common/empty.svg b/frontend/src/assets/svg/common/empty.svg deleted file mode 100644 index c54cb9aa8..000000000 --- a/frontend/src/assets/svg/common/empty.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/svg/common/expand.svg b/frontend/src/assets/svg/common/expand.svg deleted file mode 100644 index 6b20dafc2..000000000 --- a/frontend/src/assets/svg/common/expand.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/common/search.svg b/frontend/src/assets/svg/common/search.svg deleted file mode 100644 index 6534d0cc3..000000000 --- a/frontend/src/assets/svg/common/search.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/common/trash.svg b/frontend/src/assets/svg/common/trash.svg deleted file mode 100644 index 7013f349e..000000000 --- a/frontend/src/assets/svg/common/trash.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/landing/courses.svg b/frontend/src/assets/svg/landing/courses.svg deleted file mode 100644 index 3fed0cea6..000000000 --- a/frontend/src/assets/svg/landing/courses.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/frontend/src/assets/svg/landing/grades.svg b/frontend/src/assets/svg/landing/grades.svg deleted file mode 100644 index 65c30610d..000000000 --- a/frontend/src/assets/svg/landing/grades.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/frontend/src/assets/svg/landing/history.svg b/frontend/src/assets/svg/landing/history.svg deleted file mode 100644 index 71aee83e4..000000000 --- a/frontend/src/assets/svg/landing/history.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/svg/landing/main.svg b/frontend/src/assets/svg/landing/main.svg deleted file mode 100644 index f6fdc28f5..000000000 --- a/frontend/src/assets/svg/landing/main.svg +++ /dev/null @@ -1,1995 +0,0 @@ - - - - - - - - - © Janet Xu - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/svg/landing/scheduler.svg b/frontend/src/assets/svg/landing/scheduler.svg deleted file mode 100644 index aa57a5dc5..000000000 --- a/frontend/src/assets/svg/landing/scheduler.svg +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/svg/profile/account.svg b/frontend/src/assets/svg/profile/account.svg deleted file mode 100644 index f7f661b98..000000000 --- a/frontend/src/assets/svg/profile/account.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/account_selected.svg b/frontend/src/assets/svg/profile/account_selected.svg deleted file mode 100644 index bc313f5ff..000000000 --- a/frontend/src/assets/svg/profile/account_selected.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/btn_google_signin.svg b/frontend/src/assets/svg/profile/btn_google_signin.svg deleted file mode 100644 index 740eb71a5..000000000 --- a/frontend/src/assets/svg/profile/btn_google_signin.svg +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/svg/profile/edit.svg b/frontend/src/assets/svg/profile/edit.svg deleted file mode 100644 index 6dd269b3f..000000000 --- a/frontend/src/assets/svg/profile/edit.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/google.svg b/frontend/src/assets/svg/profile/google.svg deleted file mode 100644 index 630a7b827..000000000 --- a/frontend/src/assets/svg/profile/google.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/frontend/src/assets/svg/profile/lock.svg b/frontend/src/assets/svg/profile/lock.svg deleted file mode 100644 index 90b0e50a7..000000000 --- a/frontend/src/assets/svg/profile/lock.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/assets/svg/profile/notif.svg b/frontend/src/assets/svg/profile/notif.svg deleted file mode 100644 index 2db75ba5f..000000000 --- a/frontend/src/assets/svg/profile/notif.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/notif_selected.svg b/frontend/src/assets/svg/profile/notif_selected.svg deleted file mode 100644 index 20dfbe694..000000000 --- a/frontend/src/assets/svg/profile/notif_selected.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/support.svg b/frontend/src/assets/svg/profile/support.svg deleted file mode 100644 index 214fcfb5a..000000000 --- a/frontend/src/assets/svg/profile/support.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/support_selected.svg b/frontend/src/assets/svg/profile/support_selected.svg deleted file mode 100644 index 64f4b6ca1..000000000 --- a/frontend/src/assets/svg/profile/support_selected.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/frontend/src/assets/svg/profile/trash.svg b/frontend/src/assets/svg/profile/trash.svg deleted file mode 100644 index ab681bfc1..000000000 --- a/frontend/src/assets/svg/profile/trash.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/frontend/src/assets/svg/profile/world.svg b/frontend/src/assets/svg/profile/world.svg deleted file mode 100644 index 34b86a9ea..000000000 --- a/frontend/src/assets/svg/profile/world.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/frontend/src/bt/custom.ts b/frontend/src/bt/custom.ts deleted file mode 100644 index ad41dfe30..000000000 --- a/frontend/src/bt/custom.ts +++ /dev/null @@ -1,11 +0,0 @@ -// This module contains all custom BT tags defined in [src/components/custom] - -import H3, { Props as H3Props } from 'components/Custom/H3'; -import H6, { Props as H6Props } from 'components/Custom/H6'; -import P, { Props as PProps } from 'components/Custom/P'; -import A, { Props as AProps } from 'components/Custom/A'; -import Button, { Props as ButtonProps } from 'components/Custom/Button'; - -export { H3, H6, P, A, Button }; - -export type { H3Props, H6Props, PProps, AProps, ButtonProps }; diff --git a/frontend/src/bt/utils.ts b/frontend/src/bt/utils.ts deleted file mode 100644 index f6df08f2a..000000000 --- a/frontend/src/bt/utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -export const capitalize = (str: string): string => { - if (str.length === 0) return str; - - return str.charAt(0).toUpperCase() + str.substring(1); -}; diff --git a/frontend/src/components/About/AboutCarousel.tsx b/frontend/src/components/About/AboutCarousel.tsx deleted file mode 100644 index b930d542f..000000000 --- a/frontend/src/components/About/AboutCarousel.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useEffect, useRef, useState } from 'react'; -import { NavArrowLeft, NavArrowRight } from 'iconoir-react'; - -import doe from 'assets/img/about/group/doe.jpg'; -import michaels from 'assets/img/about/group/michaels.jpg'; -import retreat from 'assets/img/about/group/retreat.jpg'; -import grace_janet from 'assets/img/about/group/grace_janet.jpg'; -import will from 'assets/img/about/group/will.jpg'; -import jemma from 'assets/img/about/group/jemma.jpg'; -import christina_janet from 'assets/img/about/group/christina_janet.jpg'; -import retreat_silly from 'assets/img/about/group/retreat_silly.png'; -import zoom from 'assets/img/about/group/zoom.png'; - -enum Sliding { - Still = 0, - Right = 1, - Left = 2 -} - -const images = [ - { img: retreat_silly, alt: 'retreat silly' }, - { img: zoom, alt: 'zoom' }, - { img: doe, alt: 'doe' }, - { img: grace_janet, alt: 'grace_janet' }, - { img: retreat, alt: 'retreat' }, - { img: christina_janet, alt: 'christina_janet' }, - { img: michaels, alt: 'michaels' }, - { img: will, alt: 'will' }, - { img: jemma, alt: 'jemma' } -]; - -const wrap = (val: number) => (val + images.length) % images.length; - -const AboutCarousel = () => { - const [shownImage, setShownImage] = useState(2); - const [queuedImage, setQueuedImage] = useState(2); - const [sliding, setSliding] = useState(Sliding.Still); - const intervalID = useRef(undefined); - - useEffect(() => { - const intervalHandler = () => { - if (sliding === Sliding.Still) { - setSliding(Sliding.Left); - setQueuedImage((prev) => wrap(prev + 1)); - } - }; - - intervalID.current = window.setInterval(intervalHandler, 5000); - - return () => { - clearInterval(intervalID.current); - }; - }, [sliding]); - - const changeImage = (slide: Sliding) => { - if (sliding === Sliding.Still) { - setSliding(slide); - const direction = slide === Sliding.Left ? 1 : -1; - setQueuedImage((prev) => wrap(prev + direction)); - } - }; - - const triggerSwap = () => { - setShownImage(queuedImage); - setSliding(Sliding.Still); - }; - - const getCarouselItemClass = (idx: number) => { - let classes = 'about-carousel-item '; - if (idx === wrap(shownImage - 2)) { - classes += 'about-carousel-active-prev '; - } else if (idx === wrap(shownImage - 1)) { - classes += 'about-carousel-active-first '; - if (sliding === Sliding.Right) { - classes += 'focus-in '; - } - } else if (idx === shownImage) { - classes += 'about-carousel-active-second '; - if (sliding !== Sliding.Still) { - classes += 'focus-out '; - } - } else if (idx === wrap(shownImage + 1)) { - classes += 'about-carousel-active-third '; - if (sliding === Sliding.Left) { - classes += 'focus-in '; - } - } else if (idx === wrap(shownImage + 2)) { - classes += 'about-carousel-active-next '; - } - return classes; - }; - - const getCarouselClass = () => { - let classes = 'about-carousel '; - if (sliding === Sliding.Left) { - classes += 'about-carousel-slide-left '; - } else if (sliding === Sliding.Right) { - classes += 'about-carousel-slide-right '; - } - return classes; - }; - - return ( -
-
{ - if (e.target === e.currentTarget) triggerSwap(); - }} - > - {images.map((imgVal, index) => ( -
- {imgVal.alt} -
- ))} -
- - -
- ); -}; - -export default AboutCarousel; diff --git a/frontend/src/components/About/CurrentContributors.tsx b/frontend/src/components/About/CurrentContributors.tsx deleted file mode 100644 index e548710b5..000000000 --- a/frontend/src/components/About/CurrentContributors.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { H3 } from 'bt/custom'; -import { current } from '../../lib/contributors'; -import { Globe } from 'iconoir-react'; - -const CurrentContributors = () => ( -
-

- {current.name} -

-
- {current.items.map(({ name, img, site, role }) => ( -
-
- {name} - {name} -
-
-

{name}

- {site ? ( - - - - ) : null} -
-
{role}
-
- ))} -
-
-); - -export default CurrentContributors; diff --git a/frontend/src/components/About/PastContributors.tsx b/frontend/src/components/About/PastContributors.tsx deleted file mode 100644 index 36bde04c6..000000000 --- a/frontend/src/components/About/PastContributors.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { H3, H6 } from 'bt/custom'; -import { past } from '../../lib/contributors'; -import { Globe } from 'iconoir-react'; - -const PastContributors = () => ( -
-

- Alumni -

- {past.map((section) => ( -
-
- {section.name} -
-
- {section.items.map((member) => ( -
-
-

{member.name}

- {member.site ? ( - - - - ) : null} -
- {member.role ?
{member.role}
: null} -
- ))} -
-
- ))} -
-); - -export default PastContributors; diff --git a/frontend/src/components/AverageGrade/AverageGrade.module.scss b/frontend/src/components/AverageGrade/AverageGrade.module.scss new file mode 100644 index 000000000..9126bc7d5 --- /dev/null +++ b/frontend/src/components/AverageGrade/AverageGrade.module.scss @@ -0,0 +1,40 @@ +.trigger { + font-size: 14px; + line-height: 1; + user-select: none; +} + +.content { + border-radius: 4px; + padding: 12px; + background-color: var(--tooltip-color); + color: var(--neutral-400); + max-width: 256px; + font-size: 14px; + animation: fadeIn 100ms ease-in; + z-index: 998; + + .arrow { + fill: var(--tooltip-color); + } + + .title { + font-weight: 500; + color: white; + margin-bottom: 8px; + line-height: 1; + } + + .description { + line-height: 1.5; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/AverageGrade/index.tsx b/frontend/src/components/AverageGrade/index.tsx new file mode 100644 index 000000000..19805ef5e --- /dev/null +++ b/frontend/src/components/AverageGrade/index.tsx @@ -0,0 +1,94 @@ +import { useMemo } from "react"; + +import * as Tooltip from "@radix-ui/react-tooltip"; + +import styles from "./AverageGrade.module.scss"; + +interface AverageGradeProps { + gradeAverage: number | null; +} + +export default function AverageGrade({ gradeAverage }: AverageGradeProps) { + const text = useMemo( + () => + !gradeAverage + ? "N/A" + : gradeAverage > 4 + ? "A+" + : gradeAverage > 3.7 + ? "A" + : gradeAverage > 3.5 + ? "A-" + : gradeAverage > 3 + ? "B+" + : gradeAverage > 2.7 + ? "B" + : gradeAverage > 2.5 + ? "B-" + : gradeAverage > 2 + ? "C+" + : gradeAverage > 1.7 + ? "C" + : gradeAverage > 1.5 + ? "C-" + : gradeAverage > 1 + ? "D+" + : gradeAverage > 0.7 + ? "D" + : gradeAverage + ? "D-" + : "F", + [gradeAverage] + ); + + const color = useMemo( + () => + !gradeAverage + ? "var(--paragraph-color)" + : gradeAverage > 3.5 + ? "var(--emerald-500)" + : gradeAverage > 2.5 + ? "var(--amber-500)" + : "var(--rose-500)", + [gradeAverage] + ); + + return ( + + +
+ {text} +
+
+ + +
+ +

Average grade

+ {gradeAverage ? ( +

+ Students have received{" "} + {["A", "F"].includes(text[0]) ? "an " : "a "} + + {text} ({gradeAverage.toLocaleString()}) + {" "} + in this course on average across all semesters this course has + been offered. +

+ ) : ( +

+ Either this course has not been previously offered, or the + average grade is not available. +

+ )} +
+
+
+
+ ); +} diff --git a/frontend/src/components/Boundary/Boundary.module.scss b/frontend/src/components/Boundary/Boundary.module.scss new file mode 100644 index 000000000..3b3e7c7b4 --- /dev/null +++ b/frontend/src/components/Boundary/Boundary.module.scss @@ -0,0 +1,5 @@ +.root { + flex-grow: 1; + display: grid; + place-items: center; +} \ No newline at end of file diff --git a/frontend/src/components/Boundary/index.tsx b/frontend/src/components/Boundary/index.tsx new file mode 100644 index 000000000..2890b1c50 --- /dev/null +++ b/frontend/src/components/Boundary/index.tsx @@ -0,0 +1,11 @@ +import { ReactNode } from "react"; + +import styles from "./Boundary.module.scss"; + +interface BoundaryProps { + children: ReactNode; +} + +export default function Boundary({ children }: BoundaryProps) { + return
{children}
; +} diff --git a/frontend/src/components/Browser/Browser.module.scss b/frontend/src/components/Browser/Browser.module.scss new file mode 100644 index 000000000..e824c7faa --- /dev/null +++ b/frontend/src/components/Browser/Browser.module.scss @@ -0,0 +1,9 @@ +.root { + position: relative; + height: 100%; + display: flex; + + &.block { + width: 100%; + } +} \ No newline at end of file diff --git a/frontend/src/components/Browser/Filters/Filters.module.scss b/frontend/src/components/Browser/Filters/Filters.module.scss new file mode 100644 index 000000000..4aaf1ce77 --- /dev/null +++ b/frontend/src/components/Browser/Filters/Filters.module.scss @@ -0,0 +1,136 @@ +.root { + width: 384px; + flex-shrink: 0; + overflow: auto; + background-color: var(--foreground-color); + + &:not(.block) { + border-right: 1px solid var(--border-color); + } + + &.block { + width: 100%; + } + + &.overlay .body { + padding-top: 12px; + } + + .body { + display: flex; + flex-direction: column; + padding: 24px; + + .button { + display: flex; + align-items: center; + gap: 12px; + font-size: 14px; + color: var(--blue-500); + line-height: 1; + cursor: pointer; + font-weight: 500; + margin-top: 12px; + transition: all 100ms ease-in-out; + + &:hover { + color: var(--blue-600); + } + } + + .label { + font-size: 14px; + color: var(--label-color); + line-height: 1; + margin-bottom: 12px; + + &:not(:first-child) { + margin-top: 24px; + } + } + + .filter { + display: flex; + align-items: center; + gap: 12px; + + & + .filter { + margin-top: 12px; + } + + &:hover .text .value { + color: var(--heading-color); + } + + &:hover .checkbox:not([data-state="checked"]), &:hover .radio:not([data-state="checked"]) { + border-color: var(--heading-color); + } + + .text { + font-size: 14px; + color: var(--label-color); + line-height: 1; + flex-grow: 1; + + .value { + font-weight: 500; + color: var(--paragraph-color); + } + } + + .radio { + width: 16px; + height: 16px; + border-radius: 50%; + border: 2px solid var(--paragraph-color); + position: relative; + + &::after { + content: ""; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: var(--blue-500); + opacity: 0; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + + &[data-state="checked"] { + border-color: var(--blue-500); + + &::after { + opacity: 1; + } + + & + .text .value { + color: var(--heading-color); + } + } + } + + .checkbox { + width: 16px; + height: 16px; + display: grid; + place-items: center; + border-radius: 4px; + + &[data-state="checked"] { + background-color: var(--blue-500); + color: white; + + & + .text .value { + color: var(--heading-color); + } + } + + &[data-state="unchecked"] { + border: 2px solid var(--paragraph-color); + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/components/Browser/Filters/index.tsx b/frontend/src/components/Browser/Filters/index.tsx new file mode 100644 index 000000000..f1e6835ca --- /dev/null +++ b/frontend/src/components/Browser/Filters/index.tsx @@ -0,0 +1,478 @@ +import { useMemo, useState } from "react"; + +import * as Checkbox from "@radix-ui/react-checkbox"; +import * as RadioGroup from "@radix-ui/react-radio-group"; +import classNames from "classnames"; +import { Check, NavArrowDown, NavArrowUp } from "iconoir-react"; +import { useSearchParams } from "react-router-dom"; + +import { Component, ICourse, Semester, components } from "@/lib/api"; + +import Header from "../Header"; +import { + Day, + Level, + SortBy, + Unit, + getFilteredCourses, + getLevel, +} from "../browser"; +import styles from "./Filters.module.scss"; + +interface FiltersProps { + overlay: boolean; + block: boolean; + includedCourses: ICourse[]; + excludedCourses: ICourse[]; + currentCourses: ICourse[]; + currentComponents: Component[]; + currentUnits: Unit[]; + currentLevels: Level[]; + onOpenChange: (open: boolean) => void; + open: boolean; + currentSemester: Semester; + currentYear: number; + currentQuery: string; + currentDays: Day[]; + currentSortBy: SortBy; + setCurrentSortBy: (sortBy: SortBy) => void; + setCurrentQuery: (query: string) => void; + setCurrentComponents: (components: Component[]) => void; + setCurrentUnits: (units: Unit[]) => void; + setCurrentLevels: (levels: Level[]) => void; + setCurrentDays: (days: Day[]) => void; + persistent?: boolean; +} + +export default function Filters({ + overlay, + block, + includedCourses, + excludedCourses, + currentCourses, + currentComponents, + currentLevels, + currentUnits, + currentDays, + onOpenChange, + open, + currentSemester, + currentYear, + currentQuery, + currentSortBy, + setCurrentSortBy, + setCurrentQuery, + setCurrentComponents, + setCurrentUnits, + setCurrentLevels, + setCurrentDays, + persistent, +}: FiltersProps) { + const [expanded, setExpanded] = useState(false); + const [searchParams, setSearchParams] = useSearchParams(); + + const filteredLevels = useMemo(() => { + const courses = + currentLevels.length === 0 + ? includedCourses + : getFilteredCourses( + excludedCourses, + currentComponents, + currentUnits, + [], + currentDays + ).includedCourses; + + return courses.reduce( + (acc, course) => { + const level = getLevel(course.academicCareer, course.number); + + acc[level] += 1; + + return acc; + }, + { + "Lower Division": 0, + "Upper Division": 0, + Graduate: 0, + Extension: 0, + } as Record + ); + }, [ + excludedCourses, + includedCourses, + currentUnits, + currentComponents, + currentLevels, + currentDays, + ]); + + const filteredComponents = useMemo(() => { + const filteredComponents = Object.keys(components).reduce( + (acc, component) => { + acc[component] = 0; + return acc; + }, + {} as Record + ); + + const courses = + currentComponents.length === 0 + ? includedCourses + : getFilteredCourses( + excludedCourses, + [], + currentUnits, + currentLevels, + currentDays + ).includedCourses; + + for (const course of courses) { + const { component } = course.classes[0].primarySection; + + filteredComponents[component] += 1; + } + + return filteredComponents; + }, [ + excludedCourses, + includedCourses, + currentComponents, + currentUnits, + currentLevels, + currentDays, + ]); + + const filteredDays = useMemo(() => { + const filteredDays = Object.values(Day).reduce( + (acc, day) => { + acc[day] = 0; + return acc; + }, + {} as Record + ); + + const courses = + currentDays.length === 0 + ? includedCourses + : getFilteredCourses( + excludedCourses, + currentComponents, + currentUnits, + currentLevels, + [] + ).includedCourses; + + for (const course of courses) { + const days = course.classes.reduce( + (acc, { primarySection: { meetings } }) => { + const days = meetings?.[0]?.days; + + if (!days) return acc; + + return [ + acc[0] || days[0], + acc[1] || days[1], + acc[2] || days[2], + acc[3] || days[3], + acc[4] || days[4], + acc[5] || days[5], + acc[6] || days[6], + ]; + }, + [] as boolean[] + ); + + for (const index in days) { + if (!days[index]) continue; + + filteredDays[index as Day] += 1; + } + } + + return filteredDays; + }, [ + excludedCourses, + includedCourses, + currentComponents, + currentUnits, + currentLevels, + currentDays, + ]); + + const filteredUnits = useMemo(() => { + const filteredUnits = Object.values(Unit).reduce( + (acc, units) => { + acc[units] = 0; + return acc; + }, + {} as Record + ); + + const courses = + currentUnits.length === 0 + ? includedCourses + : getFilteredCourses( + excludedCourses, + currentComponents, + [], + currentLevels, + currentDays + ).includedCourses; + + for (const course of courses) { + const { unitsMin, unitsMax } = course.classes.reduce( + (acc, { unitsMax, unitsMin }) => ({ + unitsMin: Math.min(5, Math.floor(Math.min(acc.unitsMin, unitsMin))), + unitsMax: Math.min(Math.floor(Math.max(acc.unitsMax, unitsMax))), + }), + { unitsMax: 0, unitsMin: Infinity } + ); + + [...Array(unitsMax - unitsMin || 1)].forEach((_, index) => { + const units = unitsMin + index; + + filteredUnits[ + units === 5 ? Unit.FivePlus : (units.toString() as Unit) + ] += 1; + }); + } + + return filteredUnits; + }, [ + excludedCourses, + includedCourses, + currentUnits, + currentComponents, + currentLevels, + currentDays, + ]); + + const update = ( + name: string, + state: T[], + setState: (state: T[]) => void, + value: T, + checked: boolean + ) => { + if (persistent) { + if (checked) { + searchParams.set(name, [...state, value].join(",")); + } else { + const filtered = state.filter((parameter) => parameter !== value); + + if (filtered.length > 0) { + searchParams.set(name, filtered.join(",")); + } else { + searchParams.delete(name); + } + } + + setSearchParams(searchParams); + + return; + } + + setState( + checked + ? [...state, value] + : state.filter((parameter) => parameter !== value) + ); + }; + + const handleValueChange = (value: SortBy) => { + if (persistent) { + if (value === SortBy.Relevance) searchParams.delete("sortBy"); + else searchParams.set("sortBy", value); + setSearchParams(searchParams); + + return; + } + + console.log(value); + setCurrentSortBy(value); + }; + + return ( +
+ {open && overlay && ( +
+ )} +
+

Sort by

+ + {Object.values(SortBy).map((sortBy) => ( +
+ + + + +
+ ))} +
+

Level

+ {Object.values(Level).map((level) => { + const active = currentLevels.includes(level as Level); + + return ( +
+ + update( + "levels", + currentLevels, + setCurrentLevels, + level, + checked as boolean + ) + } + > + + + + + +
+ ); + })} +

Units

+ {Object.values(Unit).map((unit) => { + const active = currentUnits.includes(unit); + + return ( +
+ + update( + "units", + currentUnits, + setCurrentUnits, + unit, + checked as boolean + ) + } + > + + + + + +
+ ); + })} +

Kind

+ {Object.keys(filteredComponents) + .slice(0, expanded ? undefined : 5) + .map((component) => { + const active = currentComponents.includes(component as Component); + + return ( +
+ + update( + "components", + currentComponents, + setCurrentComponents, + component as Component, + checked as boolean + ) + } + > + + + + + +
+ ); + })} +
setExpanded(!expanded)}> + {expanded ? : } + {expanded ? "View less" : "View more"} +
+

Day

+ {Object.entries(Day).map(([key, day]) => { + const active = currentDays.includes(day); + + return ( +
+ + update( + "days", + currentDays, + setCurrentDays, + day, + checked as boolean + ) + } + > + + + + + +
+ ); + })} +
+
+ ); +} diff --git a/frontend/src/components/Browser/Header/Header.module.scss b/frontend/src/components/Browser/Header/Header.module.scss new file mode 100644 index 000000000..4a5c0dd48 --- /dev/null +++ b/frontend/src/components/Browser/Header/Header.module.scss @@ -0,0 +1,42 @@ +.root { + padding: 12px; + position: sticky; + top: 0; + z-index: 1; + background: linear-gradient(to bottom, var(--background-color), transparent); + + &.overlay .group { + padding-right: 8px; + } + + .group { + border: 1px solid var(--blue-500); + border-radius: 4px; + height: 48px; + background-color: var(--foreground-color); + display: flex; + align-items: center; + gap: 16px; + padding: 0 16px; + + &:has(.input:focus) { + outline: 4px solid color-mix(in srgb, var(--blue-500) 25%, transparent); + } + + .label { + font-size: 12px; + color: var(--label-color); + line-height: 1; + } + + .input { + color: var(--heading-color); + font-size: 14px; + height: 100%; + + &::placeholder { + color: var(--paragraph-color); + } + } + } +} diff --git a/frontend/src/components/Browser/Header/index.tsx b/frontend/src/components/Browser/Header/index.tsx new file mode 100644 index 000000000..2fe9e0396 --- /dev/null +++ b/frontend/src/components/Browser/Header/index.tsx @@ -0,0 +1,95 @@ +import { forwardRef } from "react"; + +import classNames from "classnames"; +import { Filter, FilterSolid } from "iconoir-react"; +import { useSearchParams } from "react-router-dom"; + +import IconButton from "@/components/IconButton"; +import { ICourse, Semester } from "@/lib/api"; + +import styles from "./Header.module.scss"; + +interface HeaderProps { + currentQuery: string; + currentCourses: ICourse[]; + open: boolean; + overlay: boolean; + onOpenChange: (open: boolean) => void; + currentSemester: Semester; + currentYear: number; + className?: string; + autoFocus?: boolean; + setCurrentQuery: (query: string) => void; + persistent?: boolean; +} + +const Header = forwardRef( + ( + { + currentQuery, + currentCourses, + open, + overlay, + onOpenChange, + currentSemester, + currentYear, + className, + autoFocus, + setCurrentQuery, + persistent, + }, + ref + ) => { + const [searchParams, setSearchParams] = useSearchParams(); + + const handleQueryChange = (value: string) => { + if (persistent) { + if (value) searchParams.set("query", value); + else searchParams.delete("query"); + setSearchParams(searchParams); + + return; + } + + setCurrentQuery(value); + }; + + return ( +
+
+ handleQueryChange(event.target.value)} + placeholder={`Search ${currentSemester} ${currentYear} courses...`} + autoFocus={autoFocus} + // TODO: onFocus could not be passed down from the parent + onFocus={() => overlay && open && onOpenChange(false)} + /> +
+ {currentCourses.length.toLocaleString()} +
+ {overlay && ( + onOpenChange(!open)}> + {open ? : } + + )} +
+
+ ); + } +); + +Header.displayName = "Header"; + +export default Header; diff --git a/frontend/src/components/Browser/List/Course/Course.module.scss b/frontend/src/components/Browser/List/Course/Course.module.scss new file mode 100644 index 000000000..497080a1b --- /dev/null +++ b/frontend/src/components/Browser/List/Course/Course.module.scss @@ -0,0 +1,68 @@ +.root { + border: 1px solid var(--border-color); + border-radius: 8px; + flex-shrink: 0; + background-color: var(--foreground-color); + position: relative; + padding: 0 16px; + // box-shadow: 0 1px 2px rgb(0 0 0 / 2.5%); + + .class { + padding: 16px 0; + display: flex; + gap: 16px; + align-items: flex-start; + cursor: pointer; + + &:hover .column .icon { + color: var(--heading-color); + } + + .column { + display: flex; + flex-direction: column; + gap: 8px; + flex-shrink: 0; + + .icon { + color: var(--paragraph-color); + transition: all 100ms ease-in-out; + } + } + + &:not(:last-child) { + border-bottom: 1px solid var(--border-color); + } + } + + .text { + flex-grow: 1; + font-size: 14px; + + .heading, .title { + color: var(--heading-color); + margin-bottom: 8px; + line-height: 1; + } + + .heading { + font-weight: 700; + } + + .title { + font-weight: 500; + } + + .description { + color: var(--paragraph-color); + line-height: 1.5; + } + + .row { + display: flex; + gap: 12px; + margin-top: 12px; + align-items: center; + } + } +} \ No newline at end of file diff --git a/frontend/src/components/Browser/List/Course/index.tsx b/frontend/src/components/Browser/List/Course/index.tsx new file mode 100644 index 000000000..6f34e7d48 --- /dev/null +++ b/frontend/src/components/Browser/List/Course/index.tsx @@ -0,0 +1,178 @@ +import { forwardRef, useMemo } from "react"; + +import { + ArrowRight, + ArrowSeparateVertical, + ArrowUnionVertical, +} from "iconoir-react"; + +import AverageGrade from "@/components/AverageGrade"; +import Capacity from "@/components/Capacity"; +import Units from "@/components/Units"; +import { ICourse, components } from "@/lib/api"; + +import styles from "./Course.module.scss"; + +interface CourseProps { + expanded: boolean; + setExpanded: (expanded: boolean) => void; + onClassSelect: (number: string) => void; + index: number; +} + +const Course = forwardRef( + ( + { + title: courseTitle, + subject, + classes, + number: courseNumber, + gradeAverage, + expanded, + setExpanded, + onClassSelect, + index, + }, + ref + ) => { + const isolated = useMemo(() => classes.length === 1, [classes]); + + const { + courseCount, + courseCapacity, + courseWaitlistCount, + courseWaitlistCapacity, + courseMinimum, + courseMaximum, + } = useMemo( + () => + classes.reduce( + ( + { + courseCount, + courseCapacity, + courseWaitlistCount, + courseWaitlistCapacity, + courseMinimum, + courseMaximum, + }, + { + primarySection: { + waitlistCount, + waitlistMax, + enrollCount, + enrollMax, + }, + unitsMax, + unitsMin, + } + ) => ({ + courseWaitlistCount: courseWaitlistCount + waitlistCount, + courseWaitlistCapacity: courseWaitlistCapacity + waitlistMax, + courseCount: courseCount + enrollCount, + courseCapacity: courseCapacity + enrollMax, + courseMinimum: Math.min(courseMinimum, unitsMin), + courseMaximum: Math.max(courseMaximum, unitsMax), + }), + { + courseCount: 0, + courseCapacity: 0, + courseWaitlistCount: 0, + courseWaitlistCapacity: 0, + courseMinimum: Infinity, + courseMaximum: 0, + } + ), + [classes] + ); + + const handleClick = (number?: string) => { + if (number) onClassSelect(number); + else if (isolated) onClassSelect(classes[0].number); + else setExpanded(!expanded); + }; + + return ( +
+
handleClick()}> +
+

+ {subject} {courseNumber} +

+

+ {isolated && classes[0].title ? classes[0].title : courseTitle} +

+
+ + + +
+
+
+
+ {isolated ? ( + + ) : expanded ? ( + + ) : ( + + )} +
+
+
+ {expanded && + classes.map( + ({ + unitsMax, + unitsMin, + title: classTitle, + number: classNumber, + primarySection: { + enrollCount, + enrollMax, + waitlistCount, + waitlistMax, + component, + }, + }) => ( +
handleClick(classNumber)} + > +
+

+ {components[component]} {classNumber} +

+

+ {classTitle || courseTitle} +

+
+ + +
+
+
+
+ +
+
+
+ ) + )} +
+ ); + } +); + +export default Course; diff --git a/frontend/src/components/Browser/List/List.module.scss b/frontend/src/components/Browser/List/List.module.scss new file mode 100644 index 000000000..4d4e8dc1e --- /dev/null +++ b/frontend/src/components/Browser/List/List.module.scss @@ -0,0 +1,88 @@ +.root { + width: 384px; + flex-shrink: 0; + overflow: auto; + background-color: var(--background-color); + + &:not(.block) { + border-right: 1px solid var(--border-color); + } + + &.block { + width: 100%; + } + + .view { + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + min-height: 100%; + + .body { + padding: 0 12px; + position: absolute; + top: 0; + left: 0; + width: 100%; + display: flex; + flex-direction: column; + gap: 12px; + } + + .placeholder { + color: var(--paragraph-color); + flex-grow: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 0 24px 12px; + gap: 16px; + font-size: 16px; + + .heading { + font-weight: 500; + color: var(--heading-color); + margin-bottom: 8px; + } + + .description { + line-height: 1.5; + } + } + + .footer { + padding: 12px; + position: sticky; + bottom: 0; + background: linear-gradient(to top, var(--background-color), transparent); + + .button { + width: 100%; + height: 48px; + display: flex; + align-items: center; + border-radius: 4px; + background-color: var(--blue-500); + color: white; + padding: 0 16px; + gap: 16px; + cursor: pointer; + transition: all 100ms ease-in-out; + + .text { + flex-grow: 1; + font-size: 14px; + font-weight: 500; + line-height: 1; + } + + &:hover { + background-color: var(--blue-600); + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/components/Browser/List/index.tsx b/frontend/src/components/Browser/List/index.tsx new file mode 100644 index 000000000..9ea1c6b80 --- /dev/null +++ b/frontend/src/components/Browser/List/index.tsx @@ -0,0 +1,147 @@ +import { useEffect, useRef } from "react"; + +import { useVirtualizer } from "@tanstack/react-virtual"; +import classNames from "classnames"; +import { ArrowRight, FrameAltEmpty, Sparks } from "iconoir-react"; +import { Link, useSearchParams } from "react-router-dom"; + +import LoadingIndicator from "@/components/LoadingIndicator"; +import { ICourse, Semester } from "@/lib/api"; + +import Header from "../Header"; +import Course from "./Course"; +import styles from "./List.module.scss"; + +interface ListProps { + currentCourses: ICourse[]; + onClassSelect: (course: ICourse, number: string) => void; + onOpenChange: (open: boolean) => void; + open: boolean; + overlay: boolean; + block: boolean; + currentSemester: Semester; + currentYear: number; + currentQuery: string; + expandedCourses: boolean[]; + setExpanded: (index: number, expanded: boolean) => void; + setCurrentQuery: (query: string) => void; + persistent?: boolean; + loading: boolean; +} + +export default function List({ + currentCourses: currentCourses, + onClassSelect, + currentSemester, + currentYear, + open, + overlay, + block, + onOpenChange, + currentQuery, + expandedCourses, + setExpanded, + setCurrentQuery, + persistent, + loading, +}: ListProps) { + const rootRef = useRef(null); + const [searchParams] = useSearchParams(); + + const virtualizer = useVirtualizer({ + count: currentCourses.length, + getScrollElement: () => rootRef.current, + estimateSize: () => 136, + paddingStart: 72, + paddingEnd: 72, + gap: 12, + }); + + useEffect(() => { + rootRef.current?.scrollTo({ top: 0 }); + }, [searchParams]); + + const items = virtualizer.getVirtualItems(); + + const totalSize = virtualizer.getTotalSize(); + + return ( +
+
+
+ {loading ? ( +
+ +
+

Fetching courses...

+

+ Search for, filter, and sort courses to narrow down your + results. +

+
+
+ ) : items.length === 0 ? ( +
+ +
+

No courses found

+

+ Find courses by broadening your search or entering a different + query. +

+
+
+ ) : ( +
+ {items.map(({ key, index }) => { + const course = currentCourses[index]; + + return ( + setExpanded(index, expanded)} + onClassSelect={(number) => onClassSelect(course, number)} + /> + ); + })} +
+ )} +
+ + +

Try exploring courses

+ + +
+
+
+ ); +} diff --git a/frontend/src/components/Browser/browser.ts b/frontend/src/components/Browser/browser.ts new file mode 100644 index 000000000..799d50d2d --- /dev/null +++ b/frontend/src/components/Browser/browser.ts @@ -0,0 +1,128 @@ +import { AcademicCareer, Component, ICourse, academicCareers } from "@/lib/api"; + +export enum SortBy { + Relevance = "Relevance", + Units = "Units", + AverageGrade = "Average grade", + OpenSeats = "Open seats", + PercentOpenSeats = "Percent open seats", +} + +export enum Level { + LowerDivision = "Lower Division", + UpperDivision = "Upper Division", + Graduate = "Graduate", + Extension = "Extension", +} + +export enum Unit { + FivePlus = "5+", + Four = "4", + Three = "3", + Two = "2", + One = "1", + Zero = "0", +} + +export enum Day { + Sunday = "0", + Monday = "1", + Tuesday = "2", + Wednesday = "3", + Thursday = "4", + Friday = "5", + Saturday = "6", +} + +export const getLevel = (academicCareer: AcademicCareer, number: string) => { + return academicCareer === AcademicCareer.Undergraduate + ? number.match(/(\d)\d\d/) + ? Level.UpperDivision + : Level.LowerDivision + : (academicCareers[academicCareer] as Level); +}; + +export const getFilteredCourses = ( + courses: ICourse[], + currentComponents: Component[], + currentUnits: Unit[], + currentLevels: Level[], + currentDays: Day[] +) => { + return courses.reduce( + (acc, course) => { + // Filter by component + if (currentComponents.length > 0) { + const { component } = course.classes[0].primarySection; + + if (!currentComponents.includes(component)) { + acc.excludedCourses.push(course); + + return acc; + } + } + + // Filter by level + if (currentLevels.length > 0) { + const level = getLevel(course.academicCareer, course.number); + + if (!currentLevels.includes(level)) { + acc.excludedCourses.push(course); + + return acc; + } + } + + // Filter by units + if (currentUnits.length > 0) { + const { unitsMin, unitsMax } = course.classes.reduce( + (acc, { unitsMax, unitsMin }) => ({ + unitsMin: Math.min(5, Math.floor(Math.min(acc.unitsMin, unitsMin))), + unitsMax: Math.min(Math.floor(Math.max(acc.unitsMax, unitsMax))), + }), + { unitsMax: 0, unitsMin: Infinity } + ); + + const includesUnits = [...Array(unitsMax - unitsMin || 1)].some( + (_, index) => { + const units = unitsMin + index; + + return currentUnits.includes( + unitsMin + index === 5 ? Unit.FivePlus : (`${units}` as Unit) + ); + } + ); + + if (!includesUnits) { + acc.excludedCourses.push(course); + + return acc; + } + } + + // Filter by days + if (currentDays.length > 0) { + const includesDays = currentDays.some((day) => + course.classes.some( + ({ primarySection: { meetings } }) => + meetings?.[0]?.days[parseInt(day)] + ) + ); + + if (!includesDays) { + acc.excludedCourses.push(course); + + return acc; + } + } + + acc.includedCourses.push(course); + + return acc; + }, + { includedCourses: [], excludedCourses: [] } as { + includedCourses: ICourse[]; + excludedCourses: ICourse[]; + } + ); +}; diff --git a/frontend/src/components/Browser/index.tsx b/frontend/src/components/Browser/index.tsx new file mode 100644 index 000000000..13908b5c1 --- /dev/null +++ b/frontend/src/components/Browser/index.tsx @@ -0,0 +1,366 @@ +import { useMemo, useState } from "react"; + +import { useQuery } from "@apollo/client"; +import classNames from "classnames"; +import Fuse from "fuse.js"; +import { useSearchParams } from "react-router-dom"; + +import useWindowDimensions from "@/hooks/useWindowDimensions"; +import { + Component, + GET_CLASSES, + GetClassesResponse, + ICourse, + Semester, +} from "@/lib/api"; +import { subjects } from "@/lib/course"; + +import styles from "./Browser.module.scss"; +import Filters from "./Filters"; +import List from "./List"; +import { Day, Level, SortBy, Unit, getFilteredCourses } from "./browser"; + +const initializeFuse = (courses: ICourse[]) => { + const list = courses.map((course) => { + const { title, subject, number, classes } = course; + + // For prefixed courses, prefer the number and add an abbreviation with the prefix + const containsPrefix = /^[a-zA-Z].*/.test(number); + const alternateNumber = number.slice(1); + + const term = subject.toLowerCase(); + + const alternateNames = subjects[term]?.abbreviations.reduce( + (acc, abbreviation) => { + // Add alternate names for abbreviations + const abbreviations = [ + `${abbreviation}${number}`, + `${abbreviation} ${number}`, + ]; + + if (containsPrefix) { + abbreviations.push( + `${abbreviation}${alternateNumber}`, + `${abbreviation} ${alternateNumber}` + ); + } + + return [...acc, ...abbreviations]; + }, + // Add alternate names + containsPrefix + ? [ + `${subject}${number}`, + `${subject} ${alternateNumber}`, + `${subject}${alternateNumber}`, + ] + : [`${subject}${number}`] + ); + + return { + title, + subject, + number, + name: `${subject} ${number}`, + alternateNames, + classes, + }; + }); + + const options = { + includeScore: true, + ignoreLocation: true, + threshold: 0.25, + keys: [ + { name: "number", weight: 1.2 }, + "name", + "title", + "classes.title", + { + name: "alternateNames", + weight: 2, + }, + { name: "subject", weight: 1.5 }, + ], + // TODO: Fuse types are wrong for sortFn + // eslint-disable-next-line @typescript-eslint/no-explicit-any + sortFn: (a: any, b: any) => { + // First, sort by score + if (a.score - b.score) return a.score - b.score; + + // Otherwise, sort by number + return a.item[0].v.toLowerCase().localeCompare(b.item[0].v.toLowerCase()); + }, + }; + + return new Fuse(list, options); +}; + +interface BrowserProps { + onClassSelect: (course: ICourse, number: string) => void; + responsive?: boolean; + semester: Semester; + year: number; + persistent?: boolean; +} + +export default function Browser({ + onClassSelect, + responsive = true, + semester: currentSemester, + year: currentYear, + persistent, +}: BrowserProps) { + const [open, setOpen] = useState(false); + const [searchParams] = useSearchParams(); + const { width } = useWindowDimensions(); + + const [expandedCourses, setExpandedCourses] = useState([]); + + const [localQuery, setLocalQuery] = useState(""); + const [localComponents, setLocalComponents] = useState([]); + const [localUnits, setLocalUnits] = useState([]); + const [localLevels, setLocalLevels] = useState([]); + const [localDays, setLocalDays] = useState([]); + const [localSortBy, setLocalSortBy] = useState(SortBy.Relevance); + + const block = useMemo(() => width <= 992, [width]); + + const overlay = useMemo( + () => (responsive && width <= 1400) || block, + [width, responsive, block] + ); + + const { data, loading } = useQuery(GET_CLASSES, { + variables: { + term: { + semester: currentSemester, + year: currentYear, + }, + }, + }); + + const courses = useMemo(() => data?.catalog ?? [], [data?.catalog]); + + const currentQuery = useMemo( + () => (persistent ? searchParams.get("query") ?? "" : localQuery), + [searchParams, localQuery, persistent] + ); + + const currentComponents = useMemo( + () => + persistent + ? ((searchParams + .get("components") + ?.split(",") + .filter((component) => + Object.values(Component).includes(component as Component) + ) ?? []) as Component[]) + : localComponents, + [searchParams, localComponents, persistent] + ); + + const currentUnits = useMemo( + () => + persistent + ? ((searchParams + .get("units") + ?.split(",") + .filter((unit) => Object.values(Unit).includes(unit as Unit)) ?? + []) as Unit[]) + : localUnits, + [searchParams, localUnits, persistent] + ); + + const currentLevels = useMemo( + () => + persistent + ? ((searchParams + .get("levels") + ?.split(",") + .filter((level) => Object.values(Level).includes(level as Level)) ?? + []) as Level[]) + : localLevels, + [searchParams, localLevels, persistent] + ); + + const currentDays = useMemo( + () => + persistent + ? ((searchParams + .get("days") + ?.split(",") + .filter((day) => Object.values(Day).includes(day as Day)) ?? + []) as Day[]) + : localDays, + [searchParams, localDays, persistent] + ); + + const currentSortBy = useMemo(() => { + if (persistent) { + const parameter = searchParams.get("sortBy") as SortBy; + + return Object.values(SortBy).includes(parameter) + ? parameter + : SortBy.Relevance; + } + + return localSortBy; + }, [searchParams, localSortBy, persistent]); + + const { includedCourses, excludedCourses } = useMemo( + () => + getFilteredCourses( + courses, + currentComponents, + currentUnits, + currentLevels, + currentDays + ), + [courses, currentComponents, currentUnits, currentLevels, currentDays] + ); + + const fuse = useMemo( + () => initializeFuse(includedCourses), + [includedCourses] + ); + + const setExpanded = (index: number, expanded: boolean) => { + setExpandedCourses((expandedCourses) => { + const _expandedCourses = structuredClone(expandedCourses); + _expandedCourses[index] = expanded; + return _expandedCourses; + }); + }; + + const currentCourses = useMemo(() => { + let filteredCourses = currentQuery + ? fuse + .search(currentQuery) + .map(({ refIndex }) => includedCourses[refIndex]) + : includedCourses; + + if (currentSortBy) { + // Clone the courses to avoid sorting in-place + filteredCourses = structuredClone(filteredCourses).sort((a, b) => { + if (currentSortBy === SortBy.AverageGrade) { + return b.gradeAverage === a.gradeAverage + ? 0 + : b.gradeAverage === null + ? -1 + : a.gradeAverage === null + ? 1 + : b.gradeAverage - a.gradeAverage; + } + + if (currentSortBy === SortBy.Units) { + const getUnits = (course: ICourse) => + course.classes.reduce( + (acc, { unitsMax }) => Math.max(acc, unitsMax), + 0 + ); + + return getUnits(b) - getUnits(a); + } + + if (currentSortBy === SortBy.OpenSeats) { + const getOpenSeats = (course: ICourse) => + course.classes.reduce( + (acc, { primarySection: { enrollCount, enrollMax } }) => + acc + (enrollMax - enrollCount), + 0 + ); + + return getOpenSeats(b) - getOpenSeats(a); + } + + if (currentSortBy === SortBy.PercentOpenSeats) { + const getPercentOpenSeats = (course: ICourse) => { + const { enrollCount, enrollMax } = course.classes.reduce( + (acc, { primarySection: { enrollCount, enrollMax } }) => ({ + enrollCount: acc.enrollCount + enrollCount, + enrollMax: acc.enrollMax + enrollMax, + }), + { enrollCount: 0, enrollMax: 0 } + ); + + return enrollMax === 0 ? 0 : (enrollMax - enrollCount) / enrollMax; + }; + + return getPercentOpenSeats(b) - getPercentOpenSeats(a); + } + + // Courses are by default sorted by relevance and number + return 0; + }); + } + + return filteredCourses; + }, [currentQuery, fuse, includedCourses, currentSortBy]); + + // Update local and persistent filters + const updateState = (setState: (state: T) => void, state: T) => { + setState(state); + setExpandedCourses([]); + }; + + return ( +
+ {(open || !overlay) && ( + updateState(setLocalQuery, query)} + setCurrentUnits={(units) => updateState(setLocalUnits, units)} + setCurrentLevels={(levels) => updateState(setLocalLevels, levels)} + setCurrentDays={(days) => updateState(setLocalDays, days)} + setCurrentSortBy={(sortBy) => updateState(setLocalSortBy, sortBy)} + setCurrentComponents={(components) => + updateState(setLocalComponents, components) + } + /> + )} + {(!open || !overlay) && ( + updateState(setLocalQuery, query)} + /> + )} +
+ ); +} diff --git a/frontend/src/components/Button/Button.module.scss b/frontend/src/components/Button/Button.module.scss new file mode 100644 index 000000000..11fbaf099 --- /dev/null +++ b/frontend/src/components/Button/Button.module.scss @@ -0,0 +1,40 @@ +.root { + height: 32px; + border-radius: 4px; + padding: 0 12px; + display: flex; + flex-shrink: 0; + align-items: center; + font-size: 14px; + font-weight: 500; + line-height: 1; + cursor: pointer; + transition: all 100ms ease-in-out; + gap: 8px; + background-color: var(--blue-500); + color: white; + user-select: none; + + &:hover { + background-color: var(--blue-600); + } + + &:active { + background-color: var(--blue-700); + } + + &.secondary { + border: 1px solid var(--border-color); + color: var(--paragraph-color); + background-color: var(--button-color); + + &:hover { + background-color: var(--button-hover-color); + color: var(--heading-color); + } + + &:active { + background-color: var(--button-active-color); + } + } +} \ No newline at end of file diff --git a/frontend/src/components/Button/index.tsx b/frontend/src/components/Button/index.tsx new file mode 100644 index 000000000..85dbf2b84 --- /dev/null +++ b/frontend/src/components/Button/index.tsx @@ -0,0 +1,38 @@ +import { ComponentPropsWithoutRef, ReactNode, forwardRef } from "react"; + +import classNames from "classnames"; + +import styles from "./Button.module.scss"; + +interface ButtonProps { + children: ReactNode; + className?: string; + secondary?: boolean; + active?: boolean; +} + +const Button = forwardRef< + HTMLButtonElement, + ButtonProps & Omit, keyof ButtonProps> +>(({ active, children, className, secondary, ...props }, forwardedRef) => { + return ( + + ); +}); + +Button.displayName = "Button"; + +export default Button; diff --git a/frontend/src/components/CCN/CCN.module.scss b/frontend/src/components/CCN/CCN.module.scss new file mode 100644 index 000000000..088658fa1 --- /dev/null +++ b/frontend/src/components/CCN/CCN.module.scss @@ -0,0 +1,45 @@ +.trigger { + display: flex; + gap: 4px; + align-items: center; + color: var(--label-color); + font-size: 14px; + line-height: 1; + cursor: pointer; + max-width: fit-content; +} + +.content { + border-radius: 4px; + padding: 12px; + background-color: var(--tooltip-color); + color: var(--neutral-400); + max-width: 256px; + font-size: 14px; + animation: fadeIn 100ms ease-in; + z-index: 998; + + .arrow { + fill: var(--tooltip-color); + } + + .title { + font-weight: 500; + color: white; + margin-bottom: 8px; + line-height: 1; + } + + .description { + line-height: 1.5; + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/CCN/index.tsx b/frontend/src/components/CCN/index.tsx new file mode 100644 index 000000000..f2d3fd0ea --- /dev/null +++ b/frontend/src/components/CCN/index.tsx @@ -0,0 +1,82 @@ +import { MouseEvent, useRef, useState } from "react"; + +import * as Tooltip from "@radix-ui/react-tooltip"; +import { ClipboardCheck, Hashtag, PasteClipboard } from "iconoir-react"; + +import styles from "./CCN.module.scss"; + +interface CCNProps { + ccn: string; + tooltip?: false; +} + +export default function CCN({ ccn, tooltip }: CCNProps) { + const textRef = useRef(null); + + const [over, setOver] = useState(false); + const [copied, setCopied] = useState(false); + + const [timeoutId, setTimeoutId] = useState | null>(null); + + const handleClick = (event: MouseEvent) => { + event.stopPropagation(); + + if (!textRef.current) return; + + if (timeoutId) clearTimeout(timeoutId); + + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(textRef.current); + selection?.removeAllRanges(); + selection?.addRange(range); + + navigator.clipboard.writeText(ccn); + + setCopied(true); + + const _timeoutId = setTimeout(() => setCopied(false), 1000); + setTimeoutId(_timeoutId); + }; + + return ( + + +
setOver(true)} + onMouseLeave={() => setOver(false)} + > + {copied ? ( + + ) : over ? ( + + ) : ( + + )} + {ccn} +
+
+ + +
+ +

Class number

+

+ Use this number to search for and enroll in this class within the + CalCentral Enrollment Center. +

+
+
+
+
+ ); +} diff --git a/frontend/src/components/Capacity/Capacity.module.scss b/frontend/src/components/Capacity/Capacity.module.scss new file mode 100644 index 000000000..5b016ab28 --- /dev/null +++ b/frontend/src/components/Capacity/Capacity.module.scss @@ -0,0 +1,61 @@ +.trigger { + height: 32px; + border-radius: 16px; + background-color: var(--button-hover-color); + color: var(--paragraph-color); + display: flex; + align-items: center; + gap: 8px; + padding: 0 12px; + user-select: none; + + .text { + font-size: 14px; + line-height: 1; + + .value { + color: var(--paragraph-color); + } + } +} + +.content { + border-radius: 4px; + padding: 12px; + background-color: var(--tooltip-color); + width: 256px; + animation: fadeIn 100ms ease-in; + z-index: 998; + + .arrow { + fill: var(--tooltip-color); + } + + .divider { + height: 1px; + background-color: var(--neutral-700); + margin: 12px 0; + } + + .row { + display: flex; + justify-content: space-between; + font-size: 14px; + line-height: 1; + color: var(--neutral-400); + + .key { + font-weight: 500; + color: white; + } + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/Capacity/index.tsx b/frontend/src/components/Capacity/index.tsx new file mode 100644 index 000000000..29adf760c --- /dev/null +++ b/frontend/src/components/Capacity/index.tsx @@ -0,0 +1,108 @@ +import { useMemo } from "react"; + +import * as Tooltip from "@radix-ui/react-tooltip"; +import { User } from "iconoir-react"; + +import styles from "./Capacity.module.scss"; + +const getColor = (count: number, capacity: number) => { + const percentage = count / capacity; + + return percentage >= 0.75 + ? "var(--rose-500)" + : percentage > 0.5 + ? "var(--amber-500)" + : "var(--emerald-500)"; +}; + +interface CapacityProps { + enrollCount: number; + enrollMax: number; + waitlistCount: number; + waitlistMax: number; +} + +export default function Capacity({ + enrollCount, + enrollMax, + waitlistCount, + waitlistMax, +}: CapacityProps) { + const color = useMemo( + () => getColor(enrollCount, enrollMax), + [enrollCount, enrollMax] + ); + + const waitlistColor = useMemo( + () => getColor(waitlistCount, waitlistMax), + [waitlistCount, waitlistMax] + ); + + return ( + + +
+ +

+ {enrollCount.toLocaleString()} +  /  + {enrollMax.toLocaleString()} +

+
+
+ + +
+ +
+

Enrolled

+

+ {enrollCount.toLocaleString()} +  /  + + {enrollMax.toLocaleString()} + +  ( + + {enrollMax === 0 + ? 0 + : Math.round( + (enrollCount / enrollMax) * 100 + ).toLocaleString()} + % + + ) +

+
+
+
+

Waitlisted

+

+ + {waitlistCount.toLocaleString()} + +  /  + {waitlistMax.toLocaleString()} +  ( + + {waitlistMax === 0 + ? 0 + : Math.round( + (waitlistCount / waitlistMax) * 100 + ).toLocaleString()} + % + + ) +

+
+
+ + + + ); +} diff --git a/frontend/src/components/ClassCards/ClassCard.jsx b/frontend/src/components/ClassCards/ClassCard.jsx deleted file mode 100644 index f5971c5c7..000000000 --- a/frontend/src/components/ClassCards/ClassCard.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Col } from 'react-bootstrap'; - -import ClassCardMobile from './ClassCardMobile'; - -function ClassCard(props) { - const { - id, - course, - title, - fill, - semester, - faculty, - removeCourse, - colorId, - additionalInfo, - type, - isMobile - } = props; - - return ( - -
-
-
-
{course}
-
removeCourse(id, colorId)}> - - - -
-
-
{title}
-
{`${semester} • ${faculty}`}
- - {isMobile ? : null} -
- - ); -} - -export default ClassCard; diff --git a/frontend/src/components/ClassCards/ClassCardList.jsx b/frontend/src/components/ClassCards/ClassCardList.jsx deleted file mode 100644 index ba5b4d7b2..000000000 --- a/frontend/src/components/ClassCards/ClassCardList.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import { PureComponent } from 'react'; -import { Container, Row } from 'react-bootstrap'; - -import ClassCard from './ClassCard'; -import vars from '../../variables/Variables'; - -class ClassCardList extends PureComponent { - render() { - const { selectedCourses, removeCourse, additionalInfo, type, isMobile } = this.props; - - return ( - - - {selectedCourses.map((item, i) => ( - - ))} - - - ); - } -} - -export default ClassCardList; diff --git a/frontend/src/components/ClassCards/ClassCardMobile.jsx b/frontend/src/components/ClassCards/ClassCardMobile.jsx deleted file mode 100644 index e80e6d825..000000000 --- a/frontend/src/components/ClassCards/ClassCardMobile.jsx +++ /dev/null @@ -1,76 +0,0 @@ -import { getGradeColor, getEnrollmentDay, applyIndicatorEnrollment } from '../../utils/utils'; - -function ClassCardMobile(props) { - const { additionalInfo, type } = props; - - const nullCheck = (e) => { - return e !== undefined && e !== null; - }; - - if (type === 'grades') { - const courseLetter = additionalInfo ? additionalInfo[0] : null; - const courseGPA = additionalInfo ? additionalInfo[1] : null; - const sectionLetter = additionalInfo ? additionalInfo[2] : null; - const sectionGPA = additionalInfo ? additionalInfo[3] : null; - - return ( -
-
-
Course Average
- {nullCheck(courseLetter) ? ( -
- {courseLetter} (GPA: {courseGPA}) -
- ) : ( - '--' - )} -
-
-
Section Average
- {nullCheck(sectionLetter) ? ( -
- {sectionLetter} (GPA:{' '} - {sectionGPA}) -
- ) : ( - '--' - )} -
-
- ); - } else { - const latest_point = additionalInfo ? additionalInfo[0] : null; - const telebears = additionalInfo ? additionalInfo[1] : null; - const enrollment_info = additionalInfo ? additionalInfo[2] : null; - const waitlisted_info = additionalInfo ? additionalInfo[3] : null; - - let date_info = []; - if (latest_point != null && telebears != null) { - date_info = getEnrollmentDay(latest_point, telebears); - } - - return ( -
-
-
- {date_info ? date_info['period'] + ': ' + date_info['daysAfterPeriodStarts'] : '--'} -
-
- Enrollment Percent: - {nullCheck(enrollment_info) - ? applyIndicatorEnrollment.apply(null, enrollment_info) - : '--'} -
-
- Waitlist Percent: - {nullCheck(waitlisted_info) - ? applyIndicatorEnrollment.apply(null, waitlisted_info) - : '--'} -
-
-
- ); - } -} - -export default ClassCardMobile; diff --git a/frontend/src/components/ClassSearchBar/EnrollmentSearchBar.jsx b/frontend/src/components/ClassSearchBar/EnrollmentSearchBar.jsx deleted file mode 100644 index 26eaa1734..000000000 --- a/frontend/src/components/ClassSearchBar/EnrollmentSearchBar.jsx +++ /dev/null @@ -1,321 +0,0 @@ -import { Component } from 'react'; -import { Container, Row, Col, Button } from 'react-bootstrap'; -import hash from 'object-hash'; - -import { fetchEnrollSelected } from '../../redux/actions'; -import { connect } from 'react-redux'; -import { reactSelectCourseSearch } from 'utils/courses/search'; -import BTSelect from 'components/Custom/Select'; - -class EnrollmentSearchBar extends Component { - constructor(props) { - super(props); - - this.state = { - selectedClass: 0, - selectPrimary: this.props.selectPrimary, - selectSecondary: this.props.selectSecondary - }; - - this.queryCache = {}; - - this.handleClassSelect = this.handleClassSelect.bind(this); - this.handlePrimarySelect = this.handlePrimarySelect.bind(this); - this.handleSecondarySelect = this.handleSecondarySelect.bind(this); - this.buildCoursesOptions = this.buildCoursesOptions.bind(this); - this.buildPrimaryOptions = this.buildPrimaryOptions.bind(this); - this.buildSecondaryOptions = this.buildSecondaryOptions.bind(this); - this.getFilteredSections = this.getFilteredSections.bind(this); - this.addSelected = this.addSelected.bind(this); - this.reset = this.reset.bind(this); - } - - componentDidMount() { - let { fromCatalog } = this.props; - if (fromCatalog) { - this.handleClassSelect({ value: fromCatalog.id, addSelected: true }); - } - } - - UNSAFE_componentWillReceiveProps(nextProps) { - if (nextProps.selectPrimary !== this.state.selectPrimary) { - this.setState({ - selectPrimary: nextProps.selectPrimary - }); - } - if (nextProps.selectSecondary !== this.state.selectSecondary) { - this.setState({ - selectSecondary: nextProps.selectSecondary - }); - } - } - - handleClassSelect(updatedClass) { - const { fetchEnrollSelected } = this.props; - if (updatedClass === null) { - this.reset(); - this.setState({ - selectedClass: 0 - }); - return; - } - - this.setState({ - selectedClass: updatedClass.value, - selectPrimary: '', - selectSecondary: '' - }); - - fetchEnrollSelected(updatedClass); - } - - handlePrimarySelect(primary) { - this.setState({ - selectPrimary: primary ? primary.value : '', - selectSecondary: primary ? { value: 'all', label: 'All Instructors' } : '' - }); - } - - handleSecondarySelect(secondary) { - this.setState({ - selectSecondary: secondary ? secondary : { value: 'all', label: 'All Instructors' } - }); - } - - buildCoursesOptions(courses) { - if (!courses) { - return []; - } - const options = courses.map((course) => ({ - value: course.id, - label: `${course.abbreviation} ${course.course_number}`, - course - })); - - return options; - } - - capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); - } - - getSectionSemester(section) { - return `${this.capitalize(section.semester)} ${section.year}`; - } - - buildPrimaryOptions(sections) { - const ret = []; - const map = new Map(); - - for (const section of sections) { - let semester = this.getSectionSemester(section); - if (!map.has(semester)) { - map.set(semester, true); - ret.push({ - value: semester, - label: semester - }); - } - } - - return ret; - } - - buildSecondaryOptions(semesters, selectPrimary) { - if (semesters.length === 0 || selectPrimary === undefined || selectPrimary === '') { - return []; - } - - const ret = []; - - let sections = semesters.filter( - (semester) => this.getSectionSemester(semester) === selectPrimary - )[0].sections; - if (sections.length > 1) { - ret.push({ value: 'all', label: 'All Instructors' }); - } - - for (var section of sections) { - let instructor = `${ - section.instructor === null || section.instructor === '' ? 'None' : section.instructor - } / ${section.section_number}`; - ret.push({ - value: instructor, - label: instructor, - sectionNumber: instructor.split(' / ')[1], - sectionId: section.section_id - }); - } - return ret; - } - - getFilteredSections() { - const { selectPrimary, selectSecondary, sectionNumber } = this.state; - const { sections } = this.props; - let ret; - ret = sections - .filter((section) => { - return this.getSectionSemester(section) === selectPrimary; - })[0] - .sections.filter((section) => { - return selectSecondary.value === 'all' - ? true - : section.instructor === selectSecondary.value.split(' / ')[0]; - }) - .filter((section) => { - return sectionNumber ? section.section_number === sectionNumber : true; - }) - .map((s) => s.section_id); - return ret; - } - - addSelected() { - const { selectedClass, selectPrimary, selectSecondary } = this.state; - const { sections } = this.props; - let secondaryOptions = this.buildSecondaryOptions(sections, selectPrimary); - let instructor = ''; - let sectionId = []; - if (secondaryOptions.length === 1) { - instructor = secondaryOptions[0].value; - sectionId = [secondaryOptions[0].sectionId]; - } else { - if (selectSecondary.value === 'all') { - instructor = 'all'; - } else { - instructor = selectSecondary.value; - } - if (selectSecondary.sectionId) { - sectionId = [selectSecondary.sectionId]; - } else { - sectionId = this.getFilteredSections(); - } - } - let playlist = { - courseID: selectedClass, - instructor: instructor, - semester: selectPrimary, - sections: sectionId - }; - - playlist.id = hash(playlist); - this.props.addCourse(playlist); - this.reset(); - } - - reset() { - this.setState({ - selectPrimary: '', - selectSecondary: '' - }); - } - - render() { - const { classes, isFull, sections, isMobile } = this.props; - const { selectPrimary, selectSecondary, selectedClass } = this.state; - let primaryOptions = this.buildPrimaryOptions(sections); - let secondaryOptions = this.buildSecondaryOptions(sections, selectPrimary); - let onePrimaryOption = primaryOptions && primaryOptions.length === 1 && selectPrimary; - let oneSecondaryOption = - secondaryOptions && secondaryOptions.length === 1 && selectSecondary.value; - - let primaryOption = { value: selectPrimary, label: selectPrimary }; - let secondaryOption = selectSecondary; - - if (selectSecondary === 'all') { - secondaryOption = { value: 'all', label: 'All Instructors' }; - } - - if (selectPrimary === '') { - primaryOption = ''; - } - if (selectSecondary === '') { - secondaryOption = ''; - } - - const customStyles = { - clearIndicator: (provided, state) => ({ - ...provided, - marginRight: 0, - paddingRight: 0 - }) - }; - - return ( - - - - null - }} - styles={customStyles} - /> - - - null - }} - styles={customStyles} - /> - - - null - }} - styles={customStyles} - /> - - - - - - - ); - } -} - -const mapDispatchToProps = (dispatch) => { - return { - dispatch, - fetchEnrollSelected: (updatedClass) => dispatch(fetchEnrollSelected(updatedClass)) - }; -}; - -const mapStateToProps = (state) => { - const { sections, selectPrimary, selectSecondary } = state.enrollment; - return { - sections, - selectPrimary, - selectSecondary - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(EnrollmentSearchBar); diff --git a/frontend/src/components/ClassSearchBar/GradesSearchBar.jsx b/frontend/src/components/ClassSearchBar/GradesSearchBar.jsx deleted file mode 100644 index 2888fd472..000000000 --- a/frontend/src/components/ClassSearchBar/GradesSearchBar.jsx +++ /dev/null @@ -1,421 +0,0 @@ -import { Component } from 'react'; -import { Container, Row, Col, Button } from 'react-bootstrap'; -import hash from 'object-hash'; - -import { connect } from 'react-redux'; - -import { fetchGradeSelected } from '../../redux/actions'; -import { reactSelectCourseSearch } from 'utils/courses/search'; -import BTSelect from 'components/Custom/Select'; - -const sortOptions = [ - { value: 'instructor', label: 'By Instructor' }, - { value: 'semester', label: 'By Semester' } -]; -class GradesSearchBar extends Component { - constructor(props) { - super(props); - - this.state = { - selectedClass: 0, - selectType: 'instructor', - selectPrimary: props.selectPrimary, - selectSecondary: props.selectSecondary - }; - this.queryCache = {}; - - this.handleClassSelect = this.handleClassSelect.bind(this); - this.handleSortSelect = this.handleSortSelect.bind(this); - this.handlePrimarySelect = this.handlePrimarySelect.bind(this); - this.handleSecondarySelect = this.handleSecondarySelect.bind(this); - this.buildCoursesOptions = this.buildCoursesOptions.bind(this); - this.buildPrimaryOptions = this.buildPrimaryOptions.bind(this); - this.buildSecondaryOptions = this.buildSecondaryOptions.bind(this); - this.getFilteredSections = this.getFilteredSections.bind(this); - this.addSelected = this.addSelected.bind(this); - this.reset = this.reset.bind(this); - } - - componentDidMount() { - const { fromCatalog } = this.props; - this.setState({ - selectType: 'instructor' - }); - if (fromCatalog) { - this.handleClassSelect({ value: fromCatalog.id, addSelected: true }); - } - } - - UNSAFE_componentWillReceiveProps(nextProps) { - if (nextProps.selectPrimary !== this.state.selectPrimary) { - this.setState({ - selectPrimary: nextProps.selectPrimary - }); - } - if (nextProps.selectSecondary !== this.state.selectSecondary) { - this.setState({ - selectSecondary: nextProps.selectSecondary - }); - } - } - - handleClassSelect(updatedClass) { - const { fetchGradeSelected } = this.props; - if (updatedClass === null) { - this.reset(); - this.setState({ - selectedClass: 0, - selectPrimary: '', - selectSecondary: '' - }); - return; - } - - this.setState({ - selectedClass: updatedClass.value - }); - - fetchGradeSelected(updatedClass); - } - - handleSortSelect(sortBy) { - this.setState({ - selectType: sortBy.value, - selectPrimary: '', - selectSecondary: '' - }); - } - - handlePrimarySelect(primary) { - const { sections } = this.props; - const { selectType } = this.state; - const secondaryOptions = this.buildSecondaryOptions(sections, selectType, primary.value); - this.setState({ - selectPrimary: primary ? primary.value : '', - selectSecondary: secondaryOptions.length === 1 ? secondaryOptions[0].value : 'all' - }); - } - - handleSecondarySelect(secondary) { - this.setState({ - selectSecondary: secondary ? secondary.value : '' - }); - } - - buildCoursesOptions(courses) { - if (!courses) { - return []; - } - const options = courses.map((course) => ({ - value: course.id, - label: `${course.abbreviation} ${course.course_number}`, - course - })); - - return options; - } - - capitalize(str) { - return str.charAt(0).toUpperCase() + str.slice(1); - } - - getSectionSemester(section) { - return `${this.capitalize(section.semester)} ${section.year}`; - } - - buildPrimaryOptions(sections, selectType) { - const ret = []; - const map = new Map(); - if (selectType === 'instructor') { - if (sections.length > 1) { - ret.push({ value: 'all', label: 'All Instructors' }); - } - for (const section of sections) { - if (!map.has(section.instructor)) { - map.set(section.instructor, true); - ret.push({ - value: section.instructor, - label: section.instructor - }); - } - } - } else { - if (sections.length > 1) { - ret.push({ value: 'all', label: 'All Semesters' }); - } - for (const section of sections) { - const semester = this.getSectionSemester(section); - if (!map.has(semester)) { - map.set(semester, true); - ret.push({ - value: semester, - label: semester - }); - } - } - } - - return ret; - } - - buildSecondaryOptions(sections, selectType, selectPrimary) { - const ret = []; - - if (selectPrimary === 'all') { - let options; - if (selectType === 'instructor') { - options = [ - ...new Set(sections.map((s) => `${this.getSectionSemester(s)} / ${s.section_number}`)) - ].map((semester) => ({ - value: semester.split(' / ')[0], - label: semester, - sectionNumber: semester.split(' / ')[1] - })); - } else { - options = [...new Set(sections.map((s) => `${s.instructor} / ${s.section_number}`))].map( - (instructor) => ({ - value: instructor.split(' / ')[0], - label: instructor, - sectionNumber: instructor.split(' / ')[1] - }) - ); - } - - if (options.length > 1) { - const label = selectType === 'instructor' ? 'All Semesters' : 'All Instructors'; - ret.push({ value: 'all', label }); - } - - for (const o of options) { - ret.push(o); - } - } else { - let options; - if (selectType === 'instructor') { - options = sections - .filter((section) => section.instructor === selectPrimary) - .map((section) => { - const semester = `${this.getSectionSemester(section)} / ${section.section_number}`; - - return { - value: semester, - label: semester, - sectionNumber: semester.split(' / ')[1] - }; - }); - } else { - options = sections - .filter((section) => this.getSectionSemester(section) === selectPrimary) - .map((section) => { - const instructor = `${section.instructor} / ${section.section_number}`; - return { - value: instructor, - label: instructor, - sectionNumber: instructor.split(' / ')[1] - }; - }); - } - - if (options.length > 1) { - const label = selectType === 'instructor' ? 'All Semesters' : 'All Instructors'; - ret.push({ value: 'all', label }); - } - - for (const o of options) { - ret.push(o); - } - } - - return ret; - } - - getFilteredSections() { - const { selectType, selectPrimary, selectSecondary } = this.state; - const { sections } = this.props; - let semester = selectSecondary; - let number = -1; - if (selectSecondary.split(' ').length > 2) { - semester = selectSecondary.split(' ').slice(0, 2).join(' '); - number = selectSecondary.split(' ')[3]; - } - let ret; - - if (selectType === 'instructor') { - ret = sections - .filter((section) => - selectPrimary === 'all' ? true : section.instructor === selectPrimary - ) - .filter((section) => - semester === 'all' ? true : this.getSectionSemester(section) === semester - ) - .filter((section) => (number !== -1 ? section.section_number === number : true)); - } else { - ret = sections - .filter((section) => - selectPrimary === 'all' ? true : this.getSectionSemester(section) === selectPrimary - ) - .filter((section) => (semester === 'all' ? true : section.instructor === semester)) - .filter((section) => (number !== -1 ? section.section_number === number : true)); - } - - ret = ret.map((s) => s.grade_id); - return ret; - } - - addSelected() { - const { selectedClass, selectType, selectPrimary, selectSecondary } = this.state; - - const playlist = { - courseID: selectedClass, - instructor: selectType === 'instructor' ? selectPrimary : selectSecondary, - semester: selectType === 'semester' ? selectPrimary : selectSecondary, - sections: this.getFilteredSections() - }; - - playlist.id = hash(playlist); - this.props.addCourse(playlist); - this.reset(); - } - - reset() { - this.setState({ - selectPrimary: '', - selectSecondary: '' - }); - } - - render() { - const { classes, isFull, isMobile } = this.props; - const { selectType, selectPrimary, selectSecondary, selectedClass } = this.state; - const { sections } = this.props; - const primaryOptions = this.buildPrimaryOptions(sections, selectType); - const secondaryOptions = this.buildSecondaryOptions(sections, selectType, selectPrimary); - const onePrimaryOption = primaryOptions && primaryOptions.length === 1 && selectPrimary; - const oneSecondaryOption = secondaryOptions && secondaryOptions.length === 1 && selectSecondary; - - let primaryOption = { value: selectPrimary, label: selectPrimary }; - let secondaryOption = { value: selectSecondary, label: selectSecondary }; - - if (selectType === 'instructor') { - if (selectPrimary === 'all') { - primaryOption = { value: 'all', label: 'All Instructors' }; - } - if (selectSecondary === 'all') { - secondaryOption = { value: 'all', label: 'All Semesters' }; - } - } else { - if (selectPrimary === 'all') { - primaryOption = { value: 'all', label: 'All Semesters' }; - } - if (selectSecondary === 'all') { - secondaryOption = { value: 'all', label: 'All Instructors' }; - } - } - - if (selectPrimary === '') { - primaryOption = ''; - } - if (selectSecondary === '') { - secondaryOption = ''; - } - - const customStyles = { - clearIndicator: (provided, state) => ({ - ...provided, - marginRight: 0, - paddingRight: 0 - }) - }; - - return ( - - - - null - }} - styles={customStyles} - /> - - - null - }} - styles={customStyles} - /> - - - null - }} - styles={customStyles} - /> - - - null - }} - styles={customStyles} - /> - - - - - - - ); - } -} - -const mapDispatchToProps = (dispatch) => ({ - dispatch, - fetchGradeSelected: (updatedClass) => dispatch(fetchGradeSelected(updatedClass)) -}); - -const mapStateToProps = (state) => { - const { sections, selectPrimary, selectSecondary } = state.grade; - return { - sections, - selectPrimary, - selectSecondary - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(GradesSearchBar); diff --git a/frontend/src/components/Common/BTLoader.tsx b/frontend/src/components/Common/BTLoader.tsx deleted file mode 100644 index 65d73360c..000000000 --- a/frontend/src/components/Common/BTLoader.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { useEffect, useState } from 'react'; -import cx from 'classnames'; - -// Wait this many MS before showing the loader. -const TIME_BEFORE_LOADER = 80; - -type Props = { - /** - * Typically the loading indicator doesn't come up - * instantly so it doesn't flash for very-fast loads. - */ - showInstantly?: boolean; - - /** - * If to show a message about what is currently loading. - */ - message?: string; - - /** - * An error to show - */ - error?: Error | string | null; - - /** - * If to fill the page - */ - fill?: boolean; -}; - -const BTLoader = ({ showInstantly = false, message, error, fill = false }: Props) => { - const [showingLoader, setShowingLoader] = useState(false); - - useEffect(() => { - const loader = setTimeout(() => { - setShowingLoader(true); - }, TIME_BEFORE_LOADER); - - return () => clearTimeout(loader); - }, []); - - if (error) { - return ( -
- {typeof error === 'string' ? ( -

{error}

- ) : ( - <> -

An unexpected error occured.

-

{error.message}

- - )} -
- ); - } - - if (showingLoader || showInstantly) { - return ( -
-
-
-
-
-
- {message &&

{message}

} -
- ); - } else { - return null; - } -}; - -export default BTLoader; diff --git a/frontend/src/components/Common/Banner.tsx b/frontend/src/components/Common/Banner.tsx deleted file mode 100644 index 726607114..000000000 --- a/frontend/src/components/Common/Banner.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { FC } from 'react'; -import { connect, ConnectedProps } from 'react-redux'; -// import { Button } from 'react-bootstrap' -import { useHistory } from 'react-router-dom'; -import { Button } from 'bt/custom'; -import { ReduxState } from '../../redux/store'; -import { closeBanner } from '../../redux/common/actions'; - -import close from '../../assets/svg/common/close.svg'; - -type Props = PropsFromRedux; - -const Banner: FC = (props) => { - const history = useHistory(); - function redirect(site: string) { - history.push('/redirect?site=' + site); - } - - return props.banner ? ( -
-
-

Fall 2023 catalog + scheduler released!

-
- close -
- ) : null; -}; - -const mapState = (state: ReduxState) => ({ - banner: state.common.banner -}); - -const mapDispatch = { - closeBanner -}; - -const connector = connect(mapState, mapDispatch); - -type PropsFromRedux = ConnectedProps; - -export default connector(Banner); diff --git a/frontend/src/components/Common/Description.tsx b/frontend/src/components/Common/Description.tsx deleted file mode 100644 index c158e412d..000000000 --- a/frontend/src/components/Common/Description.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Component } from 'react'; -import Markdown from 'react-markdown'; -import { Container, Row, Col, Button } from 'react-bootstrap'; -import { Link } from 'react-router-dom'; - -export default class Description extends Component { - constructor(props) { - super(props); - this.state = { - body: '' - }; - } - - componentDidMount() { - fetch(this.props.bodyURL) - .then((response) => response.text()) - .then((text) => this.setState({ body: text })); - } - - render() { - const { body } = this.state; - const { title, link, linkName } = this.props; - - return ( -
- - - - -
-

{title}

-
- - {body} - - - - -
-
-
- ); - } -} - -export function LinkBar(props) { - const { link, linkName } = props; - - return ( -
- -
- ); -} \ No newline at end of file diff --git a/frontend/src/components/Common/FitToViewport.tsx b/frontend/src/components/Common/FitToViewport.tsx deleted file mode 100644 index b9f98a764..000000000 --- a/frontend/src/components/Common/FitToViewport.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import { FC } from 'react'; - -interface Props { - underNavbar?: boolean; -} - -const FitToViewport: FC = (props) => { - const className = 'fit-to-viewport' + (props.underNavbar ? ' under-navbar' : ''); - - return
{props.children}
; -}; - -export default FitToViewport; diff --git a/frontend/src/components/Common/Footer.tsx b/frontend/src/components/Common/Footer.tsx deleted file mode 100644 index 6bffb4f90..000000000 --- a/frontend/src/components/Common/Footer.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import React, { FC } from 'react'; -import { Container, Row, Col } from 'react-bootstrap'; -import { H6, A } from 'bt/custom'; - -const Footer: FC = () => ( - -); - -export default Footer; diff --git a/frontend/src/components/Common/Layout.tsx b/frontend/src/components/Common/Layout.tsx deleted file mode 100644 index 9ca154148..000000000 --- a/frontend/src/components/Common/Layout.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import Navigation from 'components/Common/Navigation'; -import Footer from 'components/Common/Footer'; -import { ReactNode } from 'react'; - -interface LayoutProps { - noFooter?: boolean; - children: ReactNode; -} - -const Layout = ({ children, noFooter }: LayoutProps) => { - return ( - <> - - {children} - {!noFooter &&
} - - ); -}; - -Layout.defaultProps = { - noFooter: false -}; - -export default Layout; diff --git a/frontend/src/components/Common/LogPageView.tsx b/frontend/src/components/Common/LogPageView.tsx deleted file mode 100644 index d94f9f114..000000000 --- a/frontend/src/components/Common/LogPageView.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { FC, useEffect } from 'react'; -import { useLocation } from 'react-router'; -import ReactGA from 'react-ga'; - -const gaTrackingID = 'UA-35316609-1'; - -ReactGA.initialize(gaTrackingID); - -const LogPageView: FC = () => { - const location = useLocation(); - - useEffect(() => { - ReactGA.set({ page: window.location.pathname }); - ReactGA.pageview(window.location.pathname); - }, [location.pathname]); - - return null; -}; - -export default LogPageView; diff --git a/frontend/src/components/Common/Navigation.tsx b/frontend/src/components/Common/Navigation.tsx deleted file mode 100644 index 0dec75938..000000000 --- a/frontend/src/components/Common/Navigation.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { FC, useState, useEffect } from 'react'; -import { useLocation } from 'react-router'; -import { Link } from 'react-router-dom'; -import { Navbar, Nav, NavProps } from 'react-bootstrap'; -import { connect, ConnectedProps } from 'react-redux'; -import { ReduxState } from '../../redux/store'; -import { Button } from 'bt/custom'; -import { ReactComponent as GoogleIcon } from '../../assets/svg/profile/google.svg'; - -import { useUser } from '../../graphql/hooks/user'; - -type Props = PropsFromRedux; - -const NavigationLink: FC< - { - to?: string; - onClick?: () => void; - isNew?: boolean; - } & NavProps -> = ({ to, children, isNew = false, ...props }) => ( - - {children} - -); - -const Navigation: FC = (props) => { - const [showLogin, setShowLogin] = useState(false); - - const location = useLocation(); - const { isLoggedIn } = useUser(); - - useEffect(() => { - // Hide modal when path changes - setShowLogin(false); - }, [location.pathname]); - - return ( - - - Berkeleytime - - - -
- ); - break; - case 'Full Name': - body = ( -
-

{value}

- {/* */} -
- ); - break; - default: - body = ( -
-

{value}

-
- ); - } - - return ( -
-

{attribute}

- {body} -
- ); - } -} - -export default Property; diff --git a/frontend/src/components/Profile/Resource.tsx b/frontend/src/components/Profile/Resource.tsx deleted file mode 100644 index 039d50c30..000000000 --- a/frontend/src/components/Profile/Resource.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { Link as RoutingLink } from 'react-router-dom'; - -type Props = { - text: string; - link?: string; - isDestructive?: boolean; - onClick?: () => void; -}; - -const Resource = ({ text, link, isDestructive = false, onClick }: Props) => { - const isExternal = link?.includes(':'); - const Component = (!link || isExternal ? 'a' : RoutingLink) as any; - const props = !link - ? {} - : isExternal - ? { - href: link, - target: '_blank', - rel: 'noopener noreferrer' - } - : { - to: link - }; - - return ( -
- -

{text}

-
-
- ); -}; - -export default Resource; diff --git a/frontend/src/components/Profile/Subview.tsx b/frontend/src/components/Profile/Subview.tsx deleted file mode 100644 index f6a07027f..000000000 --- a/frontend/src/components/Profile/Subview.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { FC, ReactNode } from 'react'; - -type Props = { - title: string; - className?: string; - widget?: ReactNode; -}; - -const Subview: FC = ({ title, className, widget, children }) => ( -
-
-

{title}

- {widget} -
-
{children}
-
-); - -export default Subview; diff --git a/frontend/src/components/Profile/SupportSubview.tsx b/frontend/src/components/Profile/SupportSubview.tsx deleted file mode 100644 index f18f3d454..000000000 --- a/frontend/src/components/Profile/SupportSubview.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { useDeleteUser } from '../../graphql/hooks/user'; -import Resource from './Resource'; -import Subview from './Subview'; - -const SupportSubview = () => { - const [deleteUser, { loading }] = useDeleteUser(); - - function deleteAccount() { - const didConfirm = window.confirm(`Are you sure you wish to IRREVERSIBLY delete your account?`); - if (didConfirm) { - deleteUser(); - } - } - - return ( -
- - - {loading ? ( - - ) : ( - - )} - -
- ); -}; - -export default SupportSubview; diff --git a/frontend/src/components/Profile/majors.json b/frontend/src/components/Profile/majors.json deleted file mode 100644 index adce480d0..000000000 --- a/frontend/src/components/Profile/majors.json +++ /dev/null @@ -1,136 +0,0 @@ -[ - "African American Studies", - "American Studies", - "Anthropology", - "Applied Language Studies", - "Applied Mathematics", - "Arabic", - "Architecture", - "Armenian Studies", - "Art History", - "Art Practice", - "Astrophysics", - "Atmospheric Science", - "Bioengineering", - "Biology + Business", - "Buddhist Studies", - "Celtic Studies", - "Chemical Biology", - "Chemical Engineering", - "Chemistry", - "Chicanx and Latinx Studies", - "Chinese Language", - "City Planning", - "Civil Engineering", - "Classical Civilizations", - "Classical Languages", - "Climate Science", - "Cognitive Science", - "Comparative Literature", - "Computer Science", - "Conservation and Resource Studies", - "Course Threads", - "Creative Writing", - "Dance and Performance Studies", - "Data Science", - "Demography", - "Digital Humanities", - "Disability Studies", - "Dutch Studies", - "EECS & Business Administration", - "Earth and Planetary Science", - "Economics", - "Ecosystem Management and Forestry", - "Education", - "EECS", - "Electronic Intelligent Systems", - "Energy Engineering", - "Energy and Resources", - "Engineering Physics", - "English", - "Environmental Earth Science", - "Environmental Economics and Policy", - "Environmental Engineering", - "Environmental Sciences", - "Ethnic Studies", - "Film", - "Food Systems", - "French", - "Gender and Women's Studies", - "Genetics and Plant Biology", - "Geography", - "Geology", - "Geophysics", - "GIS", - "Geosystems", - "German", - "Global Poverty and Practice", - "Global Studies", - "Greek", - "Hebrew", - "History", - "History of the Built Environment", - "Human Rights Interdisciplinary", - "IEOR", - "Integrative Biology", - "Interdisciplinary Studies", - "Italian Studies", - "Japanese Language", - "Jewish Studies", - "Journalism", - "Korean Language", - "Landscape Architecture", - "Latin", - "Legal Studies", - "LGBT Studies", - "Linguistics", - "Logic", - "Marine Science", - "Materials Science & Engineering", - "Mathematics", - "Mechanical Engineering", - "Media Studies", - "Medieval Studies", - "Microbial Biology", - "Molecular Environmental Biology", - "Molecular and Cell Biology", - "Music", - "Native American Studies", - "Near Eastern Civilizations", - "New Media", - "Nuclear Engineering", - "Nutritional Sciences", - "Persian", - "Philosophy", - "Physics", - "Planetary Science", - "Political Economy", - "Political Science", - "Pre-Med / Pre-Health", - "Prelaw Information", - "Professional Accountancy", - "Psychology", - "Public Health", - "Public Policy", - "Race and the Law", - "Rhetoric", - "Russian Culture", - "Russian Language", - "Russian Literature", - "Scandinavian", - "Science and Math Education", - "Slavic Languages and Literatures", - "Social Welfare", - "Society and Environment", - "Sociology", - "South and Southeast Asian Studies", - "Spanish and Portuguese", - "Statistics", - "Structural Engineering", - "Sustainable Design", - "Sustainable Environmental Design", - "Theater and Performance Studies", - "Tibetan", - "Turkish", - "Urban Studies" -] diff --git a/frontend/src/components/Releases/Log.jsx b/frontend/src/components/Releases/Log.jsx deleted file mode 100644 index 940f81112..000000000 --- a/frontend/src/components/Releases/Log.jsx +++ /dev/null @@ -1,35 +0,0 @@ -function Log({ date, whatsNew, fixes }) { - return ( -
-
-

{date}

-
- {whatsNew ? ( -
-

🤩 What's New

-
    - {whatsNew.map((item, i) => ( -
  • - -
  • - ))} -
-
- ) : null} - {fixes ? ( -
-

🐛 Bug Fixes

-
    - {fixes.map((item, i) => ( -
  • - -
  • - ))} -
-
- ) : null} -
- ); -} - -export default Log; diff --git a/frontend/src/components/Scheduler/AccessControl.tsx b/frontend/src/components/Scheduler/AccessControl.tsx deleted file mode 100644 index 907074799..000000000 --- a/frontend/src/components/Scheduler/AccessControl.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import { forwardRef, MouseEvent, useState } from 'react'; -import { Dropdown } from 'react-bootstrap'; -import { AccessStatus, ACCESS_STATUSES } from 'utils/scheduler/accessStatus'; - -import { ReactComponent as ExpandMore } from '../../assets/svg/common/expand.svg'; - -type ACToggleProps = { - visibility: AccessStatus; - onClick: (e: MouseEvent) => void; -}; -const ACToggle = forwardRef( - ({ visibility, onClick }: ACToggleProps, ref) => { - const status = ACCESS_STATUSES[visibility]; - - return ( - - ); - } -); - -ACToggle.displayName = 'ACToggle'; - -type Props = { - visibility: AccessStatus; - setVisibility: (newVisibility: AccessStatus) => void; - scheduleId: string; -}; - -const AccessControl = ({ visibility = 'private', setVisibility, scheduleId }: Props) => { - const [isShowing, setIsShowing] = useState(false); - - const scheduleUUID = atob(scheduleId).split(':')[1]; - const scheduleLink = `${window.location.origin}/s/${scheduleUUID}`; - - return ( - setVisibility(eventKey as AccessStatus)} - onToggle={(isOpen, event, metadata) => { - if (metadata.source === 'select') return; - setIsShowing(isOpen); - }} - show={isShowing} - > - - - {visibility === 'public' && ( -
-

Schedule Link

-

Click below to copy your schedule's link.

- { - (e.target as HTMLInputElement).select(); - document.execCommand('copy'); - }} - /> -
- )} - {Object.entries(ACCESS_STATUSES).map(([key, details]) => ( - - {details.icon} -
-
{details.name}
-
{details.description}
-
-
- ))} -
-
- ); -}; - -export default AccessControl; diff --git a/frontend/src/components/Scheduler/Calendar/CalendarCard.tsx b/frontend/src/components/Scheduler/Calendar/CalendarCard.tsx deleted file mode 100644 index e3958818a..000000000 --- a/frontend/src/components/Scheduler/Calendar/CalendarCard.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { CSSProperties, forwardRef, HTMLProps } from 'react'; -import Color from 'color'; - -export type Props = HTMLProps & { - title: string; - description: string; - color: string; - className?: string; - style?: CSSProperties; -}; - -const CalendarCard = forwardRef( - ({ title, description, color, style = {}, className = '', ...props }, ref) => { - const isLightCard = Color(color).luminosity() > 0.65; - - return ( -
-
{title}
-

{description}

-
- ); - } -); - -CalendarCard.displayName = 'CalendarCard'; - -export default CalendarCard; diff --git a/frontend/src/components/Scheduler/Calendar/CourseCalendar.tsx b/frontend/src/components/Scheduler/Calendar/CourseCalendar.tsx deleted file mode 100644 index da05fb59f..000000000 --- a/frontend/src/components/Scheduler/Calendar/CourseCalendar.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { CSSProperties, ReactNode } from 'react'; -import { range } from 'utils/range'; -import { dayToLongName, timeToHourString } from 'utils/date'; - -export type CardData = { - key?: string | number; - day: number; - startTime: number; - endTime: number; - card: ReactNode; - - /** **Do not directly provide** */ - overlapNum?: number; - - /** **Do not directly provide** */ - overlapIndex?: number; -}; - -type CourseCalendarProps = { - days?: number[]; - startTime?: number; - endTime?: number; - cards: CardData[]; -}; - -const CELL_HEIGHT = 60; -const MIN_HEIGHT = 20; -const INTER_CELL_PADDING = 0; - -/** - * Takes a list of cards and returns copies with the `numOverlaps` property set. - */ -function calculateOverlaps(cards: CardData[]): CardData[] { - const events = cards.sort((a, b) => a.startTime - b.startTime); - - const finalCards: CardData[][] = []; - let currrentEndTime = -Infinity; - - let currentOverlap: CardData[] | null = null; - - for (let i = 0; i < events.length; i++) { - const c = cards[i]; - - // If the current course doesn't overlaps - if (c.startTime >= currrentEndTime) { - currentOverlap = []; - finalCards.push(currentOverlap); - } - - currentOverlap!.push(c); - currrentEndTime = Math.max(c.endTime, currrentEndTime); - } - - return finalCards.flatMap((group) => - group.map((item, index) => ({ - ...item, - overlapIndex: index, - overlapNum: group.length - })) - ); -} - -function calculateCellStyle( - calendarStartTime: number, - { startTime, endTime, overlapNum = 0, overlapIndex = 0 }: CardData -): CSSProperties { - const visualStartTime = startTime - calendarStartTime; - const height = Math.max(MIN_HEIGHT, (endTime - startTime) * CELL_HEIGHT); - return { - 'top': visualStartTime * CELL_HEIGHT, - 'height': height, - 'left': `calc(${(overlapIndex / overlapNum) * 100}% + ${overlapIndex * INTER_CELL_PADDING}px)`, - 'width': `calc(${((overlapNum - overlapIndex) / overlapNum) * 100}% - ${ - (overlapNum - 1) * INTER_CELL_PADDING - }px)`, - '--calendar-card-lines': Math.max(1, Math.floor(height / 40)) - } as CSSProperties; -} - -const CourseCalendar = ({ - days = [1, 2, 3, 4, 5], - startTime = 8, - endTime = 20, - cards = [] -}: CourseCalendarProps) => { - const hourSlots = range(startTime, endTime); - const cardsByDay = days.map((day) => - cards - .filter((c) => c.day === day) - .filter((c) => !!c.startTime && !!c.endTime) - .sort((a, b) => a.startTime - b.startTime) - ); - - return ( -
-
-
-
- {days.map((dayIndex) => ( -
- {dayToLongName(dayIndex)} -
- ))} -
-
-
-
- {hourSlots.map((hour) => ( -
- {timeToHourString(hour)} -
- ))} -
-
- {days.map((day, dayIndex) => ( -
-
- {calculateOverlaps(cardsByDay[dayIndex]).map((card) => ( -
- {card.card} -
- ))} -
-
- ))} -
-
-
- ); -}; - -export default CourseCalendar; diff --git a/frontend/src/components/Scheduler/Calendar/CourseCard.tsx b/frontend/src/components/Scheduler/Calendar/CourseCard.tsx deleted file mode 100644 index 71424ec53..000000000 --- a/frontend/src/components/Scheduler/Calendar/CourseCard.tsx +++ /dev/null @@ -1,115 +0,0 @@ -import TrashButton from 'components/Common/TrashButton'; -import { CourseOverviewFragment } from 'graphql'; -import { OverlayTrigger, Popover } from 'react-bootstrap'; -import { courseToColor, courseToName } from 'utils/courses/course'; -import { - getColorForSection, - getCourseForSchedule, - removeSection, - Schedule, - SchedulerSectionType -} from 'utils/scheduler/scheduler'; -import { formatLocation, formatSectionTime } from 'utils/sections/section'; -import cx from 'classnames'; -import CalendarCard from './CalendarCard'; -import { combineStrings } from 'utils/string'; - -type Props = { - /** - * The course associated with the section. You - * don't need to pass this if a `schedule` is - * provided. - */ - course?: CourseOverviewFragment | null; - section: SchedulerSectionType; - - /** - * If this course card represents a section from - * a schedule, pass the schedule here. - */ - schedule?: Schedule; - - /** - * Allows the user to modify the schedule from - * this card. - */ - setSchedule?: (newSchedule: Schedule) => void; - - /** - * CSS hex color of the card, otherwise defaults - * to a color determined from the course's title. - */ - color?: string; - - /** - * Defaults to `false`. Overrides and disables noPopover. - * Also disables the dropdown. Use this if the card is - * a temporary preview and not a permanent calendar item. - */ - isPreview?: boolean; - - /** - * If to not show a popover on this node - */ - noPopover?: boolean; -}; - -const CourseCard = ({ - section, - schedule, - course = schedule ? getCourseForSchedule(schedule, section) : null, - setSchedule, - color = schedule ? getColorForSection(schedule, section) : courseToColor(section.courseId), - isPreview = false, - noPopover = false -}: Props) => { - const cardTitle = `${courseToName(course)} ${section.kind}`; - const cardDescription = combineStrings( - [formatLocation(section.locationName), formatSectionTime(section)], - ', ' - ); - - const card = ( - - ); - - if (noPopover || isPreview) { - return card; - } - - const popover = ( - -
-
-
-

{cardTitle}

- {schedule && setSchedule && ( - { - setSchedule(removeSection(schedule, section.id)); - }} - /> - )} -
-

{cardDescription}

-

CCN: {section.ccn}

-

{section.instructor}

-
- - ); - - return ( - - {card} - - ); -}; - -export default CourseCard; diff --git a/frontend/src/components/Scheduler/Calendar/SchedulerCalendar.tsx b/frontend/src/components/Scheduler/Calendar/SchedulerCalendar.tsx deleted file mode 100644 index d25602ca0..000000000 --- a/frontend/src/components/Scheduler/Calendar/SchedulerCalendar.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { ReactNode } from 'react'; -import { stringToDate } from 'utils/date'; -import { Schedule, SchedulerSectionType } from 'utils/scheduler/scheduler'; -import CourseCalendar, { CardData } from './CourseCalendar'; -import CourseCard from './CourseCard'; - -/** - * Converts time to a number representing hour - * 11:30 => 11.5 - */ -function timeToHour(time: string): number { - const date = stringToDate(time); - return date.getUTCHours() + date.getUTCMinutes() / 60; -} - -/** - * Convert section object to a card data object - * WITHOUT the actual - */ -const sectionToCard = ( - section: SchedulerSectionType, - getCard: (section: SchedulerSectionType, day: number) => ReactNode -): CardData[] => - section.days.split('').map((day) => ({ - key: `${day}:${section.id}`, - day: +day, - startTime: timeToHour(section.startTime), - endTime: timeToHour(section.endTime), - card: getCard(section, +day) - })); - -type Props = { - schedule: Schedule; - - previewSection?: SchedulerSectionType | null; - - /** - * If a set schedule function is passed. This will - * be treated as an editable calendar. - */ - setSchedule?: (newSchedule: Schedule) => void; -}; - -/** - * Outputs the calendar from a schedule object. - */ -const SchedulerCalendar = ({ schedule, setSchedule, previewSection = null }: Props) => { - const courseCards = schedule.sections - .filter((section) => section.startTime && section.endTime) - .flatMap((section) => - sectionToCard(section, () => ( - - )) - ); - - const previewCards = - previewSection && !schedule.sections.find((s) => s.id === previewSection.id) - ? sectionToCard(previewSection, () => ( - - )) - : []; - - const allCards: CardData[] = [...courseCards, ...previewCards]; - - // See if there is a card on saturday or sunday - const days: Set = new Set([1, 2, 3, 4, 5, ...allCards.map((card) => card.day)]); - - return a - b)} cards={allCards} />; -}; - -export default SchedulerCalendar; diff --git a/frontend/src/components/Scheduler/Callout.tsx b/frontend/src/components/Scheduler/Callout.tsx deleted file mode 100644 index 499032bcc..000000000 --- a/frontend/src/components/Scheduler/Callout.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import { ReactNode } from 'react'; - -type CalloutProps = { - type?: 'info' | 'warning'; - state?: 'default' | 'error'; - message: ReactNode; -}; - -const icons = { - info: ( - - - - - ), - warning: ( - - - - - - ) -}; - -const Callout = ({ type = 'info', state = 'default', message }: CalloutProps) => { - return ( - - {icons[type]} -

{message}

-
- ); -}; - -export default Callout; diff --git a/frontend/src/components/Scheduler/CourseSelector.tsx b/frontend/src/components/Scheduler/CourseSelector.tsx deleted file mode 100644 index 473447bc2..000000000 --- a/frontend/src/components/Scheduler/CourseSelector.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import BTSelect from 'components/Custom/Select'; -import { CourseOverviewFragment } from 'graphql'; -import { useMemo } from 'react'; -import { courseToName } from 'utils/courses/course'; -import { reactSelectCourseSearch } from 'utils/courses/search'; -import { compareDepartmentName } from 'utils/courses/sorting'; -import { Semester } from 'utils/playlists/semesters'; -import { - getUnitsForSchedule, - hasCourseById, - removeCourse, - Schedule, - SchedulerCourseType, - SchedulerSectionType -} from 'utils/scheduler/scheduler'; -import SchedulerCourse from './Selector/SchedulerCourse'; -import { ScheduleContext } from './ScheduleContext'; -import { unitsToString } from 'utils/courses/units'; - -type CourseType = CourseOverviewFragment; - -type CourseOptionType = { - value: string; - label: string; - course: CourseType; -}; - -type Props = { - allCourses: CourseType[]; - semester: Semester; - schedule: Schedule; - setSchedule: (newValue: Schedule) => void; - - /** - * Pass this to add the ability to preview a section when a user - * hovers over it. - */ - setPreviewSection?: (newSection: SchedulerSectionType | null) => void; -}; - -const CourseSelector = ({ - allCourses, - semester, - schedule, - setSchedule, - setPreviewSection -}: Props) => { - // Sort courses - const sortedCourses: CourseOptionType[] = useMemo( - () => - allCourses.sort(compareDepartmentName).map((course) => ({ - value: course.id, - label: courseToName(course), - course - })), - [allCourses] - ); - - function addCourse(course: SchedulerCourseType) { - setSchedule({ - ...schedule, - courses: [course, ...schedule.courses.filter((c) => c.id !== course.id)] - }); - } - - function trashCourse(courseId: string) { - setSchedule(removeCourse(schedule, courseId)); - } - - return ( -
-

- {semester.semester.charAt(0).toUpperCase() + semester.semester.slice(1)} {semester.year}{' '} - Scheduler -

- !hasCourseById(schedule, course.value))} - filterOption={reactSelectCourseSearch} - onChange={(c: CourseOptionType) => c && addCourse(c.course)} - /> -
- Scheduled Units: {unitsToString(getUnitsForSchedule(schedule))} -
-
- - {schedule.courses.map((course) => ( - trashCourse(course.id)} - /> - ))} - -
-
- ); -}; - -export default CourseSelector; diff --git a/frontend/src/components/Scheduler/Editor/RemoteScheduler.tsx b/frontend/src/components/Scheduler/Editor/RemoteScheduler.tsx deleted file mode 100644 index d3ffd3ec5..000000000 --- a/frontend/src/components/Scheduler/Editor/RemoteScheduler.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import BTLoader from 'components/Common/BTLoader'; -import { useGetScheduleForIdLazyQuery, useUpdateScheduleMutation } from 'graphql'; -import { useCallback, useEffect, useRef, useState, Dispatch, SetStateAction } from 'react'; -import { deserializeSchedule, Schedule, serializeSchedule } from 'utils/scheduler/scheduler'; -import ScheduleEditor from '../ScheduleEditor'; -import { Semester } from 'utils/playlists/semesters'; -import debounce from 'utils/debounce'; -import Callout from '../Callout'; - -// This is NOT a loop. Rather it combines all -// changes within this time interval into one -// update event. This means there will be at MOST -// one event sent in each of the specfied interval. -const SCHEDULER_AUTOSAVE_INTERVAL = 500; - -type Props = { - scheduleId: string; - schedule: Schedule; - setRawSchedule: Dispatch>; -}; - -const RemoteScheduler = ({ scheduleId, schedule, setRawSchedule }: Props) => { - const [semester, setSemester] = useState(null); - - // Whether or not we say 'is saving...' may be different from whether - // or not there is an ongoing network requests. The main constraint - // is we do NOT want to say the schedule is saved if the schedule as - // currently shown is not what's on the server. - const [isSaving, setIsSaving] = useState(false); - - // Stores the currently pending autosave mutation query. - const currentlyPendingUpdate = useRef | null>(null); - - const [getScheduleForId, { error: scheduleLoadError }] = useGetScheduleForIdLazyQuery({ - onCompleted: (data) => { - if (!data.schedule) { - alert(`Couldn't find the given schedule.`); - return; - } - - // Only update the schedule state if a save mutation is not ongoing. - if (currentlyPendingUpdate.current === null) { - const schedule = deserializeSchedule(data.schedule); - setRawSchedule(schedule); - setSemester(data.schedule); - } - } - }); - - useEffect(() => { - // Clear the update queue - currentlyPendingUpdate.current = null; - - getScheduleForId({ - variables: { - id: scheduleId - } - }); - - // NOTE: potential race condition. Any pending getScheduleForId - // should be canceled when the scheduleId changes. This is not - // implemented as Apollo doesn't seem to allow you to easily - // cancel requests, and it's not expected to happen because - // usually the requests come back in the same order. - }, [scheduleId, getScheduleForId]); - - const [updateScheduleMutation, { error: saveError }] = useUpdateScheduleMutation(); - - // Call this to save a schedule. This gets renewed when the - // scheduleId changes (to clear the save queue). - // eslint-disable-next-line react-hooks/exhaustive-deps - const saveSchedule = useCallback( - debounce(async (schedule: Schedule, semester: Semester, id: string) => { - setIsSaving(true); - - const result = updateScheduleMutation({ - variables: { - scheduleId: id, - ...serializeSchedule(schedule, semester) - } - }); - - currentlyPendingUpdate.current = result; - try { - await currentlyPendingUpdate.current; - } finally { - // If there was a autosave error, the hook - // handles that so we don't need to worry. - setIsSaving(false); - } - }, SCHEDULER_AUTOSAVE_INTERVAL), - [scheduleId] - ); - - if (!schedule || !semester) { - return ; - } - - async function setSchedule(newSchedule: Schedule) { - setRawSchedule(newSchedule); - - // Wait for previous update to finish before queuing next one - // In effect, this will result in sequential updates being - // combined due to saveSchedule being 'debounced'. This is - // also done to avoid data races. - await currentlyPendingUpdate.current; - setIsSaving(true); - saveSchedule(newSchedule, semester!, scheduleId); - } - - return ( - Saving schedule... - ) : saveError ? ( - - ) : ( - Schedule saved. - ) - } - /> - ); -}; - -export default RemoteScheduler; diff --git a/frontend/src/components/Scheduler/Onboard/CourseSearch.tsx b/frontend/src/components/Scheduler/Onboard/CourseSearch.tsx deleted file mode 100644 index f755dcee7..000000000 --- a/frontend/src/components/Scheduler/Onboard/CourseSearch.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import BTSelect from 'components/Custom/Select'; -import { CourseOverviewFragment } from 'graphql'; -import { Dispatch, SetStateAction, useMemo } from 'react'; -import { courseToName } from 'utils/courses/course'; -import { reactSelectCourseSearch } from 'utils/courses/search'; -import { compareDepartmentName } from 'utils/courses/sorting'; -import { hasCourseById, Schedule } from 'utils/scheduler/scheduler'; -import { addCourse } from './onboard'; - -type CourseType = CourseOverviewFragment; - -type CourseOptionType = { - value: string; - label: string; - course: CourseType; -}; - -type Props = { - allCourses: CourseType[]; - schedule: Schedule; - setSchedule: Dispatch>; -}; - -const CourseSelector = ({ allCourses, schedule, setSchedule }: Props) => { - // Sort courses - const sortedCourses: CourseOptionType[] = useMemo( - () => - allCourses.sort(compareDepartmentName).map((course) => ({ - value: course.id, - label: courseToName(course), - course - })), - [allCourses] - ); - - return ( -
- !hasCourseById(schedule, course.value))} - filterOption={reactSelectCourseSearch} - onChange={(c) => c && addCourse(c.course, schedule, setSchedule)} - /> -
- ); -}; - -export default CourseSelector; diff --git a/frontend/src/components/Scheduler/Onboard/SchedulerCourseCard.tsx b/frontend/src/components/Scheduler/Onboard/SchedulerCourseCard.tsx deleted file mode 100644 index 918d00ac7..000000000 --- a/frontend/src/components/Scheduler/Onboard/SchedulerCourseCard.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { formatUnits, applyIndicatorPercent, applyIndicatorGrade } from '../../../utils/utils'; -import { CourseOverviewFragment } from 'graphql'; -import { Link } from 'react-router-dom'; -import ProfileCard from './../../Profile/ProfileCard'; - -type Props = { - course: CourseOverviewFragment; - removable: boolean; - remove?: () => void; -}; - -const SchedulerCourseCard = ({ course, removable, remove }: Props) => { - return ( - - {course.enrolledPercentage !== -1 && ( - - {applyIndicatorPercent( - `${course.enrolled}/${course.enrolledMax} enrolled`, - course.enrolledPercentage - )} -  •  - - )} - {formatUnits(course.units)} - - } - aside={ - course.letterAverage && ( -
- {applyIndicatorGrade(course.letterAverage, course.letterAverage)} -
- ) - } - removable={removable} - didRemove={remove} - /> - ); -}; - -export default SchedulerCourseCard; diff --git a/frontend/src/components/Scheduler/Onboard/SelectClasses.tsx b/frontend/src/components/Scheduler/Onboard/SelectClasses.tsx deleted file mode 100644 index b953e35f2..000000000 --- a/frontend/src/components/Scheduler/Onboard/SelectClasses.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { Dispatch, SetStateAction } from 'react'; -import { Button, Col, Container, Row } from 'react-bootstrap'; -import BTLoader from 'components/Common/BTLoader'; -import CourseSearch from 'components/Scheduler/Onboard/CourseSearch'; -import SchedulerCourseCard from 'components/Scheduler/Onboard/SchedulerCourseCard'; - -import { ScheduleContext } from '../ScheduleContext'; -import { CourseOverviewFragment } from 'graphql'; -import { useUser } from '../../../graphql/hooks/user'; -import { useGetCoursesForFilterQuery } from 'graphql'; -import useLatestSemester from 'graphql/hooks/latestSemester'; -import { addCourse } from './onboard'; -import { compareDepartmentName } from 'utils/courses/sorting'; -import { Schedule, removeCourse } from 'utils/scheduler/scheduler'; - -type Props = { - // updatePage: (i: number) => void; - schedule: Schedule; - setSchedule: Dispatch>; -}; - -const SelectClasses = ({ schedule, setSchedule }: Props) => { - const { user } = useUser(); - - const savedClasses = ((user && user.savedClasses) || []) - .filter((c): c is CourseOverviewFragment => c !== null) - .sort(compareDepartmentName); - - const { semester: latestSemester, error: semesterError } = useLatestSemester(); - - // Only load the list of filters once we have the latest semester. If we - // didn't wait, we'd load all semesters' classes which is way to many. - const { data, error: coursesError } = useGetCoursesForFilterQuery({ - variables: { - playlists: latestSemester?.playlistId! - }, - skip: !latestSemester?.playlistId - }); - - const error = semesterError || coursesError; - - if (!data) { - return ( -
- {error ? 'A critical error occured loading scheduler information.' : } -
- ); - } - - // Get a list of all courses which will be used by the search bar. - const allCourses = data.allCourses?.edges.map((e) => e?.node!)!; - - function trashCourse(courseId: string) { - setSchedule(removeCourse(schedule, courseId)); - } - - return ( - - - - -
1. Select your classes
-
- Search from the course catalog for the classes you’d like to include in your schedule. -
- -
- {savedClasses - .filter( - (course) => - schedule.courses.filter((e: CourseOverviewFragment) => e.id === course.id) - .length === 0 - ) - .map((course) => ( -
- - -
- ))} -
- - -
Selected classes
-
- - {schedule.courses.map((course: CourseOverviewFragment) => ( - trashCourse(course.id)} - /> - ))} - -
- - -
-
- ); -}; - -export default SelectClasses; diff --git a/frontend/src/components/Scheduler/Onboard/TimePreferences.tsx b/frontend/src/components/Scheduler/Onboard/TimePreferences.tsx deleted file mode 100644 index 49a116eb0..000000000 --- a/frontend/src/components/Scheduler/Onboard/TimePreferences.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import { useState } from 'react'; -import { Col, Container, Row } from 'react-bootstrap'; -import { Button, P, H3, H6 } from 'bt/custom'; -import BTSelect from 'components/Custom/Select'; -import BTInput from 'components/Custom/Input'; - -const DAYS = [ - { value: 1, label: 'Monday' }, - { value: 2, label: 'Tuesday' }, - { value: 3, label: 'Wednesday' }, - { value: 4, label: 'Thursday' }, - { value: 5, label: 'Friday' } -]; - -// Hour ranges for times -const FIRST_TIME = 8; -const LAST_TIME = 18; - -const TIMES = new Array(LAST_TIME - FIRST_TIME) - .fill(null) - .map((_, i) => i + FIRST_TIME) - .map((hour): [number, string, string] => [ - hour, - `${((hour - 1) % 12) + 1}`, - hour >= 12 ? 'PM' : 'AM' - ]) - .flatMap(([hour, hourText, ampm]) => [ - { value: hour + 0.0, label: `${hourText}:00 ${ampm}` }, - { value: hour + 0.25, label: `${hourText}:15 ${ampm}` }, - { value: hour + 0.5, label: `${hourText}:30 ${ampm}` }, - { value: hour + 0.75, label: `${hourText}:45 ${ampm}` } - ]); - -type TimeBlock = { - id: string; - name: string; - startTime: number; - endTime: number; - days: number[]; -}; - -let blockIdCounter = 0; - -type Props = { - createSchedule: () => void; -}; - -const TimePreferences = ({ createSchedule }: Props) => { - const [blockName, setBlockName] = useState(''); - const [timeBlocks, setTimeBlocks] = useState([]); - - function createTimeBlock() { - const newBlock = { - id: `${blockIdCounter++}`, - name: blockName, - startTime: 0, - endTime: 0, - days: [] - }; - setTimeBlocks([newBlock, ...timeBlocks]); - setBlockName(''); - } - - return ( - - - -

- 2. Add Time Preferences (Optional) -

-

- Add blocks of time you’d prefer not to have classes. -

- setBlockName(e.target.value)} - placeholder="Add block name" - /> -
- Time - - - {' to '} - - -
-
- Day(s) - - - -
-
- -
-
-
Blocks
- {timeBlocks.length === 0 ? ( -
- - - -

You have not created time blocks.

-
- ) : ( -
- {timeBlocks.map((block) => ( -
-

{block.name}

-

9am - 11am M, T

-
- ))} -
- )} -
- - - - -
-
- ); -}; - -export default TimePreferences; diff --git a/frontend/src/components/Scheduler/Onboard/Welcome.tsx b/frontend/src/components/Scheduler/Onboard/Welcome.tsx deleted file mode 100644 index fddbc5b1a..000000000 --- a/frontend/src/components/Scheduler/Onboard/Welcome.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import { Container, Row, Col } from 'react-bootstrap'; -import { useUser } from '../../../graphql/hooks/user'; -import ProfileScheduleCard from './../../Profile/ProfileScheduleCard'; -import { getNodes } from 'utils/graphql'; -import { useLocalStorageState } from 'utils/hooks'; -import { - DEFAULT_SCHEDULE, - isScheduleEmpty, - Schedule, - SCHEDULER_LOCALSTORAGE_KEY -} from 'utils/scheduler/scheduler'; -import { Button } from 'bt/custom'; -// import { Button } from 'bt/custom'; - -type Props = { - updatePage: (i: number) => void; -}; - -const Welcome = ({ updatePage }: Props) => { - const { user } = useUser(); - - const [schedule, setSchedule] = useLocalStorageState( - SCHEDULER_LOCALSTORAGE_KEY, - DEFAULT_SCHEDULE - ); - - const savedSchedules = user - ? getNodes(user.schedules).sort((a, b) => Date.parse(b.dateCreated) - Date.parse(a.dateCreated)) - : []; - - const resetDraft = () => setSchedule(DEFAULT_SCHEDULE); - - return ( - - - -
Welcome to Berkeleytime's Scheduler
-
- Use our scheduler to build your ideal schedule. Search our catalog to add new classes or - select from saved ones, and add your own time preferences. -
- -
- {!isScheduleEmpty(schedule) && ( - - )} - -
- -
- - - {savedSchedules.length > 0 && ( -
-
Saved Schedules
-
- {savedSchedules.map((course) => ( - - ))} -
-
- )} - -
-
- ); -}; - -export default Welcome; diff --git a/frontend/src/components/Scheduler/Onboard/onboard.ts b/frontend/src/components/Scheduler/Onboard/onboard.ts deleted file mode 100644 index 19e08b49e..000000000 --- a/frontend/src/components/Scheduler/Onboard/onboard.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Dispatch, SetStateAction } from 'react'; -import { CourseOverviewFragment } from 'graphql'; -import { Schedule, SchedulerCourseType } from 'utils/scheduler/scheduler'; - -/** - * Adds a course to schedule - */ -export function addCourse( - course: SchedulerCourseType, - schedule: Schedule, - setSchedule: Dispatch> -) { - if (schedule.courses.filter((e: CourseOverviewFragment) => e.id === course.id).length === 0) { - setSchedule({ - ...schedule, - courses: [course, ...schedule.courses] - }); - } -} diff --git a/frontend/src/components/Scheduler/ScheduleContext.ts b/frontend/src/components/Scheduler/ScheduleContext.ts deleted file mode 100644 index dcf4f9024..000000000 --- a/frontend/src/components/Scheduler/ScheduleContext.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createContext, useContext } from 'react'; -import { Schedule, SchedulerSectionType } from 'utils/scheduler/scheduler'; - -type ContextType = { - schedule: Schedule; - setSchedule: (newSchedule: Schedule) => void; - setPreviewSection?: (newPreviewSection: SchedulerSectionType | null) => void; -}; - -const ScheduleContext = createContext(null as unknown as ContextType); - -const useScheduleContext = () => useContext(ScheduleContext); - -export { ScheduleContext, useScheduleContext }; diff --git a/frontend/src/components/Scheduler/ScheduleEditor.tsx b/frontend/src/components/Scheduler/ScheduleEditor.tsx deleted file mode 100644 index cce7fb688..000000000 --- a/frontend/src/components/Scheduler/ScheduleEditor.tsx +++ /dev/null @@ -1,134 +0,0 @@ -import { ChangeEvent, ReactNode, useState } from 'react'; -import { Button, Col, Row } from 'react-bootstrap'; -import CourseSelector from 'components/Scheduler/CourseSelector'; - -import { useGetCoursesForFilterQuery } from 'graphql'; -import BTLoader from 'components/Common/BTLoader'; -import { Schedule, SchedulerSectionType, scheduleToICal } from 'utils/scheduler/scheduler'; -import SchedulerCalendar from 'components/Scheduler/Calendar/SchedulerCalendar'; -import AccessControl from './AccessControl'; -import { AccessStatus } from 'utils/scheduler/accessStatus'; -import { useSemester } from 'graphql/hooks/semester'; -import { getNodes } from 'utils/graphql'; -import { Semester } from 'utils/playlists/semesters'; - -type Props = { - /** - * The semester being edited. If not provided, will - * assume the latest semester. - */ - semester?: Semester; - - /** - * The users schedule. - */ - schedule: Schedule; - - /** - * Called when the schedule should be updated. - */ - setSchedule: (newSchedule: Schedule) => void; - - /** - * This is the widget to show next to the title. - * It typically represents the schedule's save state. - */ - saveWidget?: ReactNode; - - /** - * If provided, shows access control with the - * specified ID. - */ - accessControl?: string; -}; - -const ScheduleEditor = ({ schedule, semester, setSchedule, saveWidget, accessControl }: Props) => { - const { semester: latestSemester, error: semesterError } = useSemester(semester); - - // Only load the list of filters once we have the latest semester. If we - // didn't wait, we'd load all semesters' classes which is way to many. - const { data, error: coursesError } = useGetCoursesForFilterQuery({ - variables: { - playlists: latestSemester?.playlistId! - }, - skip: !latestSemester - }); - - // If the user is hovering over a section. This will store that section - const [previewSection, setPreviewSection] = useState(null); - - const setScheduleName = (event: ChangeEvent) => - setSchedule({ - ...schedule, - name: event.target.value - }); - - const setScheduleVisibility = (newAccess: AccessStatus) => - setSchedule({ - ...schedule, - access: newAccess - }); - - if (!data || !semester) { - return ; - } - - function exportToCalendar() { - const icsData = scheduleToICal(schedule, semester!); - const icsURI = `data:text/calendar;charset=utf8,` + encodeURIComponent(icsData); - - const link = document.createElement('a'); - link.href = icsURI; - link.download = `${schedule.name}.ics`; - link.click(); - } - - const allCourses = getNodes(data.allCourses!); - - return ( - - - - - -
-
- - {saveWidget} -
-
- {accessControl && ( - - )} - -
-
- - -
- ); -}; - -export default ScheduleEditor; diff --git a/frontend/src/components/Scheduler/ScheduleModal.tsx b/frontend/src/components/Scheduler/ScheduleModal.tsx deleted file mode 100644 index c09b1e1e5..000000000 --- a/frontend/src/components/Scheduler/ScheduleModal.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import BTLoader from 'components/Common/BTLoader'; -import { useGetScheduleForIdQuery } from 'graphql'; -import { Modal } from 'react-bootstrap'; -import SchedulerCalendar from './Calendar/SchedulerCalendar'; -import { - deserializeSchedule, - formatScheduleError, - getUnitsForSchedule -} from '../../utils/scheduler/scheduler'; -import { Button } from 'bt/custom'; -import { unitsToString } from 'utils/courses/units'; - -type ContentProps = { - scheduleId: string; -}; -const ScheduleModalContent = ({ scheduleId }: ContentProps) => { - const scheduleUUID = atob(scheduleId).split(':')[1]; - const { data, error } = useGetScheduleForIdQuery({ - variables: { id: scheduleId } - }); - - if (!data?.schedule) { - return ; - } - - const schedule = deserializeSchedule(data.schedule); - const totalUnits = getUnitsForSchedule(schedule); - - return ( -
-
-
- Selected units: {unitsToString(totalUnits)} -
-
- -
-
- -
-
- -
- ); -}; - -type Props = { - scheduleId: string | null; - show: boolean; - handleClose: () => void; -}; - -const ScheduleModal = ({ scheduleId, show, handleClose }: Props) => { - return ( - - {scheduleId && } - - ); -}; - -export default ScheduleModal; diff --git a/frontend/src/components/Scheduler/Selector/LectureCard.tsx b/frontend/src/components/Scheduler/Selector/LectureCard.tsx deleted file mode 100644 index d90d983f2..000000000 --- a/frontend/src/components/Scheduler/Selector/LectureCard.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import { LectureFragment, SchedulerCourseFragment, SectionFragment } from 'graphql'; -import { ChangeEvent, CSSProperties } from 'react'; -import { Form } from 'react-bootstrap'; -import cx from 'classnames'; - -import { hasSectionById, Schedule, SchedulerSectionType } from 'utils/scheduler/scheduler'; -import { formatLocation, formatSectionEnrollment, formatSectionTime } from 'utils/sections/section'; -import { groupSections } from 'utils/sections/sort'; -import { useScheduleContext } from '../ScheduleContext'; -import { combineNodes } from 'utils/string'; - -const MAX_SECTIONS_BEFORE_SCROLL = 8; -const SCROLL_SECTION_HEIGHT = '280px'; - -type SectionProps = { - sections: SectionFragment[]; - course: SchedulerCourseFragment; - lecture: SectionFragment; - isDisabled?: boolean; -}; - -const SectionGroup = ({ sections, course, lecture, isDisabled = false }: SectionProps) => { - const { schedule, setSchedule, setPreviewSection } = useScheduleContext(); - - const shouldScroll = sections.length > MAX_SECTIONS_BEFORE_SCROLL; - - return ( -
-

{sections[0].kind}

-
- {sections.map((section) => { - const currentSection: SchedulerSectionType = { - ...section, - courseId: course.id, - lectureId: lecture.id - }; - - const sectionLabel = ( - - {section.sectionNumber}: - {combineNodes( - [ - section.wordDays, - formatSectionTime(section, false), - formatLocation(section.locationName), - formatSectionEnrollment(section) - ], - ', ' - )}{' '} - • CCN: {section.ccn} - - ); - - function setChecked(event: ChangeEvent) { - const newSchedule: Schedule = { - ...schedule, - sections: schedule.sections.filter((s) => s.id !== section.id) - }; - - // If it's not checked, then we'll check it - if (event.target.checked) { - newSchedule.sections.push(currentSection); - } - - setSchedule(newSchedule); - } - - const checked = hasSectionById(schedule, section.id); - return ( -
setPreviewSection?.(currentSection)} - onMouseLeave={() => setPreviewSection?.(null)} - > - -
- ); - })} -
-
- ); -}; - -type Props = { - section: LectureFragment; - course: SchedulerCourseFragment; - - /** - * User-readable string identifying the section - */ - sectionId?: string; - color: string; -}; - -const LectureCard = ({ section, course, sectionId, color }: Props) => { - const associatedSections = section.associatedSections.edges.map((e) => e?.node!); - - const currentSection: SchedulerSectionType = { - ...section, - courseId: course.id - }; - - // Groups sections [sec1, sec2] into 'discussion, 'lecture', etc. - // and sorts appropriately. - const sectionTypes = groupSections(associatedSections); - - const { schedule, setSchedule, setPreviewSection } = useScheduleContext(); - const checked = hasSectionById(schedule, section.id); - - function setChecked(event: ChangeEvent) { - if (event.target.checked) { - const newSchedule: Schedule = { - ...schedule, - sections: schedule.sections - .filter((s) => s.courseId !== course.id || s.lectureId === section.id) - .concat([currentSection]) - }; - - setSchedule(newSchedule); - } else { - const newSchedule: Schedule = { - ...schedule, - sections: schedule.sections.filter( - (s) => !(s.id === section.id || s.lectureId === section.id) - ) - }; - - setSchedule(newSchedule); - } - } - - return ( -
-
setPreviewSection?.(currentSection)} - onMouseLeave={() => setPreviewSection?.(null)} - > -

- - {section.kind} {sectionId} - - } - id={`${section.id}-check`} - name={`${section.id}-check`} - /> -

-

- {section.instructor ? section.instructor + ` \u{2022} ` : ''} - {section.wordDays}, {formatSectionTime(section)}, {formatLocation(section.locationName)} -

-

- {formatSectionEnrollment(section)} • CCN: {section.ccn} -

-
- {sectionTypes.map(({ category, sections }) => ( - - ))} -
- ); -}; - -export default LectureCard; diff --git a/frontend/src/components/Scheduler/Selector/SchedulerCourse.tsx b/frontend/src/components/Scheduler/Selector/SchedulerCourse.tsx deleted file mode 100644 index 3ff153f67..000000000 --- a/frontend/src/components/Scheduler/Selector/SchedulerCourse.tsx +++ /dev/null @@ -1,126 +0,0 @@ -import { CourseOverviewFragment, useGetSchedulerCourseForIdQuery } from 'graphql'; -import { useState } from 'react'; -import { courseToName } from 'utils/courses/course'; -import { Semester } from 'utils/playlists/semesters'; - -import { ReactComponent as Trash } from '../../../assets/svg/common/trash.svg'; -import LectureCard from './LectureCard'; -import BTLoader from '../../Common/BTLoader'; -import { applyIndicatorPercent } from 'utils/utils'; -import { parseUnits, unitsToString } from 'utils/courses/units'; - -import { ReactComponent as ExpandMore } from '../../../assets/svg/common/expand.svg'; -import { Collapse } from 'react-bootstrap'; -import { getColorForCourse } from 'utils/scheduler/scheduler'; -import { useScheduleContext } from '../ScheduleContext'; -import { getNodes } from 'utils/graphql'; - -type Props = { - courseId: string; - - /** - * If you have (some) course info. Passing this - * parameter will show the info you have so the - * user seems something while waiting for the - * whole component to load - */ - partialCourse?: CourseOverviewFragment; - - semester: Semester; - - /** - * If not passed, no delete button is shown. - */ - didRemove?: () => void; -}; - -const SchedulerCourse = ({ courseId, partialCourse, semester, didRemove }: Props) => { - const { data, loading } = useGetSchedulerCourseForIdQuery({ - variables: { - id: courseId, - year: semester.year, - semester: semester.semester - } - }); - const [isExpanded, setIsExpanded] = useState(false); - const { schedule } = useScheduleContext(); - - const color = getColorForCourse(schedule, courseId); - - return ( -
-
-
-
- {partialCourse ? courseToName(partialCourse) : 'Loading...'} -
- - {didRemove && ( -
- -
- )} -
-
-
- {partialCourse ? partialCourse.title : 'Loading...'} -
- {data && ( -
setIsExpanded(!isExpanded)} - > - -
- )} -
-
-
- {!data?.course ? ( - 'Loading...' - ) : ( - <> - {data.course.enrolled !== -1 && ( - <> - {applyIndicatorPercent( - `${data.course.enrolled}/${data.course.enrolledMax} enrolled`, - data.course.enrolled / data.course.enrolledMax - )}{' '} - •{' '} - - )} - {data.course.units && `${unitsToString(parseUnits(data.course.units))} units`} - - )} -
-
- {!data?.course ? ( -
- {loading ? : "A critical error occured loading this course's data."} -
- ) : ( - -
- {getNodes(data.course.sectionSet) - .filter((section) => !section.disabled) - .map((section, index) => ( - - ))} -
-
- )} -
- ); -}; - -export default SchedulerCourse; diff --git a/frontend/src/components/Time/Time.module.scss b/frontend/src/components/Time/Time.module.scss new file mode 100644 index 000000000..37f0bb009 --- /dev/null +++ b/frontend/src/components/Time/Time.module.scss @@ -0,0 +1,54 @@ +.trigger { + font-size: 14px; + line-height: 1.5; + color: var(--paragraph-color); + width: fit-content; +} + +.content { + border-radius: 4px; + padding: 12px; + background-color: var(--tooltip-color); + animation: fadeIn 100ms ease-in-out forwards; + color: var(--neutral-400); + font-size: 14px; + z-index: 998; + display: flex; + gap: 4px; + opacity: 0; + + .arrow { + fill: var(--tooltip-color); + } + + .day { + width: 24px; + height: 188px; + position: relative; + + .label { + text-align: center; + line-height: 1; + margin-bottom: 4px; + } + + .event { + width: 100%; + border-radius: 1px; + background-color: white; + position: absolute; + left: 0; + } + } + + .divider { + width: 1px; + background-color: var(--neutral-700); + } +} + +@keyframes fadeIn { + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/Time/index.tsx b/frontend/src/components/Time/index.tsx new file mode 100644 index 000000000..8d855475b --- /dev/null +++ b/frontend/src/components/Time/index.tsx @@ -0,0 +1,144 @@ +import { + Fragment, + HTMLAttributes, + forwardRef, + useImperativeHandle, + useMemo, + useRef, +} from "react"; + +import * as Tooltip from "@radix-ui/react-tooltip"; +import classNames from "classnames"; + +import styles from "./Time.module.scss"; + +const getTime = (start: string | null, end: string | null) => { + if (!start || !end) return; + + const [startHours, startMinutes] = start + .split(":") + .map((value) => parseInt(value)); + + const [endHours, endMinutes] = end.split(":").map((value) => parseInt(value)); + + if (startHours === 0) return; + + let time = `${startHours % 12 || 12}`; + if (startMinutes > 0) time += `:${startMinutes.toString().padStart(2, "0")}`; + + time += ` - ${endHours % 12 || 12}`; + if (endMinutes > 0) time += `:${endMinutes.toString().padStart(2, "0")}`; + time += endHours < 12 ? " AM" : " PM"; + + return time; +}; + +interface TimeProps { + days: boolean[] | null; + startTime: string | null; + endTime: string | null; + tooltip?: false; +} + +const Time = forwardRef< + HTMLElement, + TimeProps & HTMLAttributes +>(({ days, startTime, endTime, tooltip, className, ...props }, ref) => { + const rootRef = useRef(null); + + // Explicitly cast the ref to the correct type + useImperativeHandle( + ref, + () => rootRef.current as unknown as HTMLParagraphElement + ); + + // TODO: Use getY with a multiple instead + const bottom = useMemo(() => { + if (!endTime) return; + + const [hours, minutes] = endTime.split(":").map((value) => parseInt(value)); + + return 170 - ((hours - 6) * 10 + minutes / 6); + }, [endTime]); + + // TODO: Use getY with a multiple instead + const height = useMemo(() => { + if (!startTime || !endTime) return; + + const [startHours, startMinutes] = startTime + .split(":") + .map((value) => parseInt(value)); + + const [endHours, endMinutes] = endTime + .split(":") + .map((value) => parseInt(value)); + + return (endHours - startHours) * 10 + (endMinutes - startMinutes) / 6; + }, [startTime, endTime]); + + const value = useMemo(() => { + const time = getTime(startTime, endTime); + + if (!days?.some((day) => day) || !time) return; + + return ( + days + .reduce( + (time, day, index) => + day + ? [...time, ["Su", "M", "Tu", "W", "Th", "F", "Sa"][index]] + : time, + [] as string[] + ) + .join("") + + ", " + + time + ); + }, [days, startTime, endTime]); + + return value ? ( + + +

+ {value} +

+
+ + +
+ + {days!.map((day, index) => ( + + {index > 0 &&
} +
+
+ {["Su", "M", "Tu", "W", "Th", "F", "Sa"][index]} +
+ {day && ( +
+ )} +
+ + ))} +
+ + + + ) : ( +

+ To be determined +

+ ); +}); + +Time.displayName = "Time"; + +export default Time; diff --git a/frontend/src/components/Tooltip/Tooltip.module.scss b/frontend/src/components/Tooltip/Tooltip.module.scss new file mode 100644 index 000000000..5095c4d67 --- /dev/null +++ b/frontend/src/components/Tooltip/Tooltip.module.scss @@ -0,0 +1,27 @@ +.content { + border-radius: 4px; + height: 32px; + padding: 0 12px; + background-color: var(--tooltip-color); + animation: fadeIn 100ms ease-in; + font-size: 14px; + font-weight: 500; + line-height: 1; + color: white; + display: flex; + align-items: center; + z-index: 998; + + .arrow { + fill: var(--tooltip-color); + } +} + +@keyframes fadeIn { + from { + opacity: 0; + } + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/Tooltip/index.tsx b/frontend/src/components/Tooltip/index.tsx new file mode 100644 index 000000000..46dc7344e --- /dev/null +++ b/frontend/src/components/Tooltip/index.tsx @@ -0,0 +1,46 @@ +import { ReactNode } from "react"; + +import { + Arrow, + Content, + Portal, + Root, + TooltipContentProps, + Trigger, +} from "@radix-ui/react-tooltip"; + +import styles from "./Tooltip.module.scss"; + +interface TooltipProps { + children: ReactNode; + content: string; +} + +export default function Tooltip({ + content, + children, + sideOffset = 8, + collisionPadding = 8, + side = "bottom", + ...props +}: TooltipContentProps & Omit) { + return ( + + {children} + + +
+ + {content} +
+
+
+
+ ); +} diff --git a/frontend/src/components/Units/Units.module.scss b/frontend/src/components/Units/Units.module.scss new file mode 100644 index 000000000..f6cd0173d --- /dev/null +++ b/frontend/src/components/Units/Units.module.scss @@ -0,0 +1,5 @@ +.root { + font-size: 14px; + color: var(--paragraph-color); + line-height: 1; +} \ No newline at end of file diff --git a/frontend/src/components/Units/index.tsx b/frontend/src/components/Units/index.tsx new file mode 100644 index 000000000..881b8d103 --- /dev/null +++ b/frontend/src/components/Units/index.tsx @@ -0,0 +1,19 @@ +import { ReactNode, useMemo } from "react"; + +import styles from "./Units.module.scss"; + +interface UnitsProps { + unitsMin: number; + unitsMax: number; + children?: (units: string) => ReactNode; +} + +export default function Units({ unitsMin, unitsMax, children }: UnitsProps) { + const units = useMemo(() => { + return unitsMax === unitsMin + ? `${unitsMin} ${unitsMin === 1 ? "unit" : "units"}` + : `${unitsMin} - ${unitsMax} units`; + }, [unitsMax, unitsMin]); + + return children ? children(units) :

{units}

; +} diff --git a/frontend/src/components/Week/Event/Event.module.scss b/frontend/src/components/Week/Event/Event.module.scss new file mode 100644 index 000000000..fbb8078f9 --- /dev/null +++ b/frontend/src/components/Week/Event/Event.module.scss @@ -0,0 +1,50 @@ +.trigger { + position: absolute; + z-index: 2; + padding: 8px; + border-radius: 4px; + background-color: var(--blue-500); + font-size: 12px; + opacity: 0.5; + + &.active { + opacity: 1; + } + + .heading { + font-weight: 500; + color: white; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } + + .description { + margin-top: 4px; + color: rgb(255 255 255 / 75%); + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + } +} + +.content { + height: 128px; + width: 320px; + background-color: var(--foreground-color); + border-radius: 8px; + box-shadow: 0 0 16px rgb(0 0 0 / 10%); + z-index: 989; + opacity: 0; + animation: fadeIn 100ms ease-in-out forwards; + + .arrow { + fill: var(--foreground-color); + } +} + +@keyframes fadeIn { + to { + opacity: 1; + } +} \ No newline at end of file diff --git a/frontend/src/components/Week/Event/index.tsx b/frontend/src/components/Week/Event/index.tsx new file mode 100644 index 000000000..51a09277e --- /dev/null +++ b/frontend/src/components/Week/Event/index.tsx @@ -0,0 +1,62 @@ +import { useMemo } from "react"; + +import * as HoverCard from "@radix-ui/react-hover-card"; +import classNames from "classnames"; + +import { ISection, components } from "@/lib/api"; +import { getY } from "@/lib/schedule"; +import { getColor } from "@/lib/section"; + +import styles from "./Event.module.scss"; + +interface EventProps { + columns: number; + position: number; + active: boolean; +} + +export default function Event({ + columns, + position, + meetings: [{ startTime, endTime }], + course, + component, + number, + active, +}: EventProps & ISection) { + const top = useMemo(() => getY(startTime!), [startTime]); + + const height = useMemo(() => getY(endTime!) - top + 1, [top, endTime]); + + // TODO: Hover card content + return ( + + +
+
+ {course.subject} {course.number} +
+
+ {components[component]} {number} +
+
+
+ + +
+ +
+
+
+
+ ); +} diff --git a/frontend/src/components/Week/Week.module.scss b/frontend/src/components/Week/Week.module.scss new file mode 100644 index 000000000..c2e2f53e1 --- /dev/null +++ b/frontend/src/components/Week/Week.module.scss @@ -0,0 +1,124 @@ +.root { + display: flex; + flex-direction: column; + background-color: var(--background-color); + min-width: 1080px; + + .header { + display: flex; + border-bottom: 1px solid var(--border-color); + position: sticky; + top: 0; + background-color: var(--background-color); + font-size: 12px; + color: var(--label-color); + line-height: 1; + height: 32px; + z-index: 2; + + .timeZone { + width: 64px; + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0 12px; + border-right: 1px solid var(--border-color); + background-color: var(--background-color); + position: sticky; + left: 0; + } + + .week { + display: grid; + grid-template-columns: repeat(7, 1fr); + flex-grow: 1; + + .day { + display: flex; + align-items: center; + justify-content: center; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + } + } + } + + .view { + display: flex; + z-index: 1; + + .week { + flex-grow: 1; + display: grid; + z-index: 1; + grid-template-columns: repeat(7, 1fr); + + .day { + position: relative; + + &:not(:last-child) { + border-right: 1px solid var(--border-color); + } + + .line { + position: absolute; + z-index: 1; + left: -1px; + width: calc(100% + 1px); + height: 1px; + background-color: var(--red-500); + } + + .hour { + height: 60px; + display: flex; + align-items: center; + justify-content: center; + + &:not(:first-child) { + border-top: 1px solid var(--border-color); + } + } + } + } + + .sideBar { + flex-shrink: 0; + width: 64px; + display: flex; + flex-direction: column; + position: sticky; + left: 0; + z-index: 2; + background-color: var(--background-color); + border-right: 1px solid var(--border-color); + + .time { + position: absolute; + z-index: 1; + height: 24px; + display: flex; + align-items: center; + padding: 0 12px; + font-size: 12px; + color: white; + line-height: 1; + border-radius: 4px; + right: 0; + background-color: var(--red-500); + } + + .hour { + height: 0; + margin-top: 60px; + padding: 0 12px; + font-size: 12px; + color: var(--label-color); + text-align: right; + transform: translateY(-6px); + } + } + } +} \ No newline at end of file diff --git a/frontend/src/components/Week/index.tsx b/frontend/src/components/Week/index.tsx new file mode 100644 index 000000000..cfe31e818 --- /dev/null +++ b/frontend/src/components/Week/index.tsx @@ -0,0 +1,225 @@ +import { MouseEvent, useMemo, useRef, useState } from "react"; + +import { IClass, ISection } from "@/lib/api"; +import { getY } from "@/lib/schedule"; + +import Event from "./Event"; +import styles from "./Week.module.scss"; + +// You have to trust me on this math +const adjustAttachedEvents = ( + relevantSections: ISection[], + attachedSections: string[], + minutes: string[][], + positions: Record +) => { + const adjustedSections: string[] = []; + + const adjustSection = (id: string) => { + if (adjustedSections.includes(id)) return; + + adjustedSections.push(id); + + positions[id][1]++; + + const section = relevantSections.find((section) => id === section.ccn); + if (!section) return; + + const top = getY(section.meetings[0].startTime); + const height = getY(section.meetings[0].endTime) - top; + + for (let i = top; i < top + height; i++) { + for (const id of minutes[i]) { + adjustSection(id); + } + } + }; + + for (const id of attachedSections) { + adjustSection(id); + } +}; + +interface WeekProps { + selectedSections: ISection[]; + currentSection?: ISection | null; + y?: number | null; + updateY?: (y: number | null) => void; + classes?: IClass[]; +} + +export default function Week({ + selectedSections, + currentSection, + y: remoteY, + updateY: updateRemoteY, +}: WeekProps) { + const viewRef = useRef(null); + const [localY, setLocalY] = useState(null); + + const y = useMemo(() => localY ?? remoteY, [localY, remoteY]); + + const updateLocalY = (y: number | null) => { + setLocalY(y); + updateRemoteY?.(y); + }; + + const sections = useMemo( + () => + currentSection ? [...selectedSections, currentSection] : selectedSections, + [selectedSections, currentSection] + ); + + const days = useMemo( + () => + [...Array(7)].map((_, day) => { + const positions: Record = {}; + const minutes: string[][] = [...Array(60 * 18)].map(() => []); + + const relevantSections = sections + // Filter sections for the current day which have a time specified + .filter( + (section) => + section.meetings[0].days[day] && + section.meetings[0].startTime && + getY(section.meetings[0].startTime) > 0 + ) + // Sort sections by when they start + .sort( + (a, b) => + getY(a.meetings[0].startTime) - getY(b.meetings[0].startTime) + ); + + // Maintain an array of sections that are attached to each minute + for (const section of relevantSections) { + const top = getY(section.meetings[0].startTime); + const height = getY(section.meetings[0].endTime) - top; + + const attachedSections = minutes[top]; + + let position = 0; + + while ( + attachedSections.findIndex( + (eventId) => positions[eventId][0] === position + ) !== -1 + ) { + position++; + } + + if ( + attachedSections.length > 0 && + Math.max( + position, + ...attachedSections.map((eventId) => positions[eventId][0]) + ) === position + ) { + adjustAttachedEvents( + relevantSections, + attachedSections, + minutes, + positions + ); + } + + positions[section.ccn] = [ + position, + attachedSections.length === 0 + ? 1 + : positions[attachedSections[0]][1], + ]; + + for (let i = top; i < top + height; i++) { + minutes[i].push(section.ccn); + } + } + + return relevantSections.map((section) => { + const [position, columns] = positions[section.ccn]; + + return { + ...section, + position, + active: section.ccn !== currentSection?.ccn, + columns, + }; + }); + }), + [sections, currentSection] + ); + + const currentTime = useMemo(() => { + if (!viewRef.current || !y) return; + + const hour = (Math.floor(y / 60) + 6) % 12 || 12; + const minute = Math.floor(y % 60); + + return `${hour}:${minute < 10 ? `0${minute}` : minute}`; + }, [y]); + + const updateY = (event: MouseEvent) => { + if (!viewRef.current) return; + + const y = Math.max( + 15, + Math.min( + event.clientY - viewRef.current.getBoundingClientRect().top, + viewRef.current.clientHeight - 15 + ) + ); + + updateLocalY(y); + }; + + return ( +
+
+
PST
+
+
Sunday
+
Monday
+
Tuesday
+
Wednesday
+
Thursday
+
Friday
+
Saturday
+
+
+
updateLocalY(null)} + > +
+ {currentTime && y && ( +
+ {currentTime} +
+ )} + {[...Array(17)].map((_, hour) => ( +
+ {hour + 7 < 12 + ? `${hour + 7} AM` + : `${hour + 7 === 12 ? 12 : hour - 5} PM`} +
+ ))} +
+
+ {days.map((events, day) => ( +
+ {[...Array(18)].map((_, hour) => ( +
+ ))} + {events.map((event) => ( + + ))} + {y &&
} +
+ ))} +
+
+
+ ); +} diff --git a/frontend/src/graphql/cache.ts b/frontend/src/graphql/cache.ts deleted file mode 100644 index a167de129..000000000 --- a/frontend/src/graphql/cache.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { InMemoryCache } from '@apollo/client'; - -const cache = new InMemoryCache({ - typePolicies: { - BerkeleytimeUserType: { - fields: { - schedules: { - merge(_existing = [], incoming: any[]) { - return incoming; - } - } - } - } - } -}); - -export { cache }; diff --git a/frontend/src/graphql/client.ts b/frontend/src/graphql/client.ts deleted file mode 100644 index 9fd0a60a3..000000000 --- a/frontend/src/graphql/client.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ApolloClient, HttpLink } from '@apollo/client'; -import { cache } from './cache'; - -const httpLink = new HttpLink({ - uri: '/api/graphql' -}); - -// Explore ways to transform API responses before reaching the components -// to minimize the amount of edge -> node drilling. - -// const transformRepsonseLink = new ApolloLink((operation, forward) => { -// return forward(operation).map((response) => { -// if (response.data) { -// const { data } = response; -// const keys = Object.keys(data); - -// keys.map((key) => { -// if (data[key]['edges']) { -// if (Array.isArray(data[key]['edges'])) { -// data[key] = data[key]['edges'].map((edge) => edge.node); -// } -// } -// }); -// } -// return response; -// }); -// }); - -const client = new ApolloClient({ - link: httpLink, - cache: cache -}); - -export default client; diff --git a/frontend/src/graphql/fragments/Course.graphql b/frontend/src/graphql/fragments/Course.graphql deleted file mode 100644 index 124ada74c..000000000 --- a/frontend/src/graphql/fragments/Course.graphql +++ /dev/null @@ -1,40 +0,0 @@ -fragment Course on CourseType { - title - units - waitlisted - openSeats - letterAverage - gradeAverage - lastUpdated - id - hasEnrollment - gradeAverage - enrolledPercentage - enrolledMax - courseNumber - department - description - enrolled - abbreviation - prerequisites - - playlistSet { - edges { - node { - category - id - name - semester - year - } - } - } - - sectionSet(year: $year, semester: $semester) { - edges { - node { - ...Section - } - } - } -} diff --git a/frontend/src/graphql/fragments/CourseOverview.graphql b/frontend/src/graphql/fragments/CourseOverview.graphql deleted file mode 100644 index 0084ef966..000000000 --- a/frontend/src/graphql/fragments/CourseOverview.graphql +++ /dev/null @@ -1,14 +0,0 @@ -fragment CourseOverview on CourseType { - id - abbreviation - courseNumber - description - title - gradeAverage - letterAverage - openSeats - enrolledPercentage - enrolled - enrolledMax - units -} diff --git a/frontend/src/graphql/fragments/Filter.graphql b/frontend/src/graphql/fragments/Filter.graphql deleted file mode 100644 index f3513a46c..000000000 --- a/frontend/src/graphql/fragments/Filter.graphql +++ /dev/null @@ -1,5 +0,0 @@ -fragment Filter on PlaylistType { - id - name - category -} diff --git a/frontend/src/graphql/fragments/Lecture.graphql b/frontend/src/graphql/fragments/Lecture.graphql deleted file mode 100644 index 27f2ca627..000000000 --- a/frontend/src/graphql/fragments/Lecture.graphql +++ /dev/null @@ -1,10 +0,0 @@ -fragment Lecture on SectionType { - ...Section - associatedSections { - edges { - node { - ...Section - } - } - } -} diff --git a/frontend/src/graphql/fragments/Schedule.graphql b/frontend/src/graphql/fragments/Schedule.graphql deleted file mode 100644 index 40c62fd42..000000000 --- a/frontend/src/graphql/fragments/Schedule.graphql +++ /dev/null @@ -1,26 +0,0 @@ -fragment Schedule on ScheduleType { - id - year - semester - name - totalUnits - dateCreated - dateModified - public - - user { - user { - id - firstName - lastName - } - } - - selectedSections { - edges { - node { - ...SectionSelection - } - } - } -} diff --git a/frontend/src/graphql/fragments/ScheduleOverview.graphql b/frontend/src/graphql/fragments/ScheduleOverview.graphql deleted file mode 100644 index 6339ada29..000000000 --- a/frontend/src/graphql/fragments/ScheduleOverview.graphql +++ /dev/null @@ -1,24 +0,0 @@ -fragment ScheduleOverview on ScheduleType { - id - year - semester - name - totalUnits - dateCreated - dateModified - - selectedSections { - edges { - node { - course { - abbreviation - courseNumber - - # Get the number of units and compute it ourselves - # bc can't trust backend - units - } - } - } - } -} diff --git a/frontend/src/graphql/fragments/SchedulerCourse.graphql b/frontend/src/graphql/fragments/SchedulerCourse.graphql deleted file mode 100644 index 258dfbd56..000000000 --- a/frontend/src/graphql/fragments/SchedulerCourse.graphql +++ /dev/null @@ -1,21 +0,0 @@ -fragment SchedulerCourse on CourseType { - id - title - units - waitlisted - openSeats - enrolled - enrolledMax - courseNumber - department - description - abbreviation - - sectionSet(isPrimary: true, year: $year, semester: $semester) { - edges { - node { - ...Lecture - } - } - } -} diff --git a/frontend/src/graphql/fragments/Section.graphql b/frontend/src/graphql/fragments/Section.graphql deleted file mode 100644 index b6f833645..000000000 --- a/frontend/src/graphql/fragments/Section.graphql +++ /dev/null @@ -1,18 +0,0 @@ -fragment Section on SectionType { - id - ccn - kind - instructor - startTime - endTime - enrolled - enrolledMax - locationName - waitlisted - waitlistedMax - days - wordDays - disabled - sectionNumber - isPrimary -} diff --git a/frontend/src/graphql/fragments/SectionSelection.graphql b/frontend/src/graphql/fragments/SectionSelection.graphql deleted file mode 100644 index c4761d89e..000000000 --- a/frontend/src/graphql/fragments/SectionSelection.graphql +++ /dev/null @@ -1,19 +0,0 @@ -fragment SectionSelection on SectionSelectionType { - id - - course { - ...CourseOverview - } - - primary { - ...Section - } - - secondary { - edges { - node { - ...Section - } - } - } -} diff --git a/frontend/src/graphql/fragments/UserProfile.graphql b/frontend/src/graphql/fragments/UserProfile.graphql deleted file mode 100644 index ffbbdfa2e..000000000 --- a/frontend/src/graphql/fragments/UserProfile.graphql +++ /dev/null @@ -1,32 +0,0 @@ -fragment UserProfile on BerkeleytimeUserType { - # Basic user information - id - major - user { - id - username - firstName - lastName - email - } - - # Notification fields - emailClassUpdate - emailGradeUpdate - emailEnrollmentOpening - emailBerkeleytimeUpdate - - # Saved classes - savedClasses { - ...CourseOverview - } - - # Schedule - schedules { - edges { - node { - ...ScheduleOverview - } - } - } -} diff --git a/frontend/src/graphql/hooks/graphql.ts b/frontend/src/graphql/hooks/graphql.ts deleted file mode 100644 index 0de39f16a..000000000 --- a/frontend/src/graphql/hooks/graphql.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { - FetchResult, - LazyQueryHookOptions, - LazyQueryResult, - MutationHookOptions, - MutationResult, - MutationTuple, - QueryTuple, - OperationVariables -} from '@apollo/client'; -import { useCallback } from 'react'; - -/** - * Wraps mutation in a custom hook - */ -export const wrapMutation = - ( - mutation: ( - options?: MutationHookOptions - ) => MutationTuple, - callback: (...params: HookParameters) => MutationHookOptions - ) => - ( - options?: MutationHookOptions - ): [(...params: HookParameters) => Promise>, MutationResult] => { - const [m, fetchResult] = mutation(options); - // eslint-disable-next-line react-hooks/rules-of-hooks - const mutationRunner = useCallback((...params: HookParameters) => m(callback(...params)), [m]); - return [mutationRunner, fetchResult]; - }; - -/** - * Wraps mutation in a custom hook - */ -export const wrapLazyQuery = - < - LazyQuery extends unknown, - LazyQueryVariables extends OperationVariables, - HookParameters extends any[] - >( - lazyQuery: ( - options?: LazyQueryHookOptions - ) => QueryTuple, - callback: (...params: HookParameters) => LazyQueryHookOptions - ) => - ( - options?: LazyQueryHookOptions - ): [(...params: HookParameters) => void, LazyQueryResult] => { - const [m, fetchResult] = lazyQuery(options); - // eslint-disable-next-line react-hooks/rules-of-hooks - const queryRunner = useCallback((...params: HookParameters) => m(callback(...params)), [m]); - return [queryRunner, fetchResult]; - }; diff --git a/frontend/src/graphql/hooks/latestSemester.ts b/frontend/src/graphql/hooks/latestSemester.ts deleted file mode 100644 index 4ae812ca0..000000000 --- a/frontend/src/graphql/hooks/latestSemester.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { useGetSemestersQuery } from 'graphql'; -import { getLatestSemester, SemesterWithPlaylist } from 'utils/playlists/semesters'; -import { useState } from 'react'; -import { ApolloError } from '@apollo/client'; - -const useLatestSemester = (): { - semester: SemesterWithPlaylist | null; - loading: boolean; - error: ApolloError | undefined; -} => { - const [latestSemester, setLatestSemester] = useState(null); - - const { loading, error } = useGetSemestersQuery({ - onCompleted: (data) => { - const allPlaylists = data?.allPlaylists.edges.map((edge) => edge.node); - setLatestSemester(getLatestSemester(allPlaylists)); - } - }); - - return { semester: latestSemester, loading, error }; -}; - -export default useLatestSemester; diff --git a/frontend/src/graphql/hooks/saveCourse.ts b/frontend/src/graphql/hooks/saveCourse.ts deleted file mode 100644 index dca2cb47a..000000000 --- a/frontend/src/graphql/hooks/saveCourse.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { CourseOverviewFragment, useSaveCourseMutation, useUnsaveCourseMutation } from 'graphql'; -import { useCallback } from 'react'; -import { useUser } from './user'; - -/** - * Saves a course optimistically - */ -export const useSaveCourse = () => { - const { user } = useUser(); - const [saveCourse] = useSaveCourseMutation(); - return useCallback( - (course: CourseOverviewFragment) => - saveCourse({ - variables: { courseId: course.id }, - optimisticResponse: { - __typename: 'Mutation', - saveClass: user && { - __typename: 'SaveClass', - user: { - __typename: 'BerkeleytimeUserType', - id: user.id, - savedClasses: (user.savedClasses || []) - .filter((c) => c?.id !== course.id) - .concat([course]) - } - } - } - }), - [user, saveCourse] - ); -}; - -/** - * Unsaves a course optimistically - */ -export const useUnsaveCourse = () => { - const { user } = useUser(); - const [unsaveCourse] = useUnsaveCourseMutation(); - return useCallback( - (course: CourseOverviewFragment) => - unsaveCourse({ - variables: { courseId: course.id }, - optimisticResponse: { - __typename: 'Mutation', - removeClass: user && { - __typename: 'RemoveClass', - user: { - __typename: 'BerkeleytimeUserType', - id: user.id, - savedClasses: (user.savedClasses || []).filter((c) => c?.id !== course.id) - } - } - } - }), - [user, unsaveCourse] - ); -}; diff --git a/frontend/src/graphql/hooks/schedule.ts b/frontend/src/graphql/hooks/schedule.ts deleted file mode 100644 index 4c5990cc3..000000000 --- a/frontend/src/graphql/hooks/schedule.ts +++ /dev/null @@ -1,96 +0,0 @@ -import { Semester } from 'utils/playlists/semesters'; -import { Schedule, serializeSchedule } from 'utils/scheduler/scheduler'; -import { - DeleteScheduleMutationOptions, - GetUserDocument, - GetUserQuery, - GetUserQueryVariables, - ScheduleOverviewFragment, - useCreateScheduleMutation, - useDeleteScheduleMutation -} from 'graphql'; -import { wrapMutation } from './graphql'; - -/** - * This will create a NEW schedule. Do not use this - * to update a schedule. - */ -export const useCreateSchedule = wrapMutation( - useCreateScheduleMutation, - // @ts-ignore - (schedule: Schedule, semester: Semester) => ({ - variables: serializeSchedule(schedule, semester), - update(cache, { data }) { - const existingUser = cache.readQuery({ - query: GetUserDocument - }); - - if (existingUser?.user) { - cache.writeQuery({ - query: GetUserDocument, - data: { - user: { - ...existingUser.user, - schedules: { - edges: [ - ...existingUser.user.schedules.edges, - { - __typename: 'ScheduleTypeEdge', - node: data?.createSchedule?.schedule - } - ] - } - } - } - }); - } - } - }) -); - -/** - * Use this hook to delete a schedule. You may pass - * either the schedule GraphQL fragment or the - * schedule id. - */ -export const useDeleteSchedule = wrapMutation( - useDeleteScheduleMutation, - (schedule: ScheduleOverviewFragment | string, options?: DeleteScheduleMutationOptions) => { - const scheduleId = typeof schedule === 'string' ? schedule : schedule.id; - - return { - ...options, - variables: { - id: scheduleId - }, - optimisticResponse: { - removeSchedule: { - schedule: { - id: scheduleId - } - } - }, - update(cache) { - const existingUser = cache.readQuery({ - query: GetUserDocument - }); - - if (existingUser?.user) { - cache.writeQuery({ - query: GetUserDocument, - data: { - user: { - ...existingUser.user, - schedules: { - edges: existingUser.user.schedules.edges.filter( - (edge) => edge?.node?.id !== scheduleId - ) - } - } - } - }); - } - } - }; - } -); diff --git a/frontend/src/graphql/hooks/semester.ts b/frontend/src/graphql/hooks/semester.ts deleted file mode 100644 index 51aaede62..000000000 --- a/frontend/src/graphql/hooks/semester.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { useGetSemestersQuery } from 'graphql'; -import { ApolloError } from '@apollo/client'; -import { getNodes } from 'utils/graphql'; -import { - getLatestSemester, - Semester, - semesterToString, - SemesterWithPlaylist -} from 'utils/playlists/semesters'; - -/** - * Gets the latest semester or a populated semester. Does not run a query if the - * semester is already populated. - * @param semester - If passed a semester, get's this semester with the added playlistId. - */ -export const useSemester = ( - semester?: Semester -): { - semester: SemesterWithPlaylist | null; - loading: boolean; - error: ApolloError | undefined; -} => { - const { data, loading, error } = useGetSemestersQuery({ - variables: { - name: semester && semesterToString(semester) - }, - skip: !!semester?.playlistId - }); - - let latestSemester: SemesterWithPlaylist | null = null; - - if (semester?.playlistId) { - latestSemester = semester as SemesterWithPlaylist; - } else if (data?.allPlaylists && data.allPlaylists.edges.length >= 1) { - latestSemester = getLatestSemester(getNodes(data.allPlaylists)); - } - - // Overriding the latest semester because the dev db has data from 2020 - if (process.env.NODE_ENV === 'development' && latestSemester) { - latestSemester.semester = 'fall'; - latestSemester.year = '2020'; - } - - return { semester: latestSemester, loading, error }; -}; diff --git a/frontend/src/graphql/hooks/user.ts b/frontend/src/graphql/hooks/user.ts deleted file mode 100644 index 618ac63a8..000000000 --- a/frontend/src/graphql/hooks/user.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { useCallback } from 'react'; -import { getNodes } from 'utils/graphql'; -import { - DeleteUserMutationHookResult, - GetUserDocument, - GetUserQuery, - GetUserQueryVariables, - LoginMutationHookResult, - LogoutMutationHookResult, - UpdateUserMutationVariables, - useDeleteUserMutation, - useGetUserQuery, - useLoginMutation, - useLogoutMutation, - UserProfileFragment, - useUpdateUserMutation -} from 'graphql'; - -type UserInfo = { - /** - * This may change once the user query is loaded. This will - * be false while the user's login state is undetermined. - */ - isLoggedIn: boolean; - loading: boolean; - /** This is null while loading, or if the user isn't logged in. */ - user: UserProfileFragment | null; -}; - -/** - * Gets the current user or the login status. Note that the - * `isLoggedIn` parameter and `user` parameter will be - * `false` and `null` respectively while the user's authorization - * is unknown/loading. You can check this using the `loading` param. - * - * @example - * const { user, isLoggedIn, loading } = useUser(); - */ -export const useUser = (): UserInfo => { - const { data, loading } = useGetUserQuery({ - errorPolicy: 'all' - }); - - return { - isLoggedIn: !!data?.user, - loading, - user: data?.user ?? null - }; -}; - -/** - * Returns a function which logs in the user - */ -export const useLogin = (): LoginMutationHookResult => { - return useLoginMutation({ - update(cache, { data }) { - const user = data?.login?.user; - cache.writeQuery({ - query: GetUserDocument, - data: { user } - }); - } - }); -}; - -/** - * Returns a function which logs out - */ -export const useLogout = (): LogoutMutationHookResult => { - return useLogoutMutation({ - update(cache) { - const existingUser = cache.readQuery({ - query: GetUserDocument - }); - - // Ensure there is no user in the cache after a log out - cache.writeQuery({ - query: GetUserDocument, - data: { - user: null - } - }); - - // Invalidate all the schedules for the user (if they are private) - if (existingUser?.user) { - getNodes(existingUser.user.schedules).forEach((schedule) => - cache.modify({ - id: cache.identify(schedule), - fields(_fieldValue, details) { - return details.DELETE; - } - }) - ); - } - } - }); -}; - -/** - * Deletes the user, so logically, be careful with this and display some - * confirmation prompt before executing. - */ -export const useDeleteUser = (): DeleteUserMutationHookResult => { - return useDeleteUserMutation({ - update(cache) { - // Ensure there is no user in the cache after a log out - cache.writeQuery({ - query: GetUserDocument, - data: { - user: null - } - }); - } - }); -}; - -/** - * Returns a function for which you can pass a user, and the properties of the - * user which you wish to update, and it'll run an optimistically updated - * mutation. - */ -export const useUpdateUser = () => { - const [updateUser] = useUpdateUserMutation(); - const optimisticUpdateUser = useCallback( - (user: UserProfileFragment, variables: UpdateUserMutationVariables) => - updateUser({ - variables: variables, - optimisticResponse: { - __typename: 'Mutation', - updateUser: { - __typename: 'UpdateUser', - user: { - ...user, - ...Object.fromEntries(Object.entries(variables).filter(([k, v]) => v !== null)) - } - } - } - }), - [updateUser] - ); - - return optimisticUpdateUser; -}; diff --git a/frontend/src/graphql/index.ts b/frontend/src/graphql/index.ts deleted file mode 100644 index 88e35e565..000000000 --- a/frontend/src/graphql/index.ts +++ /dev/null @@ -1,1968 +0,0 @@ -/* eslint-disable */ /** - * - * THIS FILE IS AUTOGENERATED, DO NOT EDIT IT! - * - * instead, edit one of the `.graphql` files in this project and run - * - * npm run graphql-codegen - * - * for this file to be re-created - */ - -import { gql } from '@apollo/client'; -import * as Apollo from '@apollo/client'; -export type Maybe = T; -export type InputMaybe = T; -export type Exact = { [K in keyof T]: T[K] }; -export type MakeOptional = Omit & { [SubKey in K]?: Maybe }; -export type MakeMaybe = Omit & { [SubKey in K]: Maybe }; -const defaultOptions = {} as const; -/** All built-in and custom scalars, mapped to their actual values */ -export type Scalars = { - ID: string; - String: string; - Boolean: boolean; - Int: number; - Float: number; - /** - * The `Date` scalar type represents a Date - * value as specified by - * [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - */ - Date: unknown; - /** - * The `DateTime` scalar type represents a DateTime - * value as specified by - * [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - */ - DateTime: unknown; - /** - * The `GenericScalar` scalar type represents a generic - * GraphQL scalar value that could be: - * String, Boolean, Int, Float, List or Object. - */ - GenericScalar: unknown; - /** - * Allows use of a JSON String for input / output from the GraphQL schema. - * - * Use of this type is *not recommended* as you lose the benefits of having a defined, static - * schema (one of the key benefits of GraphQL). - */ - JSONString: unknown; - /** - * The `Time` scalar type represents a Time value as - * specified by - * [iso8601](https://en.wikipedia.org/wiki/ISO_8601). - */ - Time: unknown; -}; - -export type BerkeleytimeUserType = { - __typename: 'BerkeleytimeUserType'; - emailBerkeleytimeUpdate: Maybe; - emailClassUpdate: Maybe; - emailEnrollmentOpening: Maybe; - emailGradeUpdate: Maybe; - id: Scalars['ID']; - major: Scalars['String']; - savedClasses: Maybe>>; - schedules: ScheduleTypeConnection; - user: UserType; -}; - - -export type BerkeleytimeUserTypeSchedulesArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - -export type CourseType = Node & { - __typename: 'CourseType'; - abbreviation: Scalars['String']; - berkeleytimeuserSet: Array; - courseNumber: Scalars['String']; - crossListing: CourseTypeConnection; - department: Scalars['String']; - description: Scalars['String']; - enrolled: Scalars['Int']; - enrolledMax: Scalars['Int']; - enrolledPercentage: Scalars['Float']; - gradeAverage: Maybe; - gradeSet: GradeTypeConnection; - hasEnrollment: Scalars['Boolean']; - /** The ID of the object. */ - id: Scalars['ID']; - lastUpdated: Scalars['DateTime']; - letterAverage: Scalars['String']; - openSeats: Scalars['Int']; - playlistSet: PlaylistTypeConnection; - prerequisites: Scalars['String']; - schedulerSections: SectionSelectionTypeConnection; - sectionSet: SectionTypeConnection; - title: Scalars['String']; - units: Maybe; - waitlisted: Scalars['Int']; -}; - - -export type CourseTypeCrossListingArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - before: InputMaybe; - courseNumber: InputMaybe; - crossListing: InputMaybe>>; - department: InputMaybe; - description: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - enrolledPercentage: InputMaybe; - first: InputMaybe; - gradeAverage: InputMaybe; - hasEnrollment: InputMaybe; - hasGrades: InputMaybe; - idIn: InputMaybe; - inPlaylists: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - letterAverage: InputMaybe; - openSeats: InputMaybe; - prerequisites: InputMaybe; - title: InputMaybe; - units: InputMaybe; - waitlisted: InputMaybe; -}; - - -export type CourseTypeGradeSetArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - average: InputMaybe; - before: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - first: InputMaybe; - gradedTotal: InputMaybe; - instructor: InputMaybe; - last: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - year: InputMaybe; -}; - - -export type CourseTypePlaylistSetArgs = { - after: InputMaybe; - before: InputMaybe; - category: InputMaybe; - courses: InputMaybe>>; - first: InputMaybe; - last: InputMaybe; - name: InputMaybe; - semester: InputMaybe; - year: InputMaybe; -}; - - -export type CourseTypeSchedulerSectionsArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - - -export type CourseTypeSectionSetArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - associatedSections: InputMaybe>>; - before: InputMaybe; - ccn: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - courseTitle: InputMaybe; - days: InputMaybe; - disabled: InputMaybe; - endTime: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - finalDay: InputMaybe; - finalEnd: InputMaybe; - finalStart: InputMaybe; - first: InputMaybe; - instructionMode: InputMaybe; - instructor: InputMaybe; - isPrimary: InputMaybe; - kind: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - locationName: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - startTime: InputMaybe; - waitlisted: InputMaybe; - waitlistedMax: InputMaybe; - year: InputMaybe; -}; - -export type CourseTypeConnection = { - __typename: 'CourseTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `CourseType` and its cursor. */ -export type CourseTypeEdge = { - __typename: 'CourseTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type CreateSchedule = { - __typename: 'CreateSchedule'; - schedule: Maybe; -}; - -export type DeleteUser = { - __typename: 'DeleteUser'; - success: Maybe; -}; - -/** - * Proxy for enrollment object. Using this instead of - * a DjangoObjectType gives us higher flexibility of the data. - */ -export type EnrollmentData = { - __typename: 'EnrollmentData'; - dateCreated: Maybe; - day: Maybe; - enrolled: Maybe; - enrolledMax: Maybe; - enrolledPercent: Maybe; - waitlisted: Maybe; - waitlistedMax: Maybe; - waitlistedPercent: Maybe; -}; - -/** The return format of both queries */ -export type EnrollmentInfo = { - __typename: 'EnrollmentInfo'; - course: Maybe; - data: Maybe>>; - enrolledMax: Maybe; - enrolledPercentMax: Maybe; - enrolledScaleMax: Maybe; - section: Maybe>>; - telebears: Maybe; - waitlistedMax: Maybe; - waitlistedPercentMax: Maybe; - waitlistedScaleMax: Maybe; -}; - -export type FormConfigType = { - __typename: 'FormConfigType'; - field: Maybe; -}; - -export type GradeType = Node & { - __typename: 'GradeType'; - abbreviation: Scalars['String']; - average: Scalars['Float']; - course: CourseType; - courseNumber: Scalars['String']; - denominator: Maybe; - distribution: Maybe>>; - gradedTotal: Scalars['Int']; - /** The ID of the object. */ - id: Scalars['ID']; - instructor: Scalars['String']; - instructors: Array; - sectionGpa: Maybe; - sectionLetter: Maybe; - sectionNumber: Scalars['String']; - semester: Scalars['String']; - year: Scalars['String']; -}; - -export type GradeTypeConnection = { - __typename: 'GradeTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `GradeType` and its cursor. */ -export type GradeTypeEdge = { - __typename: 'GradeTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type LetterGradeType = { - __typename: 'LetterGradeType'; - letter: Maybe; - numerator: Maybe; - percent: Maybe; - percentileHigh: Maybe; - percentileLow: Maybe; -}; - -export type Logout = { - __typename: 'Logout'; - success: Maybe; -}; - -export type Mutation = { - __typename: 'Mutation'; - createSchedule: Maybe; - deleteUser: Maybe; - /** Login mutation using graphql_jwt */ - login: Maybe; - logout: Maybe; - refreshToken: Maybe; - removeClass: Maybe; - removeSchedule: Maybe; - saveClass: Maybe; - updateSchedule: Maybe; - updateUser: Maybe; - verifyToken: Maybe; -}; - - -export type MutationCreateScheduleArgs = { - name: InputMaybe; - public?: InputMaybe; - selectedSections: InputMaybe>>; - semester: InputMaybe; - timeblocks: InputMaybe>>; - totalUnits: InputMaybe; - year: InputMaybe; -}; - - -export type MutationLoginArgs = { - tokenId: InputMaybe; -}; - - -export type MutationRefreshTokenArgs = { - token: InputMaybe; -}; - - -export type MutationRemoveClassArgs = { - classId: InputMaybe; -}; - - -export type MutationRemoveScheduleArgs = { - scheduleId: InputMaybe; -}; - - -export type MutationSaveClassArgs = { - classId: InputMaybe; -}; - - -export type MutationUpdateScheduleArgs = { - name: InputMaybe; - public: InputMaybe; - scheduleId: InputMaybe; - selectedSections: InputMaybe>>; - timeblocks: InputMaybe>>; - totalUnits: InputMaybe; -}; - - -export type MutationUpdateUserArgs = { - emailBerkeleytimeUpdate: InputMaybe; - emailClassUpdate: InputMaybe; - emailEnrollmentOpening: InputMaybe; - emailGradeUpdate: InputMaybe; - major: InputMaybe; -}; - - -export type MutationVerifyTokenArgs = { - token: InputMaybe; -}; - -/** An object with an ID */ -export type Node = { - /** The ID of the object. */ - id: Scalars['ID']; -}; - -/** Login mutation using graphql_jwt */ -export type ObtainJsonWebToken = { - __typename: 'ObtainJSONWebToken'; - newUser: Maybe; - payload: Scalars['GenericScalar']; - refreshExpiresIn: Scalars['Int']; - user: Maybe; -}; - -/** The Relay compliant `PageInfo` type, containing data necessary to paginate this connection. */ -export type PageInfo = { - __typename: 'PageInfo'; - /** When paginating forwards, the cursor to continue. */ - endCursor: Maybe; - /** When paginating forwards, are there more items? */ - hasNextPage: Scalars['Boolean']; - /** When paginating backwards, are there more items? */ - hasPreviousPage: Scalars['Boolean']; - /** When paginating backwards, the cursor to continue. */ - startCursor: Maybe; -}; - -export type PlaylistType = Node & { - __typename: 'PlaylistType'; - category: Scalars['String']; - courses: CourseTypeConnection; - /** The ID of the object. */ - id: Scalars['ID']; - name: Scalars['String']; - semester: Scalars['String']; - year: Scalars['String']; -}; - - -export type PlaylistTypeCoursesArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - before: InputMaybe; - courseNumber: InputMaybe; - crossListing: InputMaybe>>; - department: InputMaybe; - description: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - enrolledPercentage: InputMaybe; - first: InputMaybe; - gradeAverage: InputMaybe; - hasEnrollment: InputMaybe; - hasGrades: InputMaybe; - idIn: InputMaybe; - inPlaylists: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - letterAverage: InputMaybe; - openSeats: InputMaybe; - prerequisites: InputMaybe; - title: InputMaybe; - units: InputMaybe; - waitlisted: InputMaybe; -}; - -export type PlaylistTypeConnection = { - __typename: 'PlaylistTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `PlaylistType` and its cursor. */ -export type PlaylistTypeEdge = { - __typename: 'PlaylistTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type Query = { - __typename: 'Query'; - allCourses: Maybe; - allGrades: Maybe; - allPlaylists: Maybe; - allSections: Maybe; - /** The ID of the object */ - course: Maybe; - courseEnrollmentBySection: Maybe; - courseEnrollmentBySemester: Maybe; - formConfig: Maybe; - /** The ID of the object */ - grade: Maybe; - ping: Maybe; - /** The ID of the object */ - playlist: Maybe; - schedule: Maybe; - schedules: Maybe>>; - /** The ID of the object */ - section: Maybe; - user: Maybe; -}; - - -export type QueryAllCoursesArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - before: InputMaybe; - courseNumber: InputMaybe; - crossListing: InputMaybe>>; - department: InputMaybe; - description: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - enrolledPercentage: InputMaybe; - first: InputMaybe; - gradeAverage: InputMaybe; - hasEnrollment: InputMaybe; - hasGrades: InputMaybe; - idIn: InputMaybe; - inPlaylists: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - letterAverage: InputMaybe; - openSeats: InputMaybe; - prerequisites: InputMaybe; - title: InputMaybe; - units: InputMaybe; - waitlisted: InputMaybe; -}; - - -export type QueryAllGradesArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - average: InputMaybe; - before: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - first: InputMaybe; - gradedTotal: InputMaybe; - instructor: InputMaybe; - last: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - year: InputMaybe; -}; - - -export type QueryAllPlaylistsArgs = { - after: InputMaybe; - before: InputMaybe; - category: InputMaybe; - courses: InputMaybe>>; - first: InputMaybe; - last: InputMaybe; - name: InputMaybe; - semester: InputMaybe; - year: InputMaybe; -}; - - -export type QueryAllSectionsArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - associatedSections: InputMaybe>>; - before: InputMaybe; - ccn: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - courseTitle: InputMaybe; - days: InputMaybe; - disabled: InputMaybe; - endTime: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - finalDay: InputMaybe; - finalEnd: InputMaybe; - finalStart: InputMaybe; - first: InputMaybe; - instructionMode: InputMaybe; - instructor: InputMaybe; - isPrimary: InputMaybe; - kind: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - locationName: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - startTime: InputMaybe; - waitlisted: InputMaybe; - waitlistedMax: InputMaybe; - year: InputMaybe; -}; - - -export type QueryCourseArgs = { - id: Scalars['ID']; -}; - - -export type QueryCourseEnrollmentBySectionArgs = { - sectionId: InputMaybe; -}; - - -export type QueryCourseEnrollmentBySemesterArgs = { - courseId: InputMaybe; - semester: InputMaybe; - year: InputMaybe; -}; - - -export type QueryGradeArgs = { - id: Scalars['ID']; -}; - - -export type QueryPlaylistArgs = { - id: Scalars['ID']; -}; - - -export type QueryScheduleArgs = { - id: InputMaybe; -}; - - -export type QuerySectionArgs = { - id: Scalars['ID']; -}; - -export type Refresh = { - __typename: 'Refresh'; - payload: Scalars['GenericScalar']; - refreshExpiresIn: Scalars['Int']; -}; - -export type RemoveClass = { - __typename: 'RemoveClass'; - user: Maybe; -}; - -export type RemoveSchedule = { - __typename: 'RemoveSchedule'; - schedule: Maybe; -}; - -export type SaveClass = { - __typename: 'SaveClass'; - user: Maybe; -}; - -export type ScheduleType = Node & { - __typename: 'ScheduleType'; - dateCreated: Scalars['DateTime']; - dateModified: Scalars['DateTime']; - /** The ID of the object. */ - id: Scalars['ID']; - name: Scalars['String']; - public: Scalars['Boolean']; - selectedSections: SectionSelectionTypeConnection; - semester: Scalars['String']; - timeblocks: TimeBlockTypeConnection; - totalUnits: Scalars['String']; - user: BerkeleytimeUserType; - year: Scalars['String']; -}; - - -export type ScheduleTypeSelectedSectionsArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - - -export type ScheduleTypeTimeblocksArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - -export type ScheduleTypeConnection = { - __typename: 'ScheduleTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `ScheduleType` and its cursor. */ -export type ScheduleTypeEdge = { - __typename: 'ScheduleTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type SectionSelectionInput = { - course: Scalars['ID']; - primary: InputMaybe; - secondary: InputMaybe>>; -}; - -export type SectionSelectionType = Node & { - __typename: 'SectionSelectionType'; - course: CourseType; - /** The ID of the object. */ - id: Scalars['ID']; - primary: Maybe; - schedule: ScheduleType; - secondary: SectionTypeConnection; -}; - - -export type SectionSelectionTypeSecondaryArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - associatedSections: InputMaybe>>; - before: InputMaybe; - ccn: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - courseTitle: InputMaybe; - days: InputMaybe; - disabled: InputMaybe; - endTime: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - finalDay: InputMaybe; - finalEnd: InputMaybe; - finalStart: InputMaybe; - first: InputMaybe; - instructionMode: InputMaybe; - instructor: InputMaybe; - isPrimary: InputMaybe; - kind: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - locationName: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - startTime: InputMaybe; - waitlisted: InputMaybe; - waitlistedMax: InputMaybe; - year: InputMaybe; -}; - -export type SectionSelectionTypeConnection = { - __typename: 'SectionSelectionTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `SectionSelectionType` and its cursor. */ -export type SectionSelectionTypeEdge = { - __typename: 'SectionSelectionTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type SectionType = Node & { - __typename: 'SectionType'; - abbreviation: Scalars['String']; - associatedSections: SectionTypeConnection; - ccn: Scalars['String']; - course: CourseType; - courseNumber: Scalars['String']; - courseTitle: Scalars['String']; - days: Scalars['String']; - disabled: Scalars['Boolean']; - endTime: Maybe; - enrolled: Maybe; - enrolledMax: Maybe; - finalDay: Scalars['String']; - finalEnd: Maybe; - finalStart: Maybe; - /** The ID of the object. */ - id: Scalars['ID']; - instructionMode: Scalars['String']; - instructor: Scalars['String']; - isPrimary: Scalars['Boolean']; - kind: Scalars['String']; - lastUpdated: Scalars['DateTime']; - locationName: Scalars['String']; - schedulerPrimarySections: SectionSelectionTypeConnection; - schedulerSecondarySections: SectionSelectionTypeConnection; - sectionNumber: Scalars['String']; - semester: Scalars['String']; - startTime: Maybe; - waitlisted: Maybe; - waitlistedMax: Maybe; - wordDays: Maybe; - year: Scalars['String']; -}; - - -export type SectionTypeAssociatedSectionsArgs = { - abbreviation: InputMaybe; - after: InputMaybe; - associatedSections: InputMaybe>>; - before: InputMaybe; - ccn: InputMaybe; - course: InputMaybe; - courseNumber: InputMaybe; - courseTitle: InputMaybe; - days: InputMaybe; - disabled: InputMaybe; - endTime: InputMaybe; - enrolled: InputMaybe; - enrolledMax: InputMaybe; - finalDay: InputMaybe; - finalEnd: InputMaybe; - finalStart: InputMaybe; - first: InputMaybe; - instructionMode: InputMaybe; - instructor: InputMaybe; - isPrimary: InputMaybe; - kind: InputMaybe; - last: InputMaybe; - lastUpdated: InputMaybe; - locationName: InputMaybe; - sectionNumber: InputMaybe; - semester: InputMaybe; - startTime: InputMaybe; - waitlisted: InputMaybe; - waitlistedMax: InputMaybe; - year: InputMaybe; -}; - - -export type SectionTypeSchedulerPrimarySectionsArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - - -export type SectionTypeSchedulerSecondarySectionsArgs = { - after: InputMaybe; - before: InputMaybe; - first: InputMaybe; - last: InputMaybe; -}; - -export type SectionTypeConnection = { - __typename: 'SectionTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `SectionType` and its cursor. */ -export type SectionTypeEdge = { - __typename: 'SectionTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -/** Telebears JSON */ -export type TelebearData = { - __typename: 'TelebearData'; - adjStart: Maybe; - phase1End: Maybe; - phase1Start: Maybe; - phase2End: Maybe; - phase2Start: Maybe; -}; - -export type TimeBlockInput = { - days: Scalars['String']; - endTime: Scalars['Time']; - name: Scalars['String']; - startTime: Scalars['Time']; -}; - -export type TimeBlockType = Node & { - __typename: 'TimeBlockType'; - days: Scalars['String']; - endTime: Scalars['Time']; - /** The ID of the object. */ - id: Scalars['ID']; - name: Scalars['String']; - schedule: ScheduleType; - startTime: Scalars['Time']; -}; - -export type TimeBlockTypeConnection = { - __typename: 'TimeBlockTypeConnection'; - /** Contains the nodes in this connection. */ - edges: Array>; - /** Pagination data for this connection. */ - pageInfo: PageInfo; -}; - -/** A Relay edge containing a `TimeBlockType` and its cursor. */ -export type TimeBlockTypeEdge = { - __typename: 'TimeBlockTypeEdge'; - /** A cursor for use in pagination */ - cursor: Scalars['String']; - /** The item at the end of the edge */ - node: Maybe; -}; - -export type UpdateSchedule = { - __typename: 'UpdateSchedule'; - schedule: Maybe; -}; - -export type UpdateUser = { - __typename: 'UpdateUser'; - user: Maybe; -}; - -export type UserType = { - __typename: 'UserType'; - email: Scalars['String']; - firstName: Scalars['String']; - id: Scalars['ID']; - lastName: Scalars['String']; - /** Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only. */ - username: Scalars['String']; -}; - -export type Verify = { - __typename: 'Verify'; - payload: Scalars['GenericScalar']; -}; - -export type CourseFragment = { __typename: 'CourseType', title: string, units: string, waitlisted: number, openSeats: number, letterAverage: string, gradeAverage: number, lastUpdated: unknown, id: string, hasEnrollment: boolean, enrolledPercentage: number, enrolledMax: number, courseNumber: string, department: string, description: string, enrolled: number, abbreviation: string, prerequisites: string, playlistSet: { __typename: 'PlaylistTypeConnection', edges: Array<{ __typename: 'PlaylistTypeEdge', node: { __typename: 'PlaylistType', category: string, id: string, name: string, semester: string, year: string } }> }, sectionSet: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } }; - -export type CourseOverviewFragment = { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }; - -export type FilterFragment = { __typename: 'PlaylistType', id: string, name: string, category: string }; - -export type LectureFragment = { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean, associatedSections: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } }; - -export type ScheduleFragment = { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, public: boolean, user: { __typename: 'BerkeleytimeUserType', user: { __typename: 'UserType', id: string, firstName: string, lastName: string } }, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', id: string, course: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }, primary: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }, secondary: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } }; - -export type ScheduleOverviewFragment = { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', course: { __typename: 'CourseType', abbreviation: string, courseNumber: string, units: string } } }> } }; - -export type SchedulerCourseFragment = { __typename: 'CourseType', id: string, title: string, units: string, waitlisted: number, openSeats: number, enrolled: number, enrolledMax: number, courseNumber: string, department: string, description: string, abbreviation: string, sectionSet: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean, associatedSections: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } }; - -export type SectionFragment = { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }; - -export type SectionSelectionFragment = { __typename: 'SectionSelectionType', id: string, course: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }, primary: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }, secondary: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } }; - -export type UserProfileFragment = { __typename: 'BerkeleytimeUserType', id: string, major: string, emailClassUpdate: boolean, emailGradeUpdate: boolean, emailEnrollmentOpening: boolean, emailBerkeleytimeUpdate: boolean, user: { __typename: 'UserType', id: string, username: string, firstName: string, lastName: string, email: string }, savedClasses: Array<{ __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }>, schedules: { __typename: 'ScheduleTypeConnection', edges: Array<{ __typename: 'ScheduleTypeEdge', node: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', course: { __typename: 'CourseType', abbreviation: string, courseNumber: string, units: string } } }> } } }> } }; - -export type CreateScheduleMutationVariables = Exact<{ - name: Scalars['String']; - selectedSections: Array> | InputMaybe; - timeblocks: Array> | InputMaybe; - totalUnits: Scalars['String']; - semester: Scalars['String']; - year: Scalars['String']; - public: Scalars['Boolean']; -}>; - - -export type CreateScheduleMutation = { __typename: 'Mutation', createSchedule: { __typename: 'CreateSchedule', schedule: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, public: boolean, user: { __typename: 'BerkeleytimeUserType', user: { __typename: 'UserType', id: string, firstName: string, lastName: string } }, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', id: string, course: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }, primary: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }, secondary: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } } } }; - -export type DeleteScheduleMutationVariables = Exact<{ - id: Scalars['ID']; -}>; - - -export type DeleteScheduleMutation = { __typename: 'Mutation', removeSchedule: { __typename: 'RemoveSchedule', schedule: { __typename: 'ScheduleType', id: string } } }; - -export type DeleteUserMutationVariables = Exact<{ [key: string]: never; }>; - - -export type DeleteUserMutation = { __typename: 'Mutation', deleteUser: { __typename: 'DeleteUser', success: boolean } }; - -export type LogoutMutationVariables = Exact<{ [key: string]: never; }>; - - -export type LogoutMutation = { __typename: 'Mutation', logout: { __typename: 'Logout', success: boolean } }; - -export type SaveCourseMutationVariables = Exact<{ - courseId: Scalars['ID']; -}>; - - -export type SaveCourseMutation = { __typename: 'Mutation', saveClass: { __typename: 'SaveClass', user: { __typename: 'BerkeleytimeUserType', id: string, savedClasses: Array<{ __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }> } } }; - -export type UnsaveCourseMutationVariables = Exact<{ - courseId: Scalars['ID']; -}>; - - -export type UnsaveCourseMutation = { __typename: 'Mutation', removeClass: { __typename: 'RemoveClass', user: { __typename: 'BerkeleytimeUserType', id: string, savedClasses: Array<{ __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }> } } }; - -export type UpdateScheduleMutationVariables = Exact<{ - scheduleId: Scalars['ID']; - name: Scalars['String']; - selectedSections: Array> | InputMaybe; - timeblocks: Array> | InputMaybe; - totalUnits: Scalars['String']; - public: Scalars['Boolean']; -}>; - - -export type UpdateScheduleMutation = { __typename: 'Mutation', updateSchedule: { __typename: 'UpdateSchedule', schedule: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, public: boolean, user: { __typename: 'BerkeleytimeUserType', user: { __typename: 'UserType', id: string, firstName: string, lastName: string } }, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', id: string, course: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }, primary: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }, secondary: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } } } }; - -export type UpdateUserMutationVariables = Exact<{ - emailBerkeleytimeUpdate: InputMaybe; - emailClassUpdate: InputMaybe; - emailEnrollmentOpening: InputMaybe; - emailGradeUpdate: InputMaybe; - major: InputMaybe; -}>; - - -export type UpdateUserMutation = { __typename: 'Mutation', updateUser: { __typename: 'UpdateUser', user: { __typename: 'BerkeleytimeUserType', id: string, major: string, emailGradeUpdate: boolean, emailEnrollmentOpening: boolean, emailClassUpdate: boolean, emailBerkeleytimeUpdate: boolean } } }; - -export type LoginMutationVariables = Exact<{ - token: Scalars['String']; -}>; - - -export type LoginMutation = { __typename: 'Mutation', login: { __typename: 'ObtainJSONWebToken', newUser: boolean, refreshExpiresIn: number, payload: unknown, user: { __typename: 'BerkeleytimeUserType', id: string, major: string, emailClassUpdate: boolean, emailGradeUpdate: boolean, emailEnrollmentOpening: boolean, emailBerkeleytimeUpdate: boolean, user: { __typename: 'UserType', id: string, username: string, firstName: string, lastName: string, email: string }, savedClasses: Array<{ __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }>, schedules: { __typename: 'ScheduleTypeConnection', edges: Array<{ __typename: 'ScheduleTypeEdge', node: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', course: { __typename: 'CourseType', abbreviation: string, courseNumber: string, units: string } } }> } } }> } } } }; - -export type GetCourseForIdQueryVariables = Exact<{ - id: Scalars['ID']; - year: InputMaybe; - semester: InputMaybe; -}>; - - -export type GetCourseForIdQuery = { __typename: 'Query', course: { __typename: 'CourseType', title: string, units: string, waitlisted: number, openSeats: number, letterAverage: string, gradeAverage: number, lastUpdated: unknown, id: string, hasEnrollment: boolean, enrolledPercentage: number, enrolledMax: number, courseNumber: string, department: string, description: string, enrolled: number, abbreviation: string, prerequisites: string, playlistSet: { __typename: 'PlaylistTypeConnection', edges: Array<{ __typename: 'PlaylistTypeEdge', node: { __typename: 'PlaylistType', category: string, id: string, name: string, semester: string, year: string } }> }, sectionSet: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }; - -export type GetCourseForNameQueryVariables = Exact<{ - abbreviation: Scalars['String']; - courseNumber: Scalars['String']; - year: InputMaybe; - semester: InputMaybe; -}>; - - -export type GetCourseForNameQuery = { __typename: 'Query', allCourses: { __typename: 'CourseTypeConnection', edges: Array<{ __typename: 'CourseTypeEdge', node: { __typename: 'CourseType', title: string, units: string, waitlisted: number, openSeats: number, letterAverage: string, gradeAverage: number, lastUpdated: unknown, id: string, hasEnrollment: boolean, enrolledPercentage: number, enrolledMax: number, courseNumber: string, department: string, description: string, enrolled: number, abbreviation: string, prerequisites: string, playlistSet: { __typename: 'PlaylistTypeConnection', edges: Array<{ __typename: 'PlaylistTypeEdge', node: { __typename: 'PlaylistType', category: string, id: string, name: string, semester: string, year: string } }> }, sectionSet: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } }; - -export type GetCoursesForFilterQueryVariables = Exact<{ - playlists: Scalars['String']; -}>; - - -export type GetCoursesForFilterQuery = { __typename: 'Query', allCourses: { __typename: 'CourseTypeConnection', edges: Array<{ __typename: 'CourseTypeEdge', node: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string } }> } }; - -export type GetFiltersQueryVariables = Exact<{ [key: string]: never; }>; - - -export type GetFiltersQuery = { __typename: 'Query', allPlaylists: { __typename: 'PlaylistTypeConnection', edges: Array<{ __typename: 'PlaylistTypeEdge', node: { __typename: 'PlaylistType', id: string, name: string, category: string } }> } }; - -export type GetScheduleForIdQueryVariables = Exact<{ - id: Scalars['ID']; -}>; - - -export type GetScheduleForIdQuery = { __typename: 'Query', schedule: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, public: boolean, user: { __typename: 'BerkeleytimeUserType', user: { __typename: 'UserType', id: string, firstName: string, lastName: string } }, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', id: string, course: { __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }, primary: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean }, secondary: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } } }; - -export type GetSchedulerCourseForIdQueryVariables = Exact<{ - id: Scalars['ID']; - year: InputMaybe; - semester: InputMaybe; -}>; - - -export type GetSchedulerCourseForIdQuery = { __typename: 'Query', course: { __typename: 'CourseType', id: string, title: string, units: string, waitlisted: number, openSeats: number, enrolled: number, enrolledMax: number, courseNumber: string, department: string, description: string, abbreviation: string, sectionSet: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean, associatedSections: { __typename: 'SectionTypeConnection', edges: Array<{ __typename: 'SectionTypeEdge', node: { __typename: 'SectionType', id: string, ccn: string, kind: string, instructor: string, startTime: unknown, endTime: unknown, enrolled: number, enrolledMax: number, locationName: string, waitlisted: number, waitlistedMax: number, days: string, wordDays: string, disabled: boolean, sectionNumber: string, isPrimary: boolean } }> } } }> } } }; - -export type GetSemestersQueryVariables = Exact<{ - name: InputMaybe; -}>; - - -export type GetSemestersQuery = { __typename: 'Query', allPlaylists: { __typename: 'PlaylistTypeConnection', edges: Array<{ __typename: 'PlaylistTypeEdge', node: { __typename: 'PlaylistType', id: string, name: string, category: string } }> } }; - -export type GetUserQueryVariables = Exact<{ [key: string]: never; }>; - - -export type GetUserQuery = { __typename: 'Query', user: { __typename: 'BerkeleytimeUserType', id: string, major: string, emailClassUpdate: boolean, emailGradeUpdate: boolean, emailEnrollmentOpening: boolean, emailBerkeleytimeUpdate: boolean, user: { __typename: 'UserType', id: string, username: string, firstName: string, lastName: string, email: string }, savedClasses: Array<{ __typename: 'CourseType', id: string, abbreviation: string, courseNumber: string, description: string, title: string, gradeAverage: number, letterAverage: string, openSeats: number, enrolledPercentage: number, enrolled: number, enrolledMax: number, units: string }>, schedules: { __typename: 'ScheduleTypeConnection', edges: Array<{ __typename: 'ScheduleTypeEdge', node: { __typename: 'ScheduleType', id: string, year: string, semester: string, name: string, totalUnits: string, dateCreated: unknown, dateModified: unknown, selectedSections: { __typename: 'SectionSelectionTypeConnection', edges: Array<{ __typename: 'SectionSelectionTypeEdge', node: { __typename: 'SectionSelectionType', course: { __typename: 'CourseType', abbreviation: string, courseNumber: string, units: string } } }> } } }> } } }; - -export const SectionFragmentDoc = gql` - fragment Section on SectionType { - id - ccn - kind - instructor - startTime - endTime - enrolled - enrolledMax - locationName - waitlisted - waitlistedMax - days - wordDays - disabled - sectionNumber - isPrimary -} - `; -export const CourseFragmentDoc = gql` - fragment Course on CourseType { - title - units - waitlisted - openSeats - letterAverage - gradeAverage - lastUpdated - id - hasEnrollment - gradeAverage - enrolledPercentage - enrolledMax - courseNumber - department - description - enrolled - abbreviation - prerequisites - playlistSet { - edges { - node { - category - id - name - semester - year - } - } - } - sectionSet(year: $year, semester: $semester) { - edges { - node { - ...Section - } - } - } -} - ${SectionFragmentDoc}`; -export const FilterFragmentDoc = gql` - fragment Filter on PlaylistType { - id - name - category -} - `; -export const CourseOverviewFragmentDoc = gql` - fragment CourseOverview on CourseType { - id - abbreviation - courseNumber - description - title - gradeAverage - letterAverage - openSeats - enrolledPercentage - enrolled - enrolledMax - units -} - `; -export const SectionSelectionFragmentDoc = gql` - fragment SectionSelection on SectionSelectionType { - id - course { - ...CourseOverview - } - primary { - ...Section - } - secondary { - edges { - node { - ...Section - } - } - } -} - ${CourseOverviewFragmentDoc} -${SectionFragmentDoc}`; -export const ScheduleFragmentDoc = gql` - fragment Schedule on ScheduleType { - id - year - semester - name - totalUnits - dateCreated - dateModified - public - user { - user { - id - firstName - lastName - } - } - selectedSections { - edges { - node { - ...SectionSelection - } - } - } -} - ${SectionSelectionFragmentDoc}`; -export const LectureFragmentDoc = gql` - fragment Lecture on SectionType { - ...Section - associatedSections { - edges { - node { - ...Section - } - } - } -} - ${SectionFragmentDoc}`; -export const SchedulerCourseFragmentDoc = gql` - fragment SchedulerCourse on CourseType { - id - title - units - waitlisted - openSeats - enrolled - enrolledMax - courseNumber - department - description - abbreviation - sectionSet(isPrimary: true, year: $year, semester: $semester) { - edges { - node { - ...Lecture - } - } - } -} - ${LectureFragmentDoc}`; -export const ScheduleOverviewFragmentDoc = gql` - fragment ScheduleOverview on ScheduleType { - id - year - semester - name - totalUnits - dateCreated - dateModified - selectedSections { - edges { - node { - course { - abbreviation - courseNumber - units - } - } - } - } -} - `; -export const UserProfileFragmentDoc = gql` - fragment UserProfile on BerkeleytimeUserType { - id - major - user { - id - username - firstName - lastName - email - } - emailClassUpdate - emailGradeUpdate - emailEnrollmentOpening - emailBerkeleytimeUpdate - savedClasses { - ...CourseOverview - } - schedules { - edges { - node { - ...ScheduleOverview - } - } - } -} - ${CourseOverviewFragmentDoc} -${ScheduleOverviewFragmentDoc}`; -export const CreateScheduleDocument = gql` - mutation CreateSchedule($name: String!, $selectedSections: [SectionSelectionInput]!, $timeblocks: [TimeBlockInput]!, $totalUnits: String!, $semester: String!, $year: String!, $public: Boolean!) { - createSchedule( - name: $name - selectedSections: $selectedSections - timeblocks: $timeblocks - semester: $semester - year: $year - public: $public - totalUnits: $totalUnits - ) { - schedule { - ...Schedule - } - } -} - ${ScheduleFragmentDoc}`; -export type CreateScheduleMutationFn = Apollo.MutationFunction; - -/** - * __useCreateScheduleMutation__ - * - * To run a mutation, you first call `useCreateScheduleMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useCreateScheduleMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [createScheduleMutation, { data, loading, error }] = useCreateScheduleMutation({ - * variables: { - * name: // value for 'name' - * selectedSections: // value for 'selectedSections' - * timeblocks: // value for 'timeblocks' - * totalUnits: // value for 'totalUnits' - * semester: // value for 'semester' - * year: // value for 'year' - * public: // value for 'public' - * }, - * }); - */ -export function useCreateScheduleMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(CreateScheduleDocument, options); - } -export type CreateScheduleMutationHookResult = ReturnType; -export type CreateScheduleMutationResult = Apollo.MutationResult; -export type CreateScheduleMutationOptions = Apollo.BaseMutationOptions; -export const DeleteScheduleDocument = gql` - mutation DeleteSchedule($id: ID!) { - removeSchedule(scheduleId: $id) { - schedule { - id - } - } -} - `; -export type DeleteScheduleMutationFn = Apollo.MutationFunction; - -/** - * __useDeleteScheduleMutation__ - * - * To run a mutation, you first call `useDeleteScheduleMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useDeleteScheduleMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [deleteScheduleMutation, { data, loading, error }] = useDeleteScheduleMutation({ - * variables: { - * id: // value for 'id' - * }, - * }); - */ -export function useDeleteScheduleMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(DeleteScheduleDocument, options); - } -export type DeleteScheduleMutationHookResult = ReturnType; -export type DeleteScheduleMutationResult = Apollo.MutationResult; -export type DeleteScheduleMutationOptions = Apollo.BaseMutationOptions; -export const DeleteUserDocument = gql` - mutation DeleteUser { - deleteUser { - success - } -} - `; -export type DeleteUserMutationFn = Apollo.MutationFunction; - -/** - * __useDeleteUserMutation__ - * - * To run a mutation, you first call `useDeleteUserMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useDeleteUserMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [deleteUserMutation, { data, loading, error }] = useDeleteUserMutation({ - * variables: { - * }, - * }); - */ -export function useDeleteUserMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(DeleteUserDocument, options); - } -export type DeleteUserMutationHookResult = ReturnType; -export type DeleteUserMutationResult = Apollo.MutationResult; -export type DeleteUserMutationOptions = Apollo.BaseMutationOptions; -export const LogoutDocument = gql` - mutation Logout { - logout { - success - } -} - `; -export type LogoutMutationFn = Apollo.MutationFunction; - -/** - * __useLogoutMutation__ - * - * To run a mutation, you first call `useLogoutMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useLogoutMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [logoutMutation, { data, loading, error }] = useLogoutMutation({ - * variables: { - * }, - * }); - */ -export function useLogoutMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(LogoutDocument, options); - } -export type LogoutMutationHookResult = ReturnType; -export type LogoutMutationResult = Apollo.MutationResult; -export type LogoutMutationOptions = Apollo.BaseMutationOptions; -export const SaveCourseDocument = gql` - mutation SaveCourse($courseId: ID!) { - saveClass(classId: $courseId) { - user { - id - savedClasses { - ...CourseOverview - } - } - } -} - ${CourseOverviewFragmentDoc}`; -export type SaveCourseMutationFn = Apollo.MutationFunction; - -/** - * __useSaveCourseMutation__ - * - * To run a mutation, you first call `useSaveCourseMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useSaveCourseMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [saveCourseMutation, { data, loading, error }] = useSaveCourseMutation({ - * variables: { - * courseId: // value for 'courseId' - * }, - * }); - */ -export function useSaveCourseMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(SaveCourseDocument, options); - } -export type SaveCourseMutationHookResult = ReturnType; -export type SaveCourseMutationResult = Apollo.MutationResult; -export type SaveCourseMutationOptions = Apollo.BaseMutationOptions; -export const UnsaveCourseDocument = gql` - mutation UnsaveCourse($courseId: ID!) { - removeClass(classId: $courseId) { - user { - id - savedClasses { - ...CourseOverview - } - } - } -} - ${CourseOverviewFragmentDoc}`; -export type UnsaveCourseMutationFn = Apollo.MutationFunction; - -/** - * __useUnsaveCourseMutation__ - * - * To run a mutation, you first call `useUnsaveCourseMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useUnsaveCourseMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [unsaveCourseMutation, { data, loading, error }] = useUnsaveCourseMutation({ - * variables: { - * courseId: // value for 'courseId' - * }, - * }); - */ -export function useUnsaveCourseMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(UnsaveCourseDocument, options); - } -export type UnsaveCourseMutationHookResult = ReturnType; -export type UnsaveCourseMutationResult = Apollo.MutationResult; -export type UnsaveCourseMutationOptions = Apollo.BaseMutationOptions; -export const UpdateScheduleDocument = gql` - mutation UpdateSchedule($scheduleId: ID!, $name: String!, $selectedSections: [SectionSelectionInput]!, $timeblocks: [TimeBlockInput]!, $totalUnits: String!, $public: Boolean!) { - updateSchedule( - scheduleId: $scheduleId - name: $name - selectedSections: $selectedSections - timeblocks: $timeblocks - totalUnits: $totalUnits - public: $public - ) { - schedule { - ...Schedule - } - } -} - ${ScheduleFragmentDoc}`; -export type UpdateScheduleMutationFn = Apollo.MutationFunction; - -/** - * __useUpdateScheduleMutation__ - * - * To run a mutation, you first call `useUpdateScheduleMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useUpdateScheduleMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [updateScheduleMutation, { data, loading, error }] = useUpdateScheduleMutation({ - * variables: { - * scheduleId: // value for 'scheduleId' - * name: // value for 'name' - * selectedSections: // value for 'selectedSections' - * timeblocks: // value for 'timeblocks' - * totalUnits: // value for 'totalUnits' - * public: // value for 'public' - * }, - * }); - */ -export function useUpdateScheduleMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(UpdateScheduleDocument, options); - } -export type UpdateScheduleMutationHookResult = ReturnType; -export type UpdateScheduleMutationResult = Apollo.MutationResult; -export type UpdateScheduleMutationOptions = Apollo.BaseMutationOptions; -export const UpdateUserDocument = gql` - mutation UpdateUser($emailBerkeleytimeUpdate: Boolean, $emailClassUpdate: Boolean, $emailEnrollmentOpening: Boolean, $emailGradeUpdate: Boolean, $major: String) { - updateUser( - emailBerkeleytimeUpdate: $emailBerkeleytimeUpdate - emailClassUpdate: $emailClassUpdate - emailEnrollmentOpening: $emailEnrollmentOpening - emailGradeUpdate: $emailGradeUpdate - major: $major - ) { - user { - id - major - emailGradeUpdate - emailEnrollmentOpening - emailClassUpdate - emailBerkeleytimeUpdate - } - } -} - `; -export type UpdateUserMutationFn = Apollo.MutationFunction; - -/** - * __useUpdateUserMutation__ - * - * To run a mutation, you first call `useUpdateUserMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useUpdateUserMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [updateUserMutation, { data, loading, error }] = useUpdateUserMutation({ - * variables: { - * emailBerkeleytimeUpdate: // value for 'emailBerkeleytimeUpdate' - * emailClassUpdate: // value for 'emailClassUpdate' - * emailEnrollmentOpening: // value for 'emailEnrollmentOpening' - * emailGradeUpdate: // value for 'emailGradeUpdate' - * major: // value for 'major' - * }, - * }); - */ -export function useUpdateUserMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(UpdateUserDocument, options); - } -export type UpdateUserMutationHookResult = ReturnType; -export type UpdateUserMutationResult = Apollo.MutationResult; -export type UpdateUserMutationOptions = Apollo.BaseMutationOptions; -export const LoginDocument = gql` - mutation Login($token: String!) { - login(tokenId: $token) { - newUser - refreshExpiresIn - payload - user { - ...UserProfile - } - } -} - ${UserProfileFragmentDoc}`; -export type LoginMutationFn = Apollo.MutationFunction; - -/** - * __useLoginMutation__ - * - * To run a mutation, you first call `useLoginMutation` within a React component and pass it any options that fit your needs. - * When your component renders, `useLoginMutation` returns a tuple that includes: - * - A mutate function that you can call at any time to execute the mutation - * - An object with fields that represent the current status of the mutation's execution - * - * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; - * - * @example - * const [loginMutation, { data, loading, error }] = useLoginMutation({ - * variables: { - * token: // value for 'token' - * }, - * }); - */ -export function useLoginMutation(baseOptions?: Apollo.MutationHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useMutation(LoginDocument, options); - } -export type LoginMutationHookResult = ReturnType; -export type LoginMutationResult = Apollo.MutationResult; -export type LoginMutationOptions = Apollo.BaseMutationOptions; -export const GetCourseForIdDocument = gql` - query GetCourseForId($id: ID!, $year: String, $semester: String) { - course(id: $id) { - ...Course - } -} - ${CourseFragmentDoc}`; - -/** - * __useGetCourseForIdQuery__ - * - * To run a query within a React component, call `useGetCourseForIdQuery` and pass it any options that fit your needs. - * When your component renders, `useGetCourseForIdQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetCourseForIdQuery({ - * variables: { - * id: // value for 'id' - * year: // value for 'year' - * semester: // value for 'semester' - * }, - * }); - */ -export function useGetCourseForIdQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetCourseForIdDocument, options); - } -export function useGetCourseForIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetCourseForIdDocument, options); - } -export type GetCourseForIdQueryHookResult = ReturnType; -export type GetCourseForIdLazyQueryHookResult = ReturnType; -export type GetCourseForIdQueryResult = Apollo.QueryResult; -export const GetCourseForNameDocument = gql` - query GetCourseForName($abbreviation: String!, $courseNumber: String!, $year: String, $semester: String) { - allCourses(abbreviation: $abbreviation, courseNumber: $courseNumber, first: 1) { - edges { - node { - ...Course - } - } - } -} - ${CourseFragmentDoc}`; - -/** - * __useGetCourseForNameQuery__ - * - * To run a query within a React component, call `useGetCourseForNameQuery` and pass it any options that fit your needs. - * When your component renders, `useGetCourseForNameQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetCourseForNameQuery({ - * variables: { - * abbreviation: // value for 'abbreviation' - * courseNumber: // value for 'courseNumber' - * year: // value for 'year' - * semester: // value for 'semester' - * }, - * }); - */ -export function useGetCourseForNameQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetCourseForNameDocument, options); - } -export function useGetCourseForNameLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetCourseForNameDocument, options); - } -export type GetCourseForNameQueryHookResult = ReturnType; -export type GetCourseForNameLazyQueryHookResult = ReturnType; -export type GetCourseForNameQueryResult = Apollo.QueryResult; -export const GetCoursesForFilterDocument = gql` - query GetCoursesForFilter($playlists: String!) { - allCourses(inPlaylists: $playlists) { - edges { - node { - ...CourseOverview - } - } - } -} - ${CourseOverviewFragmentDoc}`; - -/** - * __useGetCoursesForFilterQuery__ - * - * To run a query within a React component, call `useGetCoursesForFilterQuery` and pass it any options that fit your needs. - * When your component renders, `useGetCoursesForFilterQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetCoursesForFilterQuery({ - * variables: { - * playlists: // value for 'playlists' - * }, - * }); - */ -export function useGetCoursesForFilterQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetCoursesForFilterDocument, options); - } -export function useGetCoursesForFilterLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetCoursesForFilterDocument, options); - } -export type GetCoursesForFilterQueryHookResult = ReturnType; -export type GetCoursesForFilterLazyQueryHookResult = ReturnType; -export type GetCoursesForFilterQueryResult = Apollo.QueryResult; -export const GetFiltersDocument = gql` - query GetFilters { - allPlaylists { - edges { - node { - ...Filter - } - } - } -} - ${FilterFragmentDoc}`; - -/** - * __useGetFiltersQuery__ - * - * To run a query within a React component, call `useGetFiltersQuery` and pass it any options that fit your needs. - * When your component renders, `useGetFiltersQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetFiltersQuery({ - * variables: { - * }, - * }); - */ -export function useGetFiltersQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetFiltersDocument, options); - } -export function useGetFiltersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetFiltersDocument, options); - } -export type GetFiltersQueryHookResult = ReturnType; -export type GetFiltersLazyQueryHookResult = ReturnType; -export type GetFiltersQueryResult = Apollo.QueryResult; -export const GetScheduleForIdDocument = gql` - query GetScheduleForId($id: ID!) { - schedule(id: $id) { - ...Schedule - } -} - ${ScheduleFragmentDoc}`; - -/** - * __useGetScheduleForIdQuery__ - * - * To run a query within a React component, call `useGetScheduleForIdQuery` and pass it any options that fit your needs. - * When your component renders, `useGetScheduleForIdQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetScheduleForIdQuery({ - * variables: { - * id: // value for 'id' - * }, - * }); - */ -export function useGetScheduleForIdQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetScheduleForIdDocument, options); - } -export function useGetScheduleForIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetScheduleForIdDocument, options); - } -export type GetScheduleForIdQueryHookResult = ReturnType; -export type GetScheduleForIdLazyQueryHookResult = ReturnType; -export type GetScheduleForIdQueryResult = Apollo.QueryResult; -export const GetSchedulerCourseForIdDocument = gql` - query GetSchedulerCourseForId($id: ID!, $year: String, $semester: String) { - course(id: $id) { - ...SchedulerCourse - } -} - ${SchedulerCourseFragmentDoc}`; - -/** - * __useGetSchedulerCourseForIdQuery__ - * - * To run a query within a React component, call `useGetSchedulerCourseForIdQuery` and pass it any options that fit your needs. - * When your component renders, `useGetSchedulerCourseForIdQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetSchedulerCourseForIdQuery({ - * variables: { - * id: // value for 'id' - * year: // value for 'year' - * semester: // value for 'semester' - * }, - * }); - */ -export function useGetSchedulerCourseForIdQuery(baseOptions: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetSchedulerCourseForIdDocument, options); - } -export function useGetSchedulerCourseForIdLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetSchedulerCourseForIdDocument, options); - } -export type GetSchedulerCourseForIdQueryHookResult = ReturnType; -export type GetSchedulerCourseForIdLazyQueryHookResult = ReturnType; -export type GetSchedulerCourseForIdQueryResult = Apollo.QueryResult; -export const GetSemestersDocument = gql` - query GetSemesters($name: String) { - allPlaylists(category: "semester", name: $name) { - edges { - node { - ...Filter - } - } - } -} - ${FilterFragmentDoc}`; - -/** - * __useGetSemestersQuery__ - * - * To run a query within a React component, call `useGetSemestersQuery` and pass it any options that fit your needs. - * When your component renders, `useGetSemestersQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetSemestersQuery({ - * variables: { - * name: // value for 'name' - * }, - * }); - */ -export function useGetSemestersQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetSemestersDocument, options); - } -export function useGetSemestersLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetSemestersDocument, options); - } -export type GetSemestersQueryHookResult = ReturnType; -export type GetSemestersLazyQueryHookResult = ReturnType; -export type GetSemestersQueryResult = Apollo.QueryResult; -export const GetUserDocument = gql` - query GetUser { - user { - ...UserProfile - } -} - ${UserProfileFragmentDoc}`; - -/** - * __useGetUserQuery__ - * - * To run a query within a React component, call `useGetUserQuery` and pass it any options that fit your needs. - * When your component renders, `useGetUserQuery` returns an object from Apollo Client that contains loading, error, and data properties - * you can use to render your UI. - * - * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; - * - * @example - * const { data, loading, error } = useGetUserQuery({ - * variables: { - * }, - * }); - */ -export function useGetUserQuery(baseOptions?: Apollo.QueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useQuery(GetUserDocument, options); - } -export function useGetUserLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions) { - const options = {...defaultOptions, ...baseOptions} - return Apollo.useLazyQuery(GetUserDocument, options); - } -export type GetUserQueryHookResult = ReturnType; -export type GetUserLazyQueryHookResult = ReturnType; -export type GetUserQueryResult = Apollo.QueryResult; \ No newline at end of file diff --git a/frontend/src/graphql/introspection.json b/frontend/src/graphql/introspection.json deleted file mode 100644 index ae7a08226..000000000 --- a/frontend/src/graphql/introspection.json +++ /dev/null @@ -1,4151 +0,0 @@ -{ - "__schema": { - "queryType": { "name": "Query" }, - "mutationType": { "name": "Mutation" }, - "subscriptionType": null, - "types": [ - { - "kind": "OBJECT", - "name": "Query", - "description": null, - "fields": [ - { - "name": "allCourses", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "title", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "department", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "abbreviation", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "description", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "units", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "prerequisites", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "gradeAverage", - "description": null, - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - }, - { - "name": "letterAverage", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "hasEnrollment", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledPercentage", - "description": null, - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "openSeats", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "lastUpdated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "hasGrades", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "inPlaylists", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "CourseTypeConnection", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allEnrollments", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "section", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "dateCreated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlistedMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "EnrollmentTypeConnection", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allGrades", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "course", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "semester", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "year", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "abbreviation", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sectionNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "instructor", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "a1", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "a2", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "a3", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "b1", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "b2", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "b3", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "c1", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "c2", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "c3", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "d1", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "d2", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "d3", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "f", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "gradedTotal", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "p", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "np", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "average", - "description": null, - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "GradeTypeConnection", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allPlaylists", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "category", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "name", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "semester", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "year", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courses", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "PlaylistTypeConnection", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "allSections", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "course", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "abbreviation", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "year", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "semester", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseTitle", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sectionNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ccn", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "kind", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "isPrimary", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "days", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "startTime", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "endTime", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalDay", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalEnd", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalStart", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "instructor", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "disabled", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "locationName", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "instructionMode", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "lastUpdated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlistedMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "SectionTypeConnection", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "course", - "description": "The ID of the object", - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "CourseType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrollment", - "description": "The ID of the object", - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "EnrollmentType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "formConfig", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "FormConfigType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "grade", - "description": "The ID of the object", - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "GradeType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isLoggedIn", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "playlist", - "description": "The ID of the object", - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "PlaylistType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "section", - "description": "The ID of the object", - "args": [ - { - "name": "id", - "description": null, - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "SectionType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "String", - "description": "The `String` scalar type represents textual data, represented as UTF-8 character sequences. The String type is most often used by GraphQL to represent free-form human-readable text.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Int", - "description": "The `Int` scalar type represents non-fractional signed whole numeric values. Int can represent values between -(2^31) and 2^31 - 1.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Float", - "description": "The `Float` scalar type represents signed double-precision fractional values as specified by [IEEE 754](https://en.wikipedia.org/wiki/IEEE_floating_point).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "Boolean", - "description": "The `Boolean` scalar type represents `true` or `false`.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "ID", - "description": "The `ID` scalar type represents a unique identifier, often used to refetch an object or as key for a cache. The ID type appears in a JSON response as a String; however, it is not intended to be human-readable. When expected as an input type, any string (such as `\"4\"`) or integer (such as `4`) input value will be accepted as an ID.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "BerkeleytimeUserType", - "description": null, - "fields": [ - { - "name": "id", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "UserType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "major", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "savedClasses", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CourseType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "emailClassUpdate", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "emailGradeUpdate", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "emailEnrollmentOpening", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "emailBerkeleytimeUpdate", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CourseType", - "description": null, - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "title", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "department", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "abbreviation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "courseNumber", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "units", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "prerequisites", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gradeAverage", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "letterAverage", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hasEnrollment", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolled", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolledMax", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolledPercentage", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "waitlisted", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "openSeats", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastUpdated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sectionSet", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "course", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "abbreviation", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "year", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "semester", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseTitle", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "sectionNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "ccn", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "kind", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "isPrimary", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "days", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "startTime", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "endTime", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalDay", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalEnd", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "finalStart", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "instructor", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "disabled", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "locationName", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "instructionMode", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "lastUpdated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlistedMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SectionTypeConnection", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gradeSet", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "GradeTypeConnection", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "playlistSet", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "category", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "name", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "semester", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "year", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courses", - "description": null, - "type": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PlaylistTypeConnection", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "berkeleytimeuserSet", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [{ "kind": "INTERFACE", "name": "Node", "ofType": null }], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CourseTypeConnection", - "description": null, - "fields": [ - { - "name": "pageInfo", - "description": "Pagination data for this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "Contains the nodes in this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CourseTypeEdge", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "CourseTypeEdge", - "description": "A Relay edge containing a `CourseType` and its cursor.", - "fields": [ - { - "name": "node", - "description": "The item at the end of the edge", - "args": [], - "type": { "kind": "OBJECT", "name": "CourseType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "A cursor for use in pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "DateTime", - "description": "The `DateTime` scalar type represents a DateTime\nvalue as specified by\n[iso8601](https://en.wikipedia.org/wiki/ISO_8601).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EnrollmentType", - "description": null, - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "section", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SectionType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dateCreated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolled", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolledMax", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "waitlisted", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "waitlistedMax", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [{ "kind": "INTERFACE", "name": "Node", "ofType": null }], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EnrollmentTypeConnection", - "description": null, - "fields": [ - { - "name": "pageInfo", - "description": "Pagination data for this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "Contains the nodes in this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "EnrollmentTypeEdge", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "EnrollmentTypeEdge", - "description": "A Relay edge containing a `EnrollmentType` and its cursor.", - "fields": [ - { - "name": "node", - "description": "The item at the end of the edge", - "args": [], - "type": { "kind": "OBJECT", "name": "EnrollmentType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "A cursor for use in pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "FormConfigType", - "description": null, - "fields": [ - { - "name": "field", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "JSONString", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "GenericScalar", - "description": "The `GenericScalar` scalar type represents a generic\nGraphQL scalar value that could be:\nString, Boolean, Int, Float, List or Object.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GradeType", - "description": null, - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "course", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CourseType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "semester", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "year", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "abbreviation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "courseNumber", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sectionNumber", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instructor", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instructors", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "a1", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "a2", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "a3", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "b1", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "b2", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "b3", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "c1", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "c2", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "c3", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "d1", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "d2", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "d3", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "f", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "gradedTotal", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "p", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "np", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "average", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Float", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [{ "kind": "INTERFACE", "name": "Node", "ofType": null }], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GradeTypeConnection", - "description": null, - "fields": [ - { - "name": "pageInfo", - "description": "Pagination data for this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "Contains the nodes in this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "GradeTypeEdge", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "GradeTypeEdge", - "description": "A Relay edge containing a `GradeType` and its cursor.", - "fields": [ - { - "name": "node", - "description": "The item at the end of the edge", - "args": [], - "type": { "kind": "OBJECT", "name": "GradeType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "A cursor for use in pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "SCALAR", - "name": "JSONString", - "description": "Allows use of a JSON String for input / output from the GraphQL schema.\n\nUse of this type is *not recommended* as you lose the benefits of having a defined, static\nschema (one of the key benefits of GraphQL).", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Mutation", - "description": null, - "fields": [ - { - "name": "updateUser", - "description": null, - "args": [ - { - "name": "emailBerkeleytimeUpdate", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "emailClassUpdate", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "emailEnrollmentOpening", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "emailGradeUpdate", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "major", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "UpdateUser", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "saveClass", - "description": null, - "args": [ - { - "name": "classId", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "SaveClass", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "removeClass", - "description": null, - "args": [ - { - "name": "classId", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "RemoveClass", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "login", - "description": "Login mutation using graphql_jwt ", - "args": [ - { - "name": "tokenId", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "ObtainJSONWebToken", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "verifyToken", - "description": null, - "args": [ - { - "name": "token", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "Verify", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "refreshToken", - "description": null, - "args": [ - { - "name": "token", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - } - ], - "type": { "kind": "OBJECT", "name": "Refresh", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "INTERFACE", - "name": "Node", - "description": "An object with an ID", - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": [ - { "kind": "OBJECT", "name": "CourseType", "ofType": null }, - { "kind": "OBJECT", "name": "EnrollmentType", "ofType": null }, - { "kind": "OBJECT", "name": "GradeType", "ofType": null }, - { "kind": "OBJECT", "name": "PlaylistType", "ofType": null }, - { "kind": "OBJECT", "name": "SectionType", "ofType": null } - ] - }, - { - "kind": "OBJECT", - "name": "ObtainJSONWebToken", - "description": "Login mutation using graphql_jwt ", - "fields": [ - { - "name": "payload", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "GenericScalar", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "refreshExpiresIn", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "user", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "newUser", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PageInfo", - "description": "The Relay compliant `PageInfo` type, containing data necessary to paginate this connection.", - "fields": [ - { - "name": "hasNextPage", - "description": "When paginating forwards, are there more items?", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "hasPreviousPage", - "description": "When paginating backwards, are there more items?", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "startCursor", - "description": "When paginating backwards, the cursor to continue.", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endCursor", - "description": "When paginating forwards, the cursor to continue.", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PlaylistType", - "description": null, - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "category", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "semester", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "year", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "courses", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "title", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "department", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "abbreviation", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "courseNumber", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "description", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "units", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "prerequisites", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "gradeAverage", - "description": null, - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - }, - { - "name": "letterAverage", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "hasEnrollment", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledPercentage", - "description": null, - "type": { "kind": "SCALAR", "name": "Float", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "openSeats", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "lastUpdated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CourseTypeConnection", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [{ "kind": "INTERFACE", "name": "Node", "ofType": null }], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PlaylistTypeConnection", - "description": null, - "fields": [ - { - "name": "pageInfo", - "description": "Pagination data for this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "Contains the nodes in this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PlaylistTypeEdge", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "PlaylistTypeEdge", - "description": "A Relay edge containing a `PlaylistType` and its cursor.", - "fields": [ - { - "name": "node", - "description": "The item at the end of the edge", - "args": [], - "type": { "kind": "OBJECT", "name": "PlaylistType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "A cursor for use in pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Refresh", - "description": null, - "fields": [ - { - "name": "payload", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "GenericScalar", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "refreshExpiresIn", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Int", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "RemoveClass", - "description": null, - "fields": [ - { - "name": "user", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SaveClass", - "description": null, - "fields": [ - { - "name": "user", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SectionType", - "description": null, - "fields": [ - { - "name": "id", - "description": "The ID of the object.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "course", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "CourseType", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "abbreviation", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "courseNumber", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "year", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "semester", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "courseTitle", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "sectionNumber", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ccn", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isPrimary", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "days", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "startTime", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "endTime", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "finalDay", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "finalEnd", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "finalStart", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instructor", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "disabled", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locationName", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "instructionMode", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastUpdated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolled", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrolledMax", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "waitlisted", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "waitlistedMax", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enrollmentSet", - "description": null, - "args": [ - { - "name": "before", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "after", - "description": null, - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": null - }, - { - "name": "first", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "last", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "section", - "description": null, - "type": { "kind": "SCALAR", "name": "ID", "ofType": null }, - "defaultValue": null - }, - { - "name": "dateCreated", - "description": null, - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolled", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "enrolledMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlisted", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - }, - { - "name": "waitlistedMax", - "description": null, - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, - "defaultValue": null - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "EnrollmentTypeConnection", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "wordDays", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [{ "kind": "INTERFACE", "name": "Node", "ofType": null }], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SectionTypeConnection", - "description": null, - "fields": [ - { - "name": "pageInfo", - "description": "Pagination data for this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "PageInfo", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "edges", - "description": "Contains the nodes in this connection.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { "kind": "OBJECT", "name": "SectionTypeEdge", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "SectionTypeEdge", - "description": "A Relay edge containing a `SectionType` and its cursor.", - "fields": [ - { - "name": "node", - "description": "The item at the end of the edge", - "args": [], - "type": { "kind": "OBJECT", "name": "SectionType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "cursor", - "description": "A cursor for use in pagination", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UpdateUser", - "description": null, - "fields": [ - { - "name": "user", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "UserType", - "description": null, - "fields": [ - { - "name": "id", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "ID", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "password", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastLogin", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "DateTime", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isSuperuser", - "description": "Designates that this user has all permissions without explicitly assigning them.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "username", - "description": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "firstName", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "lastName", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "email", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isStaff", - "description": "Designates whether the user can log into this admin site.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isActive", - "description": "Designates whether this user should be treated as active. Unselect this instead of deleting accounts.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "dateJoined", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "DateTime", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "berkeleytimeuser", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "BerkeleytimeUserType", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "Verify", - "description": null, - "fields": [ - { - "name": "payload", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "GenericScalar", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Schema", - "description": "A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations.", - "fields": [ - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "types", - "description": "A list of all types supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "queryType", - "description": "The type that query operations will be rooted at.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "mutationType", - "description": "If this server supports mutation, the type that mutation operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "subscriptionType", - "description": "If this server support subscription, the type that subscription operations will be rooted at.", - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "directives", - "description": "A list of all directives supported by this server.", - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Directive", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Type", - "description": "The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum.\n\nDepending on the kind of a type, certain fields describe information about that type. Scalar types provide no information beyond a name, description and optional `specifiedByUrl`, while Enum types provide their values. Object and Interface types provide the fields they describe. Abstract types, Union and Interface, provide the Object types possible at runtime. List and NonNull types compose other types.", - "fields": [ - { - "name": "kind", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__TypeKind", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "name", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "specifiedByUrl", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "fields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Field", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "interfaces", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "possibleTypes", - "description": null, - "args": [], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "enumValues", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__EnumValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "inputFields", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ofType", - "description": null, - "args": [], - "type": { "kind": "OBJECT", "name": "__Type", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__TypeKind", - "description": "An enum describing what kind of type a given `__Type` is.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "SCALAR", - "description": "Indicates this type is a scalar.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Indicates this type is an object. `fields` and `interfaces` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Indicates this type is an interface. `fields`, `interfaces`, and `possibleTypes` are valid fields.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Indicates this type is a union. `possibleTypes` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Indicates this type is an enum. `enumValues` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Indicates this type is an input object. `inputFields` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "LIST", - "description": "Indicates this type is a list. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "NON_NULL", - "description": "Indicates this type is a non-null. `ofType` is a valid field.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Field", - "description": "Object and Interface types are described by a list of Fields, each of which has a name, potentially a list of arguments, and a return type.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [ - { - "name": "includeDeprecated", - "description": null, - "type": { "kind": "SCALAR", "name": "Boolean", "ofType": null }, - "defaultValue": "false" - } - ], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__InputValue", - "description": "Arguments provided to Fields or Directives and the input fields of an InputObject are represented as Input Values which describe their type and optionally a default value.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "type", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__Type", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "defaultValue", - "description": "A GraphQL-formatted string representing the default value for this input value.", - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__EnumValue", - "description": "One possible value for a given Enum. Enum values are unique values, not a placeholder for a string or numeric value. However an Enum value is returned in a JSON response as a string.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isDeprecated", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "deprecationReason", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "OBJECT", - "name": "__Directive", - "description": "A Directive provides a way to describe alternate runtime execution and type validation behavior in a GraphQL document.\n\nIn some cases, you need to provide options to alter GraphQL's execution behavior in ways field arguments will not suffice, such as conditionally including or skipping a field. Directives provide this by describing additional information to the executor.", - "fields": [ - { - "name": "name", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "description", - "description": null, - "args": [], - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "isRepeatable", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "locations", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "ENUM", "name": "__DirectiveLocation", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "args", - "description": null, - "args": [], - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { - "kind": "LIST", - "name": null, - "ofType": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "OBJECT", "name": "__InputValue", "ofType": null } - } - } - }, - "isDeprecated": false, - "deprecationReason": null - } - ], - "inputFields": null, - "interfaces": [], - "enumValues": null, - "possibleTypes": null - }, - { - "kind": "ENUM", - "name": "__DirectiveLocation", - "description": "A Directive can be adjacent to many parts of the GraphQL language, a __DirectiveLocation describes one such possible adjacencies.", - "fields": null, - "inputFields": null, - "interfaces": null, - "enumValues": [ - { - "name": "QUERY", - "description": "Location adjacent to a query operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "MUTATION", - "description": "Location adjacent to a mutation operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SUBSCRIPTION", - "description": "Location adjacent to a subscription operation.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD", - "description": "Location adjacent to a field.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_DEFINITION", - "description": "Location adjacent to a fragment definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FRAGMENT_SPREAD", - "description": "Location adjacent to a fragment spread.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INLINE_FRAGMENT", - "description": "Location adjacent to an inline fragment.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "VARIABLE_DEFINITION", - "description": "Location adjacent to a variable definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCHEMA", - "description": "Location adjacent to a schema definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "SCALAR", - "description": "Location adjacent to a scalar definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "OBJECT", - "description": "Location adjacent to an object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "FIELD_DEFINITION", - "description": "Location adjacent to a field definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ARGUMENT_DEFINITION", - "description": "Location adjacent to an argument definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INTERFACE", - "description": "Location adjacent to an interface definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "UNION", - "description": "Location adjacent to a union definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM", - "description": "Location adjacent to an enum definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "ENUM_VALUE", - "description": "Location adjacent to an enum value definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_OBJECT", - "description": "Location adjacent to an input object type definition.", - "isDeprecated": false, - "deprecationReason": null - }, - { - "name": "INPUT_FIELD_DEFINITION", - "description": "Location adjacent to an input object field definition.", - "isDeprecated": false, - "deprecationReason": null - } - ], - "possibleTypes": null - } - ], - "directives": [ - { - "name": "include", - "description": "Directs the executor to include this field or fragment only when the `if` argument is true.", - "isRepeatable": false, - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Included when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "skip", - "description": "Directs the executor to skip this field or fragment when the `if` argument is true.", - "isRepeatable": false, - "locations": ["FIELD", "FRAGMENT_SPREAD", "INLINE_FRAGMENT"], - "args": [ - { - "name": "if", - "description": "Skipped when true.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "Boolean", "ofType": null } - }, - "defaultValue": null - } - ] - }, - { - "name": "deprecated", - "description": "Marks an element of a GraphQL schema as no longer supported.", - "isRepeatable": false, - "locations": [ - "FIELD_DEFINITION", - "ARGUMENT_DEFINITION", - "INPUT_FIELD_DEFINITION", - "ENUM_VALUE" - ], - "args": [ - { - "name": "reason", - "description": "Explains why this element was deprecated, usually also including a suggestion for how to access supported similar data. Formatted using the Markdown syntax, as specified by [CommonMark](https://commonmark.org/).", - "type": { "kind": "SCALAR", "name": "String", "ofType": null }, - "defaultValue": "\"No longer supported\"" - } - ] - }, - { - "name": "specifiedBy", - "description": "Exposes a URL that specifies the behaviour of this scalar.", - "isRepeatable": false, - "locations": ["SCALAR"], - "args": [ - { - "name": "url", - "description": "The URL that specifies the behaviour of this scalar.", - "type": { - "kind": "NON_NULL", - "name": null, - "ofType": { "kind": "SCALAR", "name": "String", "ofType": null } - }, - "defaultValue": null - } - ] - } - ] - } -} diff --git a/frontend/src/graphql/mutations/CreateSchedule.graphql b/frontend/src/graphql/mutations/CreateSchedule.graphql deleted file mode 100644 index e078d3873..000000000 --- a/frontend/src/graphql/mutations/CreateSchedule.graphql +++ /dev/null @@ -1,23 +0,0 @@ -mutation CreateSchedule( - $name: String! - $selectedSections: [SectionSelectionInput]! - $timeblocks: [TimeBlockInput]! - $totalUnits: String! - $semester: String! - $year: String! - $public: Boolean! -) { - createSchedule( - name: $name - selectedSections: $selectedSections - timeblocks: $timeblocks - semester: $semester - year: $year - public: $public - totalUnits: $totalUnits - ) { - schedule { - ...Schedule - } - } -} diff --git a/frontend/src/graphql/mutations/DeleteSchedule.graphql b/frontend/src/graphql/mutations/DeleteSchedule.graphql deleted file mode 100644 index b7ba2c78e..000000000 --- a/frontend/src/graphql/mutations/DeleteSchedule.graphql +++ /dev/null @@ -1,7 +0,0 @@ -mutation DeleteSchedule($id: ID!) { - removeSchedule(scheduleId: $id) { - schedule { - id - } - } -} diff --git a/frontend/src/graphql/mutations/DeleteUser.graphql b/frontend/src/graphql/mutations/DeleteUser.graphql deleted file mode 100644 index 126327f40..000000000 --- a/frontend/src/graphql/mutations/DeleteUser.graphql +++ /dev/null @@ -1,5 +0,0 @@ -mutation DeleteUser { - deleteUser { - success - } -} diff --git a/frontend/src/graphql/mutations/Logout.graphql b/frontend/src/graphql/mutations/Logout.graphql deleted file mode 100644 index 430947857..000000000 --- a/frontend/src/graphql/mutations/Logout.graphql +++ /dev/null @@ -1,5 +0,0 @@ -mutation Logout { - logout { - success - } -} diff --git a/frontend/src/graphql/mutations/SaveCourse.graphql b/frontend/src/graphql/mutations/SaveCourse.graphql deleted file mode 100644 index 3c2a8ff86..000000000 --- a/frontend/src/graphql/mutations/SaveCourse.graphql +++ /dev/null @@ -1,10 +0,0 @@ -mutation SaveCourse($courseId: ID!) { - saveClass(classId: $courseId) { - user { - id - savedClasses { - ...CourseOverview - } - } - } -} diff --git a/frontend/src/graphql/mutations/UnsaveCourse.graphql b/frontend/src/graphql/mutations/UnsaveCourse.graphql deleted file mode 100644 index 34031f5d8..000000000 --- a/frontend/src/graphql/mutations/UnsaveCourse.graphql +++ /dev/null @@ -1,10 +0,0 @@ -mutation UnsaveCourse($courseId: ID!) { - removeClass(classId: $courseId) { - user { - id - savedClasses { - ...CourseOverview - } - } - } -} diff --git a/frontend/src/graphql/mutations/UpdateSchedule.graphql b/frontend/src/graphql/mutations/UpdateSchedule.graphql deleted file mode 100644 index 0329fcac4..000000000 --- a/frontend/src/graphql/mutations/UpdateSchedule.graphql +++ /dev/null @@ -1,21 +0,0 @@ -mutation UpdateSchedule( - $scheduleId: ID! - $name: String! - $selectedSections: [SectionSelectionInput]! - $timeblocks: [TimeBlockInput]! - $totalUnits: String! - $public: Boolean! -) { - updateSchedule( - scheduleId: $scheduleId - name: $name - selectedSections: $selectedSections - timeblocks: $timeblocks - totalUnits: $totalUnits - public: $public - ) { - schedule { - ...Schedule - } - } -} diff --git a/frontend/src/graphql/mutations/UpdateUser.graphql b/frontend/src/graphql/mutations/UpdateUser.graphql deleted file mode 100644 index 5459febf5..000000000 --- a/frontend/src/graphql/mutations/UpdateUser.graphql +++ /dev/null @@ -1,24 +0,0 @@ -mutation UpdateUser( - $emailBerkeleytimeUpdate: Boolean - $emailClassUpdate: Boolean - $emailEnrollmentOpening: Boolean - $emailGradeUpdate: Boolean - $major: String -) { - updateUser( - emailBerkeleytimeUpdate: $emailBerkeleytimeUpdate - emailClassUpdate: $emailClassUpdate - emailEnrollmentOpening: $emailEnrollmentOpening - emailGradeUpdate: $emailGradeUpdate - major: $major - ) { - user { - id # Get the ID prop so Apollo can update the user - major - emailGradeUpdate - emailEnrollmentOpening - emailClassUpdate - emailBerkeleytimeUpdate - } - } -} diff --git a/frontend/src/graphql/mutations/login.graphql b/frontend/src/graphql/mutations/login.graphql deleted file mode 100644 index ee1d6ff93..000000000 --- a/frontend/src/graphql/mutations/login.graphql +++ /dev/null @@ -1,10 +0,0 @@ -mutation Login($token: String!) { - login(tokenId: $token) { - newUser - refreshExpiresIn - payload - user { - ...UserProfile - } - } -} diff --git a/frontend/src/graphql/queries/GetCourseForId.graphql b/frontend/src/graphql/queries/GetCourseForId.graphql deleted file mode 100644 index fafc7cc7a..000000000 --- a/frontend/src/graphql/queries/GetCourseForId.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetCourseForId($id: ID!, $year: String, $semester: String) { - course(id: $id) { - ...Course - } -} diff --git a/frontend/src/graphql/queries/GetCourseForName.graphql b/frontend/src/graphql/queries/GetCourseForName.graphql deleted file mode 100644 index fde953cf5..000000000 --- a/frontend/src/graphql/queries/GetCourseForName.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query GetCourseForName( - $abbreviation: String! - $courseNumber: String! - $year: String - $semester: String -) { - allCourses(abbreviation: $abbreviation, courseNumber: $courseNumber, first: 1) { - edges { - node { - ...Course - } - } - } -} diff --git a/frontend/src/graphql/queries/GetCoursesForFilter.graphql b/frontend/src/graphql/queries/GetCoursesForFilter.graphql deleted file mode 100644 index b2d1b65f1..000000000 --- a/frontend/src/graphql/queries/GetCoursesForFilter.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query GetCoursesForFilter($playlists: String!) { - allCourses(inPlaylists: $playlists) { - edges { - node { - ...CourseOverview - } - } - } -} diff --git a/frontend/src/graphql/queries/GetFilters.graphql b/frontend/src/graphql/queries/GetFilters.graphql deleted file mode 100644 index b34ab4e21..000000000 --- a/frontend/src/graphql/queries/GetFilters.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query GetFilters { - allPlaylists { - edges { - node { - ...Filter - } - } - } -} diff --git a/frontend/src/graphql/queries/GetScheduleForId.graphql b/frontend/src/graphql/queries/GetScheduleForId.graphql deleted file mode 100644 index 63465ea9d..000000000 --- a/frontend/src/graphql/queries/GetScheduleForId.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetScheduleForId($id: ID!) { - schedule(id: $id) { - ...Schedule - } -} diff --git a/frontend/src/graphql/queries/GetSchedulerCourseForId.graphql b/frontend/src/graphql/queries/GetSchedulerCourseForId.graphql deleted file mode 100644 index 8f5b2cf74..000000000 --- a/frontend/src/graphql/queries/GetSchedulerCourseForId.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetSchedulerCourseForId($id: ID!, $year: String, $semester: String) { - course(id: $id) { - ...SchedulerCourse - } -} diff --git a/frontend/src/graphql/queries/GetSemesters.graphql b/frontend/src/graphql/queries/GetSemesters.graphql deleted file mode 100644 index 714248988..000000000 --- a/frontend/src/graphql/queries/GetSemesters.graphql +++ /dev/null @@ -1,9 +0,0 @@ -query GetSemesters($name: String) { - allPlaylists(category: "semester", name: $name) { - edges { - node { - ...Filter - } - } - } -} diff --git a/frontend/src/graphql/queries/GetUser.graphql b/frontend/src/graphql/queries/GetUser.graphql deleted file mode 100644 index e2685a467..000000000 --- a/frontend/src/graphql/queries/GetUser.graphql +++ /dev/null @@ -1,5 +0,0 @@ -query GetUser { - user { - ...UserProfile - } -} diff --git a/frontend/src/hooks/usePrefersColorScheme.tsx b/frontend/src/hooks/usePrefersColorScheme.tsx new file mode 100644 index 000000000..a835802bc --- /dev/null +++ b/frontend/src/hooks/usePrefersColorScheme.tsx @@ -0,0 +1,22 @@ +import { useEffect, useState } from "react"; + +const usePrefersColorScheme = () => { + const [value, setValue] = useState( + window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" + ); + + useEffect(() => { + const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)"); + + const handleChange = (event: MediaQueryListEvent) => + setValue(event.matches ? "dark" : "light"); + + mediaQuery.addEventListener("change", handleChange); + + return () => mediaQuery.removeEventListener("change", handleChange); + }, []); + + return value; +}; + +export default usePrefersColorScheme; diff --git a/frontend/src/hooks/useWindowDimensions.tsx b/frontend/src/hooks/useWindowDimensions.tsx new file mode 100644 index 000000000..0e901a107 --- /dev/null +++ b/frontend/src/hooks/useWindowDimensions.tsx @@ -0,0 +1,18 @@ +import { useEffect, useState } from "react"; + +export default function useWindowDimensions() { + const [height, setHeight] = useState(window.innerHeight); + const [width, setWidth] = useState(window.innerWidth); + + useEffect(() => { + const handleResize = () => { + setHeight(window.innerHeight); + setWidth(window.innerWidth); + }; + + window.addEventListener("resize", handleResize); + return () => window.removeEventListener("resize", handleResize); + }, []); + + return { height, width }; +} diff --git a/frontend/src/index.html b/frontend/src/index.html deleted file mode 100644 index 9f83a6807..000000000 --- a/frontend/src/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - - - - - - - - Berkeleytime - - -
- - diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx deleted file mode 100644 index b61ca971b..000000000 --- a/frontend/src/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { createRoot } from 'react-dom/client'; -import { BrowserRouter } from 'react-router-dom'; -import { Provider } from 'react-redux'; -import { ApolloProvider } from '@apollo/client'; - -import ScrollToTop from './components/Common/ScrollToTop'; -import LogPageView from './components/Common/LogPageView'; -import Berkeleytime from './Berkeleytime'; -import store from './redux/store'; -import client from './graphql/client'; - -import 'assets/scss/berkeleytime.scss'; -import 'react-loading-skeleton/dist/skeleton.css'; -import Banner from 'components/Common/Banner'; - -const root = createRoot(document.getElementById('root') as HTMLElement); - -root.render( - - - - - - - - - - -); diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts new file mode 100644 index 000000000..1ddb54d80 --- /dev/null +++ b/frontend/src/lib/api.ts @@ -0,0 +1,468 @@ +import { gql } from "@apollo/client"; + +export enum Semester { + Fall = "Fall", + Spring = "Spring", + Summer = "Summer", + Winter = "Winter", +} + +export enum Component { + Workshop = "WOR", + WebBasedDiscussion = "WBD", + Clinic = "CLN", + Practicum = "PRA", + DirectedGroupStudy = "GRP", + Discussion = "DIS", + Voluntary = "VOL", + Tutorial = "TUT", + FieldWork = "FLD", + Lecture = "LEC", + Supplementary = "SUP", + Laboratory = "LAB", + Session = "SES", + Studio = "STD", + SelfPaced = "SLF", + Colloquium = "COL", + WebBasedLecture = "WBL", + IndependentStudy = "IND", + Internship = "INT", + Reading = "REA", + Recitation = "REC", + Seminar = "SEM", +} + +export const components: Record = { + [Component.Lecture]: "Lecture", + [Component.Seminar]: "Seminar", + [Component.IndependentStudy]: "Independent Study", + [Component.DirectedGroupStudy]: "Directed Group Study", + [Component.Studio]: "Studio", + [Component.Laboratory]: "Laboratory", + [Component.Workshop]: "Workshop", + [Component.WebBasedDiscussion]: "Web-Based Discussion", + [Component.Clinic]: "Clinic", + [Component.Practicum]: "Practicum", + [Component.Discussion]: "Discussion", + [Component.Voluntary]: "Voluntary", + [Component.Tutorial]: "Tutorial", + [Component.FieldWork]: "Field Work", + [Component.Supplementary]: "Supplementary", + [Component.Session]: "Session", + [Component.SelfPaced]: "Self-paced", + [Component.Colloquium]: "Colloquium", + [Component.WebBasedLecture]: "Web-Based Lecture", + [Component.Internship]: "Internship", + [Component.Reading]: "Reading", + [Component.Recitation]: "Recitation", +}; + +export enum AcademicCareer { + Undergraduate = "UGRD", + Graduate = "GRAD", + Extension = "UCBX", +} + +export const academicCareers: Record = { + [AcademicCareer.Undergraduate]: "Undergraduate", + [AcademicCareer.Graduate]: "Graduate", + [AcademicCareer.Extension]: "Extension", +}; + +export enum FinalExam { + Written = "Y", + Common = "C", + None = "N", + Alternate = "A", + Undecided = "D", +} + +export interface IInstructor { + familyName: string; + givenName: string; +} + +export interface IExam { + date: string; + location: string; + final: boolean; + startTime: string; + endTime: string; +} + +export interface ISection { + ccn: string; + class: IClass; + course: ICourse; + enrollCount: number; + enrollMax: number; + component: Component; + number: string; + primary: boolean; + waitlistCount: number; + waitlistMax: number; + online: boolean; + open: boolean; + meetings: IMeeting[]; + reservations: IReservation[]; + startDate: string; + endDate: string; + exams: IExam[]; +} + +export interface IReservation { + enrollCount: number; + enrollMax: number; + group: string; +} + +export interface IMeeting { + days: boolean[]; + endTime: string; + location: string; + startTime: string; + instructors: IInstructor[]; +} + +export interface IClass { + course: ICourse; + primarySection: ISection; + sections: ISection[]; + session: string; + gradingBasis: string; + finalExam: string; + description: string | null; + year: number; + semester: Semester; + title: string | null; + unitsMax: number; + unitsMin: number; + number: string; +} + +export interface ICourse { + classes: IClass[]; + crossListing: ICourse[]; + sections: ISection[]; + requiredCourses: ICourse[]; + requirements: string | null; + primaryComponent: Component; + description: string; + fromDate: string; + gradeAverage: number | null; + gradingBasis: string; + finalExam: string | null; + academicCareer: AcademicCareer; + title: string; + subject: string; + number: string; + toDate: string; +} + +export interface IAccount { + email: string; + first_name: string; + last_name: string; +} + +export interface ISchedule { + _id: string; + name: string; + term: { + year: number; + semester: Semester; + }; +} + +export const GET_COURSE = gql` + query GetCourse($subject: String!, $courseNumber: String!) { + course(subject: $subject, courseNumber: $courseNumber) { + title + description + subject + number + academicCareer + gradeAverage + gradingBasis + finalExam + requirements + requiredCourses { + subject + number + } + classes { + year + semester + number + } + } + } +`; + +export const GET_CLASS = gql` + query GetClass( + $term: TermInput! + $subject: String! + $courseNumber: String! + $classNumber: String! + ) { + class( + term: $term + subject: $subject + courseNumber: $courseNumber + classNumber: $classNumber + ) { + title + description + unitsMax + unitsMin + number + gradingBasis + finalExam + course { + title + description + gradeAverage + subject + number + academicCareer + requirements + requiredCourses { + subject + number + } + classes { + year + semester + number + } + } + primarySection { + course { + subject + number + } + reservations { + enrollCount + enrollMax + group + } + ccn + enrollCount + enrollMax + meetings { + days + location + endTime + startTime + instructors { + familyName + givenName + } + } + exams { + date + final + location + startTime + endTime + } + component + waitlistCount + waitlistMax + number + startDate + endDate + } + sections { + course { + subject + number + } + ccn + enrollCount + enrollMax + exams { + date + final + location + startTime + endTime + } + meetings { + days + endTime + startTime + location + instructors { + familyName + givenName + } + } + component + waitlistCount + waitlistMax + number + startDate + endDate + } + } + } +`; + +export interface GetCoursesResponse { + courseList: ICourse[]; +} + +export const GET_COURSES = gql` + query GetCourses { + courseList { + subject + number + title + gradeAverage + academicCareer + finalExam + gradingBasis + classes { + year + semester + } + } + } +`; + +export interface GetClassesResponse { + catalog: ICourse[]; +} + +export const GET_CLASSES = gql` + query GetClasses($term: TermInput!) { + catalog(term: $term) { + subject + number + title + gradeAverage + academicCareer + classes { + number + title + unitsMax + session + unitsMin + finalExam + gradingBasis + primarySection { + component + online + open + enrollCount + enrollMax + waitlistCount + waitlistMax + meetings { + days + } + } + } + } + } +`; + +export interface AccountResponse { + user: IAccount; +} + +export const GET_ACCOUNT = gql` + query GetAccount { + user { + email + first_name + last_name + } + } +`; + +export interface GetScheduleResponse { + scheduleByID: ISchedule; +} + +export const GET_SCHEDULE = gql` + query GetSchedule($id: String!) { + scheduleByID(id: $id) { + _id + name + term { + year + semester + } + } + } +`; + +export const DELETE_SCHEDULE = gql` + mutation DeleteSchedule($id: ID!) { + removeScheduleByID(id: $id) + } +`; + +export interface CreateScheduleResponse { + createNewSchedule: ISchedule; +} + +export const CREATE_SCHEDULE = gql` + mutation CreateSchedule( + $name: String! + $term: TermInput! + $createdBy: String! + ) { + createNewSchedule( + main_schedule: { + courses: [] + created_by: $createdBy + name: $name + custom_events: [] + is_public: false + term: $term + } + ) { + _id + name + term { + year + semester + } + } + } +`; + +export interface GetSchedulesResponse { + schedulesByUser: ISchedule[]; +} + +export const GET_SCHEDULES = gql` + query GetSchedules($createdBy: String!) { + schedulesByUser(created_by: $createdBy) { + _id + name + term { + year + semester + } + } + } +`; + +export const signIn = (redirectURI?: string) => { + redirectURI = + redirectURI ?? window.location.pathname + window.location.search; + + window.location.href = `${window.location.origin}/api/login?redirect_uri=${redirectURI}`; +}; + +export const signOut = async (redirectURI?: string) => { + redirectURI = + redirectURI ?? window.location.pathname + window.location.search; + + window.location.href = `${window.location.origin}/api/logout?redirect_uri=${redirectURI}`; +}; diff --git a/frontend/src/lib/contributors.ts b/frontend/src/lib/contributors.ts deleted file mode 100644 index 10f82a6e8..000000000 --- a/frontend/src/lib/contributors.ts +++ /dev/null @@ -1,506 +0,0 @@ -export type Contributors = { - name: string; - items: { - name: string; - role: string; - img?: { - base: string; - silly: string | undefined; - }; - site: string | null; - }[]; -}; - -const path = (path: string) => new URL(`../assets/img/about/2022-23/${path}`, import.meta.url).href; - -export const current: Contributors = { - name: 'Current Team', - items: [ - { - name: 'Kevin Wang', - role: 'Product Manager and Backend Engineer', - site: 'https://kevwang.dev/', - img: { - base: path('kevin_1.jpg'), - silly: path('kevin_2.jpg') - } - }, - { - name: 'Zachary Zollman', - role: 'Backend Lead', - site: 'https://zacharyzollman.com/', - img: { - base: path('zachary_1.jpg'), - silly: path('zachary_2.jpg') - } - }, - { - name: 'Matthew Rowland', - role: 'Frontend Lead', - site: 'https://www.linkedin.com/in/matthew-rowland-dev/', - img: { - base: path('matthew_1.jpg'), - silly: path('matthew_2.jpg') - } - }, - { - name: 'Michelle Tran', - role: 'Design Lead', - site: 'https://michelletran.design', - img: { - base: path('michelle_1.jpg'), - silly: path('michelle_2.jpg') - } - }, - { - name: 'Henric Zhang', - role: 'Frontend Engineer', - site: null, - img: { - base: path('henric_1.jpg'), - silly: path('henric_2.jpg') - } - }, - { - name: 'Jaden Moore', - role: 'Frontend Engineer', - site: null, - img: { - base: path('jaden_1.jpg'), - silly: undefined - } - }, - { - name: 'Alexander Lew', - role: 'Frontend Engineer', - site: 'https://www.qxbytes.com', - img: { - base: path('alexander_1.jpg'), - silly: undefined - } - }, - { - name: 'Levi Kline', - role: 'Frontend Engineer', - site: 'https://levibkline.com', - img: { - base: path('levi_1.jpg'), - silly: undefined - } - }, - { - name: 'Joel Jaison', - role: 'Frontend Engineer', - site: null, - img: { - base: path('joel_1.jpg'), - silly: path('joel_1.jpg') - } - }, - { - name: 'Eric Xu', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/e-xu-at-berkeley', - img: { - base: path('eric_1.jpg'), - silly: path('eric_2.jpg') - } - }, - { - name: 'Max Wang', - role: 'Backend Engineer', - img: { - base: path('max_1.jpg'), - silly: undefined - }, - site: null - }, - { - name: 'Michael Khaykin', - role: 'Backend Engineer', - site: null, - img: { - base: path('michael_1.jpg'), - silly: undefined - } - }, - { - name: 'William Tang', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/william-tang-cal/', - img: { - base: path('william_1.jpg'), - silly: path('william_2.jpg') - } - }, - { - name: 'Ethan Ikegami', - role: 'Backend Engineer', - site: 'https://ethanikegami.com/', - img: { - base: path('ethan_1.jpg'), - silly: path('ethan_2.jpg') - } - }, - { - name: 'Carissa Cui', - role: 'Designer', - site: 'https://www.carissacui.com', - img: { - base: path('carissa_1.jpg'), - silly: undefined - } - }, - { - name: 'Joanne Chuang', - role: 'Designer', - site: null, - img: { - base: path('joanne_1.jpg'), - silly: path('joanne_2.jpg') - } - }, - { - name: 'Rachel Hua', - role: 'Designer', - site: 'https://www.linkedin.com/in/byrachelhua/', - img: { - base: path('rachel_1.jpg'), - silly: undefined - } - } - ] -}; - -export const past: Contributors[] = [ - { - name: 'Class of 2024', - items: [ - { - name: 'Kelly Ma', - role: 'Design Lead', - site: 'https://kellymadesign.com' - }, - { - name: 'Shuming Xu', - role: 'Backend Engineer', - site: 'https://shumingxu.com/' - }, - { - name: 'Alex Zhang', - role: 'Backend Engineer', - site: null - }, - { - name: 'Nikhil Jha', - role: 'Backend Engineer', - site: null - }, - { - name: 'Nikhil Ograin', - role: 'Backend Engineer', - site: null - }, - { - name: 'Vihan Bhargava', - role: 'Frontend Engineer', - site: 'https://vihan.org/' - }, - { - name: 'Gabe Mitnick', - role: 'Frontend Engineer', - site: 'https://gabe-mitnick.github.io/' - } - ] - }, - { - name: 'Class of 2023', - items: [ - { - name: 'Annie Pan', - role: 'Designer', - site: 'http://anniexpan.com/' - }, - { - name: 'Cici Wei', - role: 'Designer', - site: null - }, - { - name: 'Alex Xi', - role: 'Backend Lead', - site: 'https://www.alexhxi.com/' - }, - { - name: 'Yueheng Zhang', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/azicon/' - } - ] - }, - { - name: 'Class of 2022', - items: [ - { - name: 'Hiroshi Usui', - role: 'Backend Lead', - site: 'https://i-am.2se.xyz/' - }, - { - name: 'Danji Liu', - role: 'Design Lead', - site: 'https://www.linkedin.com/in/danji-liu/' - }, - { - name: 'Christina Shao', - role: 'Frontend Lead', - site: 'https://christinashao.github.io/' - } - ] - }, - { - name: 'Class of 2021', - items: [ - { - name: 'Grace Luo', - role: 'Product Manager', - site: 'https://www.linkedin.com/in/g-luo/' - }, - { - name: 'Christopher Liu', - role: 'Frontend Lead', - site: 'https://chrisdliu.github.io' - }, - { - name: 'Janet Xu', - role: 'Design Lead', - site: 'https://www.linkedin.com/in/janet-xu/' - }, - { - name: 'Hannah Yan', - role: 'Designer', - site: 'https://www.linkedin.com/in/yanhannah/' - }, - { - name: 'Junghyun Choy', - role: 'Designer', - site: null - }, - { - name: 'Leon Ming', - role: 'Backend Lead', - site: 'https://leon-ming.com' - }, - { - name: 'Jonathan Pan', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/jonathan-pan/' - } - ] - }, - { - name: 'Class of 2020', - items: [ - { - name: 'Will Wang', - role: 'Backend Lead / PM', - site: 'http://www.hantaowang.me' - }, - { - name: 'Jemma Kwak', - role: 'Design Lead', - site: 'https://jemmakwak.me' - }, - { - name: 'Anson Tsai', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/anson-tsai-83b9a312a/' - }, - { - name: 'Eli Wu', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/eli-w-8b192ba0/' - }, - { - name: 'Sean Meng', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/sean-meng-berkeley' - }, - { - name: 'Isabella Lau', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/xisabellalau/' - }, - { - name: 'Chloe Liu', - role: 'Frontend Engineer', - site: 'https://www.linkedin.com/in/ruochen99/' - } - ] - }, - { - name: 'Class of 2019', - items: [ - { - name: 'Sangbin Cho', - role: 'Backend Lead', - site: 'https://www.linkedin.com/in/sang-cho/' - }, - { - name: 'Evelyn Li', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/yunqil' - }, - { - name: 'Richard Liu', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/richard4912' - }, - { - name: 'Mary Liu', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/mary-y-liu' - }, - { - name: 'Kate Xu', - role: 'Frontend Lead', - site: 'https://www.linkedin.com/in/kate-shijie-xu-666b57110' - }, - { - name: 'Scott Lee', - role: 'Frontend Lead / PM', - site: 'http://scottjlee.github.io' - } - ] - }, - { - name: 'Class of 2018', - items: [ - { - name: 'Tony Situ', - role: 'Backend Lead', - site: 'https://www.linkedin.com/in/c2tonyc2' - }, - { - name: 'Vaibhav Srikaran', - role: 'Product Manager', - site: 'https://www.linkedin.com/in/vsrikaran' - }, - { - name: 'Katharine Jiang', - role: 'Frontend Engineer', - site: 'http://katharinejiang.com' - }, - { - name: 'Flora Xue', - role: 'Frontend Engineer', - site: 'https://www.linkedin.com/in/flora-zhenruo-xue' - }, - { - name: 'Alan Rosenthal', - role: 'Backend Engineer', - site: 'https://www.linkedin.com/in/alan-rosenthal-37767614a' - } - ] - }, - { - name: 'Founding Team', - items: [ - { - name: 'Christine Wang', - role: 'Fullstack Engineer', - site: 'https://www.linkedin.com/in/cwang395/' - }, - { - name: 'Emily Chen', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Eric Huynh', - role: 'Fullstack Engineer', - site: 'http://erichuynhing.com/' - }, - { - name: 'Jennifer Yu', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Justin Lu', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Kelvin Leong', - role: 'Fullstack Engineer', - site: 'https://www.linkedin.com/in/kelvinjleong/' - }, - { - name: 'Kevin Jiang', - role: 'Fullstack Engineer', - site: 'https://github.com/kevjiangba/' - }, - { - name: 'Kimya Khoshnan', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Laura Harker', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Mihir Patil', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Niraj Amalkanti', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Parsa Attari', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Ronald Lee', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Sanchit Bareja', - role: 'Fullstack Engineer', - site: null - }, - { - name: 'Sandy Zhang', - role: 'Fullstack Engineer', - site: null - } - ] - }, - { - name: 'Founders', - items: [ - { - name: 'Yuxin Zhu', - role: 'Co-Founder', - site: 'http://yuxinzhu.com/#' - }, - { - name: 'Noah Gilmore', - role: 'Co-Founder', - site: 'https://noahgilmore.com' - }, - { - name: 'Ashwin Iyengar', - role: 'Co-Founder', - site: 'https://nms.kcl.ac.uk/ashwin.iyengar' - } - ] - } -]; diff --git a/frontend/src/lib/course.ts b/frontend/src/lib/course.ts new file mode 100644 index 000000000..8fb8fea80 --- /dev/null +++ b/frontend/src/lib/course.ts @@ -0,0 +1,257 @@ +interface Subject { + abbreviations: string[]; + name: string; +} + +// TODO: https://guide.berkeley.edu/courses + +export const subjects: Record = { + astron: { + abbreviations: ["astro"], + name: "Astronomy", + }, + compsci: { + abbreviations: ["cs", "comp sci", "computer science"], + name: "Computer Science", + }, + mcellbi: { + abbreviations: ["mcb"], + name: "Molecular and Cell Biology", + }, + nusctx: { + abbreviations: ["nutrisci"], + name: "Nutritional Sciences and Toxicology", + }, + bioeng: { + abbreviations: ["bioe", "bio e", "bio p", "bio eng"], + name: "Bioengineering", + }, + biology: { + abbreviations: ["bio"], + name: "Biology", + }, + civeng: { + abbreviations: ["cive", "civ e", "civ eng"], + name: "Civil and Environmental Engineering", + }, + chmeng: { + abbreviations: ["cheme", "chm eng"], + name: "Chemical Engineering", + }, + classic: { + abbreviations: ["classics"], + name: "Classics", + }, + cogsci: { + abbreviations: ["cogsci"], + name: "Cognitive Science", + }, + colwrit: { + abbreviations: ["college writing", "col writ"], + name: "College Writing", + }, + comlit: { + abbreviations: ["complit", "com lit"], + name: "Comparative Literature", + }, + cyplan: { + abbreviations: ["cy plan", "cp"], + name: "City and Regional Planning", + }, + desinv: { + abbreviations: ["des inv", "design"], + name: "Design Innovation", + }, + deveng: { + abbreviations: ["dev eng"], + name: "Development Engineering", + }, + devstd: { + abbreviations: ["dev std"], + name: "Development Studies", + }, + datasci: { + abbreviations: ["ds", "data", "data sci"], + name: "Data Science", + }, + data: { + abbreviations: ["ds", "data", "data sci"], + name: "Data Science, Undergraduate", + }, + ealang: { + abbreviations: ["ea lang"], + name: "East Asian Languages and Cultures", + }, + envdes: { + abbreviations: ["ed", "env des"], + name: "Environmental Design", + }, + eleng: { + abbreviations: ["ee", "electrical engineering", "el eng"], + name: "Electrical Engineering", + }, + eecs: { + abbreviations: ["eecs"], + name: "Electrical Engineering and Computer Sciences", + }, + eneres: { + abbreviations: ["erg", "er", "ene,res"], + name: "Energy and Resources Group", + }, + engin: { + abbreviations: ["e", "engineering"], + name: "Engineering", + }, + envsci: { + abbreviations: ["env sci"], + name: "Environmental Sciences", + }, + ethstd: { + abbreviations: ["eth std"], + name: "Ethnic Studies", + }, + geog: { + abbreviations: ["geology", "geo"], + name: "Geography", + }, + hinurd: { + abbreviations: ["hin urd", "hin-urd"], + name: "Hindi-Urdu", + }, + integbi: { + abbreviations: ["ib"], + name: "Integrative Biology", + }, + indeng: { + abbreviations: ["ie", "ieor", "ind eng"], + name: "Industrial Engineering and Operations Research", + }, + linguis: { + abbreviations: ["ling"], + name: "Linguistics", + }, + "l&s": { + abbreviations: ["l & s", "ls", "lns"], + name: "Letters and Science", + }, + indones: { + abbreviations: ["indonesian"], + name: "Indonesian", + }, + matsci: { + abbreviations: ["mat sci", "ms", "mse"], + name: "Materials Science and Engineering", + }, + meceng: { + abbreviations: ["mec eng", "meche", "mech e", "me"], + name: "Mechanical Engineering", + }, + medst: { + abbreviations: ["med st"], + name: "Medical Studies", + }, + mestu: { + abbreviations: ["me stu", "middle eastern studies"], + name: "Middle Eastern Studies", + }, + milaff: { + abbreviations: ["mil aff"], + name: "Military Affairs", + }, + milsci: { + abbreviations: ["mil sci"], + name: "Military Science", + }, + natamst: { + abbreviations: ["native american studies", "nat am st"], + name: "Native American Studies", + }, + neurosc: { + abbreviations: ["neurosci"], + name: "Neuroscience", + }, + nuceng: { + abbreviations: ["ne", "nuc eng"], + name: "Nuclear Engineering", + }, + mediast: { + abbreviations: ["media", "media st"], + name: "Media Studies", + }, + music: { + abbreviations: ["mus"], + name: "Music", + }, + pbhlth: { + abbreviations: ["pb hlth", "ph", "pub hlth", "public health"], + name: "Public Health", + }, + physed: { + abbreviations: ["pe", "phys ed"], + name: "Physical Education", + }, + polecon: { + abbreviations: ["poliecon"], + name: "Political Economy", + }, + philo: { + abbreviations: ["philosophy", "philos", "phil"], + name: "Philosophy", + }, + plantbi: { + abbreviations: ["pmb"], + name: "Plant and Microbial Biology", + }, + polsci: { + abbreviations: ["poli", "pol sci", "polisci", "poli sci", "ps"], + name: "Political Science", + }, + pubpol: { + abbreviations: ["pub pol", "pp", "public policy"], + name: "Public Policy", + }, + pubaff: { + abbreviations: ["pubaff", "public affaris"], + name: "Public Affairs", + }, + psych: { + abbreviations: ["psychology"], + name: "Psychology", + }, + rhetor: { + abbreviations: ["rhetoric"], + name: "Rhetoric", + }, + sasian: { + abbreviations: ["s asian"], + name: "South Asian Studies", + }, + seasian: { + abbreviations: ["se asian"], + name: "Southeast Asian Studies", + }, + stat: { + abbreviations: ["stats"], + name: "Statistics", + }, + theater: { + abbreviations: ["tdps"], + name: "Theater, Dance, and Performance Studies", + }, + ugba: { + abbreviations: ["haas"], + name: "Undergraduate Business Administration", + }, + vietnms: { + abbreviations: ["vietnamese"], + name: "Vietnamese", + }, + vissci: { + abbreviations: ["vis sci"], + name: "Vision Science", + }, + visstd: { + abbreviations: ["vis std"], + name: "Visual Studies", + }, +}; diff --git a/frontend/src/lib/location.ts b/frontend/src/lib/location.ts new file mode 100644 index 000000000..3573ab258 --- /dev/null +++ b/frontend/src/lib/location.ts @@ -0,0 +1,479 @@ +/* +Berkeley Way West +Latimer +Dwinelle +Giannini +Moffitt Library +Evans +Genetics & Plant Bio +Hearst Mining +Valley Life Sciences +Off +Hildebrand +Morgan +Hearst Field Annex +Sproul Hall + +Social Sciences Building +Barker +Wheeler +Etcheverry +Anthro/Art Practice Bldg +Wurster +Physics Building +Hesse +Mulford +Li Ka Shing +Cheit +Cory +Campbell Hall +Hilgard +Haviland +Doe Library +Pimentel +GSPP +Stephens +Davis +Woo Han Fai Hall +Birge +Stanley +Tan +McEnerney +Lewis +Wellman +McCone +Jacobs Hall +North Gate +Hertz +Hargrove +Morrison +Chou Hall +South Hall +Soda +Hearst Gym +Haas Faculty Wing +Chou Hall N540 and +Berkeley Art Museum +Requested General +Chavez +Graduate Theological Union +GTU Student Services +Starr Library +Sutardja Dai +Joan and Sanford I. Weill +2251 College +2401 Bancroft +Wheeler +O'Brien +Chou Hall N440 and +Zellerbach +UC LAW +Bancroft Library +Philosophy Hall +Rec Sports Facility +Hearst Gym North Field +Hearst Pool +RSF Fieldhouse +Hearst Gym Tennis Cts +Chou Hall N340 and +Donner Lab +Blum +HAAS Faculty Wing +Gilman +2521 Channing +2240 Piedmont +*/ + +interface Building { + location?: [number, number]; + name: string; + link?: string; +} + +export const buildings: Record = { + "Berkeley Way West": { + location: [-122.26840181226721, 37.87341082732256], + name: "Berkeley Way West", + link: "https://maps.app.goo.gl/zNbknDXSgV5471ZWA", + }, + Latimer: { + location: [-122.25599531409944, 37.87312578450188], + name: "Latimer Hall", + link: "https://maps.app.goo.gl/4GuSAkkBckU87vTV8", + }, + Dwinelle: { + location: [-122.26060684824738, 37.87056638999202], + name: "Dwinelle Hall", + link: "https://maps.app.goo.gl/f42kYmyfuqUQ4Urv7", + }, + Giannini: { + location: [-122.26229667155725, 37.87354568917771], + name: "Giannini Hall", + link: "https://maps.app.goo.gl/XFQpN8hsnr8XzvYz7", + }, + "Moffitt Library": { + location: [-122.26083662991704, 37.872543936658765], + name: "Moffitt Library", + link: "https://maps.app.goo.gl/NGAetKPTgYRrwJecA", + }, + Evans: { + location: [-122.25759413529791, 37.873621559931614], + name: "Evans Hall", + link: "https://maps.app.goo.gl/XdwKVCKwo5eV7qsu6", + }, + "Genetics & Plant Bio": { + location: [-122.26474920629475, 37.873442572098185], + name: "Genetics and Plant Biology Building", + link: "https://maps.app.goo.gl/MJEptPwUVCpQr2rk7", + }, + "Hearst Mining": { + location: [-122.2571920861028, 37.87416437917678], + name: "Hearst Memorial Mining Building", + link: "https://maps.app.goo.gl/265AgZFbA1KEZL7i8", + }, + "Valley Life Sciences": { + location: [-122.26220645353504, 37.87142462552724], + name: "Valley Life Sciences Building", + link: "https://maps.app.goo.gl/gAUL3doGGsB2fqxA7", + }, + "Off Campus": { + name: "Off campus", + }, + Hildebrand: { + location: [-122.25534011894594, 37.872593339541446], + name: "Hildebrand Hall", + link: "https://maps.app.goo.gl/ErfgqYTvYuD8iF3E9", + }, + Morgan: { + location: [-122.2642069563565, 37.87332050803642], + name: "Morgan Hall", + link: "https://maps.app.goo.gl/pa6x67fXANhfqEXw6", + }, + "Hearst Field Annex": { + location: [-122.25755748098894, 37.869243966493414], + name: "Hearst Field Annex", + link: "https://maps.app.goo.gl/aj69ELTGUn6SfBoXA", + }, + "Sproul Hall": { + location: [-122.25874696852213, 37.86924395748092], + name: "Sproul Hall", + link: "https://maps.app.goo.gl/GD7E8czb7xGVyzK39", + }, + "Social Sciences Building": { + location: [-122.25798819237231, 37.870063802351076], + name: "Social Sciences Building", + link: "https://maps.app.goo.gl/181jSwt8zAK6qVcAA", + }, + Barker: { + location: [-122.2654706550479, 37.873949032493385], + name: "Barker Hall", + link: "https://maps.app.goo.gl/Z7Z5ts18ZQtQcFaj8", + }, + Wheeler: { + location: [-122.25915062833967, 37.87130919316681], + name: "Wheeler Hall", + link: "https://maps.app.goo.gl/yBmC2Do44oTxqMbT6", + }, + Etcheverry: { + location: [-122.25928093175008, 37.875681116395], + name: "Etcheverry Hall", + link: "https://maps.app.goo.gl/6TRaiEmGTko1PNZx5", + }, + "Anthro/Art Practice Bldg": { + location: [-122.25534492286732, 37.86986991079993], + name: "Anthropology and Art Practice Building", + link: "https://maps.app.goo.gl/kA5LcjADWEsLMbog9", + }, + Wurster: { + location: [-122.25489197607627, 37.87074044380782], + name: "Wurster Hall", + link: "https://maps.app.goo.gl/iVJxYu7GoCMtZsoZ9", + }, + "Physics Building": { + location: [-122.25682010086159, 37.872480670347336], + name: "Physics Building", + link: "https://maps.app.goo.gl/tVLb7dBb538MjNqRA", + }, + Hesse: { + location: [-122.25935446250307, 37.874322866992514], + name: "Hesse Hall", + link: "https://maps.app.goo.gl/f3Cv1Hd5F5rNuha19", + }, + Mulford: { + location: [-122.26447768214827, 37.87261701869861], + name: "Mulford Hall", + link: "https://maps.app.goo.gl/Yh3aAhHTCgMAeNyQ6", + }, + "Li Ka Shing": { + location: [-122.26528001690815, 37.87262266777717], + name: "Li Ka Shing Center", + link: "https://maps.app.goo.gl/8FpVG3RXy8DPVc7J9", + }, + Cheit: { + location: [-122.2543379032442, 37.87168904984896], + name: "Cheit Hall", + link: "https://maps.app.goo.gl/keLxkYXFnPcKgGrL8", + }, + Cory: { + location: [-122.25780468934755, 37.87509213485355], + name: "Cory Hall", + link: "https://maps.app.goo.gl/jLZYsoST8TtE9y1G7", + }, + "Campbell Hall": { + location: [-122.25709767500017, 37.87312763387514], + name: "Campbell Hall", + link: "https://maps.app.goo.gl/Ea3AntkJVr1UXF2u9", + }, + Hilgard: { + location: [-122.26340306795208, 37.87331983963479], + name: "Hilgard Hall", + link: "https://maps.app.goo.gl/LijbW6fezg358m7U8", + }, + Haviland: { + location: [-122.26100851764237, 37.87371692436061], + name: "Haviland Hall", + link: "https://maps.app.goo.gl/FKqPcqZQaTE6iyhX7", + }, + "Doe Library": { + location: [-122.2592358273592, 37.8722145126222], + name: "Doe Library", + link: "https://maps.app.goo.gl/GudMeULid1ocEbaw7", + }, + Pimentel: { + location: [-122.25602833267033, 37.87342920998079], + name: "Pimentel Hall", + link: "https://maps.app.goo.gl/wjmaQrXvN693bBxV7", + }, + GSPP: { + location: [-122.25790926224941, 37.87572256387491], + name: "Richard & Rhoda Goldman School", + link: "https://maps.app.goo.gl/8tHo874r1SmPjWbX7", + }, + Stephens: { + location: [-122.25750797500021, 37.87147064119593], + name: "Stephens Hall", + link: "https://maps.app.goo.gl/wGgMqX36qYzKR3CX7", + }, + Davis: { + location: [-122.25801209495167, 37.8745786463717], + name: "Davis Hall", + link: "https://maps.app.goo.gl/ZrgWVDVvBJYDxnLEA", + }, + "Woo Han Fai Hall": { + location: [-122.25586439151184, 37.86874548208747], + name: "Woo Han Fai Hall", + link: "https://maps.app.goo.gl/DrimtkfkXTWjBfnb9", + }, + Birge: { + location: [-122.25716535675937, 37.872172511655855], + name: "Birge Hall", + link: "https://maps.app.goo.gl/tuXqvxSmuPTgFsTp8", + }, + Stanley: { + location: [-122.25640023093717, 37.873858606089705], + name: "Stanley Hall", + link: "https://maps.app.goo.gl/PMijJrCeTFP9NPn8A", + }, + Tan: { + location: [-122.25651115723869, 37.873281595855836], + name: "Tan Kee Kee Hall", + link: "https://maps.app.goo.gl/w45simSmLwXzh3q58", + }, + McEnerney: { + location: [-122.2644821947179, 37.87666241423979], + name: "CNMAT", + link: "https://maps.app.goo.gl/4naDUT6Mp3C3kLh88", + }, + Lewis: { + location: [-122.25488562927272, 37.872756450742145], + name: "Lewis Hall", + link: "https://maps.app.goo.gl/y2TeJdNji1CkYjM3A", + }, + Wellman: { + location: [-122.2627907229642, 37.87317782345241], + name: "Wellman Hall", + link: "https://maps.app.goo.gl/Aue7cgmmXsv5u8Fd7", + }, + McCone: { + location: [-122.25967790769536, 37.87409189531322], + name: "McCone Hall", + link: "https://maps.app.goo.gl/rpxt4kbxrrTRhnNb7", + }, + "Jacobs Hall": { + location: [-122.25882193535269, 37.87602971606913], + name: "Jacobs Hall", + link: "https://maps.app.goo.gl/xZ9AxhnG5saW1Epf7", + }, + "North Gate": { + location: [-122.25990173190104, 37.87497525022868], + name: "North Gate Hall", + link: "https://maps.app.goo.gl/MPGKJJMv6TMrdQRw8", + }, + Hertz: { + location: [-122.25569849398121, 37.87108130391847], + name: "Hertz Hall", + link: "https://maps.app.goo.gl/p9gLFh1JR31jSgNF8", + }, + Hargrove: { + location: [-122.25618934462244, 37.87045013995676], + name: "Jean Gray Hargrove Music Library", + link: "https://maps.app.goo.gl/z2CtVqLqRSF73dvy8", + }, + Morrison: { + location: [-122.25649720028268, 37.87085305022676], + name: "Morrison Hall", + link: "https://maps.app.goo.gl/mkcYcrrb3evvNGjq8", + }, + "Chou Hall": { + location: [-122.25454360383524, 37.8723166102369], + name: "Chou Hall", + link: "https://maps.app.goo.gl/xyS4LwD9m8nsBmRM7", + }, + "South Hall": { + location: [-122.25850563373693, 37.87129997946342], + name: "South Hall", + link: "https://maps.app.goo.gl/qnT9xCkWiS2vs1cSA", + }, + Soda: { + location: [-122.25879005808657, 37.87558462382853], + name: "Soda Hall", + link: "https://maps.app.goo.gl/fxcPJG7eJs7Yznr28", + }, + "Hearst Gym": { + location: [-122.25639058707237, 37.869926045495006], + name: "Hearst Gymnasium", + link: "https://maps.app.goo.gl/KhHLrcdosZSCjVwUA", + }, + "Haas Faculty Wing": { + location: [-122.25334752655445, 37.871632438551494], + name: "Haas School of Business", + link: "https://maps.app.goo.gl/MUdpvxs5Yg8AsQC36", + }, + "Berkeley Art Museum": { + location: [-122.26647977944991, 37.87073521843178], + name: "Berkeley Art Museum and Pacific Film Archive", + link: "https://maps.app.goo.gl/sgG289Qa36AXSB4B6", + }, + "Requested General Assignment": { + name: "Requested general assignment", + }, + Chavez: { + location: [-122.26033260383534, 37.86955061087345], + name: "César Chávez Student Center", + link: "https://maps.app.goo.gl/rBzJmqoHz13cxKef9", + }, + "Graduate Theological Union": { + location: [-122.26186544616492, 37.87569417196013], + name: "Graduate Theological Union", + link: "https://maps.app.goo.gl/WXYqfaqup1bJNFRP8", + }, + "GTU Student Services Center": { + location: [-122.26144510383497, 37.87707940337083], + name: "GTU Student Services Center", + link: "https://maps.app.goo.gl/WqPaiQqrA5dKjQLa8", + }, + "Starr Library": { + location: [-122.25998112731321, 37.87359100039992], + name: "East Asian Library", + link: "https://maps.app.goo.gl/pLTHbyKNre5cMKmv9", + }, + "Sutardja Dai": { + location: [-122.25831352863513, 37.87503515928838], + name: "Sutardja Dai Hall", + link: "https://maps.app.goo.gl/su2AuVn4g2uMfWBp8", + }, + "Joan and Sanford I. Weill": { + name: "UCSF Joan and Sanford I. Weill Neurosciences Building", + }, + "2251 College": { + location: [-122.25391110710783, 37.870166332980034], + name: "Archaeological Research Facility", + link: "https://maps.app.goo.gl/31dzRoRnPyT189Py5", + }, + "2401 Bancroft": { + location: [-122.26116005869203, 37.86869499663926], + name: "Bancroft Dance Studio", + link: "https://maps.app.goo.gl/m6jzQ5xh9d3yCfsp9", + }, + "Wheeler Hall": { + location: [-122.25914745072348, 37.87130186176894], + name: "Wheeler Hall", + link: "https://maps.app.goo.gl/HikpBF5dGi3Ku8cT9", + }, + "O'Brien": { + location: [-122.2590577968863, 37.87428341581882], + name: "O'Brien Hall", + link: "https://maps.app.goo.gl/ZrgWVDVvBJYDxnLEA", + }, + Zellerbach: { + location: [-122.26133456732288, 37.86927674211004], + name: "Zellerbach Playhouse", + link: "https://maps.app.goo.gl/3Jxn1wkwEeo2hcmN8", + }, + "UC LAW": { + location: [-122.25401475499672, 37.86950825416665], + name: "UC Berkeley School of Law", + link: "https://maps.app.goo.gl/dfWiaU9b6usgQzx27", + }, + "Bancroft Library": { + location: [-122.25866103267037, 37.87231304109882], + name: "The Bancroft Library", + link: "https://maps.app.goo.gl/crRxb7m3C56ZkbP67", + }, + "Philosophy Hall": { + location: [-122.25810876150558, 37.871015571961365], + name: "Philosophy Hall", + link: "https://maps.app.goo.gl/5spQqggAbSp3Lqcx5", + }, + "Rec Sports Facility": { + location: [-122.2627939038355, 37.86859167196196], + name: "Recreational Sports Facility", + link: "https://maps.app.goo.gl/NKHX1M3wvLdKcy9eA", + }, + "Hearst Gym North Field": { + location: [-122.2569165044859, 37.870280891945036], + name: "Hearst North Field", + link: "https://maps.app.goo.gl/XuRh7APFD256fJ5L7", + }, + "Hearst Pool": { + location: [-122.25694684709053, 37.86969165728141], + name: "Hearst Gym Pool", + link: "https://maps.app.goo.gl/wXoxqAmjcLaUhT1j7", + }, + "RSF Fieldhouse": { + name: "Recreational Sports Facility Fieldhouse", + }, + "Hearst Gym Tennis Cts": { + location: [-122.25580180383541, 37.869568533057866], + name: "Hearst Tennis Courts", + link: "https://maps.app.goo.gl/vJJuUph72exgrSvQ9", + }, + "Donner Lab": { + location: [-122.25630500383518, 37.87446848531557], + name: "Donner Lab", + link: "https://maps.app.goo.gl/gWLtENgxK8yWN4hW8", + }, + Blum: { + location: [-122.25879005335187, 37.87504783275099], + name: "Blum Hall", + link: "https://maps.app.goo.gl/PfueMBhoB7mkeyURA", + }, + "HAAS Faculty Wing": { + name: "Haas School of Business", + }, + Gilman: { + location: [-122.25622839210698, 37.87261381887259], + name: "Gilman Hall", + link: "https://maps.app.goo.gl/ZPZYam2tjLoWAhpdA", + }, + "2521 Channing": { + location: [-122.25780997028515, 37.867224873257776], + name: "Institute for Research on Labor & Employment", + link: "https://maps.app.goo.gl/v5Vqvkf26JLfsRyY9", + }, + "2240 Piedmont": { + location: [-122.25287235365637, 37.87039854622979], + name: "Center for the Study of Law and Society", + link: "https://maps.app.goo.gl/eyaq4h7aaEvs4aJWA", + }, +}; diff --git a/frontend/src/lib/releases.ts b/frontend/src/lib/releases.ts deleted file mode 100644 index 6928dd38f..000000000 --- a/frontend/src/lib/releases.ts +++ /dev/null @@ -1,80 +0,0 @@ -const releases = [ - { - date: 'Jan 24, 2021', - whatsNew: [ - 'We released user profiles! Click on the bookmark icon in catalog to save a class, then click on the class in your user home to see it in the catalog. Also be sure to opt in to notifications for when we update the catalog, grades, and the site.', - 'We updated the site with Summer 2020 grade distributions.' - ], - fixes: [ - 'Updated GEOG 20 in the catalog, which no longer satisfies the L&S International Studies, Social and Behavioral Sciences Breadths.' - ] - }, - { - date: 'Dec 6, 2020', - whatsNew: [ - 'We wrote new backend APIs using GraphQL (our previous APIs use the REST framework). Although the APIs listed on our API Docs are currently supported, they may change in the future.', - 'We are now primarily hosted on the OCF\'s servers.', - 'We have added a Privacy Policy and Terms of Service to the site.' - ], - fixes: [ - 'Modified prerequisites for PB HLTH 126 in Spring 2021 as requested by the instructor.', - 'Added support for opening a course by url in catalog on mobile.', - 'Added easter eggs back into the catalog.', - 'Changed the semester dropdown in catalog to be single select rather than multi-select.' - ] - }, - { - date: 'Nov 15, 2020', - whatsNew: [ - 'We have released mobile views! You can now browse our site on your phone and tablet.', - 'We\'ve added improved search to our catalog. You can now search for courses by their names. We\'ve added a Sort By - Relevance query to give you courses that are most similar to your query (try searching "Economics" in catalog).', - "We've revamped our backend so that we now display more complete grades and enrollment data." - ], - fixes: [ - 'Modified enrollment search to display all courses we have data for. Previously, we were only displaying courses that would be offered in the coming semester.', - 'Fixed L&S requirement filters, which were temporarily broken due to a SIS API issue.' - ] - }, - { - date: 'Oct 11, 2020', - whatsNew: [ - 'We released Spring 2021 course information! You can now search for courses on our catalog.' - ], - fixes: [ - 'Fixed a bug in our enrollment scraper so that all courses we have enrollment data for are listed.', - 'Fixed a bug where certain catalog pages like COMPSCI 61B caused the screen to go completely white.', - "Fixed scrolling behavior on catalog so it's friendly for smaller screen sizes and more intuitive for users." - ] - }, - { - date: 'Aug 23, 2020', - whatsNew: [ - 'We are opening our Fall 2020 applications! Come see what roles we have open and join the OCTO team on the apply page.', - 'Our backend API can now be accessed from mobile devices, and the *_json queries now have a long option.' - ], - fixes: [ - 'Fixed a bug where many courses for which we have enrollment data do not show up.', - 'Fixed a bug where enrollment and some course data were not updating.', - 'Fixed a bug where typing in the course search bar caused the screen to go completely white.', - 'Added visible scrollbars to some scrollable elements. (You can still turn them off using your OS settings.)' - ] - }, - { - date: 'May 3, 2020', - whatsNew: [ - "We're rolling out an updated UI, which is now available on both web (and soon on mobile)!", - 'Our backend API is officially open-sourced in version v0.1! Head over to our API Documentation to check it out.', - 'This releases page will be updated with notes of new features, bug fixes, and class enrollment/grades updates.', - 'Our new FAQ page answers some common questions we\'ve gotten over the past few semesters. Feel free to send us more questions if you\'ve got them!', - 'Support for our old legacy site is now officially deprecated. You can still visit it at old.berkeleytime.com, but some features may be broken and we won\'t be maintaining it moving forward.' - ], - fixes: [ - 'Adding courses to Grades and Enrollment pages now accurately generate unique URLs, which you can share with friends to reproduce your search.', - 'Fixed an issue where the course average in Grades was not being calculated correctly.', - 'Enrollment statistics are now updated every 15 minutes.', - 'Course search is improved with better support for abbreviations for class names.' - ] - } -]; - -export default releases; diff --git a/frontend/src/lib/schedule.ts b/frontend/src/lib/schedule.ts new file mode 100644 index 000000000..d55c7d63f --- /dev/null +++ b/frontend/src/lib/schedule.ts @@ -0,0 +1,4 @@ +export const getY = (time: string) => { + const [hour, minute] = time.split(":"); + return (parseInt(hour) - 6) * 60 + parseInt(minute); +}; diff --git a/frontend/src/lib/section.ts b/frontend/src/lib/section.ts new file mode 100644 index 000000000..b18f8aa04 --- /dev/null +++ b/frontend/src/lib/section.ts @@ -0,0 +1,64 @@ +import { Component, Semester } from "./api"; + +export const getExternalLink = ( + year: number, + semester: Semester, + subject: string, + courseNumber: string, + sectionNumber: string, + kind: Component +) => { + return `https://classes.berkeley.edu/content/${year}-${semester.toLowerCase()}-${subject.toLowerCase()}-${courseNumber}-${sectionNumber}-${kind.toLowerCase()}-${sectionNumber}`; +}; + +const colors = [ + "var(--red-500)", + "var(--orange-500)", + "var(--yellow-500)", + "var(--green-500)", + "var(--teal-500)", + "var(--blue-500)", + "var(--indigo-500)", + "var(--purple-500)", + "var(--pink-500)", + "var(--amber-500)", + "var(--lime-500)", + "var(--emerald-500)", + "var(--cyan-500)", + "var(--sky-500)", + "var(--violet-500)", + "var(--fuchsia-500)", + "var(--rose-500)", + "var(--red-700)", + "var(--orange-700)", + "var(--yellow-700)", + "var(--green-700)", + "var(--teal-700)", + "var(--blue-700)", + "var(--indigo-700)", + "var(--purple-700)", + "var(--pink-700)", + "var(--amber-700)", + "var(--lime-700)", + "var(--emerald-700)", + "var(--cyan-700)", + "var(--sky-700)", + "var(--violet-700)", + "var(--fuchsia-700)", + "var(--rose-700)", +]; + +export const getColor = (subject: string, number: string) => { + const value = `${subject} ${number}`; + + let hash = 0; + let character; + + for (let i = 0; i < value.length; i++) { + character = value.charCodeAt(i); + hash = (hash << 5) - hash + character; + hash |= 0; + } + + return colors[Math.abs(hash) % colors.length]; +}; diff --git a/frontend/src/main.scss b/frontend/src/main.scss new file mode 100644 index 000000000..82840c572 --- /dev/null +++ b/frontend/src/main.scss @@ -0,0 +1,339 @@ +body, p, h1, h2, h3 { + margin: 0; +} + +input, button { + font-family: unset; + border: unset; + background-color: unset; + padding: unset; +} + +input { + width: 100%; + + &:focus { + outline: none; + } +} + +a { + color: inherit; + text-decoration: none; +} + +*, *::after, *::before { + box-sizing: border-box; +} + +:root { + --slate-50: #f8fafc; + --slate-100: #f1f5f9; + --slate-200: #e2e8f0; + --slate-300: #cbd5e1; + --slate-400: #94a3b8; + --slate-500: #64748b; + --slate-600: #475569; + --slate-700: #334155; + --slate-800: #1e293b; + --slate-900: #0f172a; + --slate-950: #020617; + + --gray-50: #f9fafb; + --gray-100: #f3f4f6; + --gray-200: #e5e7eb; + --gray-300: #d1d5db; + --gray-400: #9ca3af; + --gray-500: #6b7280; + --gray-600: #4b5563; + --gray-700: #374151; + --gray-800: #1f2937; + --gray-900: #111827; + --gray-950: #030712; + + --zinc-50: #fafafa; + --zinc-100: #f4f4f5; + --zinc-200: #e4e4e7; + --zinc-300: #d4d4d8; + --zinc-400: #a1a1aa; + --zinc-500: #71717a; + --zinc-600: #52525b; + --zinc-700: #3f3f46; + --zinc-800: #27272a; + --zinc-900: #18181b; + --zinc-950: #09090b; + + --neutral-50: #fafafa; + --neutral-100: #f5f5f5; + --neutral-200: #e5e5e5; + --neutral-300: #d4d4d4; + --neutral-400: #a3a3a3; + --neutral-500: #737373; + --neutral-600: #525252; + --neutral-700: #404040; + --neutral-800: #262626; + --neutral-900: #171717; + --neutral-950: #0a0a0a; + + --stone-50: #fafaf9; + --stone-100: #f5f5f4; + --stone-200: #e7e5e4; + --stone-300: #d6d3d1; + --stone-400: #a8a29e; + --stone-500: #78716c; + --stone-600: #57534e; + --stone-700: #44403c; + --stone-800: #292524; + --stone-900: #1c1917; + --stone-950: #0c0a09; + + --red-50: #fef2f2; + --red-100: #fee2e2; + --red-200: #fecaca; + --red-300: #fca5a5; + --red-400: #f87171; + --red-500: #ef4444; + --red-600: #dc2626; + --red-700: #b91c1c; + --red-800: #991b1b; + --red-900: #7f1d1d; + --red-950: #450a0a; + + --orange-50: #fff7ed; + --orange-100: #ffedd5; + --orange-200: #fed7aa; + --orange-300: #fdba74; + --orange-400: #fb923c; + --orange-500: #f97316; + --orange-600: #ea580c; + --orange-700: #c2410c; + --orange-800: #9a3412; + --orange-900: #7c2d12; + --orange-950: #431407; + + --amber-50: #fffbeb; + --amber-100: #fef3c7; + --amber-200: #fde68a; + --amber-300: #fcd34d; + --amber-400: #fbbf24; + --amber-500: #f59e0b; + --amber-600: #d97706; + --amber-700: #b45309; + --amber-800: #92400e; + --amber-900: #78350f; + --amber-950: #451a03; + + --yellow-50: #fefce8; + --yellow-100: #fef9c3; + --yellow-200: #fef08a; + --yellow-300: #fde047; + --yellow-400: #facc15; + --yellow-500: #eab308; + --yellow-600: #ca8a04; + --yellow-700: #a16207; + --yellow-800: #854d0e; + --yellow-900: #713f12; + --yellow-950: #422006; + + --lime-50: #f7fee7; + --lime-100: #ecfccb; + --lime-200: #d9f99d; + --lime-300: #bef264; + --lime-400: #a3e635; + --lime-500: #84cc16; + --lime-600: #65a30d; + --lime-700: #4d7c0f; + --lime-800: #3f6212; + --lime-900: #365314; + --lime-950: #1a2e05; + + --green-50: #f0fdf4; + --green-100: #dcfce7; + --green-200: #bbf7d0; + --green-300: #86efac; + --green-400: #4ade80; + --green-500: #22c55e; + --green-600: #16a34a; + --green-700: #15803d; + --green-800: #166534; + --green-900: #14532d; + --green-950: #052e16; + + --emerald-50: #ecfdf5; + --emerald-100: #d1fae5; + --emerald-200: #a7f3d0; + --emerald-300: #6ee7b7; + --emerald-400: #34d399; + --emerald-500: #10b981; + --emerald-600: #059669; + --emerald-700: #047857; + --emerald-800: #065f46; + --emerald-900: #064e3b; + --emerald-950: #022c22; + + --teal-50: #f0fdfa; + --teal-100: #ccfbf1; + --teal-200: #99f6e4; + --teal-300: #5eead4; + --teal-400: #2dd4bf; + --teal-500: #14b8a6; + --teal-600: #0d9488; + --teal-700: #0f766e; + --teal-800: #115e59; + --teal-900: #134e4a; + --teal-950: #042f2e; + + --cyan-50: #ecfeff; + --cyan-100: #cffafe; + --cyan-200: #a5f3fc; + --cyan-300: #67e8f9; + --cyan-400: #22d3ee; + --cyan-500: #06b6d4; + --cyan-600: #0891b2; + --cyan-700: #0e7490; + --cyan-800: #155e75; + --cyan-900: #164e63; + --cyan-950: #083344; + + --sky-50: #f0f9ff; + --sky-100: #e0f2fe; + --sky-200: #bae6fd; + --sky-300: #7dd3fc; + --sky-400: #38bdf8; + --sky-500: #0ea5e9; + --sky-600: #0284c7; + --sky-700: #0369a1; + --sky-800: #075985; + --sky-900: #0c4a6e; + --sky-950: #083344; + + --blue-50: #eff6ff; + --blue-100: #dbeafe; + --blue-200: #bfdbfe; + --blue-300: #93c5fd; + --blue-400: #60a5fa; + --blue-500: #3b82f6; + --blue-600: #2563eb; + --blue-700: #1d4ed8; + --blue-800: #1e40af; + --blue-900: #1e3a8a; + --blue-950: #172554; + + --indigo-50: #eef2ff; + --indigo-100: #e0e7ff; + --indigo-200: #c7d2fe; + --indigo-300: #a5b4fc; + --indigo-400: #818cf8; + --indigo-500: #6366f1; + --indigo-600: #4f46e5; + --indigo-700: #4338ca; + --indigo-800: #3730a3; + --indigo-900: #312e81; + --indigo-950: #1e1b4b; + + --violet-50: #f5f3ff; + --violet-100: #ede9fe; + --violet-200: #ddd6fe; + --violet-300: #c4b5fd; + --violet-400: #a78bfa; + --violet-500: #8b5cf6; + --violet-600: #7c3aed; + --violet-700: #6d28d9; + --violet-800: #5b21b6; + --violet-900: #4c1d95; + --violet-950: #2e1065; + + --purple-50: #faf5ff; + --purple-100: #f3e8ff; + --purple-200: #e9d5ff; + --purple-300: #d8b4fe; + --purple-400: #c084fc; + --purple-500: #a855f7; + --purple-600: #9333ea; + --purple-700: #7e22ce; + --purple-800: #6b21a8; + --purple-900: #581c87; + --purple-950: #3b0764; + + --fuchsia-50: #fdf4ff; + --fuchsia-100: #fae8ff; + --fuchsia-200: #f5d0fe; + --fuchsia-300: #f0abfc; + --fuchsia-400: #e879f9; + --fuchsia-500: #d946ef; + --fuchsia-600: #c026d3; + --fuchsia-700: #a21caf; + --fuchsia-800: #86198f; + --fuchsia-900: #701a75; + --fuchsia-950: #4a044e; + + --pink-50: #fdf2f8; + --pink-100: #fce7f3; + --pink-200: #fbcfe8; + --pink-300: #f9a8d4; + --pink-400: #f472b6; + --pink-500: #ec4899; + --pink-600: #db2777; + --pink-700: #be185d; + --pink-800: #9d174d; + --pink-900: #831843; + --pink-950: #500724; + + --rose-50: #fff1f2; + --rose-100: #ffe4e6; + --rose-200: #fecdd3; + --rose-300: #fda4af; + --rose-400: #fb7185; + --rose-500: #f43f5e; + --rose-600: #e11d48; + --rose-700: #be123c; + --rose-800: #9f1239; + --rose-900: #881337; + --rose-950: #4c0519; + + --foreground-color: white; + --background-color: var(--slate-50); + --backdrop-color: var(--slate-100); + + --border-color: rgb(0 0 0 / 10%); + + --heading-color: var(--slate-900); + --paragraph-color: var(--slate-500); + --label-color: var(--slate-400); + + --button-color: white; + --button-hover-color: var(--slate-100); + --button-active-color: var(--slate-200); + + --tooltip-color: var(--neutral-900); +} + +@media (prefers-color-scheme: dark) { + :root { + --foreground-color: var(--zinc-800); + --background-color: var(--zinc-900); + --backdrop-color: var(--zinc-950); + + --border-color: var(--zinc-700); + + --heading-color: white; + --paragraph-color: var(--zinc-400); + --label-color: var(--zinc-500); + + --button-color: var(--zinc-800); + --button-hover-color: var(--zinc-700); + --button-active-color: var(--zinc-600); + + --tooltip-color: var(--zinc-950); + } +} + +body { + font-family: Inter, sans-serif; +} + +@supports (font-variation-settings: normal) { + body { + font-family: InterVariable, sans-serif; + } +} \ No newline at end of file diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx new file mode 100644 index 000000000..2fa83aabc --- /dev/null +++ b/frontend/src/main.tsx @@ -0,0 +1,18 @@ +import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client"; +import { createRoot } from "react-dom/client"; + +import App from "./App"; +import "./main.scss"; + +const client = new ApolloClient({ + uri: "/api/graphql", + cache: new InMemoryCache(), +}); + +const root = createRoot(document.getElementById("root") as HTMLElement); + +root.render( + + + +); diff --git a/frontend/src/react-app-env.d.ts b/frontend/src/react-app-env.d.ts deleted file mode 100644 index 15d0c8b42..000000000 --- a/frontend/src/react-app-env.d.ts +++ /dev/null @@ -1,6 +0,0 @@ -/// -/// - -declare module 'react-ios-switch' { - export = Switch; -} diff --git a/frontend/src/redux/actionTypes.js b/frontend/src/redux/actionTypes.js deleted file mode 100644 index 42cbb9155..000000000 --- a/frontend/src/redux/actionTypes.js +++ /dev/null @@ -1,13 +0,0 @@ -export const UPDATE_GRADE_CONTEXT = 'UPDATE_GRADE_CONTEXT'; -export const GRADE_ADD_COURSE = 'GRADE_ADD_COURSE'; -export const GRADE_REMOVE_COURSE = 'GRADE_REMOVE_COURSE'; -export const UPDATE_GRADE_DATA = 'UPDATE_GRADE_DATA'; -export const UPDATE_GRADE_SELECTED = 'UPDATE_GRADE_SELECTED'; -export const GRADE_RESET = 'GRADE_RESET'; - -export const UPDATE_ENROLL_CONTEXT = 'UPDATE_ENROLL_CONTEXT'; -export const ENROLL_ADD_COURSE = 'ENROLL_ADD_COURSE'; -export const ENROLL_REMOVE_COURSE = 'ENROLL_REMOVE_COURSE'; -export const UPDATE_ENROLL_DATA = 'UPDATE_ENROLL_DATA'; -export const UPDATE_ENROLL_SELECTED = 'UPDATE_ENROLL_SELECTED'; -export const ENROLL_RESET = 'ENROLL_RESET'; diff --git a/frontend/src/redux/actions.js b/frontend/src/redux/actions.js deleted file mode 100644 index 4b5822e70..000000000 --- a/frontend/src/redux/actions.js +++ /dev/null @@ -1,462 +0,0 @@ -/* eslint-disable */ -import axios from 'axios'; -import hash from 'object-hash'; -import { - UPDATE_GRADE_CONTEXT, - GRADE_ADD_COURSE, - GRADE_REMOVE_COURSE, - GRADE_RESET, - UPDATE_GRADE_DATA, - UPDATE_GRADE_SELECTED, - UPDATE_ENROLL_CONTEXT, - ENROLL_RESET, - ENROLL_ADD_COURSE, - ENROLL_REMOVE_COURSE, - UPDATE_ENROLL_DATA, - UPDATE_ENROLL_SELECTED -} from './actionTypes'; - -// update grade list -const updateGradeContext = (data) => ({ - type: UPDATE_GRADE_CONTEXT, - payload: { - data - } -}); - -export const gradeReset = () => ({ - type: GRADE_RESET -}); - -// add displayed course to the grade page -const gradeAddCourse = (formattedCourse) => ({ - type: GRADE_ADD_COURSE, - payload: { - formattedCourse - } -}); - -export const gradeRemoveCourse = (id, color) => ({ - type: GRADE_REMOVE_COURSE, - payload: { - id, - color - } -}); - -const updateGradeData = (gradesData) => ({ - type: UPDATE_GRADE_DATA, - payload: { - gradesData - } -}); - -const updatedGradeSelected = (data) => ({ - type: UPDATE_GRADE_SELECTED, - payload: { - data - } -}); - -// update enroll list -const updateEnrollContext = (data) => ({ - type: UPDATE_ENROLL_CONTEXT, - payload: { - data - } -}); - -export const enrollReset = () => ({ - type: ENROLL_RESET -}); - -// add displayed course to the enroll page -const enrollAddCourse = (formattedCourse) => ({ - type: ENROLL_ADD_COURSE, - payload: { - formattedCourse - } -}); - -export const enrollRemoveCourse = (id, color) => ({ - type: ENROLL_REMOVE_COURSE, - payload: { - id, - color - } -}); - -export const updateEnrollData = (enrollmentData) => ({ - type: UPDATE_ENROLL_DATA, - payload: { - enrollmentData - } -}); - -const updatedEnrollSelected = (sections) => ({ - type: UPDATE_ENROLL_SELECTED, - payload: { - sections - } -}); - -export function fetchGradeContext() { - return (dispatch) => - axios.get('/api/grades/grades_json/').then( - (res) => { - dispatch(updateGradeContext(res.data)); - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchGradeClass(course) { - return (dispatch) => - axios.get(`/api/catalog/catalog_json/course/${course.courseID}/`).then( - (res) => { - const courseData = res.data; - const formattedCourse = { - id: course.id, - course: courseData.course, - title: courseData.title, - semester: course.semester, - instructor: course.instructor, - courseID: course.courseID, - sections: course.sections, - colorId: course.colorId - }; - dispatch(gradeAddCourse(formattedCourse)); - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchGradeData(classData) { - const promises = []; - for (const course of classData) { - const { sections } = course; - const url = `/api/grades/sections/${sections.join('&')}/`; - promises.push(axios.get(url)); - } - return (dispatch) => - axios.all(promises).then( - (data) => { - let gradesData = data.map((res, i) => { - let gradesData = res.data; - gradesData['id'] = classData[i].id; - gradesData['instructor'] = - classData[i].instructor === 'all' ? 'All Instructors' : classData[i].instructor; - gradesData['semester'] = - classData[i].semester === 'all' ? 'All Semesters' : classData[i].semester; - gradesData['colorId'] = classData[i].colorId; - return gradesData; - }); - dispatch(updateGradeData(gradesData)); - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchGradeSelected(updatedClass) { - const url = `/api/grades/course_grades/${updatedClass.value}/`; - return (dispatch) => - axios.get(url).then( - (res) => { - dispatch(updatedGradeSelected(res.data)); - // if (updatedClass.addSelected) { - // this.addSelected(); - // this.handleClassSelect({value: updatedClass.value, addSelected: false}); - // } - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchGradeFromUrl(url, history) { - const toUrlForm = (s) => s.replace('/', '_').toLowerCase().split(' ').join('-'); - const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1); - let courseUrls = url.split('/')[2].split('&'); - const urlData = []; - let promises = []; - for (const c of courseUrls) { - let cUrl = c.split('-'); - let semester, instructor; - if (cUrl[2] === 'all') { - semester = cUrl[2]; - instructor = cUrl.slice(3).join('-'); - } else if (cUrl[4] === '_') { - semester = capitalize(cUrl[2]) + ' ' + cUrl[3] + ' / ' + cUrl[5]; - instructor = cUrl.slice(6).join('-').replace('_', '/'); - } else { - semester = capitalize(cUrl[2]) + ' ' + cUrl[3]; - instructor = cUrl.slice(4).join('-').replace('_', '/'); - } - urlData.push({ - colorId: cUrl[0], - courseID: cUrl[1], - semester: semester, - instructor: instructor - }); - let u = `/api/grades/course_grades/${cUrl[1]}/`; - promises.push(axios.get(u)); - } - let courses = []; - let success = true; - return (dispatch) => - axios - .all(promises) - .then( - (data) => { - courses = data.map((res, i) => { - try { - let instructor = urlData[i].instructor; - let semester = urlData[i].semester; - let sections = []; - if (instructor === 'all') { - res.data.map((item, i) => (sections[i] = item.grade_id)); - } else { - let matches = []; - if (instructor.includes('/')) { - matches = res.data.filter( - (item) => - instructor === toUrlForm(item.instructor) + '-/-' + item.section_number - ); - matches.map((item, i) => (sections[i] = item.grade_id)); - instructor = matches[0].instructor + ' / ' + matches[0].section_number; - } else { - matches = res.data.filter((item) => instructor === toUrlForm(item.instructor)); - matches.map((item, i) => (sections[i] = item.grade_id)); - instructor = matches[0].instructor; - } - } - if (semester !== 'all') { - let matches = []; - if (semester.split(' ').length > 2) { - matches = res.data.filter( - (item) => - semester === - capitalize(item.semester) + ' ' + item.year + ' / ' + item.section_number - ); - } else { - matches = res.data.filter( - (item) => semester === capitalize(item.semester) + ' ' + item.year - ); - } - let allSems = matches.map((item) => item.grade_id); - sections = sections.filter((item) => allSems.includes(item)); - } - let formattedCourse = { - courseID: parseInt(urlData[i].courseID), - instructor: instructor, - semester: semester, - sections: sections - }; - formattedCourse.id = hash(formattedCourse); - formattedCourse.colorId = urlData[i].colorId; - return formattedCourse; - } catch (err) { - success = false; - history.push('/error'); - } - }); - }, - (error) => console.log('An error occurred.', error) - ) - .then(() => { - if (success) { - promises = []; - for (const course of courses) { - const u = `/api/catalog/catalog_json/course/${course.courseID}/`; - promises.push(axios.get(u)); - } - axios.all(promises).then( - (data) => { - data.map((res, i) => { - const courseData = res.data; - const course = courses[i]; - const formattedCourse = { - id: course.id, - course: courseData.course, - title: courseData.title, - semester: course.semester, - instructor: course.instructor, - courseID: course.courseID, - sections: course.sections, - colorId: course.colorId - }; - dispatch(gradeAddCourse(formattedCourse)); - }); - }, - (error) => console.log('An error occurred.', error) - ); - } - }); -} - -export function fetchEnrollContext() { - return async (dispatch, getState) => { - // Avoid fetching enrollment data twice. - if (getState().enrollment.context?.courses) { - return; - } - - const res = await axios.get('/api/enrollment/enrollment_json/'); - dispatch(updateEnrollContext(res.data)); - }; -} - -export function fetchEnrollClass(course) { - return (dispatch) => - axios.get(`/api/catalog/catalog_json/course/${course.courseID}/`).then( - (res) => { - const courseData = res.data; - const formattedCourse = { - id: course.id, - course: courseData.course, - title: courseData.title, - semester: course.semester, - instructor: course.instructor, - courseID: course.courseID, - sections: course.sections, - colorId: course.colorId - }; - dispatch(enrollAddCourse(formattedCourse)); - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchEnrollData(classData) { - const promises = []; - for (const course of classData) { - const { instructor, courseID, semester, sections } = course; - let url; - if (instructor === 'all') { - const [sem, year] = semester.split(' '); - url = `/api/enrollment/aggregate/${courseID}/${sem.toLowerCase()}/${year}/`; - } else { - url = `/api/enrollment/data/${sections[0]}/`; - } - promises.push(axios.get(url)); - } - return (dispatch) => - axios.all(promises).then( - (data) => { - let enrollmentData = data.map((res, i) => { - let enrollmentData = res.data; - enrollmentData['id'] = classData[i].id; - enrollmentData['colorId'] = classData[i].colorId; - return enrollmentData; - }); - dispatch(updateEnrollData(enrollmentData)); - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchEnrollSelected(updatedClass) { - const url = `/api/enrollment/sections/${updatedClass.value}/`; - return (dispatch) => - axios.get(url).then( - (res) => { - dispatch(updatedEnrollSelected(res.data)); - // if (updatedClass.addSelected) { - // this.addSelected(); - // this.handleClassSelect({value: updatedClass.value, addSelected: false}); - // } - }, - (error) => console.log('An error occurred.', error) - ); -} - -export function fetchEnrollFromUrl(url, history) { - const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1); - let courseUrls = url.split('/')[2].split('&'); - const urlData = []; - let promises = []; - for (const c of courseUrls) { - let cUrl = c.split('-'); - let semester = capitalize(cUrl[2]) + ' ' + cUrl[3]; - urlData.push({ - colorId: cUrl[0], - courseID: cUrl[1], - semester: semester, - section: cUrl[4] - }); - let u = `/api/enrollment/sections/${cUrl[1]}/`; - promises.push(axios.get(u)); - } - let courses = []; - let success = true; - return (dispatch) => - axios - .all(promises) - .then( - (data) => { - courses = data.map((res, i) => { - try { - let semester = urlData[i].semester; - let section = - urlData[i].section === 'all' ? urlData[i].section : parseInt(urlData[i].section); - let sections = [section]; - let instructor = 'all'; - let match = []; - if (section === 'all') { - match = res.data.filter( - (item) => semester === capitalize(item.semester) + ' ' + item.year - )[0]; - sections = match.sections.map((item) => item.section_id); - } else { - match = res.data.map((item) => - item.sections.filter((item) => item.section_id == section) - ); - match = match.filter((item) => item.length !== 0); - instructor = match[0][0].instructor + ' / ' + match[0][0].section_number; - } - let formattedCourse = { - courseID: parseInt(urlData[i].courseID), - instructor: instructor, - semester: semester, - sections: sections - }; - formattedCourse.id = hash(formattedCourse); - formattedCourse.colorId = urlData[i].colorId; - return formattedCourse; - } catch (err) { - success = false; - history.push('/error'); - } - }); - }, - (error) => console.log('An error occurred.', error) - ) - .then(() => { - if (success) { - promises = []; - for (const course of courses) { - const u = `/api/catalog/catalog_json/course/${course.courseID}/`; - promises.push(axios.get(u)); - } - axios.all(promises).then( - (data) => { - data.map((res, i) => { - const courseData = res.data; - const course = courses[i]; - const formattedCourse = { - id: course.id, - course: courseData.course, - title: courseData.title, - semester: course.semester, - instructor: course.instructor, - courseID: course.courseID, - sections: course.sections, - colorId: course.colorId - }; - dispatch(enrollAddCourse(formattedCourse)); - }); - }, - (error) => console.log('An error occurred.', error) - ); - } - }); -} diff --git a/frontend/src/redux/auth/reducer.ts b/frontend/src/redux/auth/reducer.ts deleted file mode 100644 index 80f8b3a76..000000000 --- a/frontend/src/redux/auth/reducer.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { AuthState, LOG_IN, LOG_OUT, AuthAction } from './types'; - -const initialState: AuthState = { - loading: true, - userProfile: undefined, - isLoggedIn: false -}; - -export default function authReducer(state = initialState, action: AuthAction): AuthState { - switch (action.type) { - case LOG_IN: - return { - ...state, - loading: false, - userProfile: action.profile, - isLoggedIn: true - }; - case LOG_OUT: - return { - ...state, - loading: false, - userProfile: undefined, - isLoggedIn: false - }; - default: - return state; - } -} diff --git a/frontend/src/redux/auth/types.ts b/frontend/src/redux/auth/types.ts deleted file mode 100644 index 965604bc1..000000000 --- a/frontend/src/redux/auth/types.ts +++ /dev/null @@ -1,22 +0,0 @@ -interface UserProfile { - token: string; - email: string; - firstName: string; - lastName: string; -} - -export interface AuthState { - loading: boolean; - userProfile?: UserProfile; - isLoggedIn: boolean; -} - -export const LOG_IN = 'LOG_IN'; -export const LOG_OUT = 'LOG_OUT'; - -export type AuthAction = - | { - type: typeof LOG_IN; - profile: UserProfile; - } - | { type: typeof LOG_OUT }; diff --git a/frontend/src/redux/common/actions.ts b/frontend/src/redux/common/actions.ts deleted file mode 100644 index fbf4d3d82..000000000 --- a/frontend/src/redux/common/actions.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { - OPEN_BANNER, - CLOSE_BANNER, - CommonAction, - ENTER_MOBILE, - EXIT_MOBILE, - OPEN_LANDING_MODAL, - CLOSE_LANDING_MODAL -} from './types'; - -export const openBanner = (): CommonAction => ({ type: OPEN_BANNER }); -export const closeBanner = (): CommonAction => ({ type: CLOSE_BANNER }); -export const openLandingModal = (): CommonAction => ({ type: OPEN_LANDING_MODAL }); -export const closeLandingModal = (): CommonAction => ({ type: CLOSE_LANDING_MODAL }); -export const enterMobile = (): CommonAction => ({ type: ENTER_MOBILE }); -export const exitMobile = (): CommonAction => ({ type: EXIT_MOBILE }); diff --git a/frontend/src/redux/common/reducer.ts b/frontend/src/redux/common/reducer.ts deleted file mode 100644 index 1f69e8a3b..000000000 --- a/frontend/src/redux/common/reducer.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { - CommonState, - CommonAction, - OPEN_BANNER, - CLOSE_BANNER, - ENTER_MOBILE, - EXIT_MOBILE, - OPEN_LANDING_MODAL, - CLOSE_LANDING_MODAL -} from './types'; - -const initialState: CommonState = { - banner: false, - landingModal: false, - mobile: false -}; - -export function commonReducer(state = initialState, action: CommonAction): CommonState { - switch (action.type) { - case OPEN_BANNER: - return { - ...state, - banner: true - }; - case CLOSE_BANNER: - const bannerType = 'fa23catalog'; - localStorage.setItem('bt-hide-banner', bannerType); - return { - ...state, - banner: false - }; - case OPEN_LANDING_MODAL: - return { - ...state, - landingModal: true - }; - case CLOSE_LANDING_MODAL: - const modalType = 'sp22scheduler'; - localStorage.setItem('bt-hide-landing-modal', modalType); - return { - ...state, - landingModal: false - }; - case ENTER_MOBILE: - return { - ...state, - mobile: true - }; - case EXIT_MOBILE: - return { - ...state, - mobile: false - }; - default: - return state; - } -} diff --git a/frontend/src/redux/common/types.ts b/frontend/src/redux/common/types.ts deleted file mode 100644 index 8f3986bf6..000000000 --- a/frontend/src/redux/common/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Action } from 'redux'; - -export interface CommonState { - banner: boolean; - landingModal: boolean; - mobile: boolean; -} - -export const OPEN_BANNER = 'OPEN_BANNER'; -export const CLOSE_BANNER = 'CLOSE_BANNER'; -export const ENTER_MOBILE = 'ENTER_MOBILE'; -export const EXIT_MOBILE = 'EXIT_MOBILE'; -export const OPEN_LANDING_MODAL = 'OPEN_LANDING_MODAL'; -export const CLOSE_LANDING_MODAL = 'CLOSE_LANDING_MODAL'; - -export type CommonAction = Action; diff --git a/frontend/src/redux/reducers/enrollment.js b/frontend/src/redux/reducers/enrollment.js deleted file mode 100644 index 51f55b560..000000000 --- a/frontend/src/redux/reducers/enrollment.js +++ /dev/null @@ -1,106 +0,0 @@ -import { - UPDATE_ENROLL_CONTEXT, - ENROLL_ADD_COURSE, - UPDATE_ENROLL_DATA, - UPDATE_ENROLL_SELECTED, - ENROLL_REMOVE_COURSE, - ENROLL_RESET -} from '../actionTypes'; - -const initialState = { - context: {}, - selectedCourses: [], - enrollmentData: [], - graphData: [], - sections: [], - selectPrimary: '', - selectSecondary: '', - usedColorIds: [] -}; - -export default function enrollment(state = initialState, action) { - switch (action.type) { - case ENROLL_RESET: { - return { - ...initialState, - context: state.context - }; - } - case UPDATE_ENROLL_CONTEXT: { - const { data } = action.payload; - return { ...state, context: data }; - } - case ENROLL_ADD_COURSE: { - const { formattedCourse } = action.payload; - return { - ...state, - selectedCourses: [...state.selectedCourses, formattedCourse], - usedColorIds: [...state.usedColorIds, formattedCourse.colorId] - }; - } - case ENROLL_REMOVE_COURSE: { - const { id, color } = action.payload; - const updatedCourses = state.selectedCourses.filter((classInfo) => classInfo.id !== id); - const updatedColors = state.usedColorIds.filter((c) => c !== color); - return { - ...state, - selectedCourses: updatedCourses, - usedColorIds: updatedColors - }; - } - case UPDATE_ENROLL_DATA: { - const { enrollmentData } = action.payload; - const days = [...Array(200).keys()]; - const graphData = days.map((day) => { - const ret = { - name: day - }; - for (const enrollment of enrollmentData) { - const validTimes = enrollment.data.filter((time) => time.day >= 0); - const enrollmentTimes = {}; - for (const validTime of validTimes) { - enrollmentTimes[validTime.day] = validTime; - } - - if (day in enrollmentTimes) { - ret[enrollment.id] = (enrollmentTimes[day].enrolled_percent * 100).toFixed(1); - } - } - return ret; - }); - return { - ...state, - enrollmentData, - graphData - }; - } - case UPDATE_ENROLL_SELECTED: { - const { sections } = action.payload; - if (sections.length === 0) { - return { - ...state, - sections, - selectPrimary: '', - selectSecondary: '' - }; - } - const str = sections[0].semester.charAt(0).toUpperCase() + sections[0].semester.slice(1); - return { - ...state, - sections, - selectPrimary: `${str} ${sections[0].year}`, - selectSecondary: { value: 'all', label: 'All Instructors' } - }; - } - default: - return state; - } -} -// -// capitalize(str) { -// return str.charAt(0).toUpperCase() + str.slice(1); -// } -// -// getSectionSemester(section) { -// return `${this.capitalize(section.semester)} ${section.year}`; -// } diff --git a/frontend/src/redux/reducers/grade.js b/frontend/src/redux/reducers/grade.js deleted file mode 100644 index 45cd6650e..000000000 --- a/frontend/src/redux/reducers/grade.js +++ /dev/null @@ -1,76 +0,0 @@ -import { - UPDATE_GRADE_CONTEXT, - GRADE_ADD_COURSE, - UPDATE_GRADE_DATA, - UPDATE_GRADE_SELECTED, - GRADE_REMOVE_COURSE, - GRADE_RESET -} from '../actionTypes'; -import vars from '../../variables/Variables'; - -const initialState = { - context: {}, - selectedCourses: [], - gradesData: [], - graphData: [], - sections: [], - selectPrimary: '', - selectSecondary: '', - usedColorIds: [] -}; - -export default function grade(state = initialState, action) { - switch (action.type) { - case GRADE_RESET: { - return initialState; - } - case UPDATE_GRADE_CONTEXT: { - const { data } = action.payload; - return { ...state, context: data }; - } - case GRADE_ADD_COURSE: { - const { formattedCourse } = action.payload; - return Object.assign({}, state, { - selectedCourses: [...state.selectedCourses, formattedCourse], - usedColorIds: [...state.usedColorIds, formattedCourse.colorId] - }); - } - case GRADE_REMOVE_COURSE: { - const { id, color } = action.payload; - let updatedCourses = state.selectedCourses.filter((classInfo) => classInfo.id !== id); - let updatedColors = state.usedColorIds.filter((c) => c !== color); - return Object.assign({}, state, { - selectedCourses: updatedCourses, - usedColorIds: updatedColors - }); - } - case UPDATE_GRADE_DATA: { - const { gradesData } = action.payload; - const graphData = vars.possibleGrades.map((letterGrade) => { - const ret = { - name: letterGrade - }; - for (const grade of gradesData) { - ret[grade.id] = (grade[letterGrade].numerator / grade.denominator) * 100; - } - return ret; - }); - return { - ...state, - gradesData, - graphData - }; - } - case UPDATE_GRADE_SELECTED: { - const { data } = action.payload; - return { - ...state, - sections: data, - selectPrimary: '', - selectSecondary: '' - }; - } - default: - return state; - } -} diff --git a/frontend/src/redux/store.ts b/frontend/src/redux/store.ts deleted file mode 100644 index 70f531ab6..000000000 --- a/frontend/src/redux/store.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createStore, combineReducers, applyMiddleware, compose } from 'redux'; -import thunkMiddleware from 'redux-thunk'; - -import grade from './reducers/grade'; -import enrollment from './reducers/enrollment'; -import authReducer from './auth/reducer'; - -import { commonReducer } from './common/reducer'; - -const reducer = combineReducers({ - grade, - enrollment, - authReducer, - common: commonReducer -}); - -export type ReduxState = ReturnType; - -const composeEnhancers = - (window && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) || compose; -export default createStore(reducer, composeEnhancers(applyMiddleware(thunkMiddleware))); diff --git a/frontend/src/registerServiceWorker.js b/frontend/src/registerServiceWorker.js deleted file mode 100644 index b07128b1d..000000000 --- a/frontend/src/registerServiceWorker.js +++ /dev/null @@ -1,106 +0,0 @@ -/* eslint-disable */ - -// In production, we register a service worker to serve assets from local cache. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on the "N+1" visit to a page, since previously -// cached resources are updated in the background. - -// To learn more about the benefits of this model, read https://goo.gl/KwvDNy. -// This link also includes instructions on opting out of this behavior. - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/) -); - -export default function register() { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL(process.env.PUBLIC_URL, window.location); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374 - return; - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (!isLocalhost) { - // Is not local host. Just register service worker - registerValidSW(swUrl); - } else { - // This is running on localhost. Lets check if a service worker still exists or not. - checkValidServiceWorker(swUrl); - } - }); - } -} - -function registerValidSW(swUrl) { - navigator.serviceWorker - .register(swUrl) - .then((registration) => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the old content will have been purged and - // the fresh content will have been added to the cache. - // It's the perfect time to display a "New content is - // available; please refresh." message in your web app. - console.log('New content is available; please refresh.'); - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); - } - } - }; - }; - }) - .catch((error) => { - console.error('Error during service worker registration:', error); - }); -} - -function checkValidServiceWorker(swUrl) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then((response) => { - // Ensure service worker exists, and that we really are getting a JS file. - if ( - response.status === 404 || - response.headers.get('content-type').indexOf('javascript') === -1 - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then((registration) => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl); - } - }) - .catch(() => { - console.log('No internet connection found. App is running in offline mode.'); - }); -} - -export function unregister() { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready.then((registration) => { - registration.unregister(); - }); - } -} diff --git a/frontend/src/utils/courses/course.ts b/frontend/src/utils/courses/course.ts deleted file mode 100644 index 7c18c2be9..000000000 --- a/frontend/src/utils/courses/course.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { CourseFragment } from 'graphql'; -import { hash } from 'utils/string'; - -type CourseReference = { - abbreviation: string; - courseNumber: string; -}; - -/** - * Course to a course name - * @example - * courseToName(course) == "COMPSCI 61B" - */ -export function courseToName( - course: Pick | CourseReference | null | undefined -): string { - return course ? `${course.abbreviation} ${course.courseNumber}` : ''; -} - -/** - * Color palette for courses - */ -export const COURSE_PALETTE = ['#1AA8E5', '#18DE83', '#FCD571', '#ED5186', '#FFA414']; - -/** - * Gets a color for a course - * @param course Either a course object or the courseId. - * @returns a CSS color code. - */ -export function courseToColor(course: Pick | string | null): string { - return COURSE_PALETTE[ - (course ? hash(typeof course === 'string' ? course : course.id) : 0) % COURSE_PALETTE.length - ]; -} diff --git a/frontend/src/utils/courses/search.ts b/frontend/src/utils/courses/search.ts deleted file mode 100644 index 886e38993..000000000 --- a/frontend/src/utils/courses/search.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { CourseOverviewFragment } from 'graphql'; -import { combineQueries, normalizeSearchTerm, search } from 'utils/search'; - -type SearchableCourse = CourseOverviewFragment; - -/** - * Applies search query over list of courses - */ -export function searchCourses(courses: SearchableCourse[], rawQuery: string): SearchableCourse[] { - const query = normalizeSearchTerm(rawQuery); - const results = courses - .map<[SearchableCourse, number | null]>((course) => { - return [ - course, - combineQueries([ - searchCourse(query, getFullCourseCode(course), 1), - search(query, `${course.title}`.toLowerCase(), 0.3, 0.05) - ]) - ]; - }) - .filter((result): result is [SearchableCourse, number] => result[1] !== null) - .sort((a, b) => a[1] - b[1]) - .map(([course]) => course); - - return results; -} - -/** - * Searches for a single course - * @return a number (lower is better) representing the quality of the match - */ -function searchCourse(query: string, courseCode: string, maxPenalty?: number): number | null { - const searches = laymanToAbbreviation - .filter(([source]) => courseCode.indexOf(source) > -1) - .map(([source, replacement]) => - search(query, courseCode.replace(source, replacement), maxPenalty) - ); - - searches.push(search(query, courseCode, maxPenalty)); - - return combineQueries(searches); -} - -/** - * Runs {@link searchCourse} but for react-select - */ -export function reactSelectCourseSearch(option: any, query: string): boolean { - return searchCourse(query, option.label.toLowerCase(), 0.2) !== null; -} - -/** - * Course object to a fully-descriptive course search string. - */ -function getFullCourseCode(course: SearchableCourse): string { - const searchComponents = [course.abbreviation, course.courseNumber]; - return searchComponents.join(' ').toLowerCase(); -} - -const laymanToAbbreviation: [string, string][] = [ - ['astron', 'astro'], - ['compsci', 'cs'], - ['mcellbi', 'mcb'], - ['nusctx', 'nutrisci'], - ['bio eng', 'bioe'], - ['bio eng', 'bio e'], - ['bio phy', 'bio p'], - ['bio eng', 'bioeng'], - ['biology', 'bio'], - ['civ eng', 'cive'], - ['civ eng', 'civ e'], - ['chm eng', 'cheme'], - ['civ eng', 'civeng'], - ['classic', 'classics'], - ['cog sci', 'cogsci'], - ['colwrit', 'college writing'], - ['com lit', 'complit'], - ['com lit', 'comlit'], - ['cy plan', 'cyplan'], - ['cy plan', 'cp'], - ['des inv', 'desinv'], - ['des inv', 'design'], - ['dev eng', 'deveng'], - ['dev std', 'devstd'], - ['datasci', 'ds'], - ['ea lang', 'ealang'], - ['env des', 'ed'], - ['el eng', 'ee'], - ['ene,res', 'erg'], - ['ene,res', 'er'], - ['ene,res', 'eneres'], - ['engin', 'e'], - ['engin', 'engineering'], - ['env sci', 'envsci'], - ['eth std', 'ethstd'], - ['eura st', 'eurast'], - ['geog', 'geology'], - ['hin-urd', 'hinurd'], - ['hum bio', 'humbio'], - ['integbi', 'ib'], - ['ind eng', 'ie'], - ['ind eng', 'ieor'], - ['linguis', 'ling'], - ['l & s', 'l&s'], - ['l & s', 'ls'], - ['l & s', 'lns'], - ['malay/i', 'malayi'], - ['mat sci', 'matsci'], - ['mat sci', 'ms'], - ['mat sci', 'mse'], - ['mec eng', 'meceng'], - ['mec eng', 'meche'], - ['mec eng', 'mech e'], - ['mec eng', 'me'], - ['med st', 'medst'], - ['m e stu', 'mestu'], - ['m e stu', 'middle eastern studies'], - ['mil aff', 'milaff'], - ['mil sci', 'milsci'], - ['natamst', 'native american studies'], - ['natamst', 'nat am st'], - ['neurosc', 'neurosci'], - ['nuc eng', 'ne'], - ['ne stud', 'nestud'], - ['mediast', 'media'], - ['pb hlth', 'pbhlth'], - ['pb hlth', 'ph'], - ['pb hlth', 'pub hlth'], - ['pb hlth', 'public health'], - ['phys ed', 'pe'], - ['phys ed', 'physed'], - ['philos', 'philo'], - ['philos', 'phil'], - ['polecon', 'poli econ'], - ['polecon', 'poliecon'], - ['philo', 'philosophy'], - ['plantbi', 'pmb'], - ['pol sci', 'poli'], - ['pol sci', 'polsci'], - ['pol sci', 'polisci'], - ['pol sci', 'poli sci'], - ['pol sci', 'ps'], - ['pub pol', 'pubpol'], - ['pub pol', 'pp'], - ['pub pol', 'public policy'], - ['pub aff', 'pubaff'], - ['psych', 'psychology'], - ['rhetor', 'rhetoric'], - ['s asian', 'sasian'], - ['s,seasn', 'sseasn'], - ['stat', 'stats'], - ['theater', 'tdps'], - ['ugba', 'haas'], - ['vietnms', 'vietnamese'], - ['vis sci', 'vissci'], - ['vis std', 'visstd'] -]; diff --git a/frontend/src/utils/courses/sorting.ts b/frontend/src/utils/courses/sorting.ts deleted file mode 100644 index a7b6ad6d4..000000000 --- a/frontend/src/utils/courses/sorting.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { CourseOverviewFragment } from 'graphql'; - -export type CourseSortAttribute = - | 'relevance' - | 'average_grade' - | 'department_name' - | 'open_seats' - | 'enrolled_percentage'; - -export type SortableCourse = CourseOverviewFragment; -type CourseComparator = (courseA: SortableCourse, courseB: SortableCourse) => number; - -/** - * Comparator for department name. Essentially alphabetical order. - */ -export const compareDepartmentName: CourseComparator = (courseA, courseB) => { - const courseATitle = `${courseA.abbreviation} ${courseA.courseNumber}`; - const courseBTitle = `${courseB.abbreviation} ${courseB.courseNumber}`; - return courseATitle.localeCompare(courseBTitle); -}; - -/** - * Compares courses by relevance. "Relevance" is only a term relevant to - * searching so this defaults to "average grade" when not being - * search-filtered. - */ -export const compareRelevance: CourseComparator = (courseA, courseB) => { - return 0; -}; - -/** - * Comparator for average gpa, break ties by department name - */ -export const compareAverageGrade: CourseComparator = (courseA, courseB) => { - return courseB.gradeAverage! - courseA.gradeAverage! || compareDepartmentName(courseA, courseB); -}; - -/** - * Comparator for open seats, break ties by department name - */ -export const compareOpenSeats: CourseComparator = (courseA, courseB) => { - return courseB.openSeats! - courseA.openSeats! || compareDepartmentName(courseA, courseB); -}; - -/** - * Comparator for enrolled percentage, break ties by department name - * If percentage is -1, it is put at the end (greater than all other percents) - */ -export const compareEnrollmentPercentage: CourseComparator = (courseA, courseB) => { - if (courseA.enrolledPercentage !== -1 && courseB.enrolledPercentage !== -1) { - return ( - courseA.enrolledPercentage! - courseB.enrolledPercentage! || - compareDepartmentName(courseA, courseB) - ); - } else if (courseA.enrolledPercentage === -1 && courseB.enrolledPercentage === -1) { - return compareDepartmentName(courseA, courseB); - } else { - return courseB.enrolledPercentage! - courseA.enrolledPercentage!; - } -}; - -/** - * Returns comparator based on the sort - */ -export function sortByAttribute(sortAttribute: CourseSortAttribute): CourseComparator { - switch (sortAttribute) { - case 'relevance': - return compareRelevance; - case 'average_grade': - return compareAverageGrade; - case 'department_name': - return compareDepartmentName; - case 'open_seats': - return compareOpenSeats; - case 'enrolled_percentage': - return compareEnrollmentPercentage; - } -} diff --git a/frontend/src/utils/courses/units.ts b/frontend/src/utils/courses/units.ts deleted file mode 100644 index 26a2c8d95..000000000 --- a/frontend/src/utils/courses/units.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Represents a unit for a class. This is the way it is because some classes can - * have variable units - */ -export type Units = { - lowerBound: number; - upperBound: number; -}; - -/** - * Value representing zero units - */ -export const ZERO_UNITS = { lowerBound: 0, upperBound: 0 }; - -/** - * Adds two units - */ -export function addUnits(a: Units, b: Units): Units { - return { - lowerBound: a.lowerBound + b.lowerBound, - upperBound: a.upperBound + b.upperBound - }; -} - -/** - * Converts unit to a human-readable unit - */ -export function unitsToString(units: Units): string { - if (units.lowerBound === units.upperBound) { - return `${units.lowerBound}`; - } else { - return `${units.lowerBound}-${units.upperBound}`; - } -} - -/** - * Parses a unit string - */ -export function parseUnits(string: string): Units { - if (string.includes('-')) { - const [lower, upper] = string.split('-'); - return { - lowerBound: +lower, - upperBound: +upper - }; - } else { - const value = +string; - return { - lowerBound: value, - upperBound: value - }; - } -} diff --git a/frontend/src/utils/date.ts b/frontend/src/utils/date.ts deleted file mode 100644 index 8f986eaee..000000000 --- a/frontend/src/utils/date.ts +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Converts time string to date - */ -export function stringToDate(time: string): Date { - return new Date(`${time}Z`); -} - -/** - * Formats a time to 12-hour w/ AM PM - */ -export function formatTime(date: Date | string): string { - if (typeof date === 'string') { - date = stringToDate(date); - } - - // Sorry internationals but timezones r weird so this is go - let hours = date.getUTCHours(); - const minutes = date.getUTCMinutes().toString().padStart(2, '0'); - const ampm = hours >= 12 ? ' PM' : ' AM'; - - hours = hours % 12; - hours = hours || 12; - - const strTime = hours + ':' + minutes + ampm; - - return strTime; -} - -const DAY_NAMES = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - -const ICAL_DAY_NAMES = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; - -/** - * Converts numerical day of the week to day. e.g. 0 => Sunday. - */ -export function dayToLongName(day: number): string { - return DAY_NAMES[day]; -} - -/** - * Converts day to iCal number - */ -export const dayToICalDay = (day: number): string => ICAL_DAY_NAMES[day]; - -/** - * Converts a 'time' e.g. 13 into a time "1 PM" - */ -export function timeToHourString(time: number): string { - const floorModTime = ((time % 24) + 24) % 24; - - if (time < 12) { - return `${floorModTime}am`; - } else if (time === 12) { - return `12pm`; - } else { - return `${floorModTime % 12}pm`; - } -} - -/** - * Re-interprets a local date as a UTC date. - */ -export const reinterpretDateAsUTC = (date: Date) => - new Date(date.getTime() + new Date().getTimezoneOffset() * 60 * 1000); diff --git a/frontend/src/utils/debounce.ts b/frontend/src/utils/debounce.ts deleted file mode 100644 index db682d824..000000000 --- a/frontend/src/utils/debounce.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export default function debounce any>( - func: T, - wait: number -) { - let timeout: number | undefined; - return (...args: any[]) => { - if (!timeout) func(...args); - clearTimeout(timeout); - timeout = setTimeout(() => func(...args), wait); - }; -} diff --git a/frontend/src/utils/easterEgg.ts b/frontend/src/utils/easterEgg.ts deleted file mode 100644 index c8f388830..000000000 --- a/frontend/src/utils/easterEgg.ts +++ /dev/null @@ -1,48 +0,0 @@ -export default () => { - // eslint-disable-next-line no-console - console.log( - `%c - Hey there! Checking out how Berkeleytime works? We are a group of student developers - here at UC Berkeley. We build this site using the latest tech - Django, Kubernetes, - and more. If you love using Berkeleytime and want to see yourself as a contributor, - we are always looking for passionate individuals to help us improve our product. - - Check out our Join Us page, especially towards the start of the Fall semester when we - are recruiting. Also, send us an email at octo.berkeleytime@asuc.org letting us know you - found this message! - - - .,,uod8B8bou,,. - ..,uod8BBBBBBBBBBBBBBBBRPFT?l!i:. - ,=m8BBBBBBBBBBBBBBBRPFT?!|||||||||||||| - !...:!TVBBBRPFT||||||||||!!^^""' |||| - !.......:!?|||||!!^^""' |||| - !.........|||| |||| - !.........|||| $ |||| - !.........|||| |||| - !.........|||| |||| - !.........|||| |||| - !.........|||| |||| - \`........|||| ,|||| - .;.......|||| _.-!!||||| - .,uodWBBBBb.....|||| _.-!!|||||||||!:' - !YBBBBBBBBBBBBBBb..!|||:..-!!|||||||!iof68BBBBBb.... - !..YBBBBBBBBBBBBBBb!!||||||||!iof68BBBBBBRPFT?!:: \`. - !....YBBBBBBBBBBBBBBbaaitf68BBBBBBRPFT?!::::::::: \`. - !......YBBBBBBBBBBBBBBBBBBBRPFT?!::::::;:!^"\`;::: \`. - !........YBBBBBBBBBBRPFT?!::::::::::^''...::::::; iBBbo. - \`..........YBRPFT?!::::::::::::::::::::::::;iof68bo. WBBBBbo. - \`..........:::::::::::::::::::::::;iof688888888888b. \`YBBBP^' - \`........::::::::::::::::;iof688888888888888888888b. \` - \`......:::::::::;iof688888888888888888888888888888b. - \`....:::;iof688888888888888888888888888888888899fT! - \`..::!8888888888888888888888888888888899fT|!^"' - \`' !!988888888888888888888888899fT|!^"' - \`!!8888888888888888899fT|!^"' - \`!988888888899fT|!^"' - \`!9899fT|!^"' - \`!^"' - `, - 'font-family:monospace' - ); -}; diff --git a/frontend/src/utils/graphql.ts b/frontend/src/utils/graphql.ts deleted file mode 100644 index b19b54b16..000000000 --- a/frontend/src/utils/graphql.ts +++ /dev/null @@ -1,10 +0,0 @@ -type GraphQLEdge = { - node?: T | null; -}; - -type GraphQLConnection = { - edges: (GraphQLEdge | null)[]; -}; - -export const getNodes = (x: GraphQLConnection): T[] => - x.edges.map((edge) => edge?.node).filter((e): e is T => e !== null || e !== void 0); diff --git a/frontend/src/utils/hooks.ts b/frontend/src/utils/hooks.ts deleted file mode 100644 index 9111184a3..000000000 --- a/frontend/src/utils/hooks.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Dispatch, SetStateAction, useCallback, useState } from 'react'; - -/** - * A version of useState that presists a value across page - * refreshes using localStorage. Pass a unique 'key' - * to identify the value. - */ -export function useLocalStorageState( - key: string, - initialValue: S | (() => S) -): [S, Dispatch>] { - const [value, setValue] = useState(() => { - const value = localStorage.getItem(key); - if (value) { - try { - return JSON.parse(value); - } catch (e) {} - } - - const computedInitialValue: S = - initialValue instanceof Function ? initialValue() : initialValue; - - localStorage.setItem(key, JSON.stringify(computedInitialValue)); - return computedInitialValue; - }); - - const wrappedSetValue = useCallback( - (newValue: S | SetStateAction) => { - setValue((oldValue) => { - let updatedValue: S; - if (newValue instanceof Function) { - updatedValue = newValue(oldValue); - } else { - updatedValue = newValue; - } - localStorage.setItem(key, JSON.stringify(updatedValue)); - return updatedValue; - }); - }, - [key] - ); - - return [value, wrappedSetValue]; -} diff --git a/frontend/src/utils/playlists/semesters.ts b/frontend/src/utils/playlists/semesters.ts deleted file mode 100644 index 4efff6deb..000000000 --- a/frontend/src/utils/playlists/semesters.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { capitalize } from 'bt/utils'; -import { FilterFragment } from 'graphql'; - -type FilterablePlaylist = FilterFragment; - -const SEMESTER_TYPE_TO_OFFSET: { [key: string]: number } = { - spring: 0.0, - summer: 0.1, - fall: 0.2 -}; - -/** - * Converts a playlist to a quantifiable year value. Greater = newer - */ -function playlistToTimeComparable(playlist: FilterablePlaylist): number { - if (playlist.category === 'semester') { - const [semester, year] = playlist.name.toLowerCase().split(' '); - return +year + SEMESTER_TYPE_TO_OFFSET[semester]; - } else { - return 0; - } -} - -export type Semester = { - playlistId?: string; - year: string; - semester: string; -}; - -export type SemesterWithPlaylist = Semester & { playlistId: string }; - -/** - * Gets the latest semester from a list of playlists. - */ -export function getLatestSemester(playlists: FilterablePlaylist[]): SemesterWithPlaylist | null { - const semesterPlaylists = playlists - .filter( - (p) => - p.category === 'semester' && - (process.env.NODE_ENV !== 'development' || p.name === 'Fall 2020') - ) - .sort((a, b) => playlistToTimeComparable(b) - playlistToTimeComparable(a)); - - const semester = semesterPlaylists[0]; - if (semester) { - return playlistToSemester(semester); - } else { - return null; - } -} - -/** - * Converts playlist to semester - */ -function playlistToSemester(playlist: FilterablePlaylist): SemesterWithPlaylist { - return stringToSemester(playlist.name, playlist.id); -} - -/** - * Convert a string to a semester. - */ -function stringToSemester(string: string, playlistId: string): SemesterWithPlaylist; -function stringToSemester(string: string, playlistId?: string): Semester { - const [semester, year] = string.trim().toLowerCase().split(' '); - return { - semester, - year, - playlistId - }; -} - -/** - * Converts a semester to human-readable string - */ -export function semesterToString(semester?: Semester | null): string { - if (!semester) return ''; - return `${capitalize(semester.semester)} ${semester.year}`; -} diff --git a/frontend/src/utils/range.ts b/frontend/src/utils/range.ts deleted file mode 100644 index a84fda9f1..000000000 --- a/frontend/src/utils/range.ts +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Range from A to B - */ -export function range(a: number, b: number, step = 1): number[] { - return Array(b - a) - .fill(0) - .map((_, i) => i + a); -} diff --git a/frontend/src/utils/scheduler/accessStatus.tsx b/frontend/src/utils/scheduler/accessStatus.tsx deleted file mode 100644 index fafa34792..000000000 --- a/frontend/src/utils/scheduler/accessStatus.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { ReactComponent as Lock } from '../../assets/svg/profile/lock.svg'; -import { ReactComponent as World } from '../../assets/svg/profile/world.svg'; - -export const ACCESS_STATUSES = { - private: { - icon: , - name: 'Just Me', - description: 'Only you can access your schedule.' - }, - public: { - icon: , - name: 'With the Link', - description: 'Anyone with the link can access your schedule.' - } -}; - -export type AccessStatus = keyof typeof ACCESS_STATUSES; diff --git a/frontend/src/utils/scheduler/scheduler.ts b/frontend/src/utils/scheduler/scheduler.ts deleted file mode 100644 index ac2065ae5..000000000 --- a/frontend/src/utils/scheduler/scheduler.ts +++ /dev/null @@ -1,286 +0,0 @@ -import { - CourseOverviewFragment, - CreateScheduleMutationVariables, - ScheduleFragment, - SectionFragment -} from 'graphql'; -import { addUnits, parseUnits, Units, unitsToString, ZERO_UNITS } from 'utils/courses/units'; -import { Semester, semesterToString } from 'utils/playlists/semesters'; -import { getNodes } from '../graphql'; -import { courseToColor, courseToName, COURSE_PALETTE } from 'utils/courses/course'; -import { AccessStatus } from './accessStatus'; -import { dayToICalDay, reinterpretDateAsUTC, stringToDate } from 'utils/date'; -import { addWeeks, isBefore, min, setDay } from 'date-fns'; - -// Update the version when the scheduler schema changes. -export const SCHEDULER_LOCALSTORAGE_KEY = 'schedule:save:v1.0'; - -export type SchedulerCourseType = CourseOverviewFragment; -export type SchedulerSectionType = SectionFragment & { - /** - * The ID of the parent course of this seciton - */ - courseId: string; - - /** - * If this is a secondary section, the ID of - * the primary section. If this is undefined, - * it is a primary section. - */ - lectureId?: string; -}; - -export type Schedule = { - name: string; - access: AccessStatus; - courses: SchedulerCourseType[]; - sections: SchedulerSectionType[]; -}; - -export type BackendSchedule = CreateScheduleMutationVariables; - -export const DEFAULT_SCHEDULE: Schedule = { - name: 'My Schedule', - access: 'private', - courses: [], - sections: [] -}; - -/** - * Checks if a course is empty - */ -export const isScheduleEmpty = (schedule: Schedule): boolean => - !schedule || (schedule.courses.length === 0 && schedule.sections.length === 0); - -/** - * Gets a corresponding course for a section (assuming it exists in the - * schedule) - */ -export const getCourseForSchedule = ( - schedule: Schedule, - section: SchedulerSectionType -): SchedulerCourseType | null => schedule.courses.find((c) => c.id === section.courseId) || null; - -/** - * Gets the color for a course (based off a section) - * within a schedule. - */ -export const getColorForSection = (schedule: Schedule, section: SchedulerSectionType): string => - getColorForCourse(schedule, section.courseId); - -/** - * Gets the color for a course within a schedule. You - * can pass the course or course id. - */ -export const getColorForCourse = ( - schedule: Schedule, - course: CourseOverviewFragment | string -): string => - COURSE_PALETTE[ - (schedule.courses.length - - (schedule.courses.findIndex((c) => - typeof course === 'string' ? c.id === course : c.id === course.id - ) || 0)) % - COURSE_PALETTE.length - ]; - -/** - * Computes the amount of units in a schedule - */ -export const getUnitsForSchedule = (schedule: Schedule): Units => - schedule.courses - .filter((course) => !!schedule.sections.find((section) => section.courseId === course.id)) - .reduce( - (sum, course) => (course.units ? addUnits(sum, parseUnits(course.units)) : sum), - ZERO_UNITS - ); - -/** - * Removes a course by id - */ -export const removeCourse = (schedule: Schedule, id: string): Schedule => ({ - ...schedule, - courses: schedule.courses.filter((c) => c.id !== id), - sections: schedule.sections.filter((s) => s.courseId !== id) -}); - -/** - * Removes a section from the schedule. If a primary section is - * removed, all associated sections are also removed - */ -export const removeSection = (schedule: Schedule, sectionId: string) => ({ - ...schedule, - sections: schedule.sections.filter((s) => s.lectureId !== sectionId && s.id !== sectionId) -}); - -/** - * Checks if the scheduler has a course by Id - */ -export const hasCourseById = (schedule: Schedule, id: string): boolean => - !!schedule.courses.find((c) => c.id === id); - -/** - * Checks if the scheduler has a section by Id - */ -export const hasSectionById = (schedule: Schedule, id: string): boolean => - !!schedule.sections.find((c) => c.id === id); - -/** - * Deserializes a schedule from backend to frontend format - */ -export const deserializeSchedule = (schedule: ScheduleFragment): Schedule => ({ - name: schedule.name, - access: schedule.public ? 'public' : 'private', - courses: getNodes(schedule.selectedSections).map((section) => section.course), - sections: getNodes(schedule.selectedSections) - .flatMap((section) => - section.primary - ? [ - { ...section.primary, courseId: section.course.id }, - ...getNodes(section.secondary).map((secondary) => ({ - courseId: section.course.id, - lectureId: section.primary!.id, - ...secondary - })) - ] - : [] - ) - .filter((n): n is SchedulerSectionType => !!n) -}); - -/** - * Converts a schedule from the frontend to backend format - */ -export const serializeSchedule = (schedule: Schedule, semester: Semester): BackendSchedule => ({ - name: schedule.name, - semester: semester.semester, - year: semester.year, - public: schedule.access === 'public', - totalUnits: unitsToString(getUnitsForSchedule(schedule)), - selectedSections: schedule.courses - .map((course) => ({ - course: course.id, - primary: schedule.sections.find( - (section) => section.courseId === course.id && !section.lectureId - )?.id, - secondary: schedule.sections - .filter((section) => section.courseId === course.id && !!section.lectureId) - .map((section) => section.id) - })) - .filter((input) => !!input.primary), - timeblocks: [] -}); - -/** - * Generates iCal file string. - */ -export function scheduleToICal(schedule: Schedule, semester: Semester): string { - const SEMESTER_START = new Date(2023, 7, 23); - const LAST_COURSE_DAY = new Date(2023, 11, 1); - - const dateToICal = (date: Date) => date.toISOString().replace(/[-:Z]|\.\d+/g, ''); - - const stringToICal = (str: string) => - str.replace(/\\/g, '\\\\').replace(/\n/g, '\\n').replace(/;/g, '\\;').replace(/,/g, '\\,'); - - const DTSTAMP = dateToICal(new Date()); - - const events = schedule.sections - .map((section): [SchedulerSectionType, CourseOverviewFragment | null] => [ - section, - getCourseForSchedule(schedule, section) - ]) - .filter(([section, course]) => section.days.length >= 1 && course) - .map(([section]) => { - const course = getCourseForSchedule(schedule, section)!; - const courseName = courseToName(course); - const courseColor = courseToColor(course); - - // To find the first day of the course, we generate all - // instances of the course for the first two weeks - const firstWeek = section.days.split('').map((day) => setDay(SEMESTER_START, +day as Day)); - const secondWeek = firstWeek.map((day) => addWeeks(day, 1)); - - const firstCourseDay = reinterpretDateAsUTC( - min(firstWeek.concat(secondWeek).filter((instance) => !isBefore(instance, SEMESTER_START))) - ); - - const startTime = stringToDate(section.startTime); - const endTime = stringToDate(section.endTime); - - const startDateTime = new Date(firstCourseDay); - startDateTime.setUTCHours(startTime.getUTCHours()); - startDateTime.setUTCMinutes(startTime.getUTCMinutes()); - - const endDateTime = new Date(firstCourseDay); - endDateTime.setUTCHours(endTime.getUTCHours()); - endDateTime.setUTCMinutes(endTime.getUTCMinutes()); - - const days = section.days.split('').map((day) => dayToICalDay(+day)); - - const name = `${courseName} ${section.kind}`; - const description = `${courseName}: ${course?.title || 'Unknown Course'} - -Instructor: ${section.instructor} -Section CCN: ${section.ccn} - -Generated with the Berkeleytime scheduler (https://berkeleytime.com).`; - - return `BEGIN:VEVENT -UID:${section.id} -DTSTAMP:${DTSTAMP} -DTSTART;TZID=America/Los_Angeles:${dateToICal(startDateTime)} -DTEND;TZID=America/Los_Angeles:${dateToICal(endDateTime)} -RRULE:FREQ=WEEKLY;UNTIL=${dateToICal(LAST_COURSE_DAY)};BYDAY=${days} -LOCATION:${stringToICal(section.locationName)} -SUMMARY:${stringToICal(name)} -DESCRIPTION:${stringToICal(description)} -COLOR:${courseColor} -END:VEVENT`; - }); - - const PST_TIMEZONE_SPEC = `BEGIN:VTIMEZONE -TZID:America/Los_Angeles -X-LIC-LOCATION:America/Los_Angeles -BEGIN:DAYLIGHT -TZOFFSETFROM:-0800 -TZOFFSETTO:-0700 -TZNAME:PDT -DTSTART:19700308T020000 -RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU -END:DAYLIGHT -BEGIN:STANDARD -TZOFFSETFROM:-0700 -TZOFFSETTO:-0800 -TZNAME:PST -DTSTART:19701101T020000 -RRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU -END:STANDARD -END:VTIMEZONE`; - - return `BEGIN:VCALENDAR -METHOD:PUBLISH -PRODID:-//Berkeleytime.com//Berkeleytime Scheduler 1.0//EN -CALSCALE:GREGORIAN -VERSION:2.0 -X-WR-CALNAME: ${schedule.name} -X-WR-CALDESC: Course schedule for ${semesterToString(semester)} -X-WR-TIMEZONE:America/Los_Angeles -${PST_TIMEZONE_SPEC} -${events.join('\n')} -END:VCALENDAR -` - .split('\n') - .join('\r\n'); -} - -/** - * Formats a schedule error message - */ -export const formatScheduleError = (error?: Error | null): Error | string | null | undefined => - error && - (error.message.includes('No permission') - ? 'This schedule is not publicly accessible.' - : error.message.includes('not a valid UUID') || error.message.includes('Invalid Schedule ID') - ? 'That schedule does not exist.' - : 'An error occured loading scheduler information. Please try again later.'); diff --git a/frontend/src/utils/search.ts b/frontend/src/utils/search.ts deleted file mode 100644 index 894249ce5..000000000 --- a/frontend/src/utils/search.ts +++ /dev/null @@ -1,90 +0,0 @@ -const DEFAULT_NON_ADJACENT_PENALTY = 0.05; -const DEFAULT_START_BONUS = 0.1; - -/** - * Performs a searched clamped to maxTypos. Returns - * a negative number if not a match, else a positive number - * representing the 'distance'. `null` means a match was not found. - * - * Make sure your query and targetString are the same case. This - * doesn't handle normalization etc. - * - * This is like a fuzzy search but works better for abbrevations - * by penalizing ommisions at a much lower rate than transpositions - */ -export function search( - query: string, - targetString: string, - maxTypos = 1, - nonAdjacentPenalty: number = DEFAULT_NON_ADJACENT_PENALTY -): number | null { - // TODO: memo this function. - - const hlen = targetString.length; - const nlen = query.length; - - // If the query is longer than the target string, it can never match - if (nlen >= hlen) { - if (nlen === hlen && query === targetString) { - return 0; - } - - return null; - } - - let penalty = 0; - - outer: for (let i = 0, j = 0; i < nlen; i++) { - const nch = query.charCodeAt(i); - const start = j; - - // Try to find the search query char. - while (j < hlen) { - if (targetString.charCodeAt(j++) === nch) { - // If the matches char is NOT at the start of word or the - // beginning of the string, add a tiny penalty - if (j - 1 === 0 || targetString.charAt(j - 1) === ' ') { - penalty -= DEFAULT_START_BONUS; - } else { - penalty += Math.min(0.4, (j - start - 1) * nonAdjacentPenalty); - } - continue outer; - } - } - - // This point is reached if the character isn't found. - if (penalty < maxTypos) { - j = start; - penalty += 1; - } else { - return null; - } - } - - if (penalty > maxTypos) { - return null; - } else { - return penalty; - } -} - -/** - * Combines two search queries and returns the best result - */ -export function combineQueries(queries: (number | null)[]): number | null { - let start = Infinity; - for (let i = 0; i < queries.length; i++) { - const item = queries[i]; - if (item !== null && item < start) { - start = item; - } - } - return start === Infinity ? null : start; -} - -/** - * Normalizes a string for seraching - */ -export function normalizeSearchTerm(value: string) { - return value.trim().toLowerCase(); -} diff --git a/frontend/src/utils/sections/section.ts b/frontend/src/utils/sections/section.ts deleted file mode 100644 index 15f5743b7..000000000 --- a/frontend/src/utils/sections/section.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { SectionFragment } from 'graphql'; -import { ReactNode } from 'react'; -import { formatTime } from 'utils/date'; -import { applyIndicatorPercent } from 'utils/utils'; - -// eslint-disable-next-line @typescript-eslint/no-unused-vars -type SectionType = - | 'Clinic' - | 'Colloquium' - | 'Conversation' - | 'Demonstration' - | 'Directed Group Study' - | 'Discussion' - | 'Field Work' - | 'Independent Study' - | 'Internship' - | 'Laboratory' - | 'Lecture' - | 'Listening' - | 'Practicum' - | 'Reading' - | 'Recitation' - | 'Research' - | 'Self-paced' - | 'Seminar' - | 'Session' - | 'Simulcast' - | 'Studio' - | 'Supplementary' - | 'Tutorial' - | 'Voluntary' - | 'Web-Based Discussion' - | 'Web-Based Lecture' - | 'Workshop'; - -export const formatLocation = (location: string): string => { - if (location === 'Internet/Online') { - return 'Online'; - } else { - return location; - } -}; - -/** - * Formats a section time. - * - * @example - * formatSecctionTime(someSection) - * // "3:00pm - 4:30pm" - * - * @example - * formatSecctionTime(someSectionWithNoTime, false) - * // "" - */ -export const formatSectionTime = (section: SectionFragment, showNoTime = true): string => - section.startTime && section.endTime - ? `${formatTime(section.startTime)} \u{2013} ${formatTime(section.endTime)}` - : showNoTime - ? `no time` - : ''; - -export const formatSectionEnrollment = (section: SectionFragment): ReactNode => - section.enrolled !== null && - section.enrolledMax !== null && - section.enrolled !== undefined && - section.enrolledMax !== undefined - ? applyIndicatorPercent( - `${section.enrolled}/${section.enrolledMax} enrolled`, - section.enrolled / section.enrolledMax - ) - : 'Enrollment N/A'; - -/** - * Checks if the section is the 'enrollment' section. - * For CS classes this means its a 999 section. - * - * @example - * isEnrollmentSection({ sectionNumber: '999', ... }) - * // true - */ -export const isEnrollmentSection = (section: SectionFragment): boolean => - /^999[A-Z]?$/.test(section.sectionNumber); diff --git a/frontend/src/utils/sections/sort.ts b/frontend/src/utils/sections/sort.ts deleted file mode 100644 index 388c1fa6c..000000000 --- a/frontend/src/utils/sections/sort.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { SectionFragment } from 'graphql'; -import { stringToDate } from 'utils/date'; -import { isEnrollmentSection } from './section'; - -// Specify an ordering for section types. -const SECTION_TYPE_ORDER: { [key: string]: number } = { - Lecture: 0.1, - Discussion: 0.2, - Laboratory: 0.3 -}; - -/** - * Section time sort comparatorr - */ -function sectionSortComparator(s1: SectionFragment, s2: SectionFragment): number { - const typeA = s1.kind ? SECTION_TYPE_ORDER[s1.kind] || s1.kind[0].charCodeAt(0) : Infinity; - - const typeB = s2.kind ? SECTION_TYPE_ORDER[s2.kind] || s2.kind[0].charCodeAt(0) : Infinity; - - if (typeA !== typeB) { - return typeA - typeB; - } - - const e1 = +isEnrollmentSection(s1); - const e2 = +isEnrollmentSection(s2); - - if (e1 !== e2) { - return (e1 * 2 - 1) * -Infinity; - } - - const t1 = +s1.days[0] || Infinity; - const t2 = +s2.days[0] || Infinity; - - if (t1 !== t2) { - return t1 - t2; - } - - const d1 = +stringToDate(s1.startTime as string); - const d2 = +stringToDate(s2.startTime as string); - - if (d1 !== d2) { - return d1 - d2; - } - - const n1 = s1.sectionNumber; - const n2 = s2.sectionNumber; - - return n1.localeCompare(n2); -} - -/** - * Sorts sections - */ -export function sortSections(sections: SectionFragment[]): SectionFragment[] { - return sections.sort(sectionSortComparator); -} - -/** - * Sorts a list of sections into ([type, [sections]]) - */ -export function groupSections(sections: SectionFragment[]) { - const groups = sections.reduce( - (r, v) => ({ ...r, [v.kind]: [...(r[v.kind] ?? []), v] }), - {} as { [key: string]: SectionFragment[] } - ); - return Object.entries(groups) - .sort((a, b) => (SECTION_TYPE_ORDER[a[0]] ?? Infinity) - SECTION_TYPE_ORDER[b[0]]) - .map(([category, sections]) => ({ - category, - sections: sections.sort(sectionSortComparator) - })); -} diff --git a/frontend/src/utils/string.tsx b/frontend/src/utils/string.tsx deleted file mode 100644 index c9a490706..000000000 --- a/frontend/src/utils/string.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Fragment, ReactNode } from 'react'; - -/** - * Combines non-null components into a string seperated by seperator. - * - * @example - * combineStrings([1, null, 0, 'hello'], ', '); - * // "1, hello" - */ -export const combineStrings = (components: any[], seperator: string): string => - components.filter(Boolean).join(seperator); - -/** - * Analgous version of combineStrings for React nodes - */ -export const combineNodes = (components: ReactNode[], seperator: ReactNode): ReactNode[] => - components - .filter(Boolean) - .flatMap((item, index) => (index ? [seperator, item] : [item])) - .map((item, index) => {item}); - -/** - * Converts a string to a number - */ -export function hash(str: string): number { - let i, - l, - hval = 0x811c9dc5; - - for (i = 0, l = str.length; i < l; i++) { - hval ^= (str.charCodeAt(i) * 16127) % 255; - hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); - } - return hval >>> 0; - // // Alternative hash function to consider: - // let h1 = 0xdeadbeef, - // h2 = 0x41c6ce57; - // for (let i = 0, ch; i < string.length; i++) { - // ch = string.charCodeAt(i); - // h1 = Math.imul(h1 ^ ch, 2654435761); - // h2 = Math.imul(h2 ^ ch, 1597334677); - // } - // h1 = - // Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ - // Math.imul(h2 ^ (h2 >>> 13), 3266489909); - // h2 = - // Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ - // Math.imul(h1 ^ (h1 >>> 13), 3266489909); - // return 4294967296 * (2097151 & h2) + (h1 >>> 0); -} diff --git a/frontend/src/utils/utils.jsx b/frontend/src/utils/utils.jsx deleted file mode 100644 index 35cfc0f9c..000000000 --- a/frontend/src/utils/utils.jsx +++ /dev/null @@ -1,147 +0,0 @@ -/** - * A bunch of utility functions - */ - -/** - * Returns a paragraph tag styled with color with respect to percentage - * @param {string} text text in the paragraph tag - * @param {number} percentage percentage from 0.0 to 1.0 - */ -function applyIndicatorPercent(text, percentage) { - let theme = 'bt-indicator-red'; - if (percentage < 0.34) { - theme = 'bt-indicator-green'; - } else if (percentage < 0.67) { - theme = 'bt-indicator-orange'; - } - - return {text}; -} - -/** - * Returns a paragraph tag styled with color with respect to grade - * @param {string} text text in the paragraph tag - * @param {string | null} grade grade, either as a string (ex. "B+") or null - */ -function applyIndicatorGrade(text, grade) { - if (grade === null) { - return N/A; - } - - let theme = 'bt-indicator-red'; - if (grade[0] === 'A') { - theme = 'bt-indicator-green'; - } else if (grade[0] === 'B') { - theme = 'bt-indicator-yellow'; - } else if (grade[0] === 'C') { - theme = 'bt-indicator-orange'; - } - - return {text}; -} - -/** - * Formats units string by removing space and '.0' decimals - * - * ex: "4.0" -> "4 Units" - * "2.0 - 12.0" -> "2-12 Units" - */ -function formatUnits(units) { - return `${units} Unit${units === '1.0' || units === '1' ? '' : 's'}` - .replace(/.0/g, '') - .replace(/ - /, '-') - .replace(/ or /g, '-'); -} - -/** Accepts a percentile between 0 and 1, converts it to a string. */ -function percentileToString(percentile) { - if (percentile === 1) { - return '100th'; - } - if (percentile === 0) { - return '0th'; - } - const str = `${percentile}`.padEnd(4, '0').slice(2); - if (str[0] === '0') { - if (str[1] === '1') { - return `${str[1]}st`; - } else if (str[1] === '2') { - return `${str[1]}nd`; - } else if (str[1] === '3') { - return `${str[1]}rd`; - } else { - return `${str[1]}th`; - } - } else if (str[1] === '1' && str[0] !== '1') { - return `${str}st`; - } else if (str[1] === '2' && str[0] !== '1') { - return `${str}nd`; - } else if (str[1] === '3' && str[0] !== '1') { - return `${str}rd`; - } else { - return `${str}th`; - } -} - -function getGradeColor(grade) { - if (grade === undefined) { - return ''; - } else if (grade.includes('A') || grade === 'P') { - return 'bt-indicator-green'; - } else if (grade.includes('B')) { - return 'bt-indicator-orange'; - } else { - return 'bt-indicator-red'; - } -} - -function getEnrollmentDay(selectedPoint, telebears) { - let period = ''; - let daysAfterPeriodStarts = 0; - if (selectedPoint.day < telebears.phase2_start_day) { - period = 'Phase I'; - daysAfterPeriodStarts = selectedPoint.day - telebears.phase1_start_day; - } else if (selectedPoint.day < telebears.adj_start_day) { - period = 'Phase II'; - daysAfterPeriodStarts = selectedPoint.day - telebears.phase2_start_day; - } else { - period = 'Adjustment Period'; - daysAfterPeriodStarts = selectedPoint.day - telebears.adj_start_day; - } - return { period, daysAfterPeriodStarts }; -} - -function formatPercentage(num) { - if (num === -1) { - return 'N/A'; - } - return (num * 100).toFixed(1).toString() + '%'; -} - -function applyIndicatorEnrollment(enrolled, enrolledMax, percentage) { - let theme; - if (percentage < 0.34) { - theme = 'bt-indicator-green'; - } else if (percentage < 0.67) { - theme = 'bt-indicator-orange'; - } else { - theme = 'bt-indicator-red'; - } - - return ( - - {' '} - {enrolled}/{enrolledMax} ({`${formatPercentage(percentage)}`}) - - ); -} - -export { - applyIndicatorPercent, - applyIndicatorGrade, - formatUnits, - percentileToString, - getGradeColor, - getEnrollmentDay, - applyIndicatorEnrollment -}; diff --git a/frontend/src/variables/Variables.js b/frontend/src/variables/Variables.js deleted file mode 100644 index 39c7e0f8f..000000000 --- a/frontend/src/variables/Variables.js +++ /dev/null @@ -1,640 +0,0 @@ -// -// // -// // // For notifications -// // -// -var defaultWidth = window.screen.width > 768 ? (window.screen.width * 1) / 3 : window.screen.width; - -var style = { - Wrapper: {}, - Containers: { - DefaultStyle: { - position: 'fixed', - width: defaultWidth, - padding: '10px 10px 10px 20px', - zIndex: 9998, - WebkitBoxSizing: '', - MozBoxSizing: '', - boxSizing: '', - height: 'auto', - display: 'inline-block', - border: '0', - fontSize: '14px', - WebkitFontSmoothing: 'antialiased', - fontFamily: '"Roboto","Helvetica Neue",Arial,sans-serif', - fontWeight: '400', - color: '#FFFFFF' - }, - - tl: { - top: '0px', - bottom: 'auto', - left: '0px', - right: 'auto' - }, - - tr: { - top: '0px', - bottom: 'auto', - left: 'auto', - right: '0px' - }, - - tc: { - top: '0px', - bottom: 'auto', - margin: '0 auto', - left: '50%', - marginLeft: -(defaultWidth / 2) - }, - - bl: { - top: 'auto', - bottom: '0px', - left: '0px', - right: 'auto' - }, - - br: { - top: 'auto', - bottom: '0px', - left: 'auto', - right: '0px' - }, - - bc: { - top: 'auto', - bottom: '0px', - margin: '0 auto', - left: '50%', - marginLeft: -(defaultWidth / 2) - } - }, - - NotificationItem: { - DefaultStyle: { - position: 'relative', - width: '100%', - cursor: 'pointer', - borderRadius: '4px', - fontSize: '14px', - margin: '10px 0 0', - padding: '10px', - display: 'block', - WebkitBoxSizing: 'border-box', - MozBoxSizing: 'border-box', - boxSizing: 'border-box', - opacity: 0, - transition: 'all 0.5s ease-in-out', - WebkitTransform: 'translate3d(0, 0, 0)', - transform: 'translate3d(0, 0, 0)', - willChange: 'transform, opacity', - - isHidden: { - opacity: 0 - }, - - isVisible: { - opacity: 1 - } - }, - - success: { - borderTop: 0, - backgroundColor: '#a1e82c', - WebkitBoxShadow: 0, - MozBoxShadow: 0, - boxShadow: 0 - }, - - error: { - borderTop: 0, - backgroundColor: '#fc727a', - WebkitBoxShadow: 0, - MozBoxShadow: 0, - boxShadow: 0 - }, - - warning: { - borderTop: 0, - backgroundColor: '#ffbc67', - WebkitBoxShadow: 0, - MozBoxShadow: 0, - boxShadow: 0 - }, - - info: { - borderTop: 0, - backgroundColor: '#63d8f1', - WebkitBoxShadow: 0, - MozBoxShadow: 0, - boxShadow: 0 - } - }, - - Title: { - DefaultStyle: { - fontSize: '30px', - margin: '0', - padding: 0, - fontWeight: 'bold', - color: '#FFFFFF', - display: 'block', - left: '15px', - position: 'absolute', - top: '50%', - marginTop: '-15px' - } - }, - - MessageWrapper: { - DefaultStyle: { - marginLeft: '55px', - marginRight: '30px', - padding: '0 12px 0 0', - color: '#FFFFFF', - maxWidthwidth: '89%' - } - }, - - Dismiss: { - DefaultStyle: { - fontFamily: 'inherit', - fontSize: '21px', - color: '#000', - float: 'right', - position: 'absolute', - right: '10px', - top: '50%', - marginTop: '-13px', - backgroundColor: '#FFFFFF', - display: 'block', - borderRadius: '50%', - opacity: '.4', - lineHeight: '11px', - width: '25px', - height: '25px', - outline: '0 !important', - textAlign: 'center', - padding: '6px 3px 3px 3px', - fontWeight: '300', - marginLeft: '65px' - }, - - success: { - // color: '#f0f5ea', - // backgroundColor: '#a1e82c' - }, - - error: { - // color: '#f4e9e9', - // backgroundColor: '#fc727a' - }, - - warning: { - // color: '#f9f6f0', - // backgroundColor: '#ffbc67' - }, - - info: { - // color: '#e8f0f4', - // backgroundColor: '#63d8f1' - } - }, - - Action: { - DefaultStyle: { - background: '#ffffff', - borderRadius: '2px', - padding: '6px 20px', - fontWeight: 'bold', - margin: '10px 0 0 0', - border: 0 - }, - - success: { - backgroundColor: '#a1e82c', - color: '#ffffff' - }, - - error: { - backgroundColor: '#fc727a', - color: '#ffffff' - }, - - warning: { - backgroundColor: '#ffbc67', - color: '#ffffff' - }, - - info: { - backgroundColor: '#63d8f1', - color: '#ffffff' - } - }, - - ActionWrapper: { - DefaultStyle: { - margin: 0, - padding: 0 - } - } -}; - -// -// // -// // // For tables -// // -// -const thArray = ['ID', 'Name', 'Salary', 'Country', 'City']; -const tdArray = [ - ['1', 'Dakota Rice', '$36,738', 'Niger', 'Oud-Turnhout'], - ['2', 'Minerva Hooper', '$23,789', 'Curaçao', 'Sinaai-Waas'], - ['3', 'Sage Rodriguez', '$56,142', 'Netherlands', 'Baileux'], - ['4', 'Philip Chaney', '$38,735', 'Korea, South', 'Overland Park'], - ['5', 'Doris Greene', '$63,542', 'Malawi', 'Feldkirchen in Kärnten'], - ['6', 'Mason Porter', '$78,615', 'Chile', 'Gloucester'] -]; - -// -// // -// // // For icons -// // -// -const iconsArray = [ - 'pe-7s-album', - 'pe-7s-arc', - 'pe-7s-back-2', - 'pe-7s-bandaid', - 'pe-7s-car', - 'pe-7s-diamond', - 'pe-7s-door-lock', - 'pe-7s-eyedropper', - 'pe-7s-female', - 'pe-7s-gym', - 'pe-7s-hammer', - 'pe-7s-headphones', - 'pe-7s-helm', - 'pe-7s-hourglass', - 'pe-7s-leaf', - 'pe-7s-magic-wand', - 'pe-7s-male', - 'pe-7s-map-2', - 'pe-7s-next-2', - 'pe-7s-paint-bucket', - 'pe-7s-pendrive', - 'pe-7s-photo', - 'pe-7s-piggy', - 'pe-7s-plugin', - 'pe-7s-refresh-2', - 'pe-7s-rocket', - 'pe-7s-settings', - 'pe-7s-shield', - 'pe-7s-smile', - 'pe-7s-usb', - 'pe-7s-vector', - 'pe-7s-wine', - 'pe-7s-cloud-upload', - 'pe-7s-cash', - 'pe-7s-close', - 'pe-7s-bluetooth', - 'pe-7s-cloud-download', - 'pe-7s-way', - 'pe-7s-close-circle', - 'pe-7s-id', - 'pe-7s-angle-up', - 'pe-7s-wristwatch', - 'pe-7s-angle-up-circle', - 'pe-7s-world', - 'pe-7s-angle-right', - 'pe-7s-volume', - 'pe-7s-angle-right-circle', - 'pe-7s-users', - 'pe-7s-angle-left', - 'pe-7s-user-female', - 'pe-7s-angle-left-circle', - 'pe-7s-up-arrow', - 'pe-7s-angle-down', - 'pe-7s-switch', - 'pe-7s-angle-down-circle', - 'pe-7s-scissors', - 'pe-7s-wallet', - 'pe-7s-safe', - 'pe-7s-volume2', - 'pe-7s-volume1', - 'pe-7s-voicemail', - 'pe-7s-video', - 'pe-7s-user', - 'pe-7s-upload', - 'pe-7s-unlock', - 'pe-7s-umbrella', - 'pe-7s-trash', - 'pe-7s-tools', - 'pe-7s-timer', - 'pe-7s-ticket', - 'pe-7s-target', - 'pe-7s-sun', - 'pe-7s-study', - 'pe-7s-stopwatch', - 'pe-7s-star', - 'pe-7s-speaker', - 'pe-7s-signal', - 'pe-7s-shuffle', - 'pe-7s-shopbag', - 'pe-7s-share', - 'pe-7s-server', - 'pe-7s-search', - 'pe-7s-film', - 'pe-7s-science', - 'pe-7s-disk', - 'pe-7s-ribbon', - 'pe-7s-repeat', - 'pe-7s-refresh', - 'pe-7s-add-user', - 'pe-7s-refresh-cloud', - 'pe-7s-paperclip', - 'pe-7s-radio', - 'pe-7s-note2', - 'pe-7s-print', - 'pe-7s-network', - 'pe-7s-prev', - 'pe-7s-mute', - 'pe-7s-power', - 'pe-7s-medal', - 'pe-7s-portfolio', - 'pe-7s-like2', - 'pe-7s-plus', - 'pe-7s-left-arrow', - 'pe-7s-play', - 'pe-7s-key', - 'pe-7s-plane', - 'pe-7s-joy', - 'pe-7s-photo-gallery', - 'pe-7s-pin', - 'pe-7s-phone', - 'pe-7s-plug', - 'pe-7s-pen', - 'pe-7s-right-arrow', - 'pe-7s-paper-plane', - 'pe-7s-delete-user', - 'pe-7s-paint', - 'pe-7s-bottom-arrow', - 'pe-7s-notebook', - 'pe-7s-note', - 'pe-7s-next', - 'pe-7s-news-paper', - 'pe-7s-musiclist', - 'pe-7s-music', - 'pe-7s-mouse', - 'pe-7s-more', - 'pe-7s-moon', - 'pe-7s-monitor', - 'pe-7s-micro', - 'pe-7s-menu', - 'pe-7s-map', - 'pe-7s-map-marker', - 'pe-7s-mail', - 'pe-7s-mail-open', - 'pe-7s-mail-open-file', - 'pe-7s-magnet', - 'pe-7s-loop', - 'pe-7s-look', - 'pe-7s-lock', - 'pe-7s-lintern', - 'pe-7s-link', - 'pe-7s-like', - 'pe-7s-light', - 'pe-7s-less', - 'pe-7s-keypad', - 'pe-7s-junk', - 'pe-7s-info', - 'pe-7s-home', - 'pe-7s-help2', - 'pe-7s-help1', - 'pe-7s-graph3', - 'pe-7s-graph2', - 'pe-7s-graph1', - 'pe-7s-graph', - 'pe-7s-global', - 'pe-7s-gleam', - 'pe-7s-glasses', - 'pe-7s-gift', - 'pe-7s-folder', - 'pe-7s-flag', - 'pe-7s-filter', - 'pe-7s-file', - 'pe-7s-expand1', - 'pe-7s-exapnd2', - 'pe-7s-edit', - 'pe-7s-drop', - 'pe-7s-drawer', - 'pe-7s-download', - 'pe-7s-display2', - 'pe-7s-display1', - 'pe-7s-diskette', - 'pe-7s-date', - 'pe-7s-cup', - 'pe-7s-culture', - 'pe-7s-crop', - 'pe-7s-credit', - 'pe-7s-copy-file', - 'pe-7s-config', - 'pe-7s-compass', - 'pe-7s-comment', - 'pe-7s-coffee', - 'pe-7s-cloud', - 'pe-7s-clock', - 'pe-7s-check', - 'pe-7s-chat', - 'pe-7s-cart', - 'pe-7s-camera', - 'pe-7s-call', - 'pe-7s-calculator', - 'pe-7s-browser', - 'pe-7s-box2', - 'pe-7s-box1', - 'pe-7s-bookmarks', - 'pe-7s-bicycle', - 'pe-7s-bell', - 'pe-7s-battery', - 'pe-7s-ball', - 'pe-7s-back', - 'pe-7s-attention', - 'pe-7s-anchor', - 'pe-7s-albums', - 'pe-7s-alarm', - 'pe-7s-airplay' -]; - -// -// // -// // // // For dashboard's charts -// // -// -// Data for Pie Chart -var dataPie = { - labels: ['40%', '20%', '40%'], - series: [40, 20, 40] -}; -var legendPie = { - names: ['Open', 'Bounce', 'Unsubscribe'], - types: ['info', 'danger', 'warning'] -}; - -// Data for Line Chart -var dataSales = { - labels: ['9:00AM', '12:00AM', '3:00PM', '6:00PM', '9:00PM', '12:00PM', '3:00AM', '6:00AM'], - series: [ - [287, 385, 490, 492, 554, 586, 698, 695], - [67, 152, 143, 240, 287, 335, 435, 437], - [23, 113, 67, 108, 190, 239, 307, 308] - ] -}; -var optionsSales = { - low: 0, - high: 800, - showArea: false, - height: '245px', - axisX: { - showGrid: false - }, - lineSmooth: true, - showLine: true, - showPoint: true, - fullWidth: true, - chartPadding: { - right: 50 - } -}; -var responsiveSales = [ - [ - 'screen and (max-width: 640px)', - { - axisX: { - labelInterpolationFnc: function (value) { - return value[0]; - } - } - } - ] -]; -var legendSales = { - names: ['Open', 'Click', 'Click Second Time'], - types: ['info', 'danger', 'warning'] -}; -// Data for Bar Chart -var dataBar = { - labels: ['Jan', 'Feb', 'Mar', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - series: [ - [542, 443, 320, 780, 553, 453, 326, 434, 568, 610, 756, 895], - [412, 243, 280, 580, 453, 353, 300, 364, 368, 410, 636, 695] - ] -}; -var optionsBar = { - seriesBarDistance: 10, - axisX: { - showGrid: false - }, - height: '245px' -}; -var responsiveBar = [ - [ - 'screen and (max-width: 640px)', - { - seriesBarDistance: 5, - axisX: { - labelInterpolationFnc: function (value) { - return value[0]; - } - } - } - ] -]; -var legendBar = { - names: ['Tesla Model S', 'BMW 5 Series'], - types: ['info', 'danger'] -}; - -//Berkeleytime -var enrollment = [ - { name: 'Phase 1', percent: 50 }, - { name: 'Phase 1.5', percent: 56 }, - { name: 'Phase 2', percent: 70 }, - { name: 'Phase 2.5', percent: 90 }, - { name: 'Adjustment', percent: 95 }, - { name: 'Current', percent: 100 } -]; - -var optionsEnrollment = { - low: 0, - high: 100, - showArea: false, - height: '245px', - axisX: { - showGrid: false - }, - lineSmooth: true, - showLine: true, - showPoint: true, - fullWidth: true, - chartPadding: { - right: 50 - } -}; -var responsiveEnrollment = [ - [ - 'screen and (max-width: 640px)', - { - axisX: { - labelInterpolationFnc: function (value) { - return value[0]; - } - } - } - ] -]; - -var grades = [ - { name: 'A+', classA: 20, classB: 2 }, - { name: 'A', classA: 56, classB: 2 }, - { name: 'A-', classA: 1, classB: 2 }, - { name: 'B+', classA: 3, classB: 2 }, - { name: 'B', classA: 20, classB: 2 }, - { name: 'B-', classA: 10, classB: 2 }, - { name: 'C+', classA: 0, classB: 2 }, - { name: 'C', classA: 0, classB: 2 }, - { name: 'C-', classA: 0, classB: 2 }, - { name: 'D+', classA: 0, classB: 2 }, - { name: 'D', classA: 0, classB: 2 }, - { name: 'D-', classA: 0, classB: 2 }, - { name: 'F', classA: 0, classB: 2 } -]; - -var possibleGrades = ['A+', 'A', 'A-', 'B+', 'B', 'B-', 'C+', 'C', 'C-', 'D', 'F', 'P', 'NP']; - -var colors = ['#4EA6FB', '#6AE086', '#ED5186', '#F9E152']; - -const vars = { - style, // For notifications (App container and Notifications view) - thArray, - tdArray, // For tables (TableList view) - iconsArray, // For icons (Icons view) - dataPie, - legendPie, - dataSales, - optionsSales, - responsiveSales, // For charts (Dashboard view) - legendSales, - dataBar, - optionsBar, - responsiveBar, - legendBar, // For charts (Dashboard view) - colors, - enrollment, - optionsEnrollment, - responsiveEnrollment, - grades, - possibleGrades -}; - -export default vars; diff --git a/frontend/src/views/About.tsx b/frontend/src/views/About.tsx deleted file mode 100644 index 36a98b020..000000000 --- a/frontend/src/views/About.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { FC } from 'react'; -import { Row, Col } from 'react-bootstrap'; -import { Leaf, LightBulbOn, EmojiTalkingHappy } from 'iconoir-react'; - -import { H3, P } from 'bt/custom'; - -import CurrentContributors from '../components/About/CurrentContributors'; -import PastContributors from '../components/About/PastContributors'; -import AboutCarousel from '../components/About/AboutCarousel'; - -const About: FC = () => ( -
-
-

- About Our Team -

-

- We're a small group of student volunteers at UC Berkeley, dedicated to simplifying the - course discovery experience. We actively build, improve and maintain Berkeleytime. -

- {/* */} -
- -
-
Our Values
- - -
-
- -
Growth
-

- You’ll grow your technical skills as you tackle real challenging design and - engineering problems. -

-
-
- - - -
-
- -
Curiosity
-

- We value team members that are curious about solving difficult problems and seek out - solutions independently. -

-
-
- - - -
-
- -
Passion
-

- Genuine commitment and dedication are critical to moving the Berkeleytime product - forward. -

-
-
- -
-
- - -
-); - -export default About; diff --git a/frontend/src/views/Enrollment/Enrollment.jsx b/frontend/src/views/Enrollment/Enrollment.jsx deleted file mode 100644 index ca4e5b146..000000000 --- a/frontend/src/views/Enrollment/Enrollment.jsx +++ /dev/null @@ -1,192 +0,0 @@ -import { Component } from 'react'; -import { withRouter } from 'react-router'; - -import { connect } from 'react-redux'; -import ClassCardList from '../../components/ClassCards/ClassCardList'; -import EnrollmentGraphCard from '../../components/GraphCard/EnrollmentGraphCard'; -import EnrollmentSearchBar from '../../components/ClassSearchBar/EnrollmentSearchBar'; - -import info from '../../assets/img/images/graphs/info.svg'; - -import { - fetchEnrollContext, - fetchEnrollClass, - enrollRemoveCourse, - enrollReset, - updateEnrollData, - fetchEnrollFromUrl -} from '../../redux/actions'; - -class Enrollment extends Component { - constructor(props) { - super(props); - - this.state = { - additionalInfo: [] - }; - - this.addCourse = this.addCourse.bind(this); - this.removeCourse = this.removeCourse.bind(this); - this.fillFromUrl = this.fillFromUrl.bind(this); - this.addToUrl = this.addToUrl.bind(this); - this.refillUrl = this.refillUrl.bind(this); - this.toUrlForm = this.toUrlForm.bind(this); - this.updateClassCardEnrollment = this.updateClassCardEnrollment.bind(this); - } - - componentDidMount() { - const { fetchEnrollContext } = this.props; - fetchEnrollContext(); - this.fillFromUrl(); - } - - fillFromUrl() { - const { enrollReset, fetchEnrollFromUrl, history } = this.props; - try { - let url = history.location.pathname; - if (url && (url === '/enrollment/' || url === '/enrollment')) { - enrollReset(); - } else if (url) { - fetchEnrollFromUrl(url, history); - } - } catch (err) { - history.push('/error'); - } - } - - toUrlForm(s) { - return s.toLowerCase().split(' ').join('-'); - } - - addToUrl(course) { - const { history } = this.props; - let instructor = course.instructor === 'all' ? 'all' : course.sections[0]; - let courseUrl = `${course.colorId}-${course.courseID}-${this.toUrlForm( - course.semester - )}-${instructor}`; - let url = history.location.pathname; - if (url && !url.includes(courseUrl)) { - url += url === '/enrollment' ? '/' : ''; - url += url === '/enrollment/' ? '' : '&'; - url += courseUrl; - history.replace(url); - } - } - - addCourse(course) { - const { fetchEnrollClass, selectedCourses, usedColorIds } = this.props; - for (let selected of selectedCourses) { - if (selected.id === course.id) { - return; - } - } - - let newColorId = ''; - for (let i = 0; i < 4; i++) { - if (!usedColorIds.includes(i.toString())) { - newColorId = i.toString(); - break; - } - } - course.colorId = newColorId; - - this.addToUrl(course); - fetchEnrollClass(course); - } - - refillUrl(id) { - const { selectedCourses, history } = this.props; - let updatedCourses = selectedCourses.filter((classInfo) => classInfo.id !== id); - let url = '/enrollment/'; - for (let i = 0; i < updatedCourses.length; i++) { - let c = updatedCourses[i]; - if (i !== 0) url += '&'; - let instructor = c.instructor === 'all' ? 'all' : c.sections[0]; - url += `${c.colorId}-${c.courseID}-${this.toUrlForm(c.semester)}-${instructor}`; - } - history.replace(url); - } - - removeCourse(id, color) { - const { enrollRemoveCourse } = this.props; - this.refillUrl(id); - enrollRemoveCourse(id, color); - } - - updateClassCardEnrollment(latest_point, telebears, enrolled_info, waitlisted_info) { - var info = []; - for (var i = 0; i < latest_point.length; i++) { - info.push([latest_point[i], telebears[i], enrolled_info[i], waitlisted_info[i]]); - } - this.setState({ additionalInfo: info }); - } - - render() { - const { additionalInfo } = this.state; - const { context, selectedCourses, isMobile } = this.props; - let { location } = this.props; - let courses = context.courses; - - return ( -
-
- - - - - - {!isMobile &&
Days After Phase 1
} -
- -

- We source our historic course and enrollment data directly from Berkeley{' '} - Student Information System's Course and - Class APIs. -

-
-
-
- ); - } -} - -const mapDispatchToProps = (dispatch) => ({ - dispatch, - fetchEnrollContext: () => dispatch(fetchEnrollContext()), - fetchEnrollClass: (course) => dispatch(fetchEnrollClass(course)), - enrollRemoveCourse: (id, color) => dispatch(enrollRemoveCourse(id, color)), - enrollReset: () => dispatch(enrollReset()), - updateEnrollData: (enrollmentData) => dispatch(updateEnrollData(enrollmentData)), - fetchEnrollFromUrl: (url, history) => dispatch(fetchEnrollFromUrl(url, history)) -}); - -const mapStateToProps = (state) => { - const { context, selectedCourses, usedColorIds } = state.enrollment; - const { mobile } = state.common; - - return { - context, - selectedCourses, - usedColorIds, - isMobile: mobile - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Enrollment)); diff --git a/frontend/src/views/Error/Error.jsx b/frontend/src/views/Error/Error.jsx deleted file mode 100644 index 5651440a5..000000000 --- a/frontend/src/views/Error/Error.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import { Container, Row, Col, ButtonToolbar, ButtonGroup } from 'react-bootstrap'; -import empty_graph from '../../assets/img/images/empty-graph.png'; -import { Button } from 'bt/custom'; - -function Error() { - return ( -
- - - - empty_graph - - -

404

-

Uh oh. Looks like the page you're looking for doesn't exist.

-

Here are a couple of things you can do.

- - - - - - -
-
-
- ); -} - -export default Error; diff --git a/frontend/src/views/Faq.tsx b/frontend/src/views/Faq.tsx deleted file mode 100644 index d70827298..000000000 --- a/frontend/src/views/Faq.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import { FC } from 'react'; -import { Link } from 'react-router-dom'; -import { Container, Row, Col } from 'react-bootstrap'; - -import { H3, P, Button } from 'bt/custom'; - -import QuestionCard from 'components/Faq/QuestionCard'; - -const Faq: FC = () => ( -
- - - -

- Frequently Asked Questions -

-

Answering your most commonly asked questions.

- - -
- - - {questions.map((item, index) => ( - - ))} - - -
-
-); - -const questions = [ - { - question: 'Where does Berkeleytime get its data? Is it accurate?', - answer: ( -

- We source all our historic course and enrollment data directly from Berkeley's{' '} - Student Information System - 's Course and Class APIs. We source grade data from{' '} - CalAnswers. Let us know if anything seems - off! -

- ) - }, - { - question: 'Why does an enrollment chart show more than 100% students enrolled?', - answer: ( -

- This is not a bug; the percent enrolled graph compares the number of students enrolled at a - given time to the current enrollment cap of the class. Throughout the semester, professors - or department admins may choose to decrease the class size below the number of students - enrolled to limit further enrollment. Hence, some classes may show over 100% enrollment at - certain points in the enrollment timeline.{' '} -

- ) - }, - { - question: 'How can I contact the Berkeleytime team?', - answer: ( -

- Any questions or concerns that you have can be directed to{' '} - octo.berkeleytime@asuc.org. -

- ) - }, - { - question: 'When are grades/classes/enrollment data released?', - answer: ( -

- All of our data is made available to our users as soon as it is published by the school. For - class information, this typically occurs 2 weeks before the start of Phase I. Grades data is - typically published 2-3 months after the end of the semester. Enrollment data is refreshed - continuously as students enroll and drop classes throughout the semester. -

- ) - }, - { - question: 'Is anyone actively working on Berkeleytime?', - answer: ( -

- Yes, we're a student-run organization on campus under the{' '} - ASUC Office of the CTO. Our team meets weekly to - maintain and improve the site. You can learn more about us here! -

- ) - }, - /*{ - question: 'How do I apply to join the team?', - answer: ( -

- We typically recruit engineers and designers at the start of every fall semester. You can sign up for{' '} - recruitment updates. Also, keep an eye out on our{' '} - Facebook page for recruitment events. -

- ), - },*/ - { - question: 'I want to help user test new features!', - answer: ( -

- We love to hear it! You can sign up to receive{' '} - user testing opportunity updates. -

- ) - }, - /*{ - question: 'Berkeleytime is down/I found a bug!', - answer: ( -

- Remain calm! If you find an issue with the site or data, please let us know by submitting a{' '} - - bug report - - , and one of our on-call engineers will try to get to it as soon as possible. -

- ), - },*/ - { - question: 'Can I access your API for a project I’m working on?', - answer: ( -

- Unfortunately we discontinued our backend API as of April 30th, 2021. Please{' '} - email us and we can direct you to the data - sources we use for our API. -

- ) - }, - /*{ - question: 'How do I give feedback about the product?', - answer: ( -

- Feel free to fill out our{' '} - - feedback form - - . You can also email us at octo.berkeleytime@asuc.org, and - we'll respond as soon as we can. -

- ), - },*/ - { - question: 'Can Berkeleytime add a feature to review/rate professors and courses?', - answer: ( -

- We appreciate the feature request! The BT team has discussed this at length, and, - unfortunately, we are not able to offer any such review or rating system at the current - time. This is because we work closely with the Berkeley Academic Senate. Also as a part of - the ASUC, we cannot officially incorporate or endorse opinions we either don’t moderate or - are not our own. -

- ) - } -]; - -export default Faq; diff --git a/frontend/src/views/Grades/Grades.jsx b/frontend/src/views/Grades/Grades.jsx deleted file mode 100644 index 8421cdff2..000000000 --- a/frontend/src/views/Grades/Grades.jsx +++ /dev/null @@ -1,196 +0,0 @@ -import { Component } from 'react'; -import { withRouter } from 'react-router'; - -import { connect } from 'react-redux'; -import ClassCardList from '../../components/ClassCards/ClassCardList'; -import GradesGraphCard from '../../components/GraphCard/GradesGraphCard'; -import GradesSearchBar from '../../components/ClassSearchBar/GradesSearchBar'; - -import info from '../../assets/img/images/graphs/info.svg'; - -import { - fetchGradeContext, - fetchGradeClass, - gradeRemoveCourse, - gradeReset, - fetchGradeFromUrl -} from '../../redux/actions'; - -class Grades extends Component { - constructor(props) { - super(props); - this.state = { - // context: {}, - selectedCourses: this.props.selectedCourses, - additionalInfo: [] - }; - this.addCourse = this.addCourse.bind(this); - this.removeCourse = this.removeCourse.bind(this); - this.fillFromUrl = this.fillFromUrl.bind(this); - this.addToUrl = this.addToUrl.bind(this); - this.refillUrl = this.refillUrl.bind(this); - this.toUrlForm = this.toUrlForm.bind(this); - this.updateClassCardGrade = this.updateClassCardGrade.bind(this); - } - - componentDidMount() { - const { fetchGradeContext } = this.props; - fetchGradeContext(); - this.fillFromUrl(); - } - - UNSAFE_componentWillMount() { - this.props.gradeReset(); - } - - fillFromUrl() { - const { gradeReset, fetchGradeFromUrl, history } = this.props; - - try { - let url = history.location.pathname; - if (url && (url === '/grades/' || url === '/grades')) { - gradeReset(); - } else if (url) { - fetchGradeFromUrl(url, history); - } - } catch (err) { - history.push('/error'); - } - } - - toUrlForm(s) { - s = s.replace('/', '_'); - return s.toLowerCase().split(' ').join('-'); - } - - addToUrl(course) { - const { history } = this.props; - let instructor = this.toUrlForm(course.instructor); - let courseUrl = `${course.colorId}-${course.courseID}-${this.toUrlForm( - course.semester - )}-${instructor}`; - let url = history.location.pathname; - if (url && !url.includes(courseUrl)) { - url += url === '/grades' ? '/' : ''; - url += url === '/grades/' ? '' : '&'; - url += courseUrl; - history.replace(url); - } - } - - addCourse(course) { - const { fetchGradeClass, selectedCourses, usedColorIds } = this.props; - for (let selected of selectedCourses) { - if (selected.id === course.id) { - return; - } - } - - let newColorId = ''; - for (let i = 0; i < 4; i++) { - if (!usedColorIds.includes(i.toString())) { - newColorId = i.toString(); - break; - } - } - course.colorId = newColorId; - - this.addToUrl(course); - fetchGradeClass(course); - } - - refillUrl(id) { - const { selectedCourses, history } = this.props; - let updatedCourses = selectedCourses.filter((classInfo) => classInfo.id !== id); - let url = '/grades/'; - for (let i = 0; i < updatedCourses.length; i++) { - let c = updatedCourses[i]; - if (i !== 0) url += '&'; - url += `${c.colorId}-${c.courseID}-${this.toUrlForm(c.semester)}-${this.toUrlForm( - c.instructor - )}`; - } - history.replace(url); - } - - removeCourse(id, color) { - const { gradeRemoveCourse } = this.props; - this.refillUrl(id); - gradeRemoveCourse(id, color); - } - - updateClassCardGrade(course_letter, course_gpa, section_letter, section_gpa) { - var info = []; - for (var i = 0; i < course_letter.length; i++) { - info.push([course_letter[i], course_gpa[i], section_letter[i], section_gpa[i]]); - } - this.setState({ additionalInfo: info }); - } - - render() { - const { context, selectedCourses, isMobile } = this.props; - let { location } = this.props; - const { additionalInfo } = this.state; - let courses = context.courses; - - return ( -
-
- - - - - - -
- -

- We source our course grade data from Berkeley's official{' '} - CalAnswers database. -

-
-
-
- ); - } -} - -const mapDispatchToProps = (dispatch) => ({ - dispatch, - fetchGradeContext: () => dispatch(fetchGradeContext()), - fetchGradeClass: (course) => dispatch(fetchGradeClass(course)), - gradeRemoveCourse: (id, color) => dispatch(gradeRemoveCourse(id, color)), - gradeReset: () => dispatch(gradeReset()), - fetchGradeFromUrl: (url, history) => dispatch(fetchGradeFromUrl(url, history)) -}); - -const mapStateToProps = (state) => { - const { context, selectedCourses, usedColorIds, sections } = state.grade; - const { mobile } = state.common; - return { - context, - selectedCourses, - usedColorIds, - sections, - isMobile: mobile - }; -}; - -export default connect(mapStateToProps, mapDispatchToProps)(withRouter(Grades)); diff --git a/frontend/src/views/Landing.tsx b/frontend/src/views/Landing.tsx deleted file mode 100644 index 5bcff1411..000000000 --- a/frontend/src/views/Landing.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { FC, Suspense, lazy } from 'react'; - -import Explore from 'components/Landing/Explore'; -import Mission from 'components/Landing/Mission'; -import Blurbs from 'components/Landing/Blurbs'; -import LandingModal from 'components/Landing/LandingModal'; - -const Jumbotron = lazy(() => import('components/Landing/Jumbotron')); - -const Landing: FC = () => { - return ( - <> - -
- - - -
- - - - - ); -}; - -export default Landing; diff --git a/frontend/src/views/Login/Login.tsx b/frontend/src/views/Login/Login.tsx deleted file mode 100644 index 9afd15536..000000000 --- a/frontend/src/views/Login/Login.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { useHistory } from 'react-router'; -import { useLocation } from 'react-router-dom'; -import { useLogin } from '../../graphql/hooks/user'; -import BTLoader from 'components/Common/BTLoader'; - -function useQuery() { - return new URLSearchParams(useLocation().search); -} - -const Login = () => { - const [login, { loading }] = useLogin(); - const history = useHistory(); - const query = useQuery(); - - const id_token = query.get('id_token'); - if (!id_token) { - history.push('/error'); - return null; - } - - if (loading) { - return ; - } - - login({ - variables: { - token: id_token - } - }).then((result) => { - // If the login was successful. - if (result.data?.login?.user) { - history.push('/profile'); - } - }); - - return null; -}; - -export default Login; diff --git a/frontend/src/views/Policies/PrivacyPolicy.tsx b/frontend/src/views/Policies/PrivacyPolicy.tsx deleted file mode 100644 index ac7be0cea..000000000 --- a/frontend/src/views/Policies/PrivacyPolicy.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { FC } from 'react'; -import Description from '../../components/Common/Description'; -const url = new URL('../../../public/privacy.md', import.meta.url).href - -const PrivacyPolicy: FC = () => ( - -); - -export default PrivacyPolicy; diff --git a/frontend/src/views/Policies/TermsOfService.tsx b/frontend/src/views/Policies/TermsOfService.tsx deleted file mode 100644 index 66518921f..000000000 --- a/frontend/src/views/Policies/TermsOfService.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { FC } from 'react'; -import Description from '../../components/Common/Description'; -const url = new URL('../../../public/terms.md', import.meta.url).href - -const TermsOfService: FC = () => ( - -); - -export default TermsOfService; diff --git a/frontend/src/views/Profile/Logout.tsx b/frontend/src/views/Profile/Logout.tsx deleted file mode 100644 index 34690a76c..000000000 --- a/frontend/src/views/Profile/Logout.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import BTLoader from 'components/Common/BTLoader'; -import { useLogout, useUser } from '../../graphql/hooks/user'; -import { useEffect } from 'react'; -import { useHistory } from 'react-router'; - -const Logout = () => { - const history = useHistory(); - const [logout, { error }] = useLogout(); - const { isLoggedIn } = useUser(); - - // Log the user out when they visit this page - useEffect(() => { - logout(); - }, [logout]); - - // If the logout was successful go to the previous page. - useEffect(() => { - if (!isLoggedIn) { - history.goBack(); - } - }, [isLoggedIn, history]); - - return ( -
-
- {error ? ( - There was an error logging you out. Try refreshing - ) : ( - <> - - - )} -
-
- ); -}; - -export default Logout; diff --git a/frontend/src/views/Profile/Profile.tsx b/frontend/src/views/Profile/Profile.tsx deleted file mode 100644 index c5ed8d085..000000000 --- a/frontend/src/views/Profile/Profile.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import { ComponentType, ReactNode, useState } from 'react'; -import { Container, Button } from 'react-bootstrap'; - -import AccountSubview from '../../components/Profile/AccountSubview'; -import SupportSubview from '../../components/Profile/SupportSubview'; - -import { ReactComponent as Account } from '../../assets/svg/profile/account.svg'; -import { ReactComponent as AccountSelected } from '../../assets/svg/profile/account_selected.svg'; -import { ReactComponent as Support } from '../../assets/svg/profile/support.svg'; -import { ReactComponent as SupportSelected } from '../../assets/svg/profile/support_selected.svg'; -import { UserProfileFragment } from 'graphql'; -import BTLoader from 'components/Common/BTLoader'; -import { useUser } from '../../graphql/hooks/user'; -import { Redirect } from 'react-router'; - -const tabs: { - key: string; - label: string; - selectedImage: ReactNode; - deselectedImage: ReactNode; - component: ComponentType<{ userProfile: UserProfileFragment }> | ComponentType; -}[] = [ - { - key: 'account', - label: 'Your Account', - selectedImage: , - deselectedImage: , - component: AccountSubview - }, - { - key: 'support', - label: 'Support', - selectedImage: , - deselectedImage: , - component: SupportSubview - } -]; - -const Profile = () => { - const [tabIndex, setTabIndex] = useState(0); - const { isLoggedIn, user, loading } = useUser(); - - const TabComponent = tabs[tabIndex].component; - - // If we're not logged in, redirect. - if (!loading && !isLoggedIn) { - return ; - } - - return ( -
- -

{tabs[tabIndex].label}

-
-
- {tabs.map((tab, index) => ( - - ))} -
-
- {!user ? : } -
-
-
-
- ); -}; - -export default Profile; diff --git a/frontend/src/views/RedirectLink.tsx b/frontend/src/views/RedirectLink.tsx deleted file mode 100644 index dd7d2dfb7..000000000 --- a/frontend/src/views/RedirectLink.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { FC } from 'react'; -import { useHistory, useLocation } from 'react-router-dom'; - -// We must have an allowlist of redirects to prevent an attacker from arbitrarily opening external sites. -const allowedRedirects = new Map([ - ['workshop-facebook', 'https://www.facebook.com/events/314954970047731'], - [ - 'workshop-register', - 'https://docs.google.com/forms/d/e/1FAIpQLSf92FiqIwMc5et1ZSI_Rj1NGi3Y7Rx2kyMl8uQLSX1QzDIsuQ/viewform?usp=sf_link' - ] -]); - -const RedirectLink: FC = () => { - const params = new URLSearchParams(useLocation().search); - const site = params.get('site'); - if (site != null && allowedRedirects.has(site)) { - window.open(allowedRedirects.get(site), '_blank'); - } - const history = useHistory(); - history.goBack(); - return null; -}; - -export default RedirectLink; diff --git a/frontend/src/views/Releases/Releases.jsx b/frontend/src/views/Releases/Releases.jsx deleted file mode 100644 index 3a80e261b..000000000 --- a/frontend/src/views/Releases/Releases.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { Component } from 'react'; -import { Container, Row, Col, ButtonToolbar } from 'react-bootstrap'; -import releases from '../../lib/releases'; - -import Log from '../../components/Releases/Log'; - -class Releases extends Component { - constructor(props) { - super(props); - this.state = { - releases: [] - }; - } - - render() { - return ( -
- - - - -
-

Berkeleytime Releases

-

Keep up-to-date with our releases and bug fixes.

- -
- - -
- - - - {releases.map((item) => ( - - ))} - - - -
-
- ); - } -} - -export default Releases; diff --git a/frontend/src/views/Scheduler/LocalSchedulerPage.tsx b/frontend/src/views/Scheduler/LocalSchedulerPage.tsx deleted file mode 100644 index 7970f3577..000000000 --- a/frontend/src/views/Scheduler/LocalSchedulerPage.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { Button, OverlayTrigger, Tooltip } from 'react-bootstrap'; - -import BTLoader from 'components/Common/BTLoader'; -import { DEFAULT_SCHEDULE, Schedule, SCHEDULER_LOCALSTORAGE_KEY } from 'utils/scheduler/scheduler'; -import { useUser } from 'graphql/hooks/user'; -import { useCreateSchedule } from 'graphql/hooks/schedule'; -import { useLocalStorageState } from 'utils/hooks'; -import ScheduleEditor from '../../components/Scheduler/ScheduleEditor'; -import { useHistory } from 'react-router'; -import { useSemester } from 'graphql/hooks/semester'; -import Callout from '../../components/Scheduler/Callout'; -import { ReduxState } from 'redux/store'; -import { useSelector } from 'react-redux'; - -const LocalScheduler = () => { - const [schedule, setSchedule] = useLocalStorageState( - SCHEDULER_LOCALSTORAGE_KEY, - DEFAULT_SCHEDULE - ); - - const { isLoggedIn, loading: loadingUser } = useUser(); - const history = useHistory(); - - const { semester, error: semesterError } = useSemester(); - - const [createScheduleMutation, { loading: isSaving, error: creationError }] = useCreateSchedule({ - onCompleted: (data) => { - if (data?.createSchedule?.schedule) { - const scheduleId = data.createSchedule.schedule.id; - - // Clear the saved schedule - setSchedule(DEFAULT_SCHEDULE); - - // Redirect to the saved schedule editor. - const scheduleUUID = atob(scheduleId).split(':')[1]; - - // Defer this to the next tick - setTimeout(() => { - history.push(`/scheduler/${scheduleUUID}`); - }); - } - } - }); - - const isMobile = useSelector((state: ReduxState) => state.common.mobile); - - if (isMobile) { - return ( -
-
-

- Unfortunately, the Scheduler does not support mobile devices at this time. -

-
-
- ); - } - - if (!semester) { - return ; - } - - const createSchedule = async () => - // @ts-ignore - await createScheduleMutation(schedule, semester!); - - const saveButton = ( - - ); - - return ( -
- Saving schedule... - ) : creationError ? ( - - ) : !isLoggedIn ? ( - - {loadingUser ? 'Loading account...' : 'You must be logged in to save.'} - - } - placement="bottom" - > - {saveButton} - - ) : ( - saveButton - ) - } - /> -
- ); -}; - -export default LocalScheduler; diff --git a/frontend/src/views/Scheduler/RemoteSchedulerPage.tsx b/frontend/src/views/Scheduler/RemoteSchedulerPage.tsx deleted file mode 100644 index d2dc4fc85..000000000 --- a/frontend/src/views/Scheduler/RemoteSchedulerPage.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import BTLoader from 'components/Common/BTLoader'; -import { useUser } from 'graphql/hooks/user'; -import { useState } from 'react'; -import { Redirect, useParams } from 'react-router'; -import { DEFAULT_SCHEDULE, Schedule } from 'utils/scheduler/scheduler'; -import RemoteScheduler from '../../components/Scheduler/Editor/RemoteScheduler'; -import { ReduxState } from 'redux/store'; -import { useSelector } from 'react-redux'; - -const RemoteSchedulePage = () => { - const { isLoggedIn, loading: userLoading } = useUser(); - const [schedule, setSchedule] = useState(DEFAULT_SCHEDULE); - const { scheduleId: scheduleUUID } = useParams<{ scheduleId: string }>(); - const scheduleId = btoa(`ScheduleType:${scheduleUUID}`); - - const isMobile = useSelector((state: ReduxState) => state.common.mobile); - - if (isMobile) { - return ( -
-
-

- Unfortunately, the Scheduler does not support mobile devices at this time. -

-
-
- ); - } - - if (userLoading) { - return ( -
-
- -
-
- ); - } - - // if you're not logged in, we'll go to the schedule preview - if (!isLoggedIn && !userLoading && scheduleUUID) { - return ; - } - - return ( -
- -
- ); -}; - -export default RemoteSchedulePage; diff --git a/frontend/src/views/Scheduler/Scheduler.tsx b/frontend/src/views/Scheduler/Scheduler.tsx deleted file mode 100644 index 9c0e27dd9..000000000 --- a/frontend/src/views/Scheduler/Scheduler.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import BTLoader from 'components/Common/BTLoader'; -import SchedulerOnboard from './SchedulerOnboard'; -import { useUser } from 'graphql/hooks/user'; - -const Scheduler = () => { - const { loading: userLoading } = useUser(); - - if (userLoading) { - return ( -
-
- -
-
- ); - } - - return ( -
- -
- ); -}; - -export default Scheduler; diff --git a/frontend/src/views/Scheduler/SchedulerOnboard.tsx b/frontend/src/views/Scheduler/SchedulerOnboard.tsx deleted file mode 100644 index eba6e379f..000000000 --- a/frontend/src/views/Scheduler/SchedulerOnboard.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import { ComponentType, useState, Dispatch, SetStateAction } from 'react'; -import Welcome from 'components/Scheduler/Onboard/Welcome'; -import SelectClasses from 'components/Scheduler/Onboard/SelectClasses'; - -import { DEFAULT_SCHEDULE, Schedule } from 'utils/scheduler/scheduler'; -import { ReduxState } from 'redux/store'; -import { useSelector } from 'react-redux'; - -const pages: { - key: string; - component: ComponentType<{ - updatePage: (i: number) => void; - schedule: Schedule; - setSchedule: Dispatch>; - }>; -}[] = [ - { - key: 'welcome', - component: Welcome - }, - { - key: 'select-classes', - component: SelectClasses - } - // { - // key: 'time-preferences', - // component: TimePreferences, - // }, -]; - -const SchedulerOnboard = () => { - const [pageIndex, setPageIndex] = useState(0); - const PageComponent = pages[pageIndex].component; - - const [schedule, setSchedule] = useState(DEFAULT_SCHEDULE); - - const isMobile = useSelector((state: ReduxState) => state.common.mobile); - - if (isMobile) { - return ( -
-
-

- Unfortunately, the Scheduler does not support mobile devices at this time. -

-
-
- ); - } - - return ( -
-
- -
-
- ); -}; - -export default SchedulerOnboard; diff --git a/frontend/src/views/Scheduler/ViewSchedule.tsx b/frontend/src/views/Scheduler/ViewSchedule.tsx deleted file mode 100644 index 85d2c49d4..000000000 --- a/frontend/src/views/Scheduler/ViewSchedule.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useGetScheduleForIdQuery } from 'graphql'; -import BTLoader from 'components/Common/BTLoader'; -import { Redirect, useParams } from 'react-router'; -import { - deserializeSchedule, - formatScheduleError, - getUnitsForSchedule -} from 'utils/scheduler/scheduler'; -import SchedulerCalendar from 'components/Scheduler/Calendar/SchedulerCalendar'; -import { unitsToString } from 'utils/courses/units'; -import { useUser } from 'graphql/hooks/user'; -import { Button } from 'bt/custom'; -import { ReduxState } from 'redux/store'; -import { useSelector } from 'react-redux'; - -const ViewSchedule = () => { - const { scheduleId: scheduleUUID } = useParams<{ scheduleId?: string }>(); - const { user } = useUser(); - - const { data, error } = useGetScheduleForIdQuery({ - variables: { id: btoa(`ScheduleType:${scheduleUUID}`) }, - skip: scheduleUUID === undefined - }); - - const isMobile = useSelector((state: ReduxState) => state.common.mobile); - - if (isMobile) { - return ( -
-
-

- Unfortunately, the Scheduler does not support mobile devices at this time. -

-
-
- ); - } - - if (!scheduleUUID) { - return ; - } - - if (!data) { - return ( -
-
- -
-
- ); - } - - const schedule = deserializeSchedule(data.schedule!); - const scheduleOwner = data.schedule!.user.user; - const totalUnits = getUnitsForSchedule(schedule); - - return ( -
-
-
- Selected units: {unitsToString(totalUnits)} -
-
- -
-
- {scheduleOwner.id === user?.user.id ? ( - - ) : ( - - by {scheduleOwner.firstName} {scheduleOwner.lastName} - - )} -
-
- -
- ); -}; - -export default ViewSchedule; diff --git a/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts new file mode 100644 index 000000000..11f02fe2a --- /dev/null +++ b/frontend/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index e4e81120e..8cdac25e4 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -1,30 +1,30 @@ { - "compilerOptions": { - "rootDir": "src", - "baseUrl": "./src", - "target": "ESNext", - "useDefineForClassFields": true, - "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": true, - "skipLibCheck": true, - "esModuleInterop": false, - "allowSyntheticDefaultImports": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "moduleResolution": "Node", - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true, - "jsx": "react-jsx", - "noFallthroughCasesInSwitch": true, - "types": ["vite/client"] - }, - "include": ["src"], - "types": ["vite/client"], - "references": [ - { - "path": "./tsconfig.vite.json" - } - ] + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["ESNext", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Alias */ + "paths": { + "@/*": ["./src/*"], + }, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true + }, + "include": ["src"], + "references": [{ "path": "./tsconfig.node.json" }] } diff --git a/frontend/tsconfig.node.json b/frontend/tsconfig.node.json new file mode 100644 index 000000000..42872c59f --- /dev/null +++ b/frontend/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "bundler", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/frontend/tsconfig.vite.json b/frontend/tsconfig.vite.json deleted file mode 100644 index d3bf4b829..000000000 --- a/frontend/tsconfig.vite.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "composite": true, - "module": "ESNext", - "moduleResolution": "Node", - "allowSyntheticDefaultImports": true - }, - "include": ["vite.config.ts"] -} diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index f4949fe04..4173c9dc5 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,49 +1,16 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react-swc'; -import { visualizer } from 'rollup-plugin-visualizer'; -import { createHtmlPlugin } from 'vite-plugin-html'; -import tsconfigPaths from 'vite-tsconfig-paths'; -import svgr from 'vite-plugin-svgr'; -import path from 'path'; +import react from "@vitejs/plugin-react"; +import { resolve } from "path"; +import { defineConfig } from "vite"; export default defineConfig({ - root: path.resolve(__dirname, 'src'), - server: { - host: true, - port: 3000, - watch: { - usePolling: true - } - }, - publicDir: path.resolve(__dirname, 'public'), - plugins: [ - react(), - svgr(), - tsconfigPaths(), - visualizer(), - createHtmlPlugin({ - minify: true, - entry: '/index.tsx', - template: '/index.html' - }) - ], - resolve: { - alias: { - '~bootstrap': path.resolve(__dirname, 'node_modules/bootstrap') - } - }, - build: { - outDir: '../build', - sourcemap: false - }, - css: { - preprocessorOptions: { - scss: { - additionalData: ` - @import '/assets/scss/bt/base/responsive'; - @import '/assets/scss/bt/theming/colors'; - ` - } - } - } + server: { + host: true, + port: 3000, + }, + resolve: { + alias: { + "@": resolve(__dirname, "src"), + }, + }, + plugins: [react()], });