diff --git a/apidoc/apidoc.json b/apidoc/apidoc.json index 8b2893529d..2b7651614d 100644 --- a/apidoc/apidoc.json +++ b/apidoc/apidoc.json @@ -2,6 +2,7 @@ "name": "Habitica V3 API Documentation", "title": "Habitica", "url": "https://habitica.com", + "version": "3.0.0", "sampleUrl": null, "header": { "title": "Introduction", diff --git a/habitica-images b/habitica-images index 2fd4978a69..8d63ff55e5 160000 --- a/habitica-images +++ b/habitica-images @@ -1 +1 @@ -Subproject commit 2fd4978a69338e3b4328f7e9cbaabc520527b311 +Subproject commit 8d63ff55e5c63872f95a3c9106d0b5f90af9ab6f diff --git a/migrations/tasks/team-tasks-v2.js b/migrations/tasks/team-tasks-v2.js new file mode 100644 index 0000000000..a5c90cab95 --- /dev/null +++ b/migrations/tasks/team-tasks-v2.js @@ -0,0 +1,71 @@ +import filter from 'lodash/filter'; +import find from 'lodash/find'; +import isArray from 'lodash/isArray'; +import { model as Group } from '../../website/server/models/group'; +import { model as User } from '../../website/server/models/user'; +import * as Tasks from '../../website/server/models/task'; + +async function updateTeamTasks (team) { + const toSave = []; + const teamTasks = await Tasks.Task.find({ + 'group.id': team._id, + }).exec(); + + const teamBoardTasks = filter(teamTasks, task => !task.userId); + const teamUserTasks = filter(teamTasks, task => task.userId); + + for (const boardTask of teamBoardTasks) { + if (isArray(boardTask.group.assignedUsers)) { + boardTask.group.approval = undefined; + boardTask.group.assignedDate = undefined; + boardTask.group.assigningUsername = undefined; + boardTask.group.sharedCompletion = undefined; + + for (const assignedUserId of boardTask.group.assignedUsers) { + const assignedUser = await User.findById(assignedUserId, 'auth'); // eslint-disable-line no-await-in-loop + const userTask = find(teamUserTasks, task => task.userId === assignedUserId + && task.group.taskId === boardTask._id); + if (!boardTask.group.assignedUsersDetail) boardTask.group.assignedUsersDetail = {}; + if (userTask && assignedUser) { + boardTask.group.assignedUsersDetail[assignedUserId] = { + assignedDate: userTask.group.assignedDate, + assignedUsername: assignedUser.auth.local.username, + assigningUsername: userTask.group.assigningUsername, + completed: userTask.completed || false, + completedDate: userTask.dateCompleted, + }; + } else if (assignedUser) { + boardTask.group.assignedUsersDetail[assignedUserId] = { + assignedDate: new Date(), + assignedUsername: assignedUser.auth.local.username, + assigningUsername: null, + completed: false, + completedDate: null, + }; + } else { + const taskIndex = boardTask.group.assignedUsers.indexOf(assignedUserId); + boardTask.group.assignedUsers.splice(taskIndex, 1); + } + if (userTask) toSave.push(Tasks.Task.findByIdAndDelete(userTask._id)); + } + boardTask.markModified('group'); + toSave.push(boardTask.save()); + } + } + + return Promise.all(toSave); +} + +export default async function processTeams () { + const activeTeams = await Group.find({ + 'purchased.plan.customerId': { $exists: true }, + $or: [ + { 'purchased.plan.dateTerminated': { $exists: false } }, + { 'purchased.plan.dateTerminated': null }, + { 'purchased.plan.dateTerminated': { $gt: new Date() } }, + ], + }).exec(); + + const taskPromises = activeTeams.map(updateTeamTasks); + return Promise.all(taskPromises); +} diff --git a/package-lock.json b/package-lock.json index 32a407777f..54b6165b1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "habitica", - "version": "4.236.1", + "version": "4.243.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -22,25 +22,25 @@ } }, "@babel/compat-data": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", - "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==" + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.8.tgz", + "integrity": "sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==" }, "@babel/core": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.6.tgz", - "integrity": "sha512-cQbWBpxcbbs/IUredIPkHiAGULLV8iwgNRMFzvbhEXISp4f3rUUXE5+TIw6KwUWUR3DwyI6gmBRnmAtYaWehwQ==", + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.18.13.tgz", + "integrity": "sha512-ZisbOvRRusFktksHSG6pjj1CSvkPkcZq/KHD45LAkVP/oiHJkNBZWfpvlLmX8OtHDG8IuzsFlVRWo08w7Qxn0A==", "requires": { "@ampproject/remapping": "^2.1.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helpers": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/generator": "^7.18.13", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helpers": "^7.18.9", + "@babel/parser": "^7.18.13", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.13", + "@babel/types": "^7.18.13", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -56,103 +56,21 @@ "@babel/highlight": "^7.18.6" } }, - "@babel/compat-data": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.18.6.tgz", - "integrity": "sha512-tzulrgDT0QD6U7BJ4TKVk2SDDg7wlP39P9yAx1RfLy7vP/7rsDRlWVfbWxElslu56+r7QOhB2NSDsabYYruoZQ==" - }, "@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.13.tgz", + "integrity": "sha512-CkPg8ySSPuHTYPJYo7IRALdqyjM9HCbt/3uOBEFbzyGVP6Mn8bwFPB0jX6982JVNBlYzM1nnPkfjuXSOPtQeEQ==", "requires": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.18.13", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" } }, - "@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", - "requires": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-validator-option": "^7.18.6", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==" - }, - "@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", - "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-imports": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", - "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-module-transforms": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", - "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", - "requires": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-module-imports": "^7.18.6", - "@babel/helper-simple-access": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-simple-access": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz", - "integrity": "sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" }, - "@babel/helper-validator-option": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz", - "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" - }, "@babel/highlight": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", @@ -164,42 +82,43 @@ } }, "@babel/parser": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", - "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==" + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.13.tgz", + "integrity": "sha512-dgXcIfMuQ0kgzLB2b9tRZs7TTFFaGM2AbtA4fJgUUYukzGH4jwsS7hzQHEGs67jdehpm22vkgKwvbU+aEflgwg==" }, "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/traverse": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", - "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.13.tgz", + "integrity": "sha512-N6kt9X1jRMLPxxxPYWi7tgvJRH/rtoU+dbKAPDM44RFHiMH8igdsaSBgFeskhSl/kLWLDUvIh1RXCrTmg0/zvA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.18.13", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/parser": "^7.18.13", + "@babel/types": "^7.18.13", "debug": "^4.1.0", "globals": "^11.1.0" } }, "@babel/types": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", - "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz", + "integrity": "sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==", "requires": { + "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } @@ -214,22 +133,6 @@ "@jridgewell/trace-mapping": "^0.3.9" } }, - "browserslist": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", - "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", - "requires": { - "caniuse-lite": "^1.0.30001359", - "electron-to-chromium": "^1.4.172", - "node-releases": "^2.0.5", - "update-browserslist-db": "^1.0.4" - } - }, - "caniuse-lite": { - "version": "1.0.30001361", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz", - "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==" - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -240,16 +143,6 @@ "supports-color": "^5.3.0" } }, - "electron-to-chromium": { - "version": "1.4.173", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.173.tgz", - "integrity": "sha512-Qo3LnVW6JRNhD32viSdPebxKI7K+3WeBDjU1+Q2yZS83zAh8C2LyPpzTimlciv6U74KpY9n/0ESAhUByRke0jw==" - }, - "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==" - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -258,15 +151,30 @@ } }, "@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", + "version": "7.18.12", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.12.tgz", + "integrity": "sha512-dfQ8ebCN98SvyL7IxNMCUtZQSq5R7kxgN+r8qYTGDmmSion1hX2C0zq2yo1bsCDhXixokv1SAWTZUMYbO/V5zg==", "requires": { - "@babel/types": "^7.18.7", + "@babel/types": "^7.18.10", "@jridgewell/gen-mapping": "^0.3.2", "jsesc": "^2.5.1" }, "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, "@jridgewell/gen-mapping": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", @@ -288,46 +196,42 @@ } }, "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.6.tgz", - "integrity": "sha512-KT10c1oWEpmrIRYnthbzHgoOf6B+Xd6a5yhdbNtdhtG7aO1or5HViuf1TQR36xY/QprXA5nvxO6nAjhJ4y38jw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.18.9.tgz", + "integrity": "sha512-yFQ0YCHoIqarl8BCRwBL8ulYUaZpz3bNsA7oFepAzee+8/+ImtADXNOmO5vJvsPff3qi+hvpkY/NYBTrBQgdNw==", "requires": { "@babel/helper-explode-assignable-expression": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-compilation-targets": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.6.tgz", - "integrity": "sha512-vFjbfhNCzqdeAtZflUFrG5YIFqGTqsctrtkZ1D/NB0mDW9TwW3GmmUepYY4G9wCET5rY5ugz4OGTcLd614IzQg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz", + "integrity": "sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==", "requires": { - "@babel/compat-data": "^7.18.6", + "@babel/compat-data": "^7.18.8", "@babel/helper-validator-option": "^7.18.6", "browserslist": "^4.20.2", "semver": "^6.3.0" }, "dependencies": { - "browserslist": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", - "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", - "requires": { - "caniuse-lite": "^1.0.30001359", - "electron-to-chromium": "^1.4.172", - "node-releases": "^2.0.5", - "update-browserslist-db": "^1.0.4" - } - }, - "caniuse-lite": { - "version": "1.0.30001361", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz", - "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==" - }, - "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==" - }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -336,16 +240,16 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.6.tgz", - "integrity": "sha512-YfDzdnoxHGV8CzqHGyCbFvXg5QESPFkXlHtvdCkesLjjVMT2Adxe4FGUR5ChIb3DxSaXO12iIOCWoXdsUVwnqw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz", + "integrity": "sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", - "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-replace-supers": "^7.18.9", "@babel/helper-split-export-declaration": "^7.18.6" } }, @@ -359,14 +263,12 @@ } }, "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.2.tgz", + "integrity": "sha512-r9QJJ+uDWrd+94BSPcP6/de67ygLtvVy6cK4luE6MOuDsZIdoaPBnfSpbO/+LTifjPckbKXRuI9BB/Z2/y3iTg==", "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", + "@babel/helper-compilation-targets": "^7.17.7", + "@babel/helper-plugin-utils": "^7.16.7", "debug": "^4.1.1", "lodash.debounce": "^4.0.8", "resolve": "^1.14.2", @@ -381,9 +283,9 @@ } }, "@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==" + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", + "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==" }, "@babel/helper-explode-assignable-expression": { "version": "7.18.6", @@ -394,12 +296,29 @@ } }, "@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz", + "integrity": "sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==", "requires": { "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-hoist-variables": { @@ -411,11 +330,28 @@ } }, "@babel/helper-member-expression-to-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.6.tgz", - "integrity": "sha512-CeHxqwwipekotzPDUuJOfIMtcIHBuc7WAzLmTYWctVigqS5RktNMQ5bEwQSuGewzYnCtTWa3BARXeiLxDTv+Ng==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz", + "integrity": "sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-module-imports": { @@ -427,24 +363,34 @@ } }, "@babel/helper-module-transforms": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.6.tgz", - "integrity": "sha512-L//phhB4al5uucwzlimruukHB3jRd5JGClwRMD/ROrVjXfLqovYnvQrK/JK36WYyVwGGO7OD3kMyVTjx+WVPhw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz", + "integrity": "sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==", "requires": { - "@babel/helper-environment-visitor": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-module-imports": "^7.18.6", "@babel/helper-simple-access": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", "@babel/helper-validator-identifier": "^7.18.6", "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" }, "dependencies": { "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } } } }, @@ -457,31 +403,65 @@ } }, "@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==" + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" }, "@babel/helper-remap-async-to-generator": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.6.tgz", - "integrity": "sha512-z5wbmV55TveUPZlCLZvxWHtrjuJd+8inFhk7DG0WW87/oJuGDcjDiu7HIvGcpf5464L6xKCg3vNkmlVVz9hwyQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz", + "integrity": "sha512-dI7q50YKd8BAv3VEfgg7PS7yD3Rtbi2J1XMXaalXO0W0164hYLnh8zpjRS0mte9MfVp/tltvr/cfdXPvJr1opA==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-wrap-function": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-wrap-function": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-replace-supers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.6.tgz", - "integrity": "sha512-fTf7zoXnUGl9gF25fXCWE26t7Tvtyn6H4hkLSYhATwJvw2uYxd3aoXplMSe0g9XbwK7bmxNes7+FGO0rB/xC0g==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz", + "integrity": "sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==", "requires": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-member-expression-to-functions": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-member-expression-to-functions": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-simple-access": { @@ -493,11 +473,28 @@ } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz", - "integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } } }, "@babel/helper-split-export-declaration": { @@ -508,6 +505,11 @@ "@babel/types": "^7.18.6" } }, + "@babel/helper-string-parser": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz", + "integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==" + }, "@babel/helper-validator-identifier": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", @@ -519,24 +521,14 @@ "integrity": "sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==" }, "@babel/helper-wrap-function": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.6.tgz", - "integrity": "sha512-I5/LZfozwMNbwr/b1vhhuYD+J/mU+gfGAj5td7l5Rv9WYmH6i3Om69WGKNmlIpsVW/mF6O5bvTKbvDQZVgjqOw==", + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.18.11.tgz", + "integrity": "sha512-oBUlbv+rjZLh2Ks9SKi4aL7eKaAXBWleHzU89mP0G6BMUlRxSckk9tSIkgDGydhgFxHuGSlBQZfnaD47oBEB7w==", "requires": { - "@babel/helper-function-name": "^7.18.6", - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/helpers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.6.tgz", - "integrity": "sha512-vzSiiqbQOghPngUYt/zWGvK3LAsPhz55vc9XNN0xAl2gV4ieShI2OQli5duxWHD+72PZPTKAcfcZDE1Cwc5zsQ==", - "requires": { - "@babel/template": "^7.18.6", - "@babel/traverse": "^7.18.6", - "@babel/types": "^7.18.6" + "@babel/helper-function-name": "^7.18.9", + "@babel/template": "^7.18.10", + "@babel/traverse": "^7.18.11", + "@babel/types": "^7.18.10" }, "dependencies": { "@babel/code-frame": { @@ -547,46 +539,6 @@ "@babel/highlight": "^7.18.6" } }, - "@babel/generator": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.18.7.tgz", - "integrity": "sha512-shck+7VLlY72a2w9c3zYWuE1pwOKEiQHV7GTUbSnhyl5eu3i04t30tBY82ZRWrDfo3gkakCFtevExnxbkf2a3A==", - "requires": { - "@babel/types": "^7.18.7", - "@jridgewell/gen-mapping": "^0.3.2", - "jsesc": "^2.5.1" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.6.tgz", - "integrity": "sha512-8n6gSfn2baOY+qlp+VSzsosjCVGFqWKmDF0cCWOybh52Dw3SEyoWR1KrhMJASjLwIEkkAufZ0xvr+SxLHSpy2Q==" - }, - "@babel/helper-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.18.6.tgz", - "integrity": "sha512-0mWMxV1aC97dhjCah5U5Ua7668r5ZmSC2DLfH2EZnf9c3/dHZKiFa5pRLMH5tjSl471tY6496ZWk/kjNONBxhw==", - "requires": { - "@babel/template": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", - "requires": { - "@babel/types": "^7.18.6" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", - "requires": { - "@babel/types": "^7.18.6" - } - }, "@babel/helper-validator-identifier": { "version": "7.18.6", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", @@ -603,56 +555,30 @@ } }, "@babel/parser": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.6.tgz", - "integrity": "sha512-uQVSa9jJUe/G/304lXspfWVpKpK4euFLgGiMQFOCpM/bgcAdeoHwi/OQz23O9GK2osz26ZiXRRV9aV+Yl1O8tw==" + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", + "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==" }, "@babel/template": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.6.tgz", - "integrity": "sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", + "integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6" - } - }, - "@babel/traverse": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", - "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", - "requires": { - "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6", - "debug": "^4.1.0", - "globals": "^11.1.0" + "@babel/parser": "^7.18.10", + "@babel/types": "^7.18.10" } }, "@babel/types": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", - "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", "requires": { + "@babel/helper-string-parser": "^7.18.10", "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" } }, - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -665,6 +591,33 @@ } } }, + "@babel/helpers": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.18.9.tgz", + "integrity": "sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==", + "requires": { + "@babel/template": "^7.18.6", + "@babel/traverse": "^7.18.9", + "@babel/types": "^7.18.9" + }, + "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.13", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.13.tgz", + "integrity": "sha512-ePqfTihzW0W6XAU+aMw2ykilisStJfDnsejDCXRchCcMJ4O0+8DhPXf2YUbZ6wjBlsEmZwLK/sPweWtu8hcJYQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + } + } + }, "@babel/highlight": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", @@ -701,23 +654,23 @@ } }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.6.tgz", - "integrity": "sha512-Udgu8ZRgrBrttVz6A0EVL0SJ1z+RLbIeqsu632SA1hf0awEppD6TvdznoH+orIF8wtFFAV/Enmw9Y+9oV8TQcw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.18.9.tgz", + "integrity": "sha512-AHrP9jadvH7qlOj6PINbgSuphjQUAK7AOT7DPjBo9EHoLhQTnnK5u45e1Hd4DbSQEO9nqPWtQ89r+XEOWFScKg==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } }, "@babel/plugin-proposal-async-generator-functions": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.6.tgz", - "integrity": "sha512-WAz4R9bvozx4qwf74M+sfqPMKfSqwM0phxPTR6iJIi8robgzXwkEgmeJG1gEKhm6sDqT/U9aV3lfcqybIpev8w==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.18.10.tgz", + "integrity": "sha512-1mFuY2TOsR1hxbjCo4QL+qlIjV07p4H4EUYw2J/WCqsvFV6V9X9z9YhXbWndc/4fw+hYGlDT7egYxliMp5O6Ew==", "requires": { - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-remap-async-to-generator": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-remap-async-to-generator": "^7.18.9", "@babel/plugin-syntax-async-generators": "^7.8.4" } }, @@ -750,11 +703,11 @@ } }, "@babel/plugin-proposal-export-namespace-from": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.6.tgz", - "integrity": "sha512-zr/QcUlUo7GPo6+X1wC98NJADqmy5QTFWWhqeQWiki4XHafJtLl/YMGkmRB2szDD2IYJCCdBTd4ElwhId9T7Xw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.18.9.tgz", + "integrity": "sha512-k1NtHyOMvlDDFeb9G5PhUXuGj8m/wiwojgQVEhJ/fsVsMCpLyOP4h0uGEjYJKrRI+EVPlb5Jk+Gt9P97lOGwtA==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-export-namespace-from": "^7.8.3" } }, @@ -768,11 +721,11 @@ } }, "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.6.tgz", - "integrity": "sha512-zMo66azZth/0tVd7gmkxOkOjs2rpHyhpcFo565PUP37hSp6hSd9uUKIfTDFMz58BwqgQKhJ9YxtM5XddjXVn+Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.18.9.tgz", + "integrity": "sha512-128YbMpjCrP35IOExw2Fq+x55LMP42DzhOhX2aNNIdI9avSWl2PI0yuBWarr3RYpZBSPtabfadkH2yeRiMD61Q==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" } }, @@ -795,15 +748,15 @@ } }, "@babel/plugin-proposal-object-rest-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.6.tgz", - "integrity": "sha512-9yuM6wr4rIsKa1wlUAbZEazkCrgw2sMPEXCr4Rnwetu7cEW1NydkCWytLuYletbf8vFxdJxFhwEZqMpOx2eZyw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.18.9.tgz", + "integrity": "sha512-kDDHQ5rflIeY5xl69CEqGEZ0KY369ehsCIEbTGb4siHG5BE9sga/T0r0OUwyZNLMmZE79E1kbsqAjwFCW4ds6Q==", "requires": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.18.6" + "@babel/plugin-transform-parameters": "^7.18.8" } }, "@babel/plugin-proposal-optional-catch-binding": { @@ -816,12 +769,12 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz", - "integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" } }, @@ -1001,42 +954,42 @@ } }, "@babel/plugin-transform-block-scoping": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.6.tgz", - "integrity": "sha512-pRqwb91C42vs1ahSAWJkxOxU1RHWDn16XAa6ggQ72wjLlWyYeAcLvTtE0aM8ph3KNydy9CQF2nLYcjq1WysgxQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.9.tgz", + "integrity": "sha512-5sDIJRV1KtQVEbt/EIBwGy4T01uYIo4KRB3VUqzkhrAIOGx7AoctL9+Ux88btY0zXdDyPJ9mW+bg+v+XEkGmtw==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-classes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.6.tgz", - "integrity": "sha512-XTg8XW/mKpzAF3actL554Jl/dOYoJtv3l8fxaEczpgz84IeeVf+T1u2CSvPHuZbt0w3JkIx4rdn/MRQI7mo0HQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.9.tgz", + "integrity": "sha512-EkRQxsxoytpTlKJmSPYrsOMjCILacAjtSVkd4gChEe2kXjFCun3yohhW5I7plXJhCemM0gKsaGMcO8tinvCA5g==", "requires": { "@babel/helper-annotate-as-pure": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", "@babel/helper-optimise-call-expression": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-replace-supers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-replace-supers": "^7.18.9", "@babel/helper-split-export-declaration": "^7.18.6", "globals": "^11.1.0" } }, "@babel/plugin-transform-computed-properties": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.6.tgz", - "integrity": "sha512-9repI4BhNrR0KenoR9vm3/cIc1tSBIo+u1WVjKCAynahj25O8zfbiE6JtAtHPGQSs4yZ+bA8mRasRP+qc+2R5A==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.18.9.tgz", + "integrity": "sha512-+i0ZU1bCDymKakLxn5srGHrsAPRELC2WIbzwjLhHW9SIE1cPYkLCL0NlnXMZaM1vhfgA2+M7hySk42VBvrkBRw==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-destructuring": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.6.tgz", - "integrity": "sha512-tgy3u6lRp17ilY8r1kP4i2+HDUwxlVqq3RTc943eAWSzGgpU1qhiKpqZ5CMyHReIYPHdo3Kg8v8edKtDqSVEyQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.18.9.tgz", + "integrity": "sha512-p5VCYNddPLkZTq4XymQIaIfZNJwT9YsjkPOhkVEqt6QIpQFZVM9IltqqYpOEkJoN1DPznmxUDyZ5CTZs/ZCuHA==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-dotall-regex": { @@ -1049,11 +1002,11 @@ } }, "@babel/plugin-transform-duplicate-keys": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.6.tgz", - "integrity": "sha512-NJU26U/208+sxYszf82nmGYqVF9QN8py2HFTblPT9hbawi8+1C5a9JubODLTGFuT0qlkqVinmkwOD13s0sZktg==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.18.9.tgz", + "integrity": "sha512-d2bmXCtZXYc59/0SanQKbiWINadaJXqtvIQIzd4+hNwkWBgyCd5F/2t1kXoUdvPMrxzPvhK6EMQRROxsue+mfw==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-exponentiation-operator": { @@ -1066,29 +1019,29 @@ } }, "@babel/plugin-transform-for-of": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.6.tgz", - "integrity": "sha512-WAjoMf4wIiSsy88KmG7tgj2nFdEK7E46tArVtcgED7Bkj6Fg/tG5SbvNIOKxbFS2VFgNh6+iaPswBeQZm4ox8w==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.18.8.tgz", + "integrity": "sha512-yEfTRnjuskWYo0k1mHUqrVWaZwrdq8AYbfrpqULOJOaucGSp4mNMVps+YtA8byoevxS/urwU75vyhQIxcCgiBQ==", "requires": { "@babel/helper-plugin-utils": "^7.18.6" } }, "@babel/plugin-transform-function-name": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.6.tgz", - "integrity": "sha512-kJha/Gbs5RjzIu0CxZwf5e3aTTSlhZnHMT8zPWnJMjNpLOUgqevg+PN5oMH68nMCXnfiMo4Bhgxqj59KHTlAnA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.18.9.tgz", + "integrity": "sha512-WvIBoRPaJQ5yVHzcnJFor7oS5Ls0PYixlTYE63lCj2RtdQEl15M68FXQlxnG6wdraJIXRdR7KI+hQ7q/9QjrCQ==", "requires": { - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.6.tgz", - "integrity": "sha512-x3HEw0cJZVDoENXOp20HlypIHfl0zMIhMVZEBVTfmqbObIpsMxMbmU5nOEO8R7LYT+z5RORKPlTI5Hj4OsO9/Q==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.18.9.tgz", + "integrity": "sha512-IFQDSRoTPnrAIrI5zoZv73IFeZu2dhu6irxQjY9rNjTT53VmKg9fenjvoiOWOkJ6mm4jKVPtdMzBY98Fp4Z4cg==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-member-expression-literals": { @@ -1121,13 +1074,13 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.6.tgz", - "integrity": "sha512-UbPYpXxLjTw6w6yXX2BYNxF3p6QY225wcTkfQCy3OMnSlS/C3xGtwUjEzGkldb/sy6PWLiCQ3NbYfjWUTI3t4g==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.9.tgz", + "integrity": "sha512-zY/VSIbbqtoRoJKo2cDTewL364jSlZGvn0LKOf9ntbfxOvjfmyrdtEEOAdswOswhZEb8UH3jDkCKHd1sPgsS0A==", "requires": { "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-module-transforms": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/helper-module-transforms": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-validator-identifier": "^7.18.6", "babel-plugin-dynamic-import-node": "^2.3.3" }, @@ -1175,9 +1128,9 @@ } }, "@babel/plugin-transform-parameters": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.6.tgz", - "integrity": "sha512-FjdqgMv37yVl/gwvzkcB+wfjRI8HQmc5EgOG9iGNvUY1ok+TjsoaMP7IqCDZBhkFcM5f3OPVMs6Dmp03C5k4/A==", + "version": "7.18.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.18.8.tgz", + "integrity": "sha512-ivfbE3X2Ss+Fj8nnXvKJS6sjRG4gzwPMsP+taZC+ZzEGjAYlvENixmt1sZ5Ca6tWls+BlKSGKPJ6OOXvXCbkFg==", "requires": { "@babel/helper-plugin-utils": "^7.18.6" } @@ -1216,12 +1169,12 @@ } }, "@babel/plugin-transform-spread": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.6.tgz", - "integrity": "sha512-ayT53rT/ENF8WWexIRg9AiV9h0aIteyWn5ptfZTZQrjk/+f3WdrJGCY4c9wcgl2+MKkKPhzbYp97FTsquZpDCw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.18.9.tgz", + "integrity": "sha512-39Q814wyoOPtIB/qGopNIL9xDChOE1pNU0ZY5dO0owhiVt/5kFm4li+/bBtwc7QotG0u5EPzqhZdjMtmqBqyQA==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9" } }, "@babel/plugin-transform-sticky-regex": { @@ -1233,27 +1186,27 @@ } }, "@babel/plugin-transform-template-literals": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.6.tgz", - "integrity": "sha512-UuqlRrQmT2SWRvahW46cGSany0uTlcj8NYOS5sRGYi8FxPYPoLd5DDmMd32ZXEj2Jq+06uGVQKHxa/hJx2EzKw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.18.9.tgz", + "integrity": "sha512-S8cOWfT82gTezpYOiVaGHrCbhlHgKhQt8XH5ES46P2XWmX92yisoZywf5km75wv5sYcXDUCLMmMxOLCtthDgMA==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-typeof-symbol": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.6.tgz", - "integrity": "sha512-7m71iS/QhsPk85xSjFPovHPcH3H9qeyzsujhTc+vcdnsXavoWYJ74zx0lP5RhpC5+iDnVLO+PPMHzC11qels1g==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.18.9.tgz", + "integrity": "sha512-SRfwTtF11G2aemAZWivL7PD+C9z52v9EvMqH9BuYbabyPuKUvSWks3oCg6041pT925L4zVFqaVBeECwsmlguEw==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-escapes": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.6.tgz", - "integrity": "sha512-XNRwQUXYMP7VLuy54cr/KS/WeL3AZeORhrmeZ7iewgu+X2eBqmpaLI/hzqr9ZxCeUoq0ASK4GUzSM0BDhZkLFw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.18.10.tgz", + "integrity": "sha512-kKAdAI+YzPgGY/ftStBFXTI1LZFju38rYThnfMykS+IXy8BVx+res7s2fxf1l8I35DV2T97ezo6+SGrXz6B3iQ==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6" + "@babel/helper-plugin-utils": "^7.18.9" } }, "@babel/plugin-transform-unicode-regex": { @@ -1266,28 +1219,28 @@ } }, "@babel/preset-env": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.6.tgz", - "integrity": "sha512-WrthhuIIYKrEFAwttYzgRNQ5hULGmwTj+D6l7Zdfsv5M7IWV/OZbUfbeL++Qrzx1nVJwWROIFhCHRYQV4xbPNw==", + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.18.10.tgz", + "integrity": "sha512-wVxs1yjFdW3Z/XkNfXKoblxoHgbtUF7/l3PvvP4m02Qz9TZ6uZGxRVYjSQeR87oQmHco9zWitW5J82DJ7sCjvA==", "requires": { - "@babel/compat-data": "^7.18.6", - "@babel/helper-compilation-targets": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6", + "@babel/compat-data": "^7.18.8", + "@babel/helper-compilation-targets": "^7.18.9", + "@babel/helper-plugin-utils": "^7.18.9", "@babel/helper-validator-option": "^7.18.6", "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.18.6", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.6", - "@babel/plugin-proposal-async-generator-functions": "^7.18.6", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.18.9", + "@babel/plugin-proposal-async-generator-functions": "^7.18.10", "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-class-static-block": "^7.18.6", "@babel/plugin-proposal-dynamic-import": "^7.18.6", - "@babel/plugin-proposal-export-namespace-from": "^7.18.6", + "@babel/plugin-proposal-export-namespace-from": "^7.18.9", "@babel/plugin-proposal-json-strings": "^7.18.6", - "@babel/plugin-proposal-logical-assignment-operators": "^7.18.6", + "@babel/plugin-proposal-logical-assignment-operators": "^7.18.9", "@babel/plugin-proposal-nullish-coalescing-operator": "^7.18.6", "@babel/plugin-proposal-numeric-separator": "^7.18.6", - "@babel/plugin-proposal-object-rest-spread": "^7.18.6", + "@babel/plugin-proposal-object-rest-spread": "^7.18.9", "@babel/plugin-proposal-optional-catch-binding": "^7.18.6", - "@babel/plugin-proposal-optional-chaining": "^7.18.6", + "@babel/plugin-proposal-optional-chaining": "^7.18.9", "@babel/plugin-proposal-private-methods": "^7.18.6", "@babel/plugin-proposal-private-property-in-object": "^7.18.6", "@babel/plugin-proposal-unicode-property-regex": "^7.18.6", @@ -1309,44 +1262,59 @@ "@babel/plugin-transform-arrow-functions": "^7.18.6", "@babel/plugin-transform-async-to-generator": "^7.18.6", "@babel/plugin-transform-block-scoped-functions": "^7.18.6", - "@babel/plugin-transform-block-scoping": "^7.18.6", - "@babel/plugin-transform-classes": "^7.18.6", - "@babel/plugin-transform-computed-properties": "^7.18.6", - "@babel/plugin-transform-destructuring": "^7.18.6", + "@babel/plugin-transform-block-scoping": "^7.18.9", + "@babel/plugin-transform-classes": "^7.18.9", + "@babel/plugin-transform-computed-properties": "^7.18.9", + "@babel/plugin-transform-destructuring": "^7.18.9", "@babel/plugin-transform-dotall-regex": "^7.18.6", - "@babel/plugin-transform-duplicate-keys": "^7.18.6", + "@babel/plugin-transform-duplicate-keys": "^7.18.9", "@babel/plugin-transform-exponentiation-operator": "^7.18.6", - "@babel/plugin-transform-for-of": "^7.18.6", - "@babel/plugin-transform-function-name": "^7.18.6", - "@babel/plugin-transform-literals": "^7.18.6", + "@babel/plugin-transform-for-of": "^7.18.8", + "@babel/plugin-transform-function-name": "^7.18.9", + "@babel/plugin-transform-literals": "^7.18.9", "@babel/plugin-transform-member-expression-literals": "^7.18.6", "@babel/plugin-transform-modules-amd": "^7.18.6", "@babel/plugin-transform-modules-commonjs": "^7.18.6", - "@babel/plugin-transform-modules-systemjs": "^7.18.6", + "@babel/plugin-transform-modules-systemjs": "^7.18.9", "@babel/plugin-transform-modules-umd": "^7.18.6", "@babel/plugin-transform-named-capturing-groups-regex": "^7.18.6", "@babel/plugin-transform-new-target": "^7.18.6", "@babel/plugin-transform-object-super": "^7.18.6", - "@babel/plugin-transform-parameters": "^7.18.6", + "@babel/plugin-transform-parameters": "^7.18.8", "@babel/plugin-transform-property-literals": "^7.18.6", "@babel/plugin-transform-regenerator": "^7.18.6", "@babel/plugin-transform-reserved-words": "^7.18.6", "@babel/plugin-transform-shorthand-properties": "^7.18.6", - "@babel/plugin-transform-spread": "^7.18.6", + "@babel/plugin-transform-spread": "^7.18.9", "@babel/plugin-transform-sticky-regex": "^7.18.6", - "@babel/plugin-transform-template-literals": "^7.18.6", - "@babel/plugin-transform-typeof-symbol": "^7.18.6", - "@babel/plugin-transform-unicode-escapes": "^7.18.6", + "@babel/plugin-transform-template-literals": "^7.18.9", + "@babel/plugin-transform-typeof-symbol": "^7.18.9", + "@babel/plugin-transform-unicode-escapes": "^7.18.10", "@babel/plugin-transform-unicode-regex": "^7.18.6", "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.18.6", - "babel-plugin-polyfill-corejs2": "^0.3.1", - "babel-plugin-polyfill-corejs3": "^0.5.2", - "babel-plugin-polyfill-regenerator": "^0.3.1", + "@babel/types": "^7.18.10", + "babel-plugin-polyfill-corejs2": "^0.3.2", + "babel-plugin-polyfill-corejs3": "^0.5.3", + "babel-plugin-polyfill-regenerator": "^0.4.0", "core-js-compat": "^3.22.1", "semver": "^6.3.0" }, "dependencies": { + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -1367,9 +1335,9 @@ } }, "@babel/register": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.6.tgz", - "integrity": "sha512-tkYtONzaO8rQubZzpBnvZPFcHgh8D9F55IjOsYton4X2IBoyRn2ZSWQqySTZnUn2guZbxbQiAB27hJEbvXamhQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.18.9.tgz", + "integrity": "sha512-ZlbnXDcNYHMR25ITwwNKT88JiaukkdVj/nG7r3wnuXkOTHc60Uy05PwMCPre0hSkY68E6zK3xz+vUJSP2jWmcw==", "requires": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", @@ -1379,9 +1347,9 @@ } }, "@babel/runtime": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.6.tgz", - "integrity": "sha512-t9wi7/AW6XtKahAe20Yw0/mMljKq0B1r2fPdvaAdV/KPDZewFXdaaa6K7lxmZBZ8FBNpCiAT6iHPmd6QO9bKfQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.18.9.tgz", + "integrity": "sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==", "requires": { "regenerator-runtime": "^0.13.4" } @@ -1432,18 +1400,18 @@ } }, "@babel/traverse": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.6.tgz", - "integrity": "sha512-zS/OKyqmD7lslOtFqbscH6gMLFYOfG1YPqCKfAW5KrTeolKqvB8UelR49Fpr6y93kYkW2Ik00mT1LOGiAGvizw==", + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.18.11.tgz", + "integrity": "sha512-TG9PiM2R/cWCAy6BPJKeHzNbu4lPzOSZpeMfeNErskGpTJx6trEvFaVCbDvpcxwy49BKWmEPwiW8mrysNiDvIQ==", "requires": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.18.6", - "@babel/helper-environment-visitor": "^7.18.6", - "@babel/helper-function-name": "^7.18.6", + "@babel/generator": "^7.18.10", + "@babel/helper-environment-visitor": "^7.18.9", + "@babel/helper-function-name": "^7.18.9", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.18.6", - "@babel/types": "^7.18.6", + "@babel/parser": "^7.18.11", + "@babel/types": "^7.18.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1471,6 +1439,21 @@ "js-tokens": "^4.0.0" } }, + "@babel/parser": { + "version": "7.18.11", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.11.tgz", + "integrity": "sha512-9JKn5vN+hDt0Hdqn1PiJ2guflwP+B6Ga8qbDuoF0PzzVhrzsKIJo8yGqVk6CmMHiMei9w1C1Bp9IMJSIK+HPIQ==" + }, + "@babel/types": { + "version": "7.18.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.10.tgz", + "integrity": "sha512-MJvnbEiiNkpjo+LknnmRrqbY1GPUUggjv+wQVjetM/AONoupqRALB7I6jGqNUAZsKcRIEu2J6FRFvsczljjsaQ==", + "requires": { + "@babel/helper-string-parser": "^7.18.10", + "@babel/helper-validator-identifier": "^7.18.6", + "to-fast-properties": "^2.0.0" + } + }, "chalk": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", @@ -3025,12 +3008,12 @@ } }, "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.2.tgz", + "integrity": "sha512-LPnodUl3lS0/4wN3Rb+m+UK8s7lj2jcLRrjho4gLw+OJs+I4bvGXshINesY5xx/apM+biTnQ9reDI8yj+0M5+Q==", "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/compat-data": "^7.17.7", + "@babel/helper-define-polyfill-provider": "^0.3.2", "semver": "^6.1.1" }, "dependencies": { @@ -3042,20 +3025,20 @@ } }, "babel-plugin-polyfill-corejs3": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz", - "integrity": "sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ==", + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.3.tgz", + "integrity": "sha512-zKsXDh0XjnrUEW0mxIHLfjBfnXSMr5Q/goMe/fxpQnLm07mcOZiIZHBNWCMx60HmdvjxfXcalac0tfFg0wqxyw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", + "@babel/helper-define-polyfill-provider": "^0.3.2", "core-js-compat": "^3.21.0" } }, "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.4.0.tgz", + "integrity": "sha512-RW1cnryiADFeHmfLS+WW/G431p1PsW5qdRdz0SDRi7TKcUgc7Oh/uXkT7MZ/+tGsT1BkczEAmD5XjUyJ5SWDTw==", "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" + "@babel/helper-define-polyfill-provider": "^0.3.2" } }, "babel-runtime": { @@ -4333,7 +4316,7 @@ "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true }, "coa": { @@ -4755,39 +4738,43 @@ "dev": true }, "core-js-compat": { - "version": "3.23.3", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.23.3.tgz", - "integrity": "sha512-WSzUs2h2vvmKsacLHNTdpyOC9k43AEhcGoFlVgCY4L7aw98oSBKtPL6vD0/TqZjRWRQYdDSLkzZIni4Crbbiqw==", + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.24.1.tgz", + "integrity": "sha512-XhdNAGeRnTpp8xbD+sR/HFDK9CbeeeqXT6TuofXh3urqEevzkWmLRgrVoykodsw8okqo2pu1BOmuCKrHx63zdw==", "requires": { - "browserslist": "^4.21.0", + "browserslist": "^4.21.3", "semver": "7.0.0" }, "dependencies": { "browserslist": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.1.tgz", - "integrity": "sha512-Nq8MFCSrnJXSc88yliwlzQe3qNe3VntIjhsArW9IJOEPSHNx23FalwApUVbzAWABLhYJJ7y8AynWI/XM8OdfjQ==", + "version": "4.21.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.3.tgz", + "integrity": "sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==", "requires": { - "caniuse-lite": "^1.0.30001359", - "electron-to-chromium": "^1.4.172", - "node-releases": "^2.0.5", - "update-browserslist-db": "^1.0.4" + "caniuse-lite": "^1.0.30001370", + "electron-to-chromium": "^1.4.202", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.5" } }, "caniuse-lite": { - "version": "1.0.30001361", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001361.tgz", - "integrity": "sha512-ybhCrjNtkFji1/Wto6SSJKkWk6kZgVQsDq5QI83SafsF6FXv2JB4df9eEdH6g8sdGgqTXrFLjAxqBGgYoU3azQ==" - }, - "node-releases": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", - "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==" + "version": "1.0.30001376", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001376.tgz", + "integrity": "sha512-I27WhtOQ3X3v3it9gNs/oTpoE5KpwmqKR5oKPA8M0G7uMXh9Ty81Q904HpKUrM30ei7zfcL5jE7AXefgbOfMig==" }, "semver": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==" + }, + "update-browserslist-db": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz", + "integrity": "sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } } } }, @@ -5547,9 +5534,9 @@ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, "electron-to-chromium": { - "version": "1.4.174", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.174.tgz", - "integrity": "sha512-JER+w+9MV2MBVFOXxP036bLlNOnzbYAWrWU8sNUwoOO69T3w4564WhM5H5atd8VVS8U4vpi0i0kdoYzm1NPQgQ==" + "version": "1.4.219", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.219.tgz", + "integrity": "sha512-zoQJsXOUw0ZA0YxbjkmzBumAJRtr6je5JySuL/bAoFs0DuLiLJ+5FzRF7/ZayihxR2QcewlRZVm5QZdUhwjOgA==" }, "emitter-listener": { "version": "1.1.2", @@ -7523,7 +7510,7 @@ "github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "dev": true }, "glob": { @@ -10693,6 +10680,29 @@ "rimraf": "^2.6.2" }, "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, "rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -10700,22 +10710,6 @@ "dev": true, "requires": { "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } } } @@ -11262,7 +11256,7 @@ "noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", - "integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI=", + "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", "dev": true }, "nopt": { @@ -12783,7 +12777,7 @@ "resolve-from": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "integrity": "sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ==", "dev": true } } @@ -12913,15 +12907,15 @@ "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" }, "run-rs": { - "version": "0.7.6", - "resolved": "https://registry.npmjs.org/run-rs/-/run-rs-0.7.6.tgz", - "integrity": "sha512-k//mO+AI4EVrDoVWDZiYBAu298mJosGUoi0gXII4yHsDWmdAF6fT1m/XDwV8DIA2LebSmgYZauW2DWx43W/trQ==", + "version": "0.7.7", + "resolved": "https://registry.npmjs.org/run-rs/-/run-rs-0.7.7.tgz", + "integrity": "sha512-63cLkmCl5JDz642EvtcDvIMG4VEJ7bOI8iJ3ovnydZYPkp8VD02Khr7wcbSs2CoOA9iXdNF27XMZdw+mVLlV2A==", "dev": true, "requires": { "chalk": "2.4.1", "co": "4.6.0", "commander": "2.15.1", - "moment": "2.22.2", + "moment": "^2.29.2", "mongodb": "3.6.x", "mongodb-topology-manager": "2.1.0", "prettyjson": "1.2.2" @@ -12943,12 +12937,6 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==", "dev": true - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=", - "dev": true } } }, diff --git a/package.json b/package.json index 68c3a46de1..b32ca0a27a 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,12 @@ { "name": "habitica", "description": "A habit tracker app which treats your goals like a Role Playing Game.", - "version": "4.236.1", + "version": "4.243.0", "main": "./website/server/index.js", "dependencies": { - "@babel/core": "^7.18.6", - "@babel/preset-env": "^7.18.6", - "@babel/register": "^7.18.6", + "@babel/core": "^7.18.13", + "@babel/preset-env": "^7.18.10", + "@babel/register": "^7.18.9", "@google-cloud/trace-agent": "^5.1.6", "@parse/node-apn": "^5.1.3", "@slack/webhook": "^6.1.0", @@ -121,7 +121,7 @@ "mocha": "^5.1.1", "monk": "^7.3.4", "require-again": "^2.0.0", - "run-rs": "^0.7.6", + "run-rs": "^0.7.7", "sinon": "^13.0.2", "sinon-chai": "^3.7.0", "sinon-stub-promise": "^4.0.0" diff --git a/scripts/team-cron.js b/scripts/team-cron.js new file mode 100644 index 0000000000..11f67fbf4f --- /dev/null +++ b/scripts/team-cron.js @@ -0,0 +1,105 @@ +import forEach from 'lodash/forEach'; +import { model as Group } from '../website/server/models/group'; +import { model as User } from '../website/server/models/user'; +import * as Tasks from '../website/server/models/task'; +import { daysSince, shouldDo } from '../website/common/script/cron'; + +const TASK_VALUE_CHANGE_FACTOR = 0.9747; +const MIN_TASK_VALUE = -47.27; + +async function updateTeamTasks (team) { + const toSave = []; + let teamLeader = await User.findOne({ _id: team.leader }, 'preferences').exec(); + + if (!teamLeader) { // why would this happen? + teamLeader = { + preferences: { }, // when options are sanitized this becomes CDS 0 at UTC + }; + } + + if ( + !team.cron || !team.cron.lastProcessed + || daysSince(team.cron.lastProcessed, teamLeader.preferences) > 0 + ) { + const tasks = await Tasks.Task.find({ + 'group.id': team._id, + userId: { $exists: false }, + $or: [ + { type: 'todo', completed: false }, + { type: { $in: ['habit', 'daily'] } }, + ], + }).exec(); + + const tasksByType = { + habits: [], dailys: [], todos: [], rewards: [], + }; + forEach(tasks, task => tasksByType[`${task.type}s`].push(task)); + + forEach(tasksByType.habits, habit => { + if (!(habit.up && habit.down) && habit.value !== 0) { + habit.value *= 0.5; + if (Math.abs(habit.value) < 0.1) habit.value = 0; + toSave.push(habit.save()); + } + }); + forEach(tasksByType.todos, todo => { + if (!todo.completed) { + const delta = TASK_VALUE_CHANGE_FACTOR ** todo.value; + todo.value -= delta; + if (todo.value < MIN_TASK_VALUE) todo.value = MIN_TASK_VALUE; + toSave.push(todo.save()); + } + }); + forEach(tasksByType.dailys, daily => { + let processChecklist = false; + let assignments = 0; + let completions = 0; + for (const assignedUser in daily.group.assignedUsersDetail) { + if (Object.prototype.hasOwnProperty.call(daily.group.assignedUsersDetail, assignedUser)) { + assignments += 1; + if (daily.group.assignedUsersDetail[assignedUser].completed) { + completions += 1; + daily.group.assignedUsersDetail[assignedUser].completed = false; + } + } + } + if (completions > 0) daily.markModified('group.assignedUsersDetail'); + if (daily.completed) { + processChecklist = true; + daily.completed = false; + } else if (shouldDo(team.cron.lastProcessed, daily, teamLeader.preferences)) { + processChecklist = true; + const delta = TASK_VALUE_CHANGE_FACTOR ** daily.value; + if (assignments > 0) { + daily.value -= ((completions / assignments) * delta); + } + if (daily.value < MIN_TASK_VALUE) daily.value = MIN_TASK_VALUE; + } + daily.isDue = shouldDo(new Date(), daily, teamLeader.preferences); + if (processChecklist && daily.checklist.length > 0) { + daily.checklist.forEach(i => { i.completed = false; }); + } + toSave.push(daily.save()); + }); + + if (!team.cron) team.cron = {}; + team.cron.lastProcessed = new Date(); + toSave.push(team.save()); + } + + return Promise.all(toSave); +} + +export default async function processTeamsCron () { + const activeTeams = await Group.find({ + 'purchased.plan.customerId': { $exists: true }, + $or: [ + { 'purchased.plan.dateTerminated': { $exists: false } }, + { 'purchased.plan.dateTerminated': null }, + { 'purchased.plan.dateTerminated': { $gt: new Date() } }, + ], + }).exec(); + + const cronPromises = activeTeams.map(updateTeamTasks); + return Promise.all(cronPromises); +} diff --git a/test/api/unit/models/group_tasks.test.js b/test/api/unit/models/group_tasks.test.js index 1c60fa947b..f4a37e194c 100644 --- a/test/api/unit/models/group_tasks.test.js +++ b/test/api/unit/models/group_tasks.test.js @@ -1,12 +1,10 @@ -import { each, find, findIndex } from 'lodash'; -import { model as Challenge } from '../../../../website/server/models/challenge'; +import { each, findIndex } from 'lodash'; import { model as Group } from '../../../../website/server/models/group'; import { model as User } from '../../../../website/server/models/user'; import * as Tasks from '../../../../website/server/models/task'; describe('Group Task Methods', () => { - let guild; let leader; let challenge; let - task; + let guild; let leader; let task; const tasksToTest = { habit: { text: 'test habit', @@ -31,10 +29,6 @@ describe('Group Task Methods', () => { }, }; - function findLinkedTask (updatedLeadersTask) { - return updatedLeadersTask.group.taskId === task._id; - } - beforeEach(async () => { guild = new Group({ name: 'test party', @@ -47,19 +41,9 @@ describe('Group Task Methods', () => { guild.leader = leader._id; - challenge = new Challenge({ - name: 'Test Challenge', - shortName: 'Test', - leader: leader._id, - group: guild._id, - }); - - leader.challenges = [challenge._id]; - await Promise.all([ guild.save(), leader.save(), - challenge.save(), ]); }); @@ -78,7 +62,15 @@ describe('Group Task Methods', () => { }); it('syncs an assigned task to a user', async () => { - await guild.syncTask(task, leader); + await guild.syncTask(task, [leader], leader); + + const updatedTask = await Tasks.Task.findOne({ _id: task._id }); + expect(updatedTask.group.assignedUsers).to.contain(leader._id); + expect(updatedTask.group.assignedUsersDetail[leader._id]).to.exist; + }); + + it('creates tags for a user when task is synced', async () => { + await guild.syncTask(task, [leader], leader); const updatedLeader = await User.findOne({ _id: leader._id }); const tagIndex = findIndex(updatedLeader.tags, { id: guild._id }); @@ -88,197 +80,6 @@ describe('Group Task Methods', () => { expect(newTag.name).to.equal(guild.name); expect(newTag.group).to.equal(guild._id); }); - - it('create tags for a user when task is synced', async () => { - await guild.syncTask(task, leader); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - expect(task.group.assignedUsers).to.contain(leader._id); - expect(syncedTask).to.exist; - }); - - it('syncs updated info for assigned task to a user', async () => { - await guild.syncTask(task, leader); - const updatedTaskName = 'Update Task name'; - task.text = updatedTaskName; - await guild.syncTask(task, leader); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - expect(task.group.assignedUsers).to.contain(leader._id); - expect(syncedTask).to.exist; - expect(syncedTask.text).to.equal(task.text); - }); - - it('syncs checklist items to an assigned user', async () => { - await guild.syncTask(task, leader); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - if (task.type !== 'daily' && task.type !== 'todo') return; - - expect(syncedTask.checklist.length).to.equal(task.checklist.length); - expect(syncedTask.checklist[0].text).to.equal(task.checklist[0].text); - }); - - describe('syncs updated info', async () => { - let newMember; - - beforeEach(async () => { - newMember = new User({ - guilds: [guild._id], - }); - await newMember.save(); - - await guild.syncTask(task, leader); - await guild.syncTask(task, newMember); - }); - - it('syncs updated info for assigned task to all users', async () => { - const updatedTaskName = 'Update Task name'; - task.text = updatedTaskName; - task.group.approval.required = true; - - await guild.updateTask(task); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - const updatedMember = await User.findOne({ _id: newMember._id }); - const updatedMemberTasks = await Tasks.Task.find({ _id: { $in: updatedMember.tasksOrder[`${taskType}s`] } }); - const syncedMemberTask = find(updatedMemberTasks, findLinkedTask); - - expect(task.group.assignedUsers).to.contain(leader._id); - expect(syncedTask).to.exist; - expect(syncedTask.text).to.equal(task.text); - expect(syncedTask.group.approval.required).to.equal(true); - - expect(task.group.assignedUsers).to.contain(newMember._id); - expect(syncedMemberTask).to.exist; - expect(syncedMemberTask.text).to.equal(task.text); - expect(syncedMemberTask.group.approval.required).to.equal(true); - }); - - it('syncs a new checklist item to all assigned users', async () => { - if (task.type !== 'daily' && task.type !== 'todo') return; - - const newCheckListItem = { - text: 'Checklist Item 1', - completed: false, - }; - - task.checklist.push(newCheckListItem); - - await guild.updateTask(task, { newCheckListItem }); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - const updatedMember = await User.findOne({ _id: newMember._id }); - const updatedMemberTasks = await Tasks.Task.find({ _id: { $in: updatedMember.tasksOrder[`${taskType}s`] } }); - const syncedMemberTask = find(updatedMemberTasks, findLinkedTask); - - expect(syncedTask.checklist.length).to.equal(task.checklist.length); - expect(syncedTask.checklist[1].text).to.equal(task.checklist[1].text); - expect(syncedMemberTask.checklist.length).to.equal(task.checklist.length); - expect(syncedMemberTask.checklist[1].text).to.equal(task.checklist[1].text); - }); - - it('syncs updated info for checklist in assigned task to all users when flag is passed', async () => { - if (task.type !== 'daily' && task.type !== 'todo') return; - - const updateCheckListText = 'Updated checklist item'; - if (task.checklist) { - task.checklist[0].text = updateCheckListText; - } - - await guild.updateTask(task, { updateCheckListItems: [task.checklist[0]] }); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - const updatedMember = await User.findOne({ _id: newMember._id }); - const updatedMemberTasks = await Tasks.Task.find({ _id: { $in: updatedMember.tasksOrder[`${taskType}s`] } }); - const syncedMemberTask = find(updatedMemberTasks, findLinkedTask); - - expect(syncedTask.checklist.length).to.equal(task.checklist.length); - expect(syncedTask.checklist[0].text).to.equal(updateCheckListText); - expect(syncedMemberTask.checklist.length).to.equal(task.checklist.length); - expect(syncedMemberTask.checklist[0].text).to.equal(updateCheckListText); - }); - - it('removes a checklist item in assigned task to all users when flag is passed with checklist id', async () => { - if (task.type !== 'daily' && task.type !== 'todo') return; - - await guild.updateTask(task, { removedCheckListItemId: task.checklist[0].id }); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - const updatedMember = await User.findOne({ _id: newMember._id }); - const updatedMemberTasks = await Tasks.Task.find({ _id: { $in: updatedMember.tasksOrder[`${taskType}s`] } }); - const syncedMemberTask = find(updatedMemberTasks, findLinkedTask); - - expect(syncedTask.checklist.length).to.equal(0); - expect(syncedMemberTask.checklist.length).to.equal(0); - }); - }); - - it('removes assigned tasks when master task is deleted', async () => { - await guild.syncTask(task, leader); - await guild.removeTask(task); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ userId: leader._id, type: taskType }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - expect(updatedLeader.tasksOrder[`${taskType}s`]).to.not.include(task._id); - expect(syncedTask).to.not.exist; - }); - - it('unlinks and deletes group tasks for a user when remove-all is specified', async () => { - await guild.syncTask(task, leader); - await guild.unlinkTask(task, leader, 'remove-all'); - - const updatedLeader = await User.findOne({ _id: leader._id }); - const updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - expect(task.group.assignedUsers).to.not.contain(leader._id); - expect(syncedTask).to.not.exist; - }); - - it('unlinks and keeps group tasks for a user when keep-all is specified', async () => { - await guild.syncTask(task, leader); - - let updatedLeader = await User.findOne({ _id: leader._id }); - let updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const syncedTask = find(updatedLeadersTasks, findLinkedTask); - - await guild.unlinkTask(task, leader, 'keep-all'); - - updatedLeader = await User.findOne({ _id: leader._id }); - updatedLeadersTasks = await Tasks.Task.find({ _id: { $in: updatedLeader.tasksOrder[`${taskType}s`] } }); - const updatedSyncedTask = find( - updatedLeadersTasks, - updatedLeadersTask => updatedLeadersTask._id === syncedTask._id, - ); - - expect(task.group.assignedUsers).to.not.contain(leader._id); - expect(updatedSyncedTask).to.exist; - expect(updatedSyncedTask.group._id).to.be.undefined; - }); }); }); }); diff --git a/test/api/unit/models/task.test.js b/test/api/unit/models/task.test.js index 5921a4e2c2..5da3341cbe 100644 --- a/test/api/unit/models/task.test.js +++ b/test/api/unit/models/task.test.js @@ -246,13 +246,23 @@ describe('Task Model', () => { expect(foundTasks[0].text).to.eql(taskWithAlias.text); }); - it('scopes alias lookup to user', async () => { + it('scopes alias lookup to user when querying aliases only', async () => { await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias.alias], user._id); + expect(Tasks.Task.find).to.be.calledOnce; + expect(Tasks.Task.find).to.be.calledWithMatch({ + alias: { $in: [taskWithAlias.alias] }, + userId: user._id, + }); + }); + + it('scopes alias lookup to user when querying aliases and IDs', async () => { + await Tasks.Task.findMultipleByIdOrAlias([taskWithAlias.alias, secondTask._id], user._id); + expect(Tasks.Task.find).to.be.calledOnce; expect(Tasks.Task.find).to.be.calledWithMatch({ $or: [ - { _id: { $in: [] } }, + { _id: { $in: [secondTask._id] } }, { alias: { $in: [taskWithAlias.alias] } }, ], userId: user._id, @@ -270,10 +280,7 @@ describe('Task Model', () => { expect(Tasks.Task.find).to.be.calledOnce; expect(Tasks.Task.find).to.be.calledWithMatch({ - $or: [ - { _id: { $in: [] } }, - { alias: { $in: [taskWithAlias.alias] } }, - ], + alias: { $in: [taskWithAlias.alias] }, userId: user._id, foo: 'bar', }); diff --git a/test/api/v3/integration/groups/POST-group_remove_manager.test.js b/test/api/v3/integration/groups/POST-group_remove_manager.test.js index 894a225d26..cdc37ca79f 100644 --- a/test/api/v3/integration/groups/POST-group_remove_manager.test.js +++ b/test/api/v3/integration/groups/POST-group_remove_manager.test.js @@ -1,4 +1,3 @@ -import { find } from 'lodash'; import { createAndPopulateGroup, translate as t, @@ -11,10 +10,6 @@ describe('POST /group/:groupId/remove-manager', () => { const groupType = 'guild'; let nonManager; - function findAssignedTask (memberTask) { - return memberTask.group.id === groupToUpdate._id; - } - beforeEach(async () => { const { group, groupLeader, members } = await createAndPopulateGroup({ groupDetails: { @@ -63,28 +58,4 @@ describe('POST /group/:groupId/remove-manager', () => { expect(updatedGroup.managers[nonLeader._id]).to.not.exist; }); - - it('removes group approval notifications from a manager that is removed', async () => { - await leader.post(`/groups/${groupToUpdate._id}/add-manager`, { - managerId: nonLeader._id, - }); - const task = await leader.post(`/tasks/group/${groupToUpdate._id}`, { - text: 'test todo', - type: 'todo', - requiresApproval: true, - }); - await nonLeader.post(`/tasks/${task._id}/assign/${nonManager._id}`); - const memberTasks = await nonManager.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await nonManager.post(`/tasks/${syncedTask._id}/score/up`); - - const updatedGroup = await leader.post(`/groups/${groupToUpdate._id}/remove-manager`, { - managerId: nonLeader._id, - }); - - await nonLeader.sync(); - - expect(nonLeader.notifications.length).to.equal(1); // user gets mystery items - expect(updatedGroup.managers[nonLeader._id]).to.not.exist; - }); }); diff --git a/test/api/v3/integration/tasks/POST-tasks_clearCompletedTodos.test.js b/test/api/v3/integration/tasks/POST-tasks_clearCompletedTodos.test.js index 92fcb6a13c..ecda9500d5 100644 --- a/test/api/v3/integration/tasks/POST-tasks_clearCompletedTodos.test.js +++ b/test/api/v3/integration/tasks/POST-tasks_clearCompletedTodos.test.js @@ -13,6 +13,9 @@ describe('POST /tasks/clearCompletedTodos', () => { { 'purchased.plan.customerId': 'group-unlimited' }, ); const challenge = await generateChallenge(user, guild); + await user.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); await user.post(`/challenges/${challenge._id}/join`); const initialTodoCount = user.tasksOrder.todos.length; @@ -33,7 +36,7 @@ describe('POST /tasks/clearCompletedTodos', () => { text: 'todo 7', type: 'todo', }); - await user.post(`/tasks/${groupTask._id}/assign/${user._id}`); + await user.post(`/tasks/${groupTask._id}/assign`, [user._id]); const tasks = await user.get('/tasks/user?type=todos'); expect(tasks.length).to.equal(initialTodoCount + 7); diff --git a/test/api/v3/integration/tasks/checklists/POST-tasks_taskId_checklist_itemId_score.test.js b/test/api/v3/integration/tasks/checklists/POST-tasks_taskId_checklist_itemId_score.test.js index 4f772ebaf7..a9aae0685c 100644 --- a/test/api/v3/integration/tasks/checklists/POST-tasks_taskId_checklist_itemId_score.test.js +++ b/test/api/v3/integration/tasks/checklists/POST-tasks_taskId_checklist_itemId_score.test.js @@ -30,7 +30,7 @@ describe('POST /tasks/:taskId/checklist/:itemId/score', () => { expect(savedTask.checklist[0].completed).to.equal(true); }); - it('can use a alias to score a checklist item', async () => { + it('can use an alias to score a checklist item', async () => { const task = await user.post('/tasks/user', { type: 'daily', text: 'Daily with checklist', diff --git a/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js b/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js index b6eb29db11..dda6037419 100644 --- a/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js +++ b/test/api/v3/integration/tasks/groups/DELETE-group_tasks_id.test.js @@ -1,4 +1,3 @@ -import { find } from 'lodash'; import { translate as t, createAndPopulateGroup, @@ -8,10 +7,6 @@ describe('Groups DELETE /tasks/:id', () => { let user; let guild; let member; let member2; let task; - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - beforeEach(async () => { const { group, members, groupLeader } = await createAndPopulateGroup({ groupDetails: { @@ -35,8 +30,7 @@ describe('Groups DELETE /tasks/:id', () => { notes: 1976, }); - await user.post(`/tasks/${task._id}/assign/${member._id}`); - await user.post(`/tasks/${task._id}/assign/${member2._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id, member2._id]); }); it('deletes a group task', async () => { @@ -64,81 +58,4 @@ describe('Groups DELETE /tasks/:id', () => { message: t('messageTaskNotFound'), }); }); - - it('removes deleted taskʾs approval pending notifications from managers', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - await user.put(`/tasks/${task._id}/`, { - requiresApproval: true, - }); - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - - await user.sync(); - await member2.sync(); - expect(user.notifications.length).to.equal(3); // mystery items - expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL'); - expect(member2.notifications.length).to.equal(3); - expect(member2.notifications[2].type).to.equal('GROUP_TASK_APPROVAL'); - - await member2.del(`/tasks/${task._id}`); - - await user.sync(); - await member2.sync(); - - expect(user.notifications.length).to.equal(2); - expect(member2.notifications.length).to.equal(2); - }); - - it('deletes task from assigned user', async () => { - await user.del(`/tasks/${task._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - expect(syncedTask).to.not.exist; - }); - - it('deletes task from all assigned users', async () => { - await user.del(`/tasks/${task._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - const member2Tasks = await member2.get('/tasks/user'); - const member2SyncedTask = find(member2Tasks, findAssignedTask); - - expect(syncedTask).to.not.exist; - expect(member2SyncedTask).to.not.exist; - }); - - it('prevents a user from deleting a task they are assigned to', async () => { - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await expect(member.del(`/tasks/${syncedTask._id}`)) - .to.eventually.be.rejected.and.eql({ - code: 401, - error: 'NotAuthorized', - message: t('cantDeleteAssignedGroupTasks'), - }); - }); - - it('allows a user to delete a task after leaving a group', async () => { - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/groups/${guild._id}/leave`); - - await member.del(`/tasks/${syncedTask._id}`); - - await expect(member.get(`/tasks/${syncedTask._id}`)) - .to.eventually.be.rejected.and.eql({ - code: 404, - error: 'NotFound', - message: 'Task not found.', - }); - }); }); diff --git a/test/api/v3/integration/tasks/groups/GET-approvals_group_id.test.js b/test/api/v3/integration/tasks/groups/GET-approvals_group_id.test.js deleted file mode 100644 index 520a322399..0000000000 --- a/test/api/v3/integration/tasks/groups/GET-approvals_group_id.test.js +++ /dev/null @@ -1,78 +0,0 @@ -import { find } from 'lodash'; -import { - createAndPopulateGroup, -} from '../../../../../helpers/api-integration/v3'; - -describe('GET /approvals/group/:groupId', () => { - let user; let guild; let member; let addlMember; let task; let syncedTask; let - addlSyncedTask; - - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - - beforeEach(async () => { - const { group, members, groupLeader } = await createAndPopulateGroup({ - groupDetails: { - name: 'Test Guild', - type: 'guild', - }, - members: 2, - upgradeToGroupPlan: true, - }); - - guild = group; - user = groupLeader; - member = members[0]; // eslint-disable-line prefer-destructuring - addlMember = members[1]; // eslint-disable-line prefer-destructuring - - task = await user.post(`/tasks/group/${guild._id}`, { - text: 'test todo', - type: 'todo', - requiresApproval: true, - }); - - await user.post(`/tasks/${task._id}/assign/${member._id}`); - await user.post(`/tasks/${task._id}/assign/${addlMember._id}`); - - const memberTasks = await member.get('/tasks/user'); - syncedTask = find(memberTasks, findAssignedTask); - - const addlMemberTasks = await addlMember.get('/tasks/user'); - addlSyncedTask = find(addlMemberTasks, findAssignedTask); - - try { - await member.post(`/tasks/${syncedTask._id}/score/up`); - } catch (e) { - // eslint-disable-next-line no-empty - } - - try { - await addlMember.post(`/tasks/${addlSyncedTask._id}/score/up`); - } catch (e) { - // eslint-disable-next-line no-empty - } - }); - - it('provides only user\'s own tasks when user is not the group leader', async () => { - const approvals = await member.get(`/approvals/group/${guild._id}`); - expect(approvals[0]._id).to.equal(syncedTask._id); - expect(approvals[1]).to.not.exist; - }); - - it('allows group leaders to get a list of tasks that need approval', async () => { - const approvals = await user.get(`/approvals/group/${guild._id}`); - expect(approvals[0]._id).to.equal(syncedTask._id); - expect(approvals[1]._id).to.equal(addlSyncedTask._id); - }); - - it('allows managers to get a list of tasks that need approval', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member._id, - }); - - const approvals = await member.get(`/approvals/group/${guild._id}`); - expect(approvals[0]._id).to.equal(syncedTask._id); - expect(approvals[1]._id).to.equal(addlSyncedTask._id); - }); -}); diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js deleted file mode 100644 index 60eeaf4053..0000000000 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_approve_userId.test.js +++ /dev/null @@ -1,261 +0,0 @@ -import { find } from 'lodash'; -import { - createAndPopulateGroup, - translate as t, -} from '../../../../../helpers/api-integration/v3'; - -describe('POST /tasks/:id/approve/:userId', () => { - let user; let guild; let member; let member2; let - task; - - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - - beforeEach(async () => { - const { group, members, groupLeader } = await createAndPopulateGroup({ - groupDetails: { - name: 'Test Guild', - type: 'guild', - }, - members: 2, - upgradeToGroupPlan: true, - }); - - guild = group; - user = groupLeader; - member = members[0]; // eslint-disable-line prefer-destructuring - member2 = members[1]; // eslint-disable-line prefer-destructuring - - task = await user.post(`/tasks/group/${guild._id}`, { - text: 'test todo', - type: 'todo', - requiresApproval: true, - }); - }); - - it('errors when user is not assigned', async () => { - await expect(user.post(`/tasks/${task._id}/approve/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 404, - error: 'NotFound', - message: t('messageTaskNotFound'), - }); - }); - - it('errors when user is not the group leader', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); - await expect(member.post(`/tasks/${task._id}/approve/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('onlyGroupLeaderCanEditTasks'), - }); - }); - - it('approves an assigned user', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); - - let memberTasks = await member.get('/tasks/user'); - let syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - await user.post(`/tasks/${task._id}/approve/${member._id}`); - - await member.sync(); - - expect(member.notifications.length).to.equal(3); - expect(member.notifications[2].type).to.equal('GROUP_TASK_APPROVED'); - expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); - - memberTasks = await member.get('/tasks/user'); - syncedTask = find(memberTasks, findAssignedTask); - - expect(syncedTask.group.approval.approved).to.be.true; - expect(syncedTask.group.approval.approvingUser).to.equal(user._id); - expect(syncedTask.group.approval.dateApproved).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type - }); - - it('allows a manager to approve an assigned user', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - - await member2.post(`/tasks/${task._id}/assign/${member._id}`); - - let memberTasks = await member.get('/tasks/user'); - let syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - await member2.post(`/tasks/${task._id}/approve/${member._id}`); - await member.sync(); - - expect(member.notifications.length).to.equal(3); - expect(member.notifications[2].type).to.equal('GROUP_TASK_APPROVED'); - expect(member.notifications[2].data.message).to.equal(t('yourTaskHasBeenApproved', { taskText: task.text })); - - memberTasks = await member.get('/tasks/user'); - syncedTask = find(memberTasks, findAssignedTask); - - expect(syncedTask.group.approval.approved).to.be.true; - expect(syncedTask.group.approval.approvingUser).to.equal(member2._id); - expect(syncedTask.group.approval.dateApproved).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type - }); - - it('removes approval pending notifications from managers', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - - await member2.post(`/tasks/${task._id}/assign/${member._id}`); - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - - await user.sync(); - await member2.sync(); - expect(user.notifications.length).to.equal(3); - expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL'); - expect(member2.notifications.length).to.equal(2); - expect(member2.notifications[1].type).to.equal('GROUP_TASK_APPROVAL'); - - await member2.post(`/tasks/${task._id}/approve/${member._id}`); - - await user.sync(); - await member2.sync(); - - expect(user.notifications.length).to.equal(2); - expect(member2.notifications.length).to.equal(1); - }); - - it('prevents double approval on a task', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - - await member2.post(`/tasks/${task._id}/assign/${member._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - await member2.post(`/tasks/${task._id}/approve/${member._id}`); - - await expect(user.post(`/tasks/${task._id}/approve/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('canOnlyApproveTaskOnce'), - }); - }); - - it('prevents approving a task if it is not waiting for approval', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); - - await expect(user.post(`/tasks/${task._id}/approve/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalWasNotRequested'), - }); - }); - - it('completes master task when single-completion task is approved', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: true, - sharedCompletion: 'singleCompletion', - }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); - - const groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`); - - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); - - expect(masterTask.completed).to.equal(true); - }); - - it('deletes other assigned user tasks when single-completion task is approved', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: true, - sharedCompletion: 'singleCompletion', - }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); - - const member2Tasks = await member2.get('/tasks/user'); - - const syncedTask2 = find( - member2Tasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - expect(syncedTask2).to.equal(undefined); - }); - - it('does not complete master task when not all user tasks are approved if all assigned must complete', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: true, - sharedCompletion: 'allAssignedCompletion', - }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); - - const groupTasks = await user.get(`/tasks/group/${guild._id}`); - - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); - - expect(masterTask.completed).to.equal(false); - }); - - it('completes master task when all user tasks are approved if all assigned must complete', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: true, - sharedCompletion: 'allAssignedCompletion', - }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - await member.post(`/tasks/${syncedTask._id}/score/up`); - const member2Tasks = await member2.get('/tasks/user'); - const member2SyncedTask = find(member2Tasks, findAssignedTask); - await member2.post(`/tasks/${member2SyncedTask._id}/score/up`); - - await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/approve/${member2._id}`); - - const groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`); - - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); - - expect(masterTask.completed).to.equal(true); - }); -}); diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js index 72542aceba..58392e85e1 100644 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js +++ b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_needs-work_userId.test.js @@ -1,4 +1,3 @@ -import { find } from 'lodash'; import { createAndPopulateGroup, translate as t, @@ -8,10 +7,6 @@ describe('POST /tasks/:id/needs-work/:userId', () => { let user; let guild; let member; let member2; let task; - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - beforeEach(async () => { const { group, members, groupLeader } = await createAndPopulateGroup({ groupDetails: { @@ -37,14 +32,15 @@ describe('POST /tasks/:id/needs-work/:userId', () => { it('errors when user is not assigned', async () => { await expect(user.post(`/tasks/${task._id}/needs-work/${member._id}`)) .to.eventually.be.rejected.and.to.eql({ - code: 404, - error: 'NotFound', - message: t('messageTaskNotFound'), + code: 400, + error: 'BadRequest', + message: 'Task not completed by this user.', }); }); it('errors when user is not the group leader', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id]); + await member.post(`/tasks/${task._id}/score/up`); await expect(member.post(`/tasks/${task._id}/needs-work/${member._id}`)) .to.eventually.be.rejected.and.to.eql({ code: 401, @@ -54,132 +50,64 @@ describe('POST /tasks/:id/needs-work/:userId', () => { }); it('marks a task as needing more work', async () => { + await member.sync(); const initialNotifications = member.notifications.length; - - await user.post(`/tasks/${task._id}/assign/${member._id}`); - - let memberTasks = await member.get('/tasks/user'); - let syncedTask = find(memberTasks, findAssignedTask); + await user.post(`/tasks/${task._id}/assign`, [member._id]); // score task to require approval - await member.post(`/tasks/${syncedTask._id}/score/up`); + await member.post(`/tasks/${task._id}/score/up`); await user.post(`/tasks/${task._id}/needs-work/${member._id}`); - [memberTasks] = await Promise.all([member.get('/tasks/user'), member.sync()]); - syncedTask = find(memberTasks, findAssignedTask); - - // Check that the notification approval request has been removed - expect(syncedTask.group.approval.requested).to.equal(false); - expect(syncedTask.group.approval.requestedDate).to.equal(undefined); - // Check that the notification is correct + await member.sync(); expect(member.notifications.length).to.equal(initialNotifications + 3); const notification = member.notifications[member.notifications.length - 1]; expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK'); - const taskText = syncedTask.text; - const managerName = user.profile.name; + const taskText = task.text; + const managerName = user.auth.local.username; expect(notification.data.message).to.equal(t('taskNeedsWork', { taskText, managerName })); - expect(notification.data.task.id).to.equal(syncedTask._id); + expect(notification.data.task.id).to.equal(task._id); expect(notification.data.task.text).to.equal(taskText); - expect(notification.data.group.id).to.equal(syncedTask.group.id); + expect(notification.data.group.id).to.equal(task.group.id); expect(notification.data.group.name).to.equal(guild.name); expect(notification.data.manager.id).to.equal(user._id); expect(notification.data.manager.name).to.equal(managerName); - - // Check that the managers' GROUP_TASK_APPROVAL notifications have been removed - await user.sync(); - - expect(user.notifications.find(n => { // eslint-disable-line arrow-body-style - return n.data.taskId === syncedTask._id && n.type === 'GROUP_TASK_APPROVAL'; - })).to.equal(undefined); }); it('allows a manager to mark a task as needing work', async () => { + await member.sync(); + const initialNotifications = member.notifications.length; await user.post(`/groups/${guild._id}/add-manager`, { managerId: member2._id, }); - await member2.post(`/tasks/${task._id}/assign/${member._id}`); - - let memberTasks = await member.get('/tasks/user'); - let syncedTask = find(memberTasks, findAssignedTask); + await member2.post(`/tasks/${task._id}/assign`, [member._id]); // score task to require approval - await member.post(`/tasks/${syncedTask._id}/score/up`); - - const initialNotifications = member.notifications.length; - + await member.post(`/tasks/${task._id}/score/up`); await member2.post(`/tasks/${task._id}/needs-work/${member._id}`); - [memberTasks] = await Promise.all([member.get('/tasks/user'), member.sync()]); - syncedTask = find(memberTasks, findAssignedTask); - - // Check that the notification approval request has been removed - expect(syncedTask.group.approval.requested).to.equal(false); - expect(syncedTask.group.approval.requestedDate).to.equal(undefined); - + await member.sync(); expect(member.notifications.length).to.equal(initialNotifications + 3); const notification = member.notifications[member.notifications.length - 1]; expect(notification.type).to.equal('GROUP_TASK_NEEDS_WORK'); - const taskText = syncedTask.text; - const managerName = member2.profile.name; + const taskText = task.text; + const managerName = member2.auth.local.username; expect(notification.data.message).to.equal(t('taskNeedsWork', { taskText, managerName })); - expect(notification.data.task.id).to.equal(syncedTask._id); + expect(notification.data.task.id).to.equal(task._id); expect(notification.data.task.text).to.equal(taskText); - expect(notification.data.group.id).to.equal(syncedTask.group.id); + expect(notification.data.group.id).to.equal(task.group.id); expect(notification.data.group.name).to.equal(guild.name); expect(notification.data.manager.id).to.equal(member2._id); expect(notification.data.manager.name).to.equal(managerName); - - // Check that the managers' GROUP_TASK_APPROVAL notifications have been removed - await Promise.all([user.sync(), member2.sync()]); - - expect(user.notifications.find(n => { // eslint-disable-line arrow-body-style - return n.data.taskId === syncedTask._id && n.type === 'GROUP_TASK_APPROVAL'; - })).to.equal(undefined); - - expect(member2.notifications.find(n => { // eslint-disable-line arrow-body-style - return n.data.taskId === syncedTask._id && n.type === 'GROUP_TASK_APPROVAL'; - })).to.equal(undefined); - }); - - it('prevents marking a task as needing work if it was already approved', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - - await member2.post(`/tasks/${task._id}/assign/${member._id}`); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - await member2.post(`/tasks/${task._id}/approve/${member._id}`); - await expect(user.post(`/tasks/${task._id}/needs-work/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('canOnlyApproveTaskOnce'), - }); - }); - - it('prevents marking a task as needing work if it is not waiting for approval', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); - - await expect(user.post(`/tasks/${task._id}/needs-work/${member._id}`)) - .to.eventually.be.rejected.and.to.eql({ - code: 401, - error: 'NotAuthorized', - message: t('taskApprovalWasNotRequested'), - }); }); }); diff --git a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js index eaa3cf6484..17d653895e 100644 --- a/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js +++ b/test/api/v3/integration/tasks/groups/POST-group_tasks_id_score_direction.test.js @@ -8,10 +8,6 @@ describe('POST /tasks/:id/score/:direction', () => { let user; let guild; let member; let member2; let task; - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - beforeEach(async () => { const { group, members, groupLeader } = await createAndPopulateGroup({ groupDetails: { @@ -30,209 +26,50 @@ describe('POST /tasks/:id/score/:direction', () => { task = await user.post(`/tasks/group/${guild._id}`, { text: 'test todo', type: 'todo', - requiresApproval: true, }); - await user.post(`/tasks/${task._id}/assign/${member._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id]); }); - it('prevents user from scoring a task that needs to be approved', async () => { - await user.update({ - 'preferences.language': 'cs', - }); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - const direction = 'up'; - - const response = await member.post(`/tasks/${syncedTask._id}/score/${direction}`); - - expect(response.data.requiresApproval).to.equal(true); - expect(response.message).to.equal(t('taskApprovalHasBeenRequested')); - - const updatedTask = await member.get(`/tasks/${syncedTask._id}`); - - await user.sync(); - - expect(user.notifications.length).to.equal(3); - expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL'); - expect(user.notifications[2].data.message).to.equal(t('userHasRequestedTaskApproval', { - user: member.auth.local.username, - taskName: updatedTask.text, - taskId: updatedTask._id, - direction, - }, 'cs')); // This test only works if we have the notification translated - expect(user.notifications[2].data.groupId).to.equal(guild._id); - - expect(updatedTask.group.approval.requested).to.equal(true); - expect(updatedTask.group.approval.requestedDate).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type - }); - - it('sends notifications to all managers', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - const direction = 'up'; - - await member.post(`/tasks/${syncedTask._id}/score/${direction}`); - const updatedTask = await member.get(`/tasks/${syncedTask._id}`); - await user.sync(); - await member2.sync(); - - expect(user.notifications.length).to.equal(3); - expect(user.notifications[2].type).to.equal('GROUP_TASK_APPROVAL'); - expect(user.notifications[2].data.message).to.equal(t('userHasRequestedTaskApproval', { - user: member.auth.local.username, - taskName: updatedTask.text, - taskId: updatedTask._id, - direction, - })); - expect(user.notifications[2].data.groupId).to.equal(guild._id); - - expect(member2.notifications.length).to.equal(2); - expect(member2.notifications[1].type).to.equal('GROUP_TASK_APPROVAL'); - expect(member2.notifications[1].data.message).to.equal(t('userHasRequestedTaskApproval', { - user: member.auth.local.username, - taskName: updatedTask.text, - taskId: updatedTask._id, - direction, - })); - expect(member2.notifications[1].data.groupId).to.equal(guild._id); - }); - - it('errors when approval has already been requested', async () => { - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - - const response = await member.post(`/tasks/${syncedTask._id}/score/up`); - expect(response.data.requiresApproval).to.equal(true); - expect(response.message).to.equal(t('taskRequiresApproval')); - }); - - it('allows a user to score an approved task', async () => { - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - - await user.post(`/tasks/${task._id}/approve/${member._id}`); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - const updatedTask = await member.get(`/tasks/${syncedTask._id}`); - - expect(updatedTask.completed).to.equal(true); - expect(updatedTask.dateCompleted).to.be.a('string'); // date gets converted to a string as json doesn't have a Date type - }); - - it('completes master task when single-completion task is completed', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: false, - sharedCompletion: 'singleCompletion', - }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - const memberTasks = await member.get('/tasks/user'); - - const syncedTask = find( - memberTasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - await member.post(`/tasks/${syncedTask._id}/score/up`); + it('completes single-assigned task', async () => { + await member.post(`/tasks/${task._id}/score/up`); const groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`); - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); + const sourceTask = find(groupTasks, groupTask => groupTask._id === task._id); - expect(masterTask.completed).to.equal(true); + expect(sourceTask.completed).to.equal(true); }); - it('deletes other assigned user tasks when single-completion task is completed', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: false, - sharedCompletion: 'singleCompletion', + it('errors when task has already been completed', async () => { + await member.post(`/tasks/${task._id}/score/up`); + + await expect(member.post(`/tasks/${task._id}/score/up`)).to.be.rejected.and.to.eventually.eql({ + code: 401, + error: 'NotAuthorized', + message: t('sessionOutdated'), }); - - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - const memberTasks = await member.get('/tasks/user'); - - const syncedTask = find( - memberTasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - - const member2Tasks = await member2.get('/tasks/user'); - - const syncedTask2 = find( - member2Tasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - expect(syncedTask2).to.equal(undefined); }); - it('does not complete master task when not all user tasks are completed if all assigned must complete', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: false, - sharedCompletion: 'allAssignedCompletion', - }); + it('does not complete multi-assigned task when not all assignees have completed', async () => { + await user.post(`/tasks/${task._id}/assign`, [member2._id]); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - const memberTasks = await member.get('/tasks/user'); - - const syncedTask = find( - memberTasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - await member.post(`/tasks/${syncedTask._id}/score/up`); + await member.post(`/tasks/${task._id}/score/up`); const groupTasks = await user.get(`/tasks/group/${guild._id}`); - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); + const sourceTask = find(groupTasks, groupTask => groupTask._id === task._id); - expect(masterTask.completed).to.equal(false); + expect(sourceTask.completed).to.equal(false); }); - it('completes master task when all user tasks are completed if all assigned must complete', async () => { - const sharedCompletionTask = await user.post(`/tasks/group/${guild._id}`, { - text: 'shared completion todo', - type: 'todo', - requiresApproval: false, - sharedCompletion: 'allAssignedCompletion', - }); + it('completes multi-assigned task when all assignees have completed', async () => { + await user.post(`/tasks/${task._id}/assign`, [member2._id]); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member._id}`); - await user.post(`/tasks/${sharedCompletionTask._id}/assign/${member2._id}`); - const memberTasks = await member.get('/tasks/user'); - const member2Tasks = await member2.get('/tasks/user'); - const syncedTask = find( - memberTasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - const syncedTask2 = find( - member2Tasks, - memberTask => memberTask.group.taskId === sharedCompletionTask._id, - ); - - await member.post(`/tasks/${syncedTask._id}/score/up`); - await member2.post(`/tasks/${syncedTask2._id}/score/up`); + await member.post(`/tasks/${task._id}/score/up`); + await member2.post(`/tasks/${task._id}/score/up`); const groupTasks = await user.get(`/tasks/group/${guild._id}?type=completedTodos`); - const masterTask = find(groupTasks, groupTask => groupTask._id === sharedCompletionTask._id); + const sourceTask = find(groupTasks, groupTask => groupTask._id === task._id); - expect(masterTask.completed).to.equal(true); + expect(sourceTask.completed).to.equal(true); }); }); diff --git a/test/api/v3/integration/tasks/groups/POST-tasks_group_id_assign_user_id.test.js b/test/api/v3/integration/tasks/groups/POST-tasks_group_id_assign_user_id.test.js index 71b29a1530..2e122e78fc 100644 --- a/test/api/v3/integration/tasks/groups/POST-tasks_group_id_assign_user_id.test.js +++ b/test/api/v3/integration/tasks/groups/POST-tasks_group_id_assign_user_id.test.js @@ -39,7 +39,7 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { }); it('returns error when task is not found', async () => { - await expect(user.post(`/tasks/${generateUUID()}/assign/${member._id}`)) + await expect(user.post(`/tasks/${generateUUID()}/assign`, [member._id])) .to.eventually.be.rejected.and.eql({ code: 404, error: 'NotFound', @@ -56,7 +56,7 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { notes: 1976, }); - await expect(user.post(`/tasks/${nonGroupTask._id}/assign/${member._id}`)) + await expect(user.post(`/tasks/${nonGroupTask._id}/assign`, [member._id])) .to.eventually.be.rejected.and.eql({ code: 401, error: 'NotAuthorized', @@ -67,7 +67,7 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { it('returns error when user is not a member of the group', async () => { const nonUser = await generateUser(); - await expect(nonUser.post(`/tasks/${task._id}/assign/${member._id}`)) + await expect(nonUser.post(`/tasks/${task._id}/assign`, [member._id])) .to.eventually.be.rejected.and.eql({ code: 404, error: 'NotFound', @@ -76,7 +76,7 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { }); it('returns error when non leader tries to create a task', async () => { - await expect(member2.post(`/tasks/${task._id}/assign/${member._id}`)) + await expect(member2.post(`/tasks/${task._id}/assign`, [member._id])) .to.eventually.be.rejected.and.eql({ code: 401, error: 'NotAuthorized', @@ -84,49 +84,23 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { }); }); - it('allows user to assign themselves (claim)', async () => { - await member.post(`/tasks/${task._id}/assign/${member._id}`); - - const groupTask = await user.get(`/tasks/group/${guild._id}`); - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - expect(groupTask[0].group.assignedUsers).to.contain(member._id); - expect(syncedTask).to.exist; - }); - - it('sends notifications to group leader and managers when a task is claimed', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - await member.post(`/tasks/${task._id}/assign/${member._id}`); - await user.sync(); - await member2.sync(); - const groupTask = await user.get(`/tasks/group/${guild._id}`); - - expect(user.notifications.length).to.equal(3); // includes Guild Joined achievement - expect(user.notifications[2].type).to.equal('GROUP_TASK_CLAIMED'); - expect(user.notifications[2].data.taskId).to.equal(groupTask[0]._id); - expect(user.notifications[2].data.groupId).to.equal(guild._id); - expect(member2.notifications.length).to.equal(2); - expect(member2.notifications[1].type).to.equal('GROUP_TASK_CLAIMED'); - expect(member2.notifications[1].data.taskId).to.equal(groupTask[0]._id); - expect(member2.notifications[1].data.groupId).to.equal(guild._id); - }); - it('assigns a task to a user', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id]); const groupTask = await user.get(`/tasks/group/${guild._id}`); + await member.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); expect(groupTask[0].group.assignedUsers).to.contain(member._id); + expect(groupTask[0].group.assignedUsersDetail[member._id]).to.exist; expect(syncedTask).to.exist; }); it('sends a notification to assigned user', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id]); await member.sync(); const groupTask = await user.get(`/tasks/group/${guild._id}`); @@ -137,20 +111,27 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { }); it('assigns a task to multiple users', async () => { - await user.post(`/tasks/${task._id}/assign/${member._id}`); - await user.post(`/tasks/${task._id}/assign/${member2._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id, member2._id]); const groupTask = await user.get(`/tasks/group/${guild._id}`); + await member.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const memberTasks = await member.get('/tasks/user'); const member1SyncedTask = find(memberTasks, findAssignedTask); + await member2.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const member2Tasks = await member2.get('/tasks/user'); const member2SyncedTask = find(member2Tasks, findAssignedTask); expect(groupTask[0].group.assignedUsers).to.contain(member._id); - expect(groupTask[0].group.assignedUsers).to.contain(member2._id); + expect(groupTask[0].group.assignedUsersDetail[member._id]).to.exist; expect(member1SyncedTask).to.exist; + expect(groupTask[0].group.assignedUsers).to.contain(member2._id); + expect(groupTask[0].group.assignedUsersDetail[member2._id]).to.exist; expect(member2SyncedTask).to.exist; }); @@ -159,13 +140,17 @@ describe('POST /tasks/:taskId/assign/:memberId', () => { managerId: member2._id, }); - await member2.post(`/tasks/${task._id}/assign/${member._id}`); + await member2.post(`/tasks/${task._id}/assign`, [member._id]); const groupTask = await member2.get(`/tasks/group/${guild._id}`); + await member.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const memberTasks = await member.get('/tasks/user'); const syncedTask = find(memberTasks, findAssignedTask); expect(groupTask[0].group.assignedUsers).to.contain(member._id); + expect(groupTask[0].group.assignedUsersDetail[member._id]).to.exist; expect(syncedTask).to.exist; }); }); diff --git a/test/api/v3/integration/tasks/groups/POST-tasks_task_id_unassign.test.js b/test/api/v3/integration/tasks/groups/POST-tasks_task_id_unassign.test.js index 83d67246d6..117c9f760f 100644 --- a/test/api/v3/integration/tasks/groups/POST-tasks_task_id_unassign.test.js +++ b/test/api/v3/integration/tasks/groups/POST-tasks_task_id_unassign.test.js @@ -37,7 +37,7 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => { notes: 1976, }); - await user.post(`/tasks/${task._id}/assign/${member._id}`); + await user.post(`/tasks/${task._id}/assign`, [member._id]); }); it('returns error when task is not found', async () => { @@ -96,7 +96,7 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => { }); it('unassigns a user and only that user from a task', async () => { - await user.post(`/tasks/${task._id}/assign/${member2._id}`); + await user.post(`/tasks/${task._id}/assign`, [member2._id]); await user.post(`/tasks/${task._id}/unassign/${member._id}`); @@ -105,6 +105,9 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => { const memberTasks = await member.get('/tasks/user'); const member1SyncedTask = find(memberTasks, findAssignedTask); + await member2.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const member2Tasks = await member2.get('/tasks/user'); const member2SyncedTask = find(member2Tasks, findAssignedTask); @@ -130,20 +133,7 @@ describe('POST /tasks/:taskId/unassign/:memberId', () => { expect(syncedTask).to.not.exist; }); - it('allows a user to unassign themselves', async () => { - await member.post(`/tasks/${task._id}/unassign/${member._id}`); - - const groupTask = await user.get(`/tasks/group/${guild._id}`); - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - expect(groupTask[0].group.assignedUsers).to.not.contain(member._id); - expect(syncedTask).to.not.exist; - }); - - // @TODO: Which do we want? The user to unassign themselves or not. This test was in - // here, but then we had a request to allow to unaissgn. - xit('returns error when non leader tries to unassign their a task', async () => { + it('returns error when non leader tries to unassign a task', async () => { await expect(member.post(`/tasks/${task._id}/unassign/${member._id}`)) .to.eventually.be.rejected.and.eql({ code: 401, diff --git a/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js b/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js index abfd5ae629..330983c70c 100644 --- a/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js +++ b/test/api/v3/integration/tasks/groups/PUT-group_task_id.test.js @@ -1,4 +1,3 @@ -import { find } from 'lodash'; import { createAndPopulateGroup, translate as t, } from '../../../../../helpers/api-integration/v3'; @@ -11,10 +10,6 @@ describe('PUT /tasks/:id', () => { let habit; let todo; - function findAssignedTask (memberTask) { - return memberTask.group.id === guild._id; - } - beforeEach(async () => { const { group, members, groupLeader } = await createAndPopulateGroup({ groupDetails: { @@ -44,8 +39,7 @@ describe('PUT /tasks/:id', () => { notes: 1976, }); - await user.post(`/tasks/${habit._id}/assign/${member._id}`); - await user.post(`/tasks/${habit._id}/assign/${member2._id}`); + await user.post(`/tasks/${habit._id}/assign`, [member._id, member2._id]); }); it('updates a group task', async () => { @@ -56,28 +50,6 @@ describe('PUT /tasks/:id', () => { expect(savedHabit.notes).to.eql('some new notes'); }); - it('updates a group task - approval is required', async () => { - // allow to manage - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member._id, - }); - - // change the habit - habit = await member.put(`/tasks/${habit._id}`, { - text: 'new text!', - requiresApproval: true, - }); - - const memberTasks = await member2.get('/tasks/user'); - const syncedTask = find(memberTasks, memberTask => memberTask.group.taskId === habit._id); - - // score up to trigger approval - const response = await member2.post(`/tasks/${syncedTask._id}/score/up`); - - expect(response.data.requiresApproval).to.equal(true); - expect(response.message).to.equal(t('taskApprovalHasBeenRequested')); - }); - it('member updates a group task value - not allowed', async () => { // change the todo await expect(member.put(`/tasks/${habit._id}`, { @@ -120,7 +92,7 @@ describe('PUT /tasks/:id', () => { ], }); - await user.post(`/tasks/${habit._id}/assign/${member._id}`); + await user.post(`/tasks/${habit._id}/assign`, [member._id]); // change the checklist text habit = await user.put(`/tasks/${habit._id}`, { @@ -137,63 +109,4 @@ describe('PUT /tasks/:id', () => { expect(habit.checklist.length).to.eql(2); }); - - it('updates the linked tasks', async () => { - await user.put(`/tasks/${habit._id}`, { - text: 'some new text', - up: false, - down: false, - notes: 'some new notes', - }); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - expect(syncedTask.text).to.eql('some new text'); - expect(syncedTask.up).to.eql(false); - expect(syncedTask.down).to.eql(false); - }); - - it('updates the linked tasks for all assigned users', async () => { - await user.put(`/tasks/${habit._id}`, { - text: 'some new text', - up: false, - down: false, - notes: 'some new notes', - }); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - const member2Tasks = await member2.get('/tasks/user'); - const member2SyncedTask = find(member2Tasks, findAssignedTask); - - expect(syncedTask.text).to.eql('some new text'); - expect(syncedTask.up).to.eql(false); - expect(syncedTask.down).to.eql(false); - - expect(member2SyncedTask.text).to.eql('some new text'); - expect(member2SyncedTask.up).to.eql(false); - expect(member2SyncedTask.down).to.eql(false); - }); - - it('updates the linked tasks', async () => { - await user.post(`/groups/${guild._id}/add-manager`, { - managerId: member2._id, - }); - - await member2.put(`/tasks/${habit._id}`, { - text: 'some new text', - up: false, - down: false, - notes: 'some new notes', - }); - - const memberTasks = await member.get('/tasks/user'); - const syncedTask = find(memberTasks, findAssignedTask); - - expect(syncedTask.text).to.eql('some new text'); - expect(syncedTask.up).to.eql(false); - expect(syncedTask.down).to.eql(false); - }); }); diff --git a/test/api/v3/integration/user/POST-user_class_cast_spellId.test.js b/test/api/v3/integration/user/POST-user_class_cast_spellId.test.js index df7676b945..eeda226b45 100644 --- a/test/api/v3/integration/user/POST-user_class_cast_spellId.test.js +++ b/test/api/v3/integration/user/POST-user_class_cast_spellId.test.js @@ -145,19 +145,16 @@ describe('POST /user/class/cast/:spellId', () => { text: 'todo group', type: 'todo', }); - await groupLeader.post(`/tasks/${groupTask._id}/assign/${groupLeader._id}`); - const memberTasks = await groupLeader.get('/tasks/user'); - const syncedGroupTask = find(memberTasks, memberTask => memberTask.group.id === group._id); - + await groupLeader.post(`/tasks/${groupTask._id}/assign`, [groupLeader._id]); await groupLeader.update({ 'stats.class': 'rogue', 'stats.lvl': 11 }); await sleep(0.5); await groupLeader.sync(); - await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${syncedGroupTask._id}`)) + await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${groupTask._id}`)) .to.eventually.be.rejected.and.eql({ - code: 400, - error: 'BadRequest', - message: t('groupTasksNoCast'), + code: 404, + error: 'NotFound', + message: t('messageTaskNotFound'), }); }); @@ -279,7 +276,10 @@ describe('POST /user/class/cast/:spellId', () => { type: 'todo', }); await user.update({ 'stats.class': 'healer', 'stats.mp': 200, 'stats.lvl': 15 }); - await user.post(`/tasks/${groupTask._id}/assign/${user._id}`); + await user.post(`/tasks/${groupTask._id}/assign`, [user._id]); + await user.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); await user.post('/user/class/cast/brightness'); await user.sync(); diff --git a/test/api/v3/integration/user/POST-user_reset.test.js b/test/api/v3/integration/user/POST-user_reset.test.js index 5d750fde98..a3c00a90a3 100644 --- a/test/api/v3/integration/user/POST-user_reset.test.js +++ b/test/api/v3/integration/user/POST-user_reset.test.js @@ -100,11 +100,14 @@ describe('POST /user/reset', () => { text: 'todo group', type: 'todo', }); - await user.post(`/tasks/${groupTask._id}/assign/${user._id}`); + await user.post(`/tasks/${groupTask._id}/assign`, [user._id]); await user.post('/user/reset'); await user.sync(); + await user.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const memberTasks = await user.get('/tasks/user'); const syncedGroupTask = find(memberTasks, memberTask => memberTask.group.id === guild._id); diff --git a/test/api/v3/integration/user/PUT-user.test.js b/test/api/v3/integration/user/PUT-user.test.js index 1a0451318f..ced94b2232 100644 --- a/test/api/v3/integration/user/PUT-user.test.js +++ b/test/api/v3/integration/user/PUT-user.test.js @@ -35,7 +35,7 @@ describe('PUT /user', () => { })).to.eventually.be.rejected.and.eql({ code: 400, error: 'BadRequest', - message: 'mustBeArray', + message: 'Tag list must be an array.', }); }); diff --git a/test/api/v4/user/POST-user_class_cast_spellId.test.js b/test/api/v4/user/POST-user_class_cast_spellId.test.js index b9382bba3d..8602cb7c2a 100644 --- a/test/api/v4/user/POST-user_class_cast_spellId.test.js +++ b/test/api/v4/user/POST-user_class_cast_spellId.test.js @@ -130,19 +130,16 @@ describe('POST /user/class/cast/:spellId', () => { text: 'todo group', type: 'todo', }); - await groupLeader.post(`/tasks/${groupTask._id}/assign/${groupLeader._id}`); - const memberTasks = await groupLeader.get('/tasks/user'); - const syncedGroupTask = find(memberTasks, memberTask => memberTask.group.id === group._id); - + await groupLeader.post(`/tasks/${groupTask._id}/assign`, [groupLeader._id]); await groupLeader.update({ 'stats.class': 'rogue', 'stats.lvl': 11 }); await sleep(0.5); await groupLeader.sync(); - await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${syncedGroupTask._id}`)) + await expect(groupLeader.post(`/user/class/cast/pickPocket?targetId=${groupTask._id}`)) .to.eventually.be.rejected.and.eql({ - code: 400, - error: 'BadRequest', - message: t('groupTasksNoCast'), + code: 404, + error: 'NotFound', + message: t('messageTaskNotFound'), }); }); @@ -247,7 +244,10 @@ describe('POST /user/class/cast/:spellId', () => { type: 'todo', }); await user.update({ 'stats.class': 'healer', 'stats.mp': 200, 'stats.lvl': 15 }); - await user.post(`/tasks/${groupTask._id}/assign/${user._id}`); + await user.post(`/tasks/${groupTask._id}/assign`, [user._id]); + await user.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); await user.post('/user/class/cast/brightness'); await user.sync(); diff --git a/test/api/v4/user/POST-user_reset.test.js b/test/api/v4/user/POST-user_reset.test.js index ced9126eb2..c96e30f93a 100644 --- a/test/api/v4/user/POST-user_reset.test.js +++ b/test/api/v4/user/POST-user_reset.test.js @@ -100,11 +100,14 @@ describe('POST /user/reset', () => { text: 'todo group', type: 'todo', }); - await user.post(`/tasks/${groupTask._id}/assign/${user._id}`); + await user.post(`/tasks/${groupTask._id}/assign`, [user._id]); await user.post('/user/reset'); await user.sync(); + await user.put('/user', { + 'preferences.tasks.mirrorGroupTasks': [guild._id], + }); const memberTasks = await user.get('/tasks/user'); const syncedGroupTask = find(memberTasks, memberTask => memberTask.group.id === guild._id); diff --git a/test/api/v4/user/PUT-user.test.js b/test/api/v4/user/PUT-user.test.js index a588a6f386..1abf4f8d24 100644 --- a/test/api/v4/user/PUT-user.test.js +++ b/test/api/v4/user/PUT-user.test.js @@ -34,7 +34,7 @@ describe('PUT /user', () => { })).to.eventually.be.rejected.and.eql({ code: 400, error: 'BadRequest', - message: 'mustBeArray', + message: 'Tag list must be an array.', }); }); diff --git a/test/common/ops/scoreTask.test.js b/test/common/ops/scoreTask.test.js index 7282359aff..bee676a1fd 100644 --- a/test/common/ops/scoreTask.test.js +++ b/test/common/ops/scoreTask.test.js @@ -249,18 +249,6 @@ describe('shared.ops.scoreTask', () => { expect(ref.afterUser._tmp.quest.progressDelta).to.eql(secondTaskDelta); }); - it('does not modify stats when task need approval', () => { - todo.group.approval.required = true; - options = { - user: ref.afterUser, task: todo, direction: 'up', times: 5, cron: false, - }; - scoreTask(options); - - expect(ref.afterUser.stats.hp).to.eql(50); - expect(ref.afterUser.stats.exp).to.equal(ref.beforeUser.stats.exp); - expect(ref.afterUser.stats.gp).to.equal(ref.beforeUser.stats.gp); - }); - context('habits', () => { it('up', () => { options = { diff --git a/website/client/package-lock.json b/website/client/package-lock.json index 033c3516a6..0f25f93dfb 100644 --- a/website/client/package-lock.json +++ b/website/client/package-lock.json @@ -1799,26 +1799,26 @@ } }, "@babel/plugin-proposal-optional-chaining": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.6.tgz", - "integrity": "sha512-PatI6elL5eMzoypFAiYDpYQyMtXTn+iMhuxxQt5mAXD4fEmKorpSI3PHd+i3JXBJN3xyA6MvJv7at23HffFHwA==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.18.9.tgz", + "integrity": "sha512-v5nwt4IqBXihxGsW2QmCWMDS3B3bzGIk/EQVZz2ei7f3NJl8NzAJVvUmpDW5q1CRNY+Beb/k58UAH1Km1N411w==", "requires": { - "@babel/helper-plugin-utils": "^7.18.6", - "@babel/helper-skip-transparent-expression-wrappers": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.9", + "@babel/helper-skip-transparent-expression-wrappers": "^7.18.9", "@babel/plugin-syntax-optional-chaining": "^7.8.3" }, "dependencies": { "@babel/helper-plugin-utils": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.6.tgz", - "integrity": "sha512-gvZnm1YAAxh13eJdkb9EWHBnF3eAub3XTLCZEehHT2kWxiKVRL64+ae5Y6Ivne0mVHmMYKT+xWgZO+gQhuLUBg==" + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz", + "integrity": "sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==" }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.6.tgz", - "integrity": "sha512-4KoLhwGS9vGethZpAhYnMejWkX64wsnHPDwvOsKWU6Fg4+AlK2Jz3TyjQLMEPvz+1zemi/WBdkYxCD0bAfIkiw==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.18.9.tgz", + "integrity": "sha512-imytd2gHi3cJPsybLRbmFrF7u5BIEuI2cNheyKi3/iOBC63kNn3q8Crn2xVuESli0aM4KYsyEqKyS7lFL8YVtw==", "requires": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.18.9" } }, "@babel/helper-validator-identifier": { @@ -1827,9 +1827,9 @@ "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==" }, "@babel/types": { - "version": "7.18.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.7.tgz", - "integrity": "sha512-QG3yxTcTIBoAcQmkCs+wAPYZhu7Dk9rXKacINfNbdJDNERTbLQbHGyVG8q/YGMPeCJRIhSY0+fTc5+xuh6WPSQ==", + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.18.9.tgz", + "integrity": "sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==", "requires": { "@babel/helper-validator-identifier": "^7.18.6", "to-fast-properties": "^2.0.0" @@ -4382,6 +4382,49 @@ "postcss": "^7.0.0" } }, + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@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==" + }, + "@jridgewell/source-map": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", + "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.14", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz", + "integrity": "sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "@mdx-js/mdx": { "version": "1.6.22", "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-1.6.22.tgz", @@ -6446,6 +6489,11 @@ "@types/react": "*" } }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -7148,20 +7196,14 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } } }, "terser-webpack-plugin": { @@ -9405,6 +9447,11 @@ "@types/react": "*" } }, + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==" + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -9947,20 +9994,14 @@ } }, "terser": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz", - "integrity": "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==", + "version": "5.14.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", + "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", "requires": { + "@jridgewell/source-map": "^0.3.2", + "acorn": "^8.5.0", "commander": "^2.20.0", - "source-map": "~0.7.2", "source-map-support": "~0.5.20" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==" - } } }, "terser-webpack-plugin": { @@ -15839,9 +15880,9 @@ } }, "core-js": { - "version": "3.23.5", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.23.5.tgz", - "integrity": "sha512-7Vh11tujtAZy82da4duVreQysIoO2EvVrur7y6IzZkH1IHPSekuDi8Vuw1+YKjkbfWLRD7Nc9ICQ/sIUDutcyg==" + "version": "3.24.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.24.1.tgz", + "integrity": "sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==" }, "core-js-compat": { "version": "3.11.0", @@ -16293,7 +16334,7 @@ "de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", - "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=" + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==" }, "debug": { "version": "4.1.1", @@ -16771,9 +16812,9 @@ } }, "dompurify": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.8.tgz", - "integrity": "sha512-eVhaWoVibIzqdGYjwsBWodIQIaXFSB+cKDf4cfxLMsK0xiud6SE+/WCVx/Xw/UwQsa4cS3T2eITcdtmTg2UKcw==" + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.10.tgz", + "integrity": "sha512-o7Fg/AgC7p/XpKjf/+RC3Ok6k4St5F7Q6q6+Nnm3p2zGWioAY6dh0CbbuwOhH2UcSzKsdniE/YnE2/92JcsA+g==" }, "domutils": { "version": "1.7.0", @@ -27297,9 +27338,9 @@ "integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==" }, "terser": { - "version": "4.6.7", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.6.7.tgz", - "integrity": "sha512-fmr7M1f7DBly5cX2+rFDvmGBAaaZyPrHYK4mMdHEDAdNTqXSZgSOfqsfGq2HqPGT/1V0foZZuCZFx8CHKgAk3g==", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", "requires": { "commander": "^2.20.0", "source-map": "~0.6.1", @@ -28265,9 +28306,60 @@ "integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=" }, "vue": { - "version": "2.6.14", - "resolved": "https://registry.npmjs.org/vue/-/vue-2.6.14.tgz", - "integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ==" + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/vue/-/vue-2.7.8.tgz", + "integrity": "sha512-ncwlZx5qOcn754bCu5/tS/IWPhXHopfit79cx+uIlLMyt3vCMGcXai5yCG5y+I6cDmEj4ukRYyZail9FTQh7lQ==", + "requires": { + "@vue/compiler-sfc": "2.7.8", + "csstype": "^3.1.0" + }, + "dependencies": { + "@babel/parser": { + "version": "7.18.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.18.9.tgz", + "integrity": "sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==" + }, + "@vue/compiler-sfc": { + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-2.7.8.tgz", + "integrity": "sha512-2DK4YWKfgLnW9VDR9gnju1gcYRk3flKj8UNsms7fsRmFcg35slVTZEkqwBtX+wJBXaamFfn6NxSsZh3h12Ix/Q==", + "requires": { + "@babel/parser": "^7.18.4", + "postcss": "^8.4.14", + "source-map": "^0.6.1" + } + }, + "csstype": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", + "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==" + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + } + } }, "vue-cli-plugin-storybook": { "version": "2.1.0", @@ -28584,12 +28676,12 @@ } }, "vue-template-compiler": { - "version": "2.6.14", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.14.tgz", - "integrity": "sha512-ODQS1SyMbjKoO1JBJZojSw6FE4qnh9rIpUZn2EUT86FKizx9uH5z6uXiIrm4/Nb/gwxTi/o17ZDEGWAXHvtC7g==", + "version": "2.7.8", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.8.tgz", + "integrity": "sha512-eQqdcUpJKJpBRPDdxCNsqUoT0edNvdt1jFjtVnVS/LPPmr0BU2jWzXlrf6BVMeODtdLewB3j8j3WjNiB+V+giw==", "requires": { "de-indent": "^1.0.2", - "he": "^1.1.0" + "he": "^1.2.0" } }, "vue-template-es2015-compiler": { diff --git a/website/client/package.json b/website/client/package.json index b06039e038..de0c012ae1 100644 --- a/website/client/package.json +++ b/website/client/package.json @@ -32,8 +32,8 @@ "bootstrap": "^4.6.0", "bootstrap-vue": "^2.22.0", "chai": "^4.3.6", - "core-js": "^3.23.5", - "dompurify": "^2.3.8", + "core-js": "^3.24.1", + "dompurify": "^2.3.10", "eslint": "^6.8.0", "eslint-config-habitrpg": "^6.2.0", "eslint-plugin-mocha": "^5.3.0", @@ -55,16 +55,16 @@ "svgo-loader": "^2.2.1", "uuid": "^8.3.2", "validator": "^13.7.0", - "vue": "^2.6.14", + "vue": "^2.7.8", "vue-cli-plugin-storybook": "2.1.0", "vue-mugen-scroll": "^0.2.6", "vue-router": "^3.5.4", - "vue-template-compiler": "^2.6.14", + "vue-template-compiler": "^2.7.8", "vuedraggable": "^2.24.3", "vuejs-datepicker": "git://github.com/habitrpg/vuejs-datepicker.git#153d339e4dbebb73733658aeda1d5b7fcc55b0a0", "webpack": "^4.46.0" }, "devDependencies": { - "@babel/plugin-proposal-optional-chaining": "^7.18.6" + "@babel/plugin-proposal-optional-chaining": "^7.18.9" } } diff --git a/website/client/scripts/npm-postinstall.js b/website/client/scripts/npm-postinstall.js index d710bc97aa..ed949bb316 100644 --- a/website/client/scripts/npm-postinstall.js +++ b/website/client/scripts/npm-postinstall.js @@ -7,7 +7,7 @@ if (process.env.NODE_ENV === 'production') { stdio: 'inherit', }); - execSync('npm run storybook:build', { + /* execSync('npm run storybook:build', { stdio: 'inherit', - }); + }); */ } diff --git a/website/client/src/assets/css/sprites/spritesmith-main.css b/website/client/src/assets/css/sprites/spritesmith-main.css index 7c30e005ba..277ff3f148 100644 --- a/website/client/src/assets/css/sprites/spritesmith-main.css +++ b/website/client/src/assets/css/sprites/spritesmith-main.css @@ -463,6 +463,11 @@ width: 48px; height: 52px; } +.achievement-woodlandWizard2x { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/achievement-woodlandWizard2x.png'); + width: 60px; + height: 64px; +} .achievement-zodiac2x { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/achievement-zodiac2x.png'); width: 60px; @@ -565,6 +570,11 @@ width: 141px; height: 147px; } +.background_autumn_picnic { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_autumn_picnic.png'); + width: 141px; + height: 147px; +} .background_autumn_poplars { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_autumn_poplars.png'); width: 141px; @@ -690,6 +700,11 @@ width: 141px; height: 147px; } +.background_by_a_campfire { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_by_a_campfire.png'); + width: 141px; + height: 147px; +} .background_camping_out { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_camping_out.png'); width: 141px; @@ -1354,6 +1369,11 @@ width: 141px; height: 147px; } +.background_messy_room { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_messy_room.png'); + width: 141px; + height: 147px; +} .background_meteor_shower { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_meteor_shower.png'); width: 141px; @@ -1424,6 +1444,11 @@ width: 141px; height: 147px; } +.background_old_photo { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_old_photo.png'); + width: 141px; + height: 147px; +} .background_on_a_castle_wall { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_on_a_castle_wall.png'); width: 141px; @@ -1509,6 +1534,11 @@ width: 141px; height: 147px; } +.background_rainbow_eucalyptus { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rainbow_eucalyptus.png'); + width: 141px; + height: 147px; +} .background_rainbow_meadow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_rainbow_meadow.png'); width: 141px; @@ -1819,6 +1849,11 @@ width: 141px; height: 147px; } +.background_theatre_stage { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_theatre_stage.png'); + width: 141px; + height: 147px; +} .background_throne_room { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/background_throne_room.png'); width: 141px; @@ -2106,6 +2141,11 @@ width: 68px; height: 68px; } +.icon_background_autumn_picnic { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_autumn_picnic.png'); + width: 68px; + height: 68px; +} .icon_background_autumn_poplars { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_autumn_poplars.png'); width: 68px; @@ -2231,6 +2271,11 @@ width: 68px; height: 68px; } +.icon_background_by_a_campfire { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_by_a_campfire.png'); + width: 68px; + height: 68px; +} .icon_background_camping_out { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_camping_out.png'); width: 68px; @@ -2900,6 +2945,11 @@ width: 68px; height: 68px; } +.icon_background_messy_room { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_messy_room.png'); + width: 68px; + height: 68px; +} .icon_background_meteor_shower { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_meteor_shower.png'); width: 68px; @@ -2970,6 +3020,11 @@ width: 68px; height: 68px; } +.icon_background_old_photo { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_old_photo.png'); + width: 68px; + height: 68px; +} .icon_background_on_a_castle_wall { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_on_a_castle_wall.png'); width: 68px; @@ -3055,6 +3110,11 @@ width: 68px; height: 68px; } +.icon_background_rainbow_eucalyptus { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_rainbow_eucalyptus.png'); + width: 68px; + height: 68px; +} .icon_background_rainbow_meadow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_rainbow_meadow.png'); width: 68px; @@ -3370,6 +3430,11 @@ width: 68px; height: 68px; } +.icon_background_theatre_stage { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_theatre_stage.png'); + width: 68px; + height: 68px; +} .icon_background_throne_room { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/icon_background_throne_room.png'); width: 68px; @@ -18475,6 +18540,11 @@ width: 114px; height: 87px; } +.eyewear_armoire_comedyMask { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_armoire_comedyMask.png'); + width: 114px; + height: 90px; +} .eyewear_armoire_goofyGlasses { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_armoire_goofyGlasses.png'); width: 90px; @@ -18485,6 +18555,11 @@ width: 90px; height: 90px; } +.eyewear_armoire_tragedyMask { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_armoire_tragedyMask.png'); + width: 114px; + height: 90px; +} .headAccessory_armoire_comicalArrow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/headAccessory_armoire_comicalArrow.png'); width: 90px; @@ -18970,6 +19045,11 @@ width: 90px; height: 90px; } +.shield_armoire_dustpan { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_dustpan.png'); + width: 114px; + height: 90px; +} .shield_armoire_fancyBlownGlassVase { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_armoire_fancyBlownGlassVase.png'); width: 114px; @@ -19685,6 +19765,11 @@ width: 68px; height: 68px; } +.shop_eyewear_armoire_comedyMask { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_eyewear_armoire_comedyMask.png'); + width: 68px; + height: 68px; +} .shop_eyewear_armoire_goofyGlasses { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_eyewear_armoire_goofyGlasses.png'); width: 68px; @@ -19695,6 +19780,11 @@ width: 68px; height: 68px; } +.shop_eyewear_armoire_tragedyMask { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_eyewear_armoire_tragedyMask.png'); + width: 68px; + height: 68px; +} .shop_headAccessory_armoire_comicalArrow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_headAccessory_armoire_comicalArrow.png'); width: 68px; @@ -20180,6 +20270,11 @@ width: 68px; height: 68px; } +.shop_shield_armoire_dustpan { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_dustpan.png'); + width: 68px; + height: 68px; +} .shop_shield_armoire_fancyBlownGlassVase { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_armoire_fancyBlownGlassVase.png'); width: 68px; @@ -20565,6 +20660,11 @@ width: 68px; height: 68px; } +.shop_weapon_armoire_featherDuster { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_featherDuster.png'); + width: 68px; + height: 68px; +} .shop_weapon_armoire_festivalFirecracker { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_festivalFirecracker.png'); width: 68px; @@ -20805,6 +20905,11 @@ width: 68px; height: 68px; } +.shop_weapon_armoire_pushBroom { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_pushBroom.png'); + width: 68px; + height: 68px; +} .shop_weapon_armoire_rancherLasso { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_armoire_rancherLasso.png'); width: 68px; @@ -21430,6 +21535,11 @@ width: 114px; height: 90px; } +.weapon_armoire_featherDuster { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_featherDuster.png'); + width: 114px; + height: 90px; +} .weapon_armoire_festivalFirecracker { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_festivalFirecracker.png'); width: 90px; @@ -21670,6 +21780,11 @@ width: 114px; height: 90px; } +.weapon_armoire_pushBroom { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_pushBroom.png'); + width: 114px; + height: 90px; +} .weapon_armoire_rancherLasso { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_armoire_rancherLasso.png'); width: 90px; @@ -26925,6 +27040,56 @@ width: 117px; height: 120px; } +.eyewear_mystery_202208 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/eyewear_mystery_202208.png'); + width: 114px; + height: 90px; +} +.head_mystery_202208 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/head_mystery_202208.png'); + width: 114px; + height: 90px; +} +.shop_eyewear_mystery_202208 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_eyewear_mystery_202208.png'); + width: 68px; + height: 68px; +} +.shop_head_mystery_202208 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_head_mystery_202208.png'); + width: 68px; + height: 68px; +} +.shop_set_mystery_202208 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202208.png'); + width: 68px; + height: 68px; +} +.shield_mystery_202209 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shield_mystery_202209.png'); + width: 114px; + height: 90px; +} +.shop_set_mystery_202209 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_set_mystery_202209.png'); + width: 68px; + height: 68px; +} +.shop_shield_mystery_202209 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_shield_mystery_202209.png'); + width: 68px; + height: 68px; +} +.shop_weapon_mystery_202209 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/shop_weapon_mystery_202209.png'); + width: 68px; + height: 68px; +} +.weapon_mystery_202209 { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/weapon_mystery_202209.png'); + width: 114px; + height: 90px; +} .broad_armor_mystery_301404 { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/broad_armor_mystery_301404.png'); width: 90px; @@ -36603,6 +36768,11 @@ width: 105px; height: 105px; } +.Mount_Body_BearCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_BearCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_BearCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_BearCub-Rainbow.png'); width: 105px; @@ -37018,6 +37188,11 @@ width: 105px; height: 105px; } +.Mount_Body_Cactus-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Cactus-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_Cactus-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Cactus-Rainbow.png'); width: 105px; @@ -37533,6 +37708,11 @@ width: 105px; height: 105px; } +.Mount_Body_Dragon-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Dragon-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_Dragon-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Dragon-Rainbow.png'); width: 105px; @@ -37948,6 +38128,11 @@ width: 105px; height: 105px; } +.Mount_Body_FlyingPig-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_FlyingPig-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_FlyingPig-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_FlyingPig-Rainbow.png'); width: 105px; @@ -38213,6 +38398,11 @@ width: 105px; height: 105px; } +.Mount_Body_Fox-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Fox-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_Fox-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Fox-Rainbow.png'); width: 105px; @@ -38868,6 +39058,11 @@ width: 105px; height: 105px; } +.Mount_Body_LionCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_LionCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_LionCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_LionCub-Rainbow.png'); width: 105px; @@ -39353,6 +39548,11 @@ width: 105px; height: 105px; } +.Mount_Body_PandaCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_PandaCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_PandaCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_PandaCub-Rainbow.png'); width: 105px; @@ -40573,6 +40773,11 @@ width: 105px; height: 105px; } +.Mount_Body_TigerCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_TigerCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Body_TigerCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_TigerCub-Rainbow.png'); width: 105px; @@ -41148,6 +41353,11 @@ width: 135px; height: 135px; } +.Mount_Body_Wolf-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Wolf-Porcelain.png'); + width: 135px; + height: 135px; +} .Mount_Body_Wolf-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Body_Wolf-Rainbow.png'); width: 135px; @@ -41668,6 +41878,11 @@ width: 105px; height: 105px; } +.Mount_Head_BearCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_BearCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_BearCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_BearCub-Rainbow.png'); width: 105px; @@ -42083,6 +42298,11 @@ width: 105px; height: 105px; } +.Mount_Head_Cactus-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Cactus-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_Cactus-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Cactus-Rainbow.png'); width: 105px; @@ -42598,6 +42818,11 @@ width: 105px; height: 105px; } +.Mount_Head_Dragon-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Dragon-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_Dragon-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Dragon-Rainbow.png'); width: 105px; @@ -43013,6 +43238,11 @@ width: 105px; height: 105px; } +.Mount_Head_FlyingPig-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_FlyingPig-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_FlyingPig-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_FlyingPig-Rainbow.png'); width: 105px; @@ -43278,6 +43508,11 @@ width: 105px; height: 105px; } +.Mount_Head_Fox-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Fox-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_Fox-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Fox-Rainbow.png'); width: 105px; @@ -43933,6 +44168,11 @@ width: 105px; height: 105px; } +.Mount_Head_LionCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_LionCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_LionCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_LionCub-Rainbow.png'); width: 105px; @@ -44418,6 +44658,11 @@ width: 105px; height: 105px; } +.Mount_Head_PandaCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_PandaCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_PandaCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_PandaCub-Rainbow.png'); width: 105px; @@ -45638,6 +45883,11 @@ width: 105px; height: 105px; } +.Mount_Head_TigerCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_TigerCub-Porcelain.png'); + width: 105px; + height: 105px; +} .Mount_Head_TigerCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_TigerCub-Rainbow.png'); width: 105px; @@ -46213,6 +46463,11 @@ width: 135px; height: 135px; } +.Mount_Head_Wolf-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Wolf-Porcelain.png'); + width: 135px; + height: 135px; +} .Mount_Head_Wolf-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Head_Wolf-Rainbow.png'); width: 135px; @@ -46738,6 +46993,11 @@ width: 81px; height: 99px; } +.Mount_Icon_BearCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_BearCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_BearCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_BearCub-Rainbow.png'); width: 81px; @@ -47153,6 +47413,11 @@ width: 81px; height: 99px; } +.Mount_Icon_Cactus-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Cactus-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_Cactus-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Cactus-Rainbow.png'); width: 81px; @@ -47668,6 +47933,11 @@ width: 81px; height: 99px; } +.Mount_Icon_Dragon-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Dragon-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_Dragon-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Dragon-Rainbow.png'); width: 81px; @@ -48083,6 +48353,11 @@ width: 81px; height: 99px; } +.Mount_Icon_FlyingPig-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_FlyingPig-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_FlyingPig-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_FlyingPig-Rainbow.png'); width: 81px; @@ -48348,6 +48623,11 @@ width: 81px; height: 99px; } +.Mount_Icon_Fox-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Fox-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_Fox-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Fox-Rainbow.png'); width: 81px; @@ -49008,6 +49288,11 @@ width: 81px; height: 99px; } +.Mount_Icon_LionCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_LionCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_LionCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_LionCub-Rainbow.png'); width: 81px; @@ -49493,6 +49778,11 @@ width: 81px; height: 99px; } +.Mount_Icon_PandaCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_PandaCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_PandaCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_PandaCub-Rainbow.png'); width: 81px; @@ -50713,6 +51003,11 @@ width: 81px; height: 99px; } +.Mount_Icon_TigerCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_TigerCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_TigerCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_TigerCub-Rainbow.png'); width: 81px; @@ -51288,6 +51583,11 @@ width: 81px; height: 99px; } +.Mount_Icon_Wolf-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Wolf-Porcelain.png'); + width: 81px; + height: 99px; +} .Mount_Icon_Wolf-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Mount_Icon_Wolf-Rainbow.png'); width: 81px; @@ -51818,6 +52118,11 @@ width: 81px; height: 99px; } +.Pet-BearCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-BearCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-BearCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-BearCub-Rainbow.png'); width: 81px; @@ -52248,6 +52553,11 @@ width: 81px; height: 99px; } +.Pet-Cactus-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Cactus-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-Cactus-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Cactus-Rainbow.png'); width: 81px; @@ -52783,6 +53093,11 @@ width: 81px; height: 99px; } +.Pet-Dragon-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Dragon-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-Dragon-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Dragon-Rainbow.png'); width: 81px; @@ -53213,6 +53528,11 @@ width: 81px; height: 99px; } +.Pet-FlyingPig-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-FlyingPig-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-FlyingPig-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-FlyingPig-Rainbow.png'); width: 81px; @@ -53493,6 +53813,11 @@ width: 81px; height: 99px; } +.Pet-Fox-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Fox-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-Fox-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Fox-Rainbow.png'); width: 81px; @@ -54168,6 +54493,11 @@ width: 81px; height: 99px; } +.Pet-LionCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-LionCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-LionCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-LionCub-Rainbow.png'); width: 81px; @@ -54668,6 +54998,11 @@ width: 81px; height: 99px; } +.Pet-PandaCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-PandaCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-PandaCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-PandaCub-Rainbow.png'); width: 81px; @@ -55913,6 +56248,11 @@ width: 81px; height: 99px; } +.Pet-TigerCub-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-TigerCub-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-TigerCub-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-TigerCub-Rainbow.png'); width: 81px; @@ -56508,6 +56848,11 @@ width: 81px; height: 99px; } +.Pet-Wolf-Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Wolf-Porcelain.png'); + width: 81px; + height: 99px; +} .Pet-Wolf-Rainbow { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet-Wolf-Rainbow.png'); width: 81px; @@ -56838,6 +57183,11 @@ width: 68px; height: 68px; } +.Pet_HatchingPotion_Porcelain { + background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_HatchingPotion_Porcelain.png'); + width: 68px; + height: 68px; +} .Pet_HatchingPotion_Purple { background-image: url('https://habitica-assets.s3.amazonaws.com/mobileApp/images/Pet_HatchingPotion_Purple.png'); width: 68px; diff --git a/website/client/src/assets/images/bug.png b/website/client/src/assets/images/bug.png new file mode 100644 index 0000000000..e3116a7229 Binary files /dev/null and b/website/client/src/assets/images/bug.png differ diff --git a/website/client/src/assets/images/group-plans/purple-diagonal.png b/website/client/src/assets/images/group-plans/purple-diagonal.png new file mode 100644 index 0000000000..f928a387f7 Binary files /dev/null and b/website/client/src/assets/images/group-plans/purple-diagonal.png differ diff --git a/website/client/src/assets/images/group-plans/task-columns.png b/website/client/src/assets/images/group-plans/task-columns.png new file mode 100644 index 0000000000..f755d4a488 Binary files /dev/null and b/website/client/src/assets/images/group-plans/task-columns.png differ diff --git a/website/client/src/assets/images/group-plans/task-columns@2x.png b/website/client/src/assets/images/group-plans/task-columns@2x.png new file mode 100644 index 0000000000..057b77b4e6 Binary files /dev/null and b/website/client/src/assets/images/group-plans/task-columns@2x.png differ diff --git a/website/client/src/assets/images/group-plans/task-columns@3x.png b/website/client/src/assets/images/group-plans/task-columns@3x.png new file mode 100644 index 0000000000..072709382c Binary files /dev/null and b/website/client/src/assets/images/group-plans/task-columns@3x.png differ diff --git a/website/client/src/assets/scss/create-task.scss b/website/client/src/assets/scss/create-task.scss index c97d9afb05..42a04b2522 100644 --- a/website/client/src/assets/scss/create-task.scss +++ b/website/client/src/assets/scss/create-task.scss @@ -1,9 +1,56 @@ .create-task-area { position: absolute; - right: 24px; + right: 12px; top: -24px; z-index: 998; align-items: center; + + .dropdown { + width: 140px; + border-radius: 2px; + box-shadow: 0 3px 6px 0 rgba(26, 24, 29, 0.16), 0 3px 6px 0 rgba(26, 24, 29, 0.24); + background-color: $white; + margin-top: 2px; + position: absolute; + right: 0px; + + .task-icon { + width: 30px; + } + + .task-label { + margin-top: 1px; + } + + .dropdown-item:hover { + .svg-icon { + color: $purple-300; + } + } + .svg-icon { + color: $gray-200; + + &.icon-habit { + width: 30px; + height: 20px; + } + + &.icon-daily { + width: 24px; + height: 20px; + } + + &.icon-todo { + width: 20px; + height: 20px; + } + + &.icon-reward { + width: 26px; + height: 20px; + } + } + } } .slide-tasks-btns-leave-active, .slide-tasks-btns-enter-active { @@ -17,70 +64,14 @@ overflow-x: hidden; } -.diamond-btn { - margin-left: 24px; - background: $white; - width: 40px; - height: 40px; - display: flex; - justify-content: center; - align-items: center; - border-radius: 4px; - box-shadow: 0 2px 2px 0 rgba($black, 0.16), 0 1px 4px 0 rgba($black, 0.12); - cursor: pointer; - color: $gray-200; - transform: rotate(45deg); - - &:hover:not(.create-btn) { - color: $purple-400; - box-shadow: 0 1px 8px 0 rgba($black, 0.12), 0 4px 4px 0 rgba($black, 0.16); - } - - .svg-icon { - width: 20px; - height: 20px; - transform: rotate(-45deg); - - &.icon-habit { - width: 24px; - height: 16px; - } - - &.icon-daily { - width: 21.6px; - height: 18px; - } - - &.icon-todo { - width: 18px; - height: 18px; - } - - &.icon-reward { - width: 23.4px; - height: 18px; - } - } -} - .create-btn { color: $white; - background-color: $green-100; - height: 48px; - width: 48px; + background-color: $purple-200; + height: 32px; .svg-icon { - width: 16px; - height: 16px; - transform: rotate(-45deg); - transition: transform 0.3s cubic-bezier(0, 1, 0.5, 1); - } - - &.open { - background: $gray-200 !important; - - .svg-icon { - transform: rotate(-90deg); - } + color: $purple-500; + width: 10px; + height: 10px; } } diff --git a/website/client/src/assets/scss/task.scss b/website/client/src/assets/scss/task.scss index 4ff3a77810..dbd19622e3 100644 --- a/website/client/src/assets/scss/task.scss +++ b/website/client/src/assets/scss/task.scss @@ -30,7 +30,7 @@ &-bg { background: $maroon-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $maroon-100 !important; } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -41,7 +41,7 @@ &-modal { &-bg { background: $maroon-100 !important; } - &-headings { color: $white; } + &-headings { color: $white !important; } &-icon { color: $maroon-100 !important; } &-text { color: $red-1 !important; } &-content { @@ -61,7 +61,7 @@ &-bg { background: $red-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $red-100 !important; } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -92,7 +92,7 @@ &-bg { background: $orange-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($orange-1, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $orange-100 !important; } &-inner-habit { background: rgba($orange-1, 0.25) !important; } @@ -123,7 +123,7 @@ &-bg { background: $yellow-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($yellow-1, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $yellow-100 !important; } &-inner-habit { background: rgba($yellow-1, 0.25) !important; } @@ -154,7 +154,7 @@ &-bg { background: $green-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $green-100 !important; } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -186,7 +186,7 @@ &-bg { background: $teal-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $teal-100 !important; } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -217,7 +217,7 @@ &-bg { background: $blue-100 !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $blue-100 !important; } &-inner-habit { background: rgba($black, 0.25) !important; } @@ -249,7 +249,7 @@ &-bg { background: $purple-task !important; .habit-control:not(.task-not-scoreable):hover { background: rgba($black, 0.5) !important; } - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-inner-habit { background: rgba($black, 0.25) !important; } &-inner-daily-todo { background: rgba($white, 0.5) !important; } @@ -258,7 +258,7 @@ &-modal { &-bg { background: $purple-300 !important; } - &-headings { color: $white; } + &-headings { color: $white !important; } &-icon { color: $purple-300 !important; } &-text { color: $black !important; } &-content { @@ -281,11 +281,11 @@ background: rgba($yellow-100, 0.15) !important; .small-text { color: $yellow-1 !important; } - &:hover { background: rgba($yellow-100, 0.25) !important; } + &:hover:not(.task-not-scoreable) { background: rgba($yellow-100, 0.25) !important; } } &-bg-noninteractive { - background: rgba($yellow-100, 0.15) !important; - .small-text { color: $yellow-1 !important; } + background-color: $gray-500 !important; + .small-text { color: $gray-100 !important; } } } } @@ -312,7 +312,7 @@ &-control { &-bg { background: $gray-200 !important; - .daily-todo-control:hover { background: rgba($white, 0.75) !important; } + .daily-todo-control:not(.task-not-scoreable):hover { background: rgba($white, 0.75) !important; } } &-bg-noninteractive { background: $gray-200 !important; @@ -323,7 +323,7 @@ background: $gray-600; .task-title, .task-notes { - color: $gray-300 !important; + opacity: 0.75; } } } diff --git a/website/client/src/assets/svg/last-complete.svg b/website/client/src/assets/svg/last-complete.svg new file mode 100644 index 0000000000..bda38f7415 --- /dev/null +++ b/website/client/src/assets/svg/last-complete.svg @@ -0,0 +1,3 @@ + + + diff --git a/website/client/src/assets/svg/users.svg b/website/client/src/assets/svg/users.svg index ca1d736b16..8d4d0ec37e 100644 --- a/website/client/src/assets/svg/users.svg +++ b/website/client/src/assets/svg/users.svg @@ -1,20 +1 @@ - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/website/client/src/components/auth/registerLoginReset.vue b/website/client/src/components/auth/registerLoginReset.vue index 60a08f3b70..890581ca5f 100644 --- a/website/client/src/components/auth/registerLoginReset.vue +++ b/website/client/src/components/auth/registerLoginReset.vue @@ -757,8 +757,7 @@ export default { }, 500), sanitizeRedirect (redirect) { if (!redirect) return '/'; - let sanitizedString = DOMPurify.sanitize(redirect).replace(/\\|\/\/|\./g, ''); - sanitizedString = `/${sanitizedString}`; + const sanitizedString = DOMPurify.sanitize(redirect).replace(/\\|\/\/|\./g, ''); return sanitizedString; }, async register () { diff --git a/website/client/src/components/challenges/groupChallenges.vue b/website/client/src/components/challenges/groupChallenges.vue index 6a19e34700..fc370700c8 100644 --- a/website/client/src/components/challenges/groupChallenges.vue +++ b/website/client/src/components/challenges/groupChallenges.vue @@ -112,10 +112,8 @@ export default { }, }, watch: { - 'group._id': { - async groupId () { - this.loadChallenges(); - }, + 'group._id': function groupId () { + this.loadChallenges(); }, }, mounted () { diff --git a/website/client/src/components/group-plans/groupPlansUpdateModal.vue b/website/client/src/components/group-plans/groupPlansUpdateModal.vue new file mode 100644 index 0000000000..30205a0576 --- /dev/null +++ b/website/client/src/components/group-plans/groupPlansUpdateModal.vue @@ -0,0 +1,204 @@ + + + + + + + diff --git a/website/client/src/components/group-plans/index.vue b/website/client/src/components/group-plans/index.vue index bd4fd903da..c49a9fa846 100644 --- a/website/client/src/components/group-plans/index.vue +++ b/website/client/src/components/group-plans/index.vue @@ -28,7 +28,7 @@ {{ $t('groupBilling') }} -
+
diff --git a/website/client/src/components/group-plans/taskInformation.vue b/website/client/src/components/group-plans/taskInformation.vue index ddee1d5826..eec37e17aa 100644 --- a/website/client/src/components/group-plans/taskInformation.vue +++ b/website/client/src/components/group-plans/taskInformation.vue @@ -1,5 +1,8 @@ + + @@ -142,6 +143,7 @@ import loginIncentives from './achievements/login-incentives'; import onboardingComplete from './achievements/onboardingComplete'; import verifyUsername from './settings/verifyUsername'; import firstDrops from './achievements/firstDrops'; +import groupPlansUpdate from './group-plans/groupPlansUpdateModal'; const NOTIFICATIONS = { // general notifications @@ -268,6 +270,7 @@ export default { genericAchievement, onboardingComplete, firstDrops, + groupPlansUpdate, }, mixins: [notifications, guide], data () { @@ -612,7 +615,7 @@ export default { const yesterUtcOffset = yesterDay.utcOffset(); dailys.forEach(task => { - if (task && task.group.approval && task.group.approval.requested) return; + if (task.group && task.group.id) return; if (task.completed) return; const due = shouldDo(yesterDay, task, { timezoneUtcOffset: yesterUtcOffset }); if (task.yesterDaily && due) this.yesterDailies.push(task); diff --git a/website/client/src/components/static/faq.vue b/website/client/src/components/static/faq.vue index 8398dffcc0..b9bb3a9d6e 100644 --- a/website/client/src/components/static/faq.vue +++ b/website/client/src/components/static/faq.vue @@ -94,6 +94,7 @@ export default { 'gems', 'bugs-features', 'world-boss', + 'group-plans', ]; const hash = window.location.hash.replace('#', ''); @@ -105,11 +106,6 @@ export default { wikiTechAssistanceEmail: `mailto:${TECH_ASSISTANCE_EMAIL}`, }, visible: hash && headings.includes(hash) ? hash : null, - // @TODO webFaqStillNeedHelp: { - // linkStart: '[', - // linkEnd: '](/groups/guild/5481ccf3-5d2d-48a9-a871-70a7380cee5a)', - // }, - // "webFaqStillNeedHelp": "If you have a question that isn't on this list or on the [Wiki FAQ](https://habitica.fandom.com/wiki/FAQ), come ask in the <%= linkStart %>Habitica Help guild<%= linkEnd %>! We're happy to help." }; }, mounted () { diff --git a/website/client/src/components/tasks/approvalFooter.vue b/website/client/src/components/tasks/approvalFooter.vue index 7a8080667b..511aea25e6 100644 --- a/website/client/src/components/tasks/approvalFooter.vue +++ b/website/client/src/components/tasks/approvalFooter.vue @@ -1,59 +1,117 @@ @@ -61,148 +119,220 @@ diff --git a/website/client/src/components/tasks/column.vue b/website/client/src/components/tasks/column.vue index 157118afb9..3cae7ba8ed 100644 --- a/website/client/src/components/tasks/column.vue +++ b/website/client/src/components/tasks/column.vue @@ -43,7 +43,7 @@ class="tasks-list" > -
- - -
-
-
-
-
- -
@@ -281,7 +238,7 @@
@@ -297,7 +254,7 @@
@@ -314,7 +271,7 @@
@@ -344,8 +301,7 @@
@@ -405,7 +361,7 @@
@@ -428,16 +384,16 @@
-
- - -
+ class="col-10 mb-1" + >{{ $t('assignTo') }} + + {{ $t('clear') }} +
-
- - -