diff --git a/.eslintrc.js b/.eslintrc.js index ee3dbce6..a5518f73 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -1,8 +1,8 @@ module.exports = { root: true, - parser: '@typescript-eslint/parser', // Specifies the ESLint parser extends: [ + 'eslint:recommended', 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin 'prettier/@typescript-eslint', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. @@ -30,6 +30,8 @@ module.exports = { '@typescript-eslint/explicit-function-return-type': 'off', 'prettier/prettier': ['error', { endOfLine: 'auto' }], 'formatjs/no-offset': 'error', + 'no-unused-vars': 'off', + '@typescript-eslint/no-unused-vars': ['error'], }, overrides: [ { @@ -52,6 +54,5 @@ module.exports = { jest: true, es6: true, }, - reportUnusedDisableDirectives: true, }; diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..c188c311 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 sct + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index be9cd226..19985f53 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,19 @@ Overseerr

+Overseerr Release Overseerr CI

+

+ +Discord + +Docker pulls + +Translation status + +Language grade: JavaScript +

**Overseerr** is a tool for managing requests for your media library. It integrates with existing services such as **Sonarr** and **Radarr**! @@ -11,25 +22,77 @@ - Full Plex integration. Login and manage user access with Plex! - Integrates easily with your existing services. Currently Overseerr supports Sonarr and Radarr. More in the future! -- Syncs to your Plex library to know what titles you already have -- Complex request system that allows users to request individual seasons or movies in a friendly, easy to use UI -- Incredibly simple request management UI. Don't dig through the app to simply approve recent requests +- Syncs to your Plex library to know what titles you already have. +- Complex request system that allows users to request individual seasons or movies in a friendly, easy to use UI. +- Incredibly simple request management UI. Don't dig through the app to simply approve recent requests. +- Granular permissions system - Mobile friendly design, for when you need to approve requests on the go! ## In Development -- A lot! +- User profiles +- User settings page to give users the ability to modify their Overseerr experience to their liking +- Version update notifications in-app + +## Planned Features + +- More notification types (Slack/Telegram/etc) +- Issues system. This will allow users to report issues with content on your media server. +- Local user system (for those who do not use Plex) +- Compatiblity APIs to work with existing tools in your system + +## Running Overseerr + +Currently, the only distribution of Overseerr is through Docker images. If you have Docker, you can run Overseerr with the following command: + +``` +docker run -d \ + -e LOG_LEVEL=info \ + -e TZ=Asia/Tokyo \ + -p 5055:3000 \ + -v /path/to/appdata/config:/config \ + --restart unless-stopped \ + sctx/overseer +``` + +After running Overseerr for the first time, visit the web UI at http://[address]:5055 and complete the setup steps to configure Overseerr. + +⚠️ Overseerr is currently under very heavy, rapid development and things are likely to break often. We need all the help we can get to find bugs and get them fixed to hit a more stable release. If you would like to help test the bleeding edge, please use the image **sctx/overseerr:develop** instead! ⚠️ + +## Preview + + + +## Support + +- You can reach us for support on [Discord](https://discord.gg/ySfaEUcQ). +- Bugs can be opened with an issue on [Github](https://github.com/sct/overseerr/issues). ## API Documentation -- Coming soon +Full API documentation will soon be published automatically and available outside of running the app. But currently, you can access the api docs by running Overseerr locally and visiting http://localhost:3000/api-docs ## Contribution +Anyone is welcome to contribute to Docker and pull requests are greatly appreciated! Contributors will be recognized in the future on this very README. + +### Developing Overseerr + You can develop Overseer entirely in docker. Make sure you have [Docker Desktop](https://www.docker.com/products/docker-desktop) installed before continuing. 1. Make sure you have [Docker Desktop](https://www.docker.com/products/docker-desktop) installed. -2. Run `docker-compose up -d` to start the server +2. Run `docker-compose up -d` to start the server. 3. Access the container at http://localhost:3000 -That's it! +If Docker isn't your jam, you can always run Overseer with the following yarn commands: + +``` +yarn +yarn dev +``` + +You will need NodeJS installed. Once it's built and running, access it locally at http://localhost:3000 just like Docker. + +### Translation + +We use [Weblate](https://hosted.weblate.org/engage/overseerr/) for our translations so please feel free to contribute to localizing Overseerr! diff --git a/package.json b/package.json index 156616da..dbee0f2f 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "migration:run": "ts-node --project server/tsconfig.json ./node_modules/.bin/typeorm migration:run", "format": "prettier --write ." }, + "license": "MIT", "dependencies": { "@svgr/webpack": "^5.4.0", "axios": "^0.20.0", @@ -36,6 +37,7 @@ "pug": "^3.0.0", "react": "16.13.1", "react-dom": "16.13.1", + "react-intersection-observer": "^8.31.0", "react-intl": "^5.8.5", "react-spring": "^8.0.27", "react-toast-notifications": "^2.4.0", @@ -46,14 +48,14 @@ "swagger-ui-express": "^4.1.4", "swr": "^0.3.5", "typeorm": "^0.2.26", - "uuid": "^8.3.0", + "uuid": "^8.3.1", "winston": "^3.3.3", "xml2js": "^0.4.23", "yamljs": "^0.3.0", "yup": "^0.29.3" }, "devDependencies": { - "@babel/cli": "^7.11.6", + "@babel/cli": "^7.12.8", "@commitlint/cli": "^11.0.0", "@commitlint/config-conventional": "^11.0.0", "@semantic-release/changelog": "^5.0.1", @@ -68,38 +70,38 @@ "@types/email-templates": "^7.1.0", "@types/express": "^4.17.8", "@types/express-session": "^1.17.0", - "@types/lodash": "^4.14.161", - "@types/node": "^14.10.0", + "@types/lodash": "^4.14.165", + "@types/node": "^14.14.10", "@types/node-schedule": "^1.3.1", "@types/nodemailer": "^6.4.0", - "@types/react": "^16.9.49", - "@types/react-dom": "^16.9.8", + "@types/react": "^17.0.0", + "@types/react-dom": "^17.0.0", "@types/react-toast-notifications": "^2.4.0", "@types/react-transition-group": "^4.4.0", "@types/swagger-ui-express": "^4.1.2", "@types/uuid": "^8.3.0", - "@types/xml2js": "^0.4.5", + "@types/xml2js": "^0.4.7", "@types/yamljs": "^0.2.31", - "@types/yup": "^0.29.9", - "@typescript-eslint/eslint-plugin": "^4.0.0", - "@typescript-eslint/parser": "^3.10.1", + "@types/yup": "^0.29.10", + "@typescript-eslint/eslint-plugin": "^4.9.1", + "@typescript-eslint/parser": "^4.9.1", "autoprefixer": "^9", "babel-plugin-react-intl": "^8.2.2", "babel-plugin-react-intl-auto": "^3.3.0", "commitizen": "^4.2.1", "copyfiles": "^2.4.0", "cz-conventional-changelog": "^3.3.0", - "eslint": "^7.10.0", - "eslint-config-prettier": "^6.11.0", - "eslint-plugin-formatjs": "^2.7.10", - "eslint-plugin-jsx-a11y": "^6.3.1", - "eslint-plugin-prettier": "^3.1.4", - "eslint-plugin-react": "^7.20.6", - "eslint-plugin-react-hooks": "^4.1.2", + "eslint": "^7.15.0", + "eslint-config-prettier": "^7.0.0", + "eslint-plugin-formatjs": "^2.9.10", + "eslint-plugin-jsx-a11y": "^6.4.1", + "eslint-plugin-prettier": "^3.2.0", + "eslint-plugin-react": "^7.21.5", + "eslint-plugin-react-hooks": "^4.2.0", "extract-react-intl-messages": "^4.1.1", - "husky": "^4.3.0", - "lint-staged": "^10.4.0", - "nodemon": "^2.0.4", + "husky": "^4.3.5", + "lint-staged": "^10.5.3", + "nodemon": "^2.0.6", "postcss": "^7", "postcss-preset-env": "^6.7.0", "prettier": "^2.1.2", diff --git a/public/preview.png b/public/preview.png new file mode 100644 index 00000000..7d90433e Binary files /dev/null and b/public/preview.png differ diff --git a/server/api/themoviedb.ts b/server/api/themoviedb.ts index 2aad437c..4260cdfc 100644 --- a/server/api/themoviedb.ts +++ b/server/api/themoviedb.ts @@ -679,9 +679,10 @@ class TheMovieDb { public getMovieTrending = async ({ page = 1, timeWindow = 'day', - }: { page?: number; timeWindow?: 'day' | 'week' } = {}): Promise< - TmdbSearchMovieResponse - > => { + }: { + page?: number; + timeWindow?: 'day' | 'week'; + } = {}): Promise => { try { const response = await this.axios.get( `/trending/movie/${timeWindow}`, @@ -701,9 +702,10 @@ class TheMovieDb { public getTvTrending = async ({ page = 1, timeWindow = 'day', - }: { page?: number; timeWindow?: 'day' | 'week' } = {}): Promise< - TmdbSearchTvResponse - > => { + }: { + page?: number; + timeWindow?: 'day' | 'week'; + } = {}): Promise => { try { const response = await this.axios.get( `/trending/tv/${timeWindow}`, diff --git a/server/entity/Media.ts b/server/entity/Media.ts index 435cfb0a..8f2f8ff6 100644 --- a/server/entity/Media.ts +++ b/server/entity/Media.ts @@ -100,7 +100,7 @@ class Media { } @AfterUpdate() - private async notifyAvailable() { + private async _notifyAvailable() { if (this.status === MediaStatus.AVAILABLE) { if (this.mediaType === MediaType.MOVIE) { const requestRepository = getRepository(MediaRequest); diff --git a/server/entity/MediaRequest.ts b/server/entity/MediaRequest.ts index 6c42fad0..b00ddd9c 100644 --- a/server/entity/MediaRequest.ts +++ b/server/entity/MediaRequest.ts @@ -62,7 +62,7 @@ export class MediaRequest { } @AfterInsert() - private async notifyNewRequest() { + private async _notifyNewRequest() { if (this.status === MediaRequestStatus.PENDING) { const mediaRepository = getRepository(Media); const media = await mediaRepository.findOne({ @@ -110,7 +110,7 @@ export class MediaRequest { * auto approved content */ @AfterUpdate() - private async notifyApproved() { + private async _notifyApproved() { if (this.status === MediaRequestStatus.APPROVED) { const mediaRepository = getRepository(Media); const media = await mediaRepository.findOne({ @@ -151,7 +151,7 @@ export class MediaRequest { @AfterUpdate() @AfterInsert() - private async updateParentStatus() { + private async _updateParentStatus() { const mediaRepository = getRepository(Media); const media = await mediaRepository.findOne({ where: { id: this.media.id }, @@ -206,7 +206,7 @@ export class MediaRequest { } @AfterRemove() - private async handleRemoveParentUpdate() { + private async _handleRemoveParentUpdate() { const mediaRepository = getRepository(Media); const fullMedia = await mediaRepository.findOneOrFail({ where: { id: this.media.id }, @@ -219,7 +219,7 @@ export class MediaRequest { @AfterUpdate() @AfterInsert() - private async sendToRadarr() { + private async _sendToRadarr() { if ( this.status === MediaRequestStatus.APPROVED && this.type === MediaType.MOVIE @@ -267,7 +267,7 @@ export class MediaRequest { @AfterUpdate() @AfterInsert() - private async sendToSonarr() { + private async _sendToSonarr() { if ( this.status === MediaRequestStatus.APPROVED && this.type === MediaType.TV diff --git a/server/entity/Season.ts b/server/entity/Season.ts index 0a5562ea..a591c3ca 100644 --- a/server/entity/Season.ts +++ b/server/entity/Season.ts @@ -8,7 +8,6 @@ import { AfterInsert, AfterUpdate, getRepository, - RelationId, } from 'typeorm'; import { MediaStatus } from '../constants/media'; import Media from './Media'; @@ -42,7 +41,7 @@ class Season { @AfterInsert() @AfterUpdate() - private async sendSeasonAvailableNotification() { + private async _sendSeasonAvailableNotification() { if (this.status === MediaStatus.AVAILABLE) { try { const lazyMedia = await this.media; diff --git a/server/index.ts b/server/index.ts index e29a5b7e..e85fb150 100644 --- a/server/index.ts +++ b/server/index.ts @@ -5,7 +5,7 @@ import { createConnection, getRepository } from 'typeorm'; import routes from './routes'; import bodyParser from 'body-parser'; import cookieParser from 'cookie-parser'; -import session from 'express-session'; +import session, { Store } from 'express-session'; import { TypeormStore } from 'connect-typeorm/out'; import YAML from 'yamljs'; import swaggerUi from 'swagger-ui-express'; @@ -29,7 +29,7 @@ app .then(async () => { await createConnection(); // Load Settings - getSettings().load(); + const settings = getSettings().load(); // Register Notification Agents notificationManager.registerAgents([new DiscordAgent(), new EmailAgent()]); @@ -47,7 +47,7 @@ app server.use( '/api', session({ - secret: 'verysecret', + secret: settings.clientId, resave: false, saveUninitialized: false, cookie: { @@ -56,7 +56,7 @@ app store: new TypeormStore({ cleanupLimit: 2, ttl: 1000 * 60 * 60 * 24 * 30, - }).connect(sessionRespository), + }).connect(sessionRespository) as Store, }) ); const apiDocs = YAML.load(API_SPEC_PATH); @@ -71,7 +71,7 @@ app * OpenAPI validator. Otherwise, they are treated as objects instead of strings * and response validation will fail */ - server.use((req, res, next) => { + server.use((_req, res, next) => { const original = res.json; res.json = function jsonp(json) { return original.call(this, JSON.parse(JSON.stringify(json))); @@ -83,8 +83,10 @@ app server.use( ( err: { status: number; message: string; errors: string[] }, - req: Request, + _req: Request, res: Response, + // We must provide a next function for the function signature here even though its not used + // eslint-disable-next-line @typescript-eslint/no-unused-vars _next: NextFunction ) => { // format error @@ -96,10 +98,7 @@ app ); const port = Number(process.env.PORT) || 3000; - server.listen(port, (err) => { - if (err) { - throw err; - } + server.listen(port, () => { logger.info(`Server ready on port ${port}`, { label: 'SERVER', }); diff --git a/server/lib/notifications/agents/discord.ts b/server/lib/notifications/agents/discord.ts index c293f418..008e9149 100644 --- a/server/lib/notifications/agents/discord.ts +++ b/server/lib/notifications/agents/discord.ts @@ -127,7 +127,9 @@ class DiscordAgent implements NotificationAgent { }; } - public shouldSend(type: Notification): boolean { + // TODO: Add checking for type here once we add notification type filters for agents + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public shouldSend(_type: Notification): boolean { const settings = getSettings(); if ( diff --git a/server/lib/notifications/agents/email.ts b/server/lib/notifications/agents/email.ts index 779eee21..050c98e7 100644 --- a/server/lib/notifications/agents/email.ts +++ b/server/lib/notifications/agents/email.ts @@ -7,10 +7,12 @@ import Email from 'email-templates'; import logger from '../../../logger'; import { getRepository } from 'typeorm'; import { User } from '../../../entity/User'; -import { hasPermission, Permission } from '../../permissions'; +import { Permission } from '../../permissions'; class EmailAgent implements NotificationAgent { - public shouldSend(type: Notification): boolean { + // TODO: Add checking for type here once we add notification type filters for agents + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public shouldSend(_type: Notification): boolean { const settings = getSettings(); if (settings.notifications.agents.email.enabled) { diff --git a/server/lib/settings.ts b/server/lib/settings.ts index a490aebe..1fcb48bf 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -84,7 +84,7 @@ interface NotificationSettings { } interface AllSettings { - clientId?: string; + clientId: string; main: MainSettings; plex: PlexSettings; radarr: RadarrSettings[]; @@ -100,8 +100,9 @@ class Settings { constructor(initialSettings?: AllSettings) { this.data = { + clientId: '', main: { - apiKey: 'temp', + apiKey: '', applicationUrl: '', }, plex: { @@ -143,6 +144,10 @@ class Settings { } get main(): MainSettings { + if (!this.data.main.apiKey) { + this.data.main.apiKey = this.generateApiKey(); + this.save(); + } return this.data.main; } @@ -199,6 +204,16 @@ class Settings { return this.data.clientId; } + public regenerateApiKey(): MainSettings { + this.main.apiKey = this.generateApiKey(); + this.save(); + return this.main; + } + + private generateApiKey(): string { + return Buffer.from(`${Date.now()}${this.clientId}`).toString('base64'); + } + /** * Settings Load * diff --git a/server/models/Movie.ts b/server/models/Movie.ts index da5f2355..11f357e7 100644 --- a/server/models/Movie.ts +++ b/server/models/Movie.ts @@ -1,5 +1,4 @@ import { TmdbMovieDetails } from '../api/themoviedb'; -import { MediaRequest } from '../entity/MediaRequest'; import { ProductionCompany, Genre, diff --git a/server/models/Search.ts b/server/models/Search.ts index 5830b2a1..72e647e9 100644 --- a/server/models/Search.ts +++ b/server/models/Search.ts @@ -3,7 +3,6 @@ import type { TmdbPersonResult, TmdbTvResult, } from '../api/themoviedb'; -import type { MediaRequest } from '../entity/MediaRequest'; import Media from '../entity/Media'; export type MediaType = 'tv' | 'movie' | 'person'; diff --git a/server/routes/discover.ts b/server/routes/discover.ts index ae01802f..e6c9de45 100644 --- a/server/routes/discover.ts +++ b/server/routes/discover.ts @@ -1,9 +1,5 @@ import { Router } from 'express'; -import TheMovieDb, { - TmdbMovieResult, - TmdbTvResult, - TmdbPersonResult, -} from '../api/themoviedb'; +import TheMovieDb from '../api/themoviedb'; import { mapMovieResult, mapTvResult, mapPersonResult } from '../models/Search'; import Media from '../entity/Media'; import { isMovie, isPerson } from '../utils/typeHelpers'; diff --git a/server/routes/movie.ts b/server/routes/movie.ts index eefdc8db..492b22f7 100644 --- a/server/routes/movie.ts +++ b/server/routes/movie.ts @@ -1,7 +1,6 @@ import { Router } from 'express'; import TheMovieDb from '../api/themoviedb'; import { mapMovieDetails } from '../models/Movie'; -import { MediaRequest } from '../entity/MediaRequest'; import { mapMovieResult } from '../models/Search'; import Media from '../entity/Media'; import RottenTomatoes from '../api/rottentomatoes'; diff --git a/server/routes/person.ts b/server/routes/person.ts index 7a6305ae..9ee1be91 100644 --- a/server/routes/person.ts +++ b/server/routes/person.ts @@ -1,5 +1,4 @@ import { Router } from 'express'; -import next from 'next'; import TheMovieDb from '../api/themoviedb'; import logger from '../logger'; import { diff --git a/server/routes/settings.ts b/server/routes/settings.ts index b4f033fc..422510f2 100644 --- a/server/routes/settings.ts +++ b/server/routes/settings.ts @@ -4,10 +4,11 @@ import { RadarrSettings, SonarrSettings, Library, + MainSettings, } from '../lib/settings'; import { getRepository } from 'typeorm'; import { User } from '../entity/User'; -import PlexAPI, { PlexLibrary } from '../api/plexapi'; +import PlexAPI from '../api/plexapi'; import { jobPlexFullSync } from '../job/plexsync'; import SonarrAPI from '../api/sonarr'; import RadarrAPI from '../api/radarr'; @@ -19,9 +20,15 @@ import { merge } from 'lodash'; const settingsRoutes = Router(); -settingsRoutes.get('/main', (_req, res) => { +settingsRoutes.get('/main', (req, res) => { const settings = getSettings(); + if (!req.user?.hasPermission(Permission.ADMIN)) { + return res.status(200).json({ + applicationUrl: settings.main.applicationUrl, + } as Partial); + } + res.status(200).json(settings.main); }); @@ -120,7 +127,7 @@ settingsRoutes.get('/plex/sync', (req, res) => { return res.status(200).json(jobPlexFullSync.status()); }); -settingsRoutes.get('/radarr', (req, res) => { +settingsRoutes.get('/radarr', (_req, res) => { const settings = getSettings(); res.status(200).json(settings.radarr); @@ -261,7 +268,7 @@ settingsRoutes.delete<{ id: string }>('/radarr/:id', (req, res) => { return res.status(200).json(removed[0]); }); -settingsRoutes.get('/sonarr', (req, res) => { +settingsRoutes.get('/sonarr', (_req, res) => { const settings = getSettings(); res.status(200).json(settings.sonarr); @@ -372,7 +379,7 @@ settingsRoutes.delete<{ id: string }>('/sonarr/:id', (req, res) => { return res.status(200).json(removed[0]); }); -settingsRoutes.get('/jobs', (req, res) => { +settingsRoutes.get('/jobs', (_req, res) => { return res.status(200).json( scheduledJobs.map((job) => ({ name: job.name, @@ -384,7 +391,7 @@ settingsRoutes.get('/jobs', (req, res) => { settingsRoutes.get( '/initialize', isAuthenticated(Permission.ADMIN), - (req, res) => { + (_req, res) => { const settings = getSettings(); settings.public.initialized = true; @@ -394,7 +401,7 @@ settingsRoutes.get( } ); -settingsRoutes.get('/notifications/discord', (req, res) => { +settingsRoutes.get('/notifications/discord', (_req, res) => { const settings = getSettings(); res.status(200).json(settings.notifications.agents.discord); @@ -409,7 +416,7 @@ settingsRoutes.post('/notifications/discord', (req, res) => { res.status(200).json(settings.notifications.agents.discord); }); -settingsRoutes.get('/notifications/email', (req, res) => { +settingsRoutes.get('/notifications/email', (_req, res) => { const settings = getSettings(); res.status(200).json(settings.notifications.agents.email); diff --git a/server/routes/tv.ts b/server/routes/tv.ts index d8988700..9f9201e4 100644 --- a/server/routes/tv.ts +++ b/server/routes/tv.ts @@ -1,6 +1,5 @@ import { Router } from 'express'; import TheMovieDb from '../api/themoviedb'; -import { MediaRequest } from '../entity/MediaRequest'; import { mapTvDetails, mapSeasonWithEpisodes } from '../models/Tv'; import { mapTvResult } from '../models/Search'; import Media from '../entity/Media'; diff --git a/server/routes/user.ts b/server/routes/user.ts index ef8990cb..60753e9b 100644 --- a/server/routes/user.ts +++ b/server/routes/user.ts @@ -5,7 +5,7 @@ import { hasPermission, Permission } from '../lib/permissions'; const router = Router(); -router.get('/', async (req, res) => { +router.get('/', async (_req, res) => { const userRepository = getRepository(User); const users = await userRepository.find(); diff --git a/src/components/Common/Table/index.tsx b/src/components/Common/Table/index.tsx new file mode 100644 index 00000000..52bac6dc --- /dev/null +++ b/src/components/Common/Table/index.tsx @@ -0,0 +1,85 @@ +import React, { AllHTMLAttributes } from 'react'; +import { withProperties } from '../../../utils/typeHelpers'; + +const TBody: React.FC = ({ children }) => { + return ( + {children} + ); +}; + +const TH: React.FC> = ({ + children, + className, + ...props +}) => { + const style = [ + 'px-6 py-3 bg-gray-500 text-left text-xs leading-4 font-medium text-gray-200 uppercase tracking-wider', + ]; + + if (className) { + style.push(className); + } + + return ( + + {children} + + ); +}; + +interface TDProps extends AllHTMLAttributes { + alignText?: 'left' | 'center' | 'right'; + noPadding?: boolean; +} + +const TD: React.FC = ({ + children, + alignText = 'left', + noPadding, + className, + ...props +}) => { + const style = ['whitespace-nowrap text-sm leading-5 text-white']; + + switch (alignText) { + case 'left': + style.push('text-left'); + break; + case 'center': + style.push('text-center'); + break; + case 'right': + style.push('text-right'); + break; + } + + if (!noPadding) { + style.push('px-6 py-4'); + } + + if (className) { + style.push(className); + } + + return ( + + {children} + + ); +}; + +const Table: React.FC = ({ children }) => { + return ( +
+
+
+
+ {children}
+
+
+
+
+ ); +}; + +export default withProperties(Table, { TH, TBody, TD }); diff --git a/src/components/Discover/index.tsx b/src/components/Discover/index.tsx index 803968e5..38ec079b 100644 --- a/src/components/Discover/index.tsx +++ b/src/components/Discover/index.tsx @@ -7,13 +7,11 @@ import type { } from '../../../server/models/Search'; import TitleCard from '../TitleCard'; import PersonCard from '../PersonCard'; -import { MediaRequest } from '../../../server/entity/MediaRequest'; import TmdbTitleCard from '../TitleCard/TmdbTitleCard'; import Slider from '../Slider'; import Link from 'next/link'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import { LanguageContext } from '../../context/LanguageContext'; -import type Media from '../../../server/entity/Media'; import type { MediaResultsResponse } from '../../../server/interfaces/api/mediaInterfaces'; import type { RequestResultsResponse } from '../../../server/interfaces/api/requestInterfaces'; import RequestCard from '../RequestCard'; diff --git a/src/components/MovieDetails/index.tsx b/src/components/MovieDetails/index.tsx index e8bb3f38..77f26f79 100644 --- a/src/components/MovieDetails/index.tsx +++ b/src/components/MovieDetails/index.tsx @@ -522,7 +522,7 @@ const MovieDetails: React.FC = ({ movie }) => { ( = ({ request }) => { + const { ref, inView } = useInView({ + triggerOnce: true, + }); const intl = useIntl(); const { hasPermission } = useUser(); const { locale } = useContext(LanguageContext); @@ -49,7 +51,7 @@ const RequestCard: React.FC = ({ request }) => { ? `/api/v1/movie/${request.media.tmdbId}` : `/api/v1/tv/${request.media.tmdbId}`; const { data: title, error } = useSWR( - `${url}?language=${locale}` + inView ? `${url}?language=${locale}` : null ); const { data: requestData, error: requestError, revalidate } = useSWR< MediaRequest @@ -66,7 +68,11 @@ const RequestCard: React.FC = ({ request }) => { }; if (!title && !error) { - return ; + return ( +
+ +
+ ); } if (!requestData && !requestError) { @@ -102,28 +108,11 @@ const RequestCard: React.FC = ({ request }) => { username: requestData.requestedBy.username, })} -
- {requestData.media.status === MediaStatus.AVAILABLE && ( - - {intl.formatMessage(globalMessages.available)} - - )} - {requestData.media.status === MediaStatus.PARTIALLY_AVAILABLE && ( - - {intl.formatMessage(globalMessages.partiallyavailable)} - - )} - {requestData.media.status === MediaStatus.PROCESSING && ( - - {intl.formatMessage(globalMessages.unavailable)} - - )} - {requestData.media.status === MediaStatus.PENDING && ( - - {intl.formatMessage(globalMessages.pending)} - - )} -
+ {requestData.media.status && ( +
+ +
+ )} {request.seasons.length > 0 && (
{intl.formatMessage(messages.seasons)} diff --git a/src/components/RequestList/RequestItem/index.tsx b/src/components/RequestList/RequestItem/index.tsx new file mode 100644 index 00000000..d2ea4a73 --- /dev/null +++ b/src/components/RequestList/RequestItem/index.tsx @@ -0,0 +1,250 @@ +import React, { useContext } from 'react'; +import { useInView } from 'react-intersection-observer'; +import type { MediaRequest } from '../../../../server/entity/MediaRequest'; +import { + useIntl, + FormattedDate, + FormattedRelativeTime, + defineMessages, +} from 'react-intl'; +import { useUser, Permission } from '../../../hooks/useUser'; +import { LanguageContext } from '../../../context/LanguageContext'; +import type { MovieDetails } from '../../../../server/models/Movie'; +import type { TvDetails } from '../../../../server/models/Tv'; +import useSWR from 'swr'; +import Badge from '../../Common/Badge'; +import StatusBadge from '../../StatusBadge'; +import Table from '../../Common/Table'; +import { MediaRequestStatus } from '../../../../server/constants/media'; +import Button from '../../Common/Button'; +import axios from 'axios'; +import globalMessages from '../../../i18n/globalMessages'; +import Link from 'next/link'; + +const messages = defineMessages({ + requestedby: 'Requested by {username}', + seasons: 'Seasons', + notavailable: 'N/A', +}); + +const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { + return (movie as MovieDetails).title !== undefined; +}; + +interface RequestItemProps { + request: MediaRequest; + onDelete: () => void; +} + +const RequestItem: React.FC = ({ request, onDelete }) => { + const { ref, inView } = useInView({ + triggerOnce: true, + }); + const intl = useIntl(); + const { hasPermission } = useUser(); + const { locale } = useContext(LanguageContext); + const url = + request.type === 'movie' + ? `/api/v1/movie/${request.media.tmdbId}` + : `/api/v1/tv/${request.media.tmdbId}`; + const { data: title, error } = useSWR( + inView ? `${url}?language=${locale}` : null + ); + const { data: requestData, revalidate } = useSWR( + `/api/v1/request/${request.id}`, + { + initialData: request, + } + ); + + const modifyRequest = async (type: 'approve' | 'decline') => { + const response = await axios.get(`/api/v1/request/${request.id}/${type}`); + + if (response) { + revalidate(); + } + }; + + const deleteRequest = async () => { + await axios.delete(`/api/v1/request/${request.id}`); + + onDelete(); + }; + + if (!title && !error) { + return ( + + + + ); + } + + if (!title || !requestData) { + return ( + + + + ); + } + + return ( + + + + + + + + + + + + {isMovie(title) ? title.title : title.name} + + +
+ {intl.formatMessage(messages.requestedby, { + username: requestData.requestedBy.username, + })} +
+ {requestData.seasons.length > 0 && ( +
+ {intl.formatMessage(messages.seasons)} + {requestData.seasons.map((season) => ( + + {season.seasonNumber} + + ))} +
+ )} +
+ + + + +
+ + + +
+
+ +
+ {requestData.modifiedBy ? ( + + {requestData.modifiedBy.username} ( + + ) + + ) : ( + N/A + )} +
+
+ + {requestData.status !== MediaRequestStatus.PENDING && + hasPermission(Permission.MANAGE_REQUESTS) && ( + + )} + {requestData.status === MediaRequestStatus.PENDING && + hasPermission(Permission.MANAGE_REQUESTS) && ( + <> + + + + + + + + )} + + + ); +}; + +export default RequestItem; diff --git a/src/components/RequestList/index.tsx b/src/components/RequestList/index.tsx new file mode 100644 index 00000000..4a62237b --- /dev/null +++ b/src/components/RequestList/index.tsx @@ -0,0 +1,109 @@ +import React, { useState } from 'react'; +import useSWR from 'swr'; +import type { RequestResultsResponse } from '../../../server/interfaces/api/requestInterfaces'; +import LoadingSpinner from '../Common/LoadingSpinner'; +import RequestItem from './RequestItem'; +import Header from '../Common/Header'; +import Table from '../Common/Table'; +import Button from '../Common/Button'; +import { defineMessages, useIntl } from 'react-intl'; + +const messages = defineMessages({ + requests: 'Requests', + mediaInfo: 'Media Info', + status: 'Status', + requestedAt: 'Requested At', + modifiedBy: 'Last Modified By', + showingresults: + 'Showing {from} to {to} of {total} results', + next: 'Next', + previous: 'Previous', +}); + +const RequestList: React.FC = () => { + const intl = useIntl(); + const [pageIndex, setPageIndex] = useState(0); + + const { data, error, revalidate } = useSWR( + `/api/v1/request?take=10&skip=${pageIndex * 10}` + ); + if (!data && !error) { + return ; + } + + if (!data) { + return ; + } + + const hasNextPage = data.pageInfo.pages > pageIndex + 1; + const hasPrevPage = pageIndex > 0; + + return ( + <> +
{intl.formatMessage(messages.requests)}
+ + + + {intl.formatMessage(messages.mediaInfo)} + {intl.formatMessage(messages.status)} + {intl.formatMessage(messages.requestedAt)} + {intl.formatMessage(messages.modifiedBy)} + + + + {data.results.map((request) => { + return ( + revalidate()} + /> + ); + })} + + + + + + +
+ + ); +}; + +export default RequestList; diff --git a/src/components/RequestModal/TvRequestModal.tsx b/src/components/RequestModal/TvRequestModal.tsx index f3feb0c6..6f13a670 100644 --- a/src/components/RequestModal/TvRequestModal.tsx +++ b/src/components/RequestModal/TvRequestModal.tsx @@ -11,10 +11,10 @@ import { MediaStatus, MediaRequestStatus, } from '../../../server/constants/media'; -import { TvDetails, SeasonWithEpisodes } from '../../../server/models/Tv'; -import type SeasonRequest from '../../../server/entity/SeasonRequest'; +import { TvDetails } from '../../../server/models/Tv'; import Badge from '../Common/Badge'; import globalMessages from '../../i18n/globalMessages'; +import SeasonRequest from '../../../server/entity/SeasonRequest'; const messages = defineMessages({ requestadmin: 'Your request will be immediately approved.', diff --git a/src/components/RequestModal/index.tsx b/src/components/RequestModal/index.tsx index 044f0953..e87adb60 100644 --- a/src/components/RequestModal/index.tsx +++ b/src/components/RequestModal/index.tsx @@ -1,10 +1,8 @@ import React from 'react'; -import useSWR from 'swr'; import MovieRequestModal from './MovieRequestModal'; -import type { MediaRequest } from '../../../server/entity/MediaRequest'; import type { MediaStatus } from '../../../server/constants/media'; import TvRequestModal from './TvRequestModal'; -import { useTransition, animated } from 'react-spring'; +import { useTransition } from 'react-spring'; interface RequestModalProps { show: boolean; @@ -21,7 +19,6 @@ const RequestModal: React.FC = ({ show, tmdbId, onComplete, - onError, onUpdating, onCancel, }) => { diff --git a/src/components/Settings/Notifications/NotificationsDiscord.tsx b/src/components/Settings/Notifications/NotificationsDiscord.tsx index c0374ec7..4eae75a6 100644 --- a/src/components/Settings/Notifications/NotificationsDiscord.tsx +++ b/src/components/Settings/Notifications/NotificationsDiscord.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Field, Form, Formik } from 'formik'; import useSWR from 'swr'; import LoadingSpinner from '../../Common/LoadingSpinner'; diff --git a/src/components/Settings/Notifications/NotificationsEmail.tsx b/src/components/Settings/Notifications/NotificationsEmail.tsx index 7f5e3b35..d581f423 100644 --- a/src/components/Settings/Notifications/NotificationsEmail.tsx +++ b/src/components/Settings/Notifications/NotificationsEmail.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React from 'react'; import { Field, Form, Formik } from 'formik'; import useSWR from 'swr'; import LoadingSpinner from '../../Common/LoadingSpinner'; diff --git a/src/components/Settings/RadarrModal/index.tsx b/src/components/Settings/RadarrModal/index.tsx index 2912fa1b..5542facf 100644 --- a/src/components/Settings/RadarrModal/index.tsx +++ b/src/components/Settings/RadarrModal/index.tsx @@ -226,7 +226,7 @@ const RadarrModal: React.FC = ({ okText={ isSubmitting ? intl.formatMessage(messages.saving) - : !!radarr + : radarr ? intl.formatMessage(messages.save) : intl.formatMessage(messages.add) } diff --git a/src/components/Settings/SettingsJobs.tsx b/src/components/Settings/SettingsJobs.tsx index 3af92a74..5e9364b0 100644 --- a/src/components/Settings/SettingsJobs.tsx +++ b/src/components/Settings/SettingsJobs.tsx @@ -3,6 +3,7 @@ import useSWR from 'swr'; import LoadingSpinner from '../Common/LoadingSpinner'; import { FormattedRelativeTime, defineMessages, useIntl } from 'react-intl'; import Button from '../Common/Button'; +import Table from '../Common/Table'; const messages = defineMessages({ jobname: 'Job Name', @@ -21,55 +22,38 @@ const SettingsJobs: React.FC = () => { } return ( -
-
-
-
- - - - - - - - - - {data?.map((job, index) => ( - - - - - - ))} - -
- {intl.formatMessage(messages.jobname)} - - {intl.formatMessage(messages.nextexecution)} -
-
- {job.name} -
-
-
- -
-
- -
-
-
-
-
+ + + {intl.formatMessage(messages.jobname)} + {intl.formatMessage(messages.nextexecution)} + + + + {data?.map((job, index) => ( + + +
{job.name}
+
+ +
+ +
+
+ + + + + ))} + +
); }; diff --git a/src/components/Settings/SettingsLayout.tsx b/src/components/Settings/SettingsLayout.tsx index 49c4eda7..13bc1801 100644 --- a/src/components/Settings/SettingsLayout.tsx +++ b/src/components/Settings/SettingsLayout.tsx @@ -80,7 +80,7 @@ const SettingsLayout: React.FC = ({ children }) => { diff --git a/src/components/Settings/SettingsMain.tsx b/src/components/Settings/SettingsMain.tsx index fdb6c249..611e11b9 100644 --- a/src/components/Settings/SettingsMain.tsx +++ b/src/components/Settings/SettingsMain.tsx @@ -7,6 +7,7 @@ import { Form, Formik, Field } from 'formik'; import axios from 'axios'; import Button from '../Common/Button'; import { defineMessages, useIntl } from 'react-intl'; +import { useUser, Permission } from '../../hooks/useUser'; const messages = defineMessages({ generalsettings: 'General Settings', @@ -19,6 +20,7 @@ const messages = defineMessages({ }); const SettingsMain: React.FC = () => { + const { hasPermission } = useUser(); const intl = useIntl(); const { data, error, revalidate } = useSWR( '/api/v1/settings/main' @@ -41,7 +43,6 @@ const SettingsMain: React.FC = () => {
{ @@ -56,43 +57,45 @@ const SettingsMain: React.FC = () => { } }} > - {({ errors, touched, isSubmitting }) => { + {({ isSubmitting }) => { return (
-
- -
-
- - - + {hasPermission(Permission.ADMIN) && ( +
+ +
+
+ + + +
-
+ )}
diff --git a/src/components/Settings/SonarrModal/index.tsx b/src/components/Settings/SonarrModal/index.tsx index aa8e7080..c6674781 100644 --- a/src/components/Settings/SonarrModal/index.tsx +++ b/src/components/Settings/SonarrModal/index.tsx @@ -229,7 +229,7 @@ const SonarrModal: React.FC = ({ okText={ isSubmitting ? intl.formatMessage(messages.saving) - : !!sonarr + : sonarr ? intl.formatMessage(messages.save) : intl.formatMessage(messages.add) } diff --git a/src/components/StatusBadge/index.tsx b/src/components/StatusBadge/index.tsx new file mode 100644 index 00000000..f56e8ae3 --- /dev/null +++ b/src/components/StatusBadge/index.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import { MediaStatus } from '../../../server/constants/media'; +import Badge from '../Common/Badge'; +import { useIntl } from 'react-intl'; +import globalMessages from '../../i18n/globalMessages'; + +interface StatusBadgeProps { + status: MediaStatus; +} + +const StatusBadge: React.FC = ({ status }) => { + const intl = useIntl(); + + return ( + <> + {status === MediaStatus.AVAILABLE && ( + + {intl.formatMessage(globalMessages.available)} + + )} + {status === MediaStatus.PARTIALLY_AVAILABLE && ( + + {intl.formatMessage(globalMessages.partiallyavailable)} + + )} + {status === MediaStatus.PROCESSING && ( + + {intl.formatMessage(globalMessages.unavailable)} + + )} + {status === MediaStatus.PENDING && ( + + {intl.formatMessage(globalMessages.pending)} + + )} + + ); +}; + +export default StatusBadge; diff --git a/src/components/TitleCard/TmdbTitleCard.tsx b/src/components/TitleCard/TmdbTitleCard.tsx index 8370a812..40325a30 100644 --- a/src/components/TitleCard/TmdbTitleCard.tsx +++ b/src/components/TitleCard/TmdbTitleCard.tsx @@ -1,4 +1,5 @@ import React, { useContext } from 'react'; +import { useInView } from 'react-intersection-observer'; import useSWR from 'swr'; import type { MovieDetails } from '../../../server/models/Movie'; import type { TvDetails } from '../../../server/models/Tv'; @@ -15,15 +16,22 @@ const isMovie = (movie: MovieDetails | TvDetails): movie is MovieDetails => { }; const TmdbTitleCard: React.FC = ({ tmdbId, type }) => { + const { ref, inView } = useInView({ + triggerOnce: true, + }); const { locale } = useContext(LanguageContext); const url = type === 'movie' ? `/api/v1/movie/${tmdbId}` : `/api/v1/tv/${tmdbId}`; const { data: title, error } = useSWR( - `${url}?language=${locale}` + inView ? `${url}?language=${locale}` : null ); if (!title && !error) { - return ; + return ( +
+ +
+ ); } if (!title) { diff --git a/src/components/TvDetails/index.tsx b/src/components/TvDetails/index.tsx index 22965a14..f9a0bdb0 100644 --- a/src/components/TvDetails/index.tsx +++ b/src/components/TvDetails/index.tsx @@ -156,12 +156,12 @@ const TvDetails: React.FC = ({ tv }) => { /> setShowManager(false)} subText={data.name} >

- {intl.formatMessage(messages.manageModalTitle)} + {intl.formatMessage(messages.manageModalRequests)}

    @@ -473,7 +473,7 @@ const TvDetails: React.FC = ({ tv }) => {
( { return ( <>
{intl.formatMessage(messages.userlist)}
-
-
-
-
- - - - - - - - - - - - - - {data?.map((user) => ( - - - - - - - - - - ))} - -
- {intl.formatMessage(messages.username)} - - {intl.formatMessage(messages.totalrequests)} - - {intl.formatMessage(messages.usertype)} - - {intl.formatMessage(messages.role)} - - {intl.formatMessage(messages.created)} - - {intl.formatMessage(messages.lastupdated)} -
-
-
- -
-
-
- {user.username} -
-
- {user.email} -
-
-
-
-
- {user.requestCount} -
-
- - {intl.formatMessage(messages.plexuser)} - - - {hasPermission(Permission.ADMIN, user.permissions) - ? intl.formatMessage(messages.admin) - : intl.formatMessage(messages.user)} - - - - - - - -
-
-
-
-
+ + + + {intl.formatMessage(messages.username)} + {intl.formatMessage(messages.totalrequests)} + {intl.formatMessage(messages.usertype)} + {intl.formatMessage(messages.role)} + {intl.formatMessage(messages.created)} + {intl.formatMessage(messages.lastupdated)} + + + + + {data?.map((user) => ( + + +
+
+ +
+
+
+ {user.username} +
+
+ {user.email} +
+
+
+
+ +
{user.requestCount}
+
+ + + {intl.formatMessage(messages.plexuser)} + + + + {hasPermission(Permission.ADMIN, user.permissions) + ? intl.formatMessage(messages.admin) + : intl.formatMessage(messages.user)} + + + + + + + + + + + + + ))} + +
); }; diff --git a/src/context/UserContext.tsx b/src/context/UserContext.tsx index 93c18ea3..24809a18 100644 --- a/src/context/UserContext.tsx +++ b/src/context/UserContext.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react'; +import React, { useEffect, useRef } from 'react'; import { User, useUser } from '../hooks/useUser'; import { useRouter } from 'next/dist/client/router'; @@ -17,20 +17,19 @@ export const UserContext: React.FC = ({ }) => { const { user, error, revalidate } = useUser({ initialData: initialUser }); const router = useRouter(); + const routing = useRef(false); useEffect(() => { revalidate(); }, [router.pathname, revalidate]); useEffect(() => { - let routing = false; - if ( !router.pathname.match(/(setup|login)/) && (!user || error) && - !routing + !routing.current ) { - routing = true; + routing.current = true; location.href = '/login'; } }, [router, user, error]); diff --git a/src/hooks/useUser.ts b/src/hooks/useUser.ts index 5f33a93b..bd6e0bb3 100644 --- a/src/hooks/useUser.ts +++ b/src/hooks/useUser.ts @@ -1,5 +1,4 @@ import useSwr from 'swr'; -import { useRef } from 'react'; import { hasPermission, Permission } from '../../server/lib/permissions'; export interface User { diff --git a/src/i18n/globalMessages.ts b/src/i18n/globalMessages.ts index 7fc65657..448b2d9c 100644 --- a/src/i18n/globalMessages.ts +++ b/src/i18n/globalMessages.ts @@ -13,6 +13,7 @@ const globalMessages = defineMessages({ cancel: 'Cancel', approve: 'Approve', decline: 'Decline', + delete: 'Delete', }); export default globalMessages; diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 7c7dc71f..25d3306c 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -51,6 +51,17 @@ "components.RequestBlock.seasons": "Seasons", "components.RequestCard.requestedby": "Requested by {username}", "components.RequestCard.seasons": "Seasons", + "components.RequestList.RequestItem.notavailable": "N/A", + "components.RequestList.RequestItem.requestedby": "Requested by {username}", + "components.RequestList.RequestItem.seasons": "Seasons", + "components.RequestList.mediaInfo": "Media Info", + "components.RequestList.modifiedBy": "Last Modified By", + "components.RequestList.next": "Next", + "components.RequestList.previous": "Previous", + "components.RequestList.requestedAt": "Requested At", + "components.RequestList.requests": "Requests", + "components.RequestList.showingresults": "Showing {from} to {to} of {total} results", + "components.RequestList.status": "Status", "components.RequestModal.cancel": "Cancel Request", "components.RequestModal.cancelling": "Cancelling...", "components.RequestModal.cancelrequest": "This will remove your request. Are you sure you want to continue?", @@ -275,6 +286,7 @@ "i18n.cancel": "Cancel", "i18n.decline": "Decline", "i18n.declined": "Declined", + "i18n.delete": "Delete", "i18n.movies": "Movies", "i18n.partiallyavailable": "Partially Available", "i18n.pending": "Pending", diff --git a/src/i18n/locale/fr.json b/src/i18n/locale/fr.json index 501da299..9ce8e30a 100644 --- a/src/i18n/locale/fr.json +++ b/src/i18n/locale/fr.json @@ -51,6 +51,17 @@ "components.RequestBlock.seasons": "Saisons", "components.RequestCard.requestedby": "Demandé par {username}", "components.RequestCard.seasons": "Saisons", + "components.RequestList.RequestItem.notavailable": "", + "components.RequestList.RequestItem.requestedby": "", + "components.RequestList.RequestItem.seasons": "", + "components.RequestList.mediaInfo": "", + "components.RequestList.modifiedBy": "", + "components.RequestList.next": "", + "components.RequestList.previous": "", + "components.RequestList.requestedAt": "", + "components.RequestList.requests": "", + "components.RequestList.showingresults": "", + "components.RequestList.status": "", "components.RequestModal.cancel": "Annuler la Demande", "components.RequestModal.cancelling": "Annulation...", "components.RequestModal.cancelrequest": "Votre demande d'ajout va être annulée. Êtes-vous sûr de vouloir annuler?", @@ -275,6 +286,7 @@ "i18n.cancel": "Annuler", "i18n.decline": "Refuser", "i18n.declined": "Refusé", + "i18n.delete": "", "i18n.movies": "Films", "i18n.partiallyavailable": "Partiellement Disponible", "i18n.pending": "En Attente", diff --git a/src/i18n/locale/ja.json b/src/i18n/locale/ja.json index c57e228c..78e6d7d3 100644 --- a/src/i18n/locale/ja.json +++ b/src/i18n/locale/ja.json @@ -1,290 +1,302 @@ { - "components.Discover.discovermovies": "人気の映画", - "components.Discover.discovertv": "人気のテレビ番組", - "components.Discover.nopending": "", - "components.Discover.popularmovies": "人気の映画", - "components.Discover.populartv": "人気のテレビ番組", - "components.Discover.recentlyAdded": "", - "components.Discover.recentrequests": "最近のリクエスト", - "components.Discover.trending": "", - "components.Discover.upcoming": "", - "components.Discover.upcomingmovies": "", - "components.Layout.LanguagePicker.changelanguage": "言語", - "components.Layout.SearchInput.searchPlaceholder": "作品名で検索", - "components.Layout.Sidebar.dashboard": "ホーム", - "components.Layout.Sidebar.requests": "リクエスト", - "components.Layout.Sidebar.settings": "設定", - "components.Layout.Sidebar.users": "", - "components.Layout.UserDropdown.signout": "", - "components.Layout.alphawarning": "", - "components.Login.signinplex": "", - "components.MovieDetails.approve": "", - "components.MovieDetails.available": "", - "components.MovieDetails.budget": "興行収入", - "components.MovieDetails.cancelrequest": "チャンセルリクエスト", - "components.MovieDetails.cast": "キャスト", - "components.MovieDetails.decline": "", - "components.MovieDetails.manageModalClearMedia": "", - "components.MovieDetails.manageModalClearMediaWarning": "", - "components.MovieDetails.manageModalNoRequests": "", - "components.MovieDetails.manageModalRequests": "リクエスト", - "components.MovieDetails.manageModalTitle": "", - "components.MovieDetails.originallanguage": "言語", - "components.MovieDetails.overview": "ストーリー", - "components.MovieDetails.overviewunavailable": "", - "components.MovieDetails.pending": "リクエスト中", - "components.MovieDetails.recommendations": "オススメの作品", - "components.MovieDetails.recommendationssubtext": "", - "components.MovieDetails.releasedate": "公開日", - "components.MovieDetails.request": "リクエストする", - "components.MovieDetails.revenue": "製作費", - "components.MovieDetails.runtime": "{minutes}分", - "components.MovieDetails.similar": "関連作品", - "components.MovieDetails.similarsubtext": "", - "components.MovieDetails.status": "状態", - "components.MovieDetails.unavailable": "", - "components.MovieDetails.userrating": "ユーザー評価", - "components.MovieDetails.viewrequest": "", - "components.PlexLoginButton.loading": "", - "components.PlexLoginButton.loggingin": "", - "components.PlexLoginButton.loginwithplex": "", - "components.RequestBlock.seasons": "", - "components.RequestCard.requestedby": "", - "components.RequestCard.seasons": "", - "components.RequestModal.cancel": "チャンセルリクエスト", - "components.RequestModal.cancelling": "", - "components.RequestModal.cancelrequest": "このリクエストをキャンセルしてよろしいですか?", - "components.RequestModal.close": "", - "components.RequestModal.extras": "", - "components.RequestModal.notrequested": "", - "components.RequestModal.numberofepisodes": "", - "components.RequestModal.pendingrequest": "", - "components.RequestModal.request": "リクエストする", - "components.RequestModal.requestCancel": "", - "components.RequestModal.requestSuccess": "", - "components.RequestModal.requestadmin": "このリクエストが今すぐ承認致します。よろしいですか?", - "components.RequestModal.requestfrom": "", - "components.RequestModal.requesting": "", - "components.RequestModal.requestseasons": "", - "components.RequestModal.requesttitle": "", - "components.RequestModal.season": "", - "components.RequestModal.seasonnumber": "", - "components.RequestModal.selectseason": "", - "components.RequestModal.status": "状態", - "components.Search.searchresults": "", - "components.Settings.Notifications.agentenabled": "", - "components.Settings.Notifications.authPass": "", - "components.Settings.Notifications.authUser": "", - "components.Settings.Notifications.emailsender": "", - "components.Settings.Notifications.enableSsl": "", - "components.Settings.Notifications.save": "", - "components.Settings.Notifications.saving": "", - "components.Settings.Notifications.smtpHost": "", - "components.Settings.Notifications.smtpPort": "", - "components.Settings.Notifications.validationFromRequired": "", - "components.Settings.Notifications.validationSmtpHostRequired": "", - "components.Settings.Notifications.validationSmtpPortRequired": "", - "components.Settings.Notifications.validationWebhookUrlRequired": "", - "components.Settings.Notifications.webhookUrl": "", - "components.Settings.Notifications.webhookUrlPlaceholder": "", - "components.Settings.RadarrModal.add": "", - "components.Settings.RadarrModal.apiKey": "", - "components.Settings.RadarrModal.apiKeyPlaceholder": "", - "components.Settings.RadarrModal.baseUrl": "", - "components.Settings.RadarrModal.baseUrlPlaceholder": "", - "components.Settings.RadarrModal.createradarr": "", - "components.Settings.RadarrModal.defaultserver": "", - "components.Settings.RadarrModal.editradarr": "", - "components.Settings.RadarrModal.hostname": "", - "components.Settings.RadarrModal.minimumAvailability": "", - "components.Settings.RadarrModal.port": "", - "components.Settings.RadarrModal.qualityprofile": "", - "components.Settings.RadarrModal.rootfolder": "", - "components.Settings.RadarrModal.save": "", - "components.Settings.RadarrModal.saving": "", - "components.Settings.RadarrModal.selectMinimumAvailability": "", - "components.Settings.RadarrModal.selectQualityProfile": "", - "components.Settings.RadarrModal.selectRootFolder": "", - "components.Settings.RadarrModal.server4k": "", - "components.Settings.RadarrModal.servername": "", - "components.Settings.RadarrModal.servernamePlaceholder": "", - "components.Settings.RadarrModal.ssl": "", - "components.Settings.RadarrModal.test": "", - "components.Settings.RadarrModal.testing": "", - "components.Settings.RadarrModal.toastRadarrTestFailure": "", - "components.Settings.RadarrModal.toastRadarrTestSuccess": "", - "components.Settings.RadarrModal.validationApiKeyRequired": "", - "components.Settings.RadarrModal.validationHostnameRequired": "", - "components.Settings.RadarrModal.validationPortRequired": "", - "components.Settings.RadarrModal.validationProfileRequired": "", - "components.Settings.RadarrModal.validationRootFolderRequired": "", - "components.Settings.SonarrModal.add": "", - "components.Settings.SonarrModal.apiKey": "", - "components.Settings.SonarrModal.apiKeyPlaceholder": "", - "components.Settings.SonarrModal.baseUrl": "", - "components.Settings.SonarrModal.baseUrlPlaceholder": "", - "components.Settings.SonarrModal.createsonarr": "", - "components.Settings.SonarrModal.defaultserver": "", - "components.Settings.SonarrModal.editsonarr": "", - "components.Settings.SonarrModal.hostname": "", - "components.Settings.SonarrModal.port": "", - "components.Settings.SonarrModal.qualityprofile": "", - "components.Settings.SonarrModal.rootfolder": "", - "components.Settings.SonarrModal.save": "", - "components.Settings.SonarrModal.saving": "", - "components.Settings.SonarrModal.seasonfolders": "", - "components.Settings.SonarrModal.selectQualityProfile": "", - "components.Settings.SonarrModal.selectRootFolder": "", - "components.Settings.SonarrModal.server4k": "", - "components.Settings.SonarrModal.servername": "", - "components.Settings.SonarrModal.servernamePlaceholder": "", - "components.Settings.SonarrModal.ssl": "", - "components.Settings.SonarrModal.test": "", - "components.Settings.SonarrModal.testing": "", - "components.Settings.SonarrModal.toastRadarrTestFailure": "", - "components.Settings.SonarrModal.toastRadarrTestSuccess": "", - "components.Settings.SonarrModal.validationApiKeyRequired": "", - "components.Settings.SonarrModal.validationHostnameRequired": "", - "components.Settings.SonarrModal.validationPortRequired": "", - "components.Settings.SonarrModal.validationProfileRequired": "", - "components.Settings.SonarrModal.validationRootFolderRequired": "", - "components.Settings.activeProfile": "", - "components.Settings.addradarr": "", - "components.Settings.address": "", - "components.Settings.addsonarr": "", - "components.Settings.apikey": "", - "components.Settings.applicationurl": "", - "components.Settings.cancelscan": "", - "components.Settings.copied": "", - "components.Settings.currentlibrary": "", - "components.Settings.default": "", - "components.Settings.default4k": "", - "components.Settings.delete": "", - "components.Settings.deleteserverconfirm": "", - "components.Settings.edit": "", - "components.Settings.generalsettings": "", - "components.Settings.generalsettingsDescription": "", - "components.Settings.hostname": "", - "components.Settings.jobname": "", - "components.Settings.librariesRemaining": "", - "components.Settings.manualscan": "", - "components.Settings.manualscanDescription": "", - "components.Settings.menuAbout": "", - "components.Settings.menuGeneralSettings": "", - "components.Settings.menuJobs": "", - "components.Settings.menuLogs": "", - "components.Settings.menuNotifications": "", - "components.Settings.menuPlexSettings": "", - "components.Settings.menuServices": "", - "components.Settings.nextexecution": "", - "components.Settings.notificationsettings": "", - "components.Settings.notificationsettingsDescription": "", - "components.Settings.notrunning": "", - "components.Settings.plexlibraries": "", - "components.Settings.plexlibrariesDescription": "", - "components.Settings.plexsettings": "", - "components.Settings.plexsettingsDescription": "", - "components.Settings.port": "", - "components.Settings.radarrSettingsDescription": "", - "components.Settings.radarrsettings": "", - "components.Settings.runnow": "", - "components.Settings.save": "", - "components.Settings.saving": "", - "components.Settings.servername": "", - "components.Settings.servernamePlaceholder": "", - "components.Settings.sonarrSettingsDescription": "", - "components.Settings.sonarrsettings": "", - "components.Settings.ssl": "", - "components.Settings.startscan": "", - "components.Settings.sync": "", - "components.Settings.syncing": "", - "components.Setup.configureplex": "", - "components.Setup.configureservices": "", - "components.Setup.continue": "", - "components.Setup.finish": "", - "components.Setup.finishing": "", - "components.Setup.loginwithplex": "", - "components.Setup.signinMessage": "", - "components.Setup.welcome": "", - "components.Slider.noresults": "", - "components.TitleCard.movie": "", - "components.TitleCard.tvshow": "", - "components.TvDetails.approve": "", - "components.TvDetails.approverequests": "", - "components.TvDetails.available": "", - "components.TvDetails.cancelrequest": "チャンセルリクエスト", - "components.TvDetails.cast": "キャスト", - "components.TvDetails.decline": "", - "components.TvDetails.declinerequests": "", - "components.TvDetails.manageModalClearMedia": "", - "components.TvDetails.manageModalClearMediaWarning": "", - "components.TvDetails.manageModalNoRequests": "", - "components.TvDetails.manageModalRequests": "リクエスト", - "components.TvDetails.manageModalTitle": "", - "components.TvDetails.originallanguage": "言語", - "components.TvDetails.overview": "ストーリー", - "components.TvDetails.overviewunavailable": "", - "components.TvDetails.pending": "リクエスト中", - "components.TvDetails.recommendations": "オススメの作品", - "components.TvDetails.recommendationssubtext": "", - "components.TvDetails.request": "リクエストする", - "components.TvDetails.requestmore": "", - "components.TvDetails.similar": "", - "components.TvDetails.similarsubtext": "", - "components.TvDetails.status": "状態", - "components.TvDetails.unavailable": "", - "components.TvDetails.userrating": "ユーザー評価", - "components.UserEdit.admin": "", - "components.UserEdit.adminDescription": "", - "components.UserEdit.autoapprove": "", - "components.UserEdit.autoapproveDescription": "", - "components.UserEdit.avatar": "", - "components.UserEdit.edituser": "", - "components.UserEdit.email": "", - "components.UserEdit.managerequests": "", - "components.UserEdit.managerequestsDescription": "", - "components.UserEdit.permissions": "", - "components.UserEdit.request": "リクエストする", - "components.UserEdit.requestDescription": "", - "components.UserEdit.save": "", - "components.UserEdit.saving": "", - "components.UserEdit.settings": "", - "components.UserEdit.settingsDescription": "", - "components.UserEdit.userfail": "", - "components.UserEdit.username": "", - "components.UserEdit.users": "", - "components.UserEdit.usersDescription": "", - "components.UserEdit.usersaved": "", - "components.UserEdit.vote": "", - "components.UserEdit.voteDescription": "", - "components.UserList.admin": "", - "components.UserList.created": "", - "components.UserList.delete": "", - "components.UserList.edit": "", - "components.UserList.lastupdated": "", - "components.UserList.plexuser": "", - "components.UserList.role": "", - "components.UserList.totalrequests": "", - "components.UserList.user": "", - "components.UserList.userlist": "", - "components.UserList.username": "", - "components.UserList.usertype": "", - "i18n.approve": "", - "i18n.approved": "", - "i18n.available": "", - "i18n.cancel": "", - "i18n.decline": "", - "i18n.declined": "", - "i18n.movies": "", - "i18n.partiallyavailable": "", - "i18n.pending": "リクエスト中", - "i18n.processing": "", - "i18n.tvshows": "", - "i18n.unavailable": "", - "pages.internalServerError": "", - "pages.oops": "ああ", - "pages.pageNotFound": "", - "pages.returnHome": "ホームへ戻る", - "pages.serviceUnavailable": "", - "pages.somethingWentWrong": "" -} \ No newline at end of file + "components.Discover.discovermovies": "人気の映画", + "components.Discover.discovertv": "人気のテレビ番組", + "components.Discover.nopending": "", + "components.Discover.popularmovies": "人気の映画", + "components.Discover.populartv": "人気のテレビ番組", + "components.Discover.recentlyAdded": "", + "components.Discover.recentrequests": "最近のリクエスト", + "components.Discover.trending": "", + "components.Discover.upcoming": "", + "components.Discover.upcomingmovies": "", + "components.Layout.LanguagePicker.changelanguage": "言語", + "components.Layout.SearchInput.searchPlaceholder": "作品名で検索", + "components.Layout.Sidebar.dashboard": "ホーム", + "components.Layout.Sidebar.requests": "リクエスト", + "components.Layout.Sidebar.settings": "設定", + "components.Layout.Sidebar.users": "", + "components.Layout.UserDropdown.signout": "", + "components.Layout.alphawarning": "", + "components.Login.signinplex": "", + "components.MovieDetails.approve": "", + "components.MovieDetails.available": "", + "components.MovieDetails.budget": "興行収入", + "components.MovieDetails.cancelrequest": "チャンセルリクエスト", + "components.MovieDetails.cast": "キャスト", + "components.MovieDetails.decline": "", + "components.MovieDetails.manageModalClearMedia": "", + "components.MovieDetails.manageModalClearMediaWarning": "", + "components.MovieDetails.manageModalNoRequests": "", + "components.MovieDetails.manageModalRequests": "リクエスト", + "components.MovieDetails.manageModalTitle": "", + "components.MovieDetails.originallanguage": "言語", + "components.MovieDetails.overview": "ストーリー", + "components.MovieDetails.overviewunavailable": "", + "components.MovieDetails.pending": "リクエスト中", + "components.MovieDetails.recommendations": "オススメの作品", + "components.MovieDetails.recommendationssubtext": "", + "components.MovieDetails.releasedate": "公開日", + "components.MovieDetails.request": "リクエストする", + "components.MovieDetails.revenue": "製作費", + "components.MovieDetails.runtime": "{minutes}分", + "components.MovieDetails.similar": "関連作品", + "components.MovieDetails.similarsubtext": "", + "components.MovieDetails.status": "状態", + "components.MovieDetails.unavailable": "", + "components.MovieDetails.userrating": "ユーザー評価", + "components.MovieDetails.viewrequest": "", + "components.PlexLoginButton.loading": "", + "components.PlexLoginButton.loggingin": "", + "components.PlexLoginButton.loginwithplex": "", + "components.RequestBlock.seasons": "", + "components.RequestCard.requestedby": "", + "components.RequestCard.seasons": "", + "components.RequestList.RequestItem.notavailable": "", + "components.RequestList.RequestItem.requestedby": "", + "components.RequestList.RequestItem.seasons": "", + "components.RequestList.mediaInfo": "", + "components.RequestList.modifiedBy": "", + "components.RequestList.next": "", + "components.RequestList.previous": "", + "components.RequestList.requestedAt": "", + "components.RequestList.requests": "", + "components.RequestList.showingresults": "", + "components.RequestList.status": "", + "components.RequestModal.cancel": "チャンセルリクエスト", + "components.RequestModal.cancelling": "", + "components.RequestModal.cancelrequest": "このリクエストをキャンセルしてよろしいですか?", + "components.RequestModal.close": "", + "components.RequestModal.extras": "", + "components.RequestModal.notrequested": "", + "components.RequestModal.numberofepisodes": "", + "components.RequestModal.pendingrequest": "", + "components.RequestModal.request": "リクエストする", + "components.RequestModal.requestCancel": "", + "components.RequestModal.requestSuccess": "", + "components.RequestModal.requestadmin": "このリクエストが今すぐ承認致します。よろしいですか?", + "components.RequestModal.requestfrom": "", + "components.RequestModal.requesting": "", + "components.RequestModal.requestseasons": "", + "components.RequestModal.requesttitle": "", + "components.RequestModal.season": "", + "components.RequestModal.seasonnumber": "", + "components.RequestModal.selectseason": "", + "components.RequestModal.status": "状態", + "components.Search.searchresults": "", + "components.Settings.Notifications.agentenabled": "", + "components.Settings.Notifications.authPass": "", + "components.Settings.Notifications.authUser": "", + "components.Settings.Notifications.emailsender": "", + "components.Settings.Notifications.enableSsl": "", + "components.Settings.Notifications.save": "", + "components.Settings.Notifications.saving": "", + "components.Settings.Notifications.smtpHost": "", + "components.Settings.Notifications.smtpPort": "", + "components.Settings.Notifications.validationFromRequired": "", + "components.Settings.Notifications.validationSmtpHostRequired": "", + "components.Settings.Notifications.validationSmtpPortRequired": "", + "components.Settings.Notifications.validationWebhookUrlRequired": "", + "components.Settings.Notifications.webhookUrl": "", + "components.Settings.Notifications.webhookUrlPlaceholder": "", + "components.Settings.RadarrModal.add": "", + "components.Settings.RadarrModal.apiKey": "", + "components.Settings.RadarrModal.apiKeyPlaceholder": "", + "components.Settings.RadarrModal.baseUrl": "", + "components.Settings.RadarrModal.baseUrlPlaceholder": "", + "components.Settings.RadarrModal.createradarr": "", + "components.Settings.RadarrModal.defaultserver": "", + "components.Settings.RadarrModal.editradarr": "", + "components.Settings.RadarrModal.hostname": "", + "components.Settings.RadarrModal.minimumAvailability": "", + "components.Settings.RadarrModal.port": "", + "components.Settings.RadarrModal.qualityprofile": "", + "components.Settings.RadarrModal.rootfolder": "", + "components.Settings.RadarrModal.save": "", + "components.Settings.RadarrModal.saving": "", + "components.Settings.RadarrModal.selectMinimumAvailability": "", + "components.Settings.RadarrModal.selectQualityProfile": "", + "components.Settings.RadarrModal.selectRootFolder": "", + "components.Settings.RadarrModal.server4k": "", + "components.Settings.RadarrModal.servername": "", + "components.Settings.RadarrModal.servernamePlaceholder": "", + "components.Settings.RadarrModal.ssl": "", + "components.Settings.RadarrModal.test": "", + "components.Settings.RadarrModal.testing": "", + "components.Settings.RadarrModal.toastRadarrTestFailure": "", + "components.Settings.RadarrModal.toastRadarrTestSuccess": "", + "components.Settings.RadarrModal.validationApiKeyRequired": "", + "components.Settings.RadarrModal.validationHostnameRequired": "", + "components.Settings.RadarrModal.validationPortRequired": "", + "components.Settings.RadarrModal.validationProfileRequired": "", + "components.Settings.RadarrModal.validationRootFolderRequired": "", + "components.Settings.SonarrModal.add": "", + "components.Settings.SonarrModal.apiKey": "", + "components.Settings.SonarrModal.apiKeyPlaceholder": "", + "components.Settings.SonarrModal.baseUrl": "", + "components.Settings.SonarrModal.baseUrlPlaceholder": "", + "components.Settings.SonarrModal.createsonarr": "", + "components.Settings.SonarrModal.defaultserver": "", + "components.Settings.SonarrModal.editsonarr": "", + "components.Settings.SonarrModal.hostname": "", + "components.Settings.SonarrModal.port": "", + "components.Settings.SonarrModal.qualityprofile": "", + "components.Settings.SonarrModal.rootfolder": "", + "components.Settings.SonarrModal.save": "", + "components.Settings.SonarrModal.saving": "", + "components.Settings.SonarrModal.seasonfolders": "", + "components.Settings.SonarrModal.selectQualityProfile": "", + "components.Settings.SonarrModal.selectRootFolder": "", + "components.Settings.SonarrModal.server4k": "", + "components.Settings.SonarrModal.servername": "", + "components.Settings.SonarrModal.servernamePlaceholder": "", + "components.Settings.SonarrModal.ssl": "", + "components.Settings.SonarrModal.test": "", + "components.Settings.SonarrModal.testing": "", + "components.Settings.SonarrModal.toastRadarrTestFailure": "", + "components.Settings.SonarrModal.toastRadarrTestSuccess": "", + "components.Settings.SonarrModal.validationApiKeyRequired": "", + "components.Settings.SonarrModal.validationHostnameRequired": "", + "components.Settings.SonarrModal.validationPortRequired": "", + "components.Settings.SonarrModal.validationProfileRequired": "", + "components.Settings.SonarrModal.validationRootFolderRequired": "", + "components.Settings.activeProfile": "", + "components.Settings.addradarr": "", + "components.Settings.address": "", + "components.Settings.addsonarr": "", + "components.Settings.apikey": "", + "components.Settings.applicationurl": "", + "components.Settings.cancelscan": "", + "components.Settings.copied": "", + "components.Settings.currentlibrary": "", + "components.Settings.default": "", + "components.Settings.default4k": "", + "components.Settings.delete": "", + "components.Settings.deleteserverconfirm": "", + "components.Settings.edit": "", + "components.Settings.generalsettings": "", + "components.Settings.generalsettingsDescription": "", + "components.Settings.hostname": "", + "components.Settings.jobname": "", + "components.Settings.librariesRemaining": "", + "components.Settings.manualscan": "", + "components.Settings.manualscanDescription": "", + "components.Settings.menuAbout": "", + "components.Settings.menuGeneralSettings": "", + "components.Settings.menuJobs": "", + "components.Settings.menuLogs": "", + "components.Settings.menuNotifications": "", + "components.Settings.menuPlexSettings": "", + "components.Settings.menuServices": "", + "components.Settings.nextexecution": "", + "components.Settings.notificationsettings": "", + "components.Settings.notificationsettingsDescription": "", + "components.Settings.notrunning": "", + "components.Settings.plexlibraries": "", + "components.Settings.plexlibrariesDescription": "", + "components.Settings.plexsettings": "", + "components.Settings.plexsettingsDescription": "", + "components.Settings.port": "", + "components.Settings.radarrSettingsDescription": "", + "components.Settings.radarrsettings": "", + "components.Settings.runnow": "", + "components.Settings.save": "", + "components.Settings.saving": "", + "components.Settings.servername": "", + "components.Settings.servernamePlaceholder": "", + "components.Settings.sonarrSettingsDescription": "", + "components.Settings.sonarrsettings": "", + "components.Settings.ssl": "", + "components.Settings.startscan": "", + "components.Settings.sync": "", + "components.Settings.syncing": "", + "components.Setup.configureplex": "", + "components.Setup.configureservices": "", + "components.Setup.continue": "", + "components.Setup.finish": "", + "components.Setup.finishing": "", + "components.Setup.loginwithplex": "", + "components.Setup.signinMessage": "", + "components.Setup.welcome": "", + "components.Slider.noresults": "", + "components.TitleCard.movie": "", + "components.TitleCard.tvshow": "", + "components.TvDetails.approve": "", + "components.TvDetails.approverequests": "", + "components.TvDetails.available": "", + "components.TvDetails.cancelrequest": "チャンセルリクエスト", + "components.TvDetails.cast": "キャスト", + "components.TvDetails.decline": "", + "components.TvDetails.declinerequests": "", + "components.TvDetails.manageModalClearMedia": "", + "components.TvDetails.manageModalClearMediaWarning": "", + "components.TvDetails.manageModalNoRequests": "", + "components.TvDetails.manageModalRequests": "リクエスト", + "components.TvDetails.manageModalTitle": "", + "components.TvDetails.originallanguage": "言語", + "components.TvDetails.overview": "ストーリー", + "components.TvDetails.overviewunavailable": "", + "components.TvDetails.pending": "リクエスト中", + "components.TvDetails.recommendations": "オススメの作品", + "components.TvDetails.recommendationssubtext": "", + "components.TvDetails.request": "リクエストする", + "components.TvDetails.requestmore": "", + "components.TvDetails.similar": "", + "components.TvDetails.similarsubtext": "", + "components.TvDetails.status": "状態", + "components.TvDetails.unavailable": "", + "components.TvDetails.userrating": "ユーザー評価", + "components.UserEdit.admin": "", + "components.UserEdit.adminDescription": "", + "components.UserEdit.autoapprove": "", + "components.UserEdit.autoapproveDescription": "", + "components.UserEdit.avatar": "", + "components.UserEdit.edituser": "", + "components.UserEdit.email": "", + "components.UserEdit.managerequests": "", + "components.UserEdit.managerequestsDescription": "", + "components.UserEdit.permissions": "", + "components.UserEdit.request": "リクエストする", + "components.UserEdit.requestDescription": "", + "components.UserEdit.save": "", + "components.UserEdit.saving": "", + "components.UserEdit.settings": "", + "components.UserEdit.settingsDescription": "", + "components.UserEdit.userfail": "", + "components.UserEdit.username": "", + "components.UserEdit.users": "", + "components.UserEdit.usersDescription": "", + "components.UserEdit.usersaved": "", + "components.UserEdit.vote": "", + "components.UserEdit.voteDescription": "", + "components.UserList.admin": "", + "components.UserList.created": "", + "components.UserList.delete": "", + "components.UserList.edit": "", + "components.UserList.lastupdated": "", + "components.UserList.plexuser": "", + "components.UserList.role": "", + "components.UserList.totalrequests": "", + "components.UserList.user": "", + "components.UserList.userlist": "", + "components.UserList.username": "", + "components.UserList.usertype": "", + "i18n.approve": "", + "i18n.approved": "", + "i18n.available": "", + "i18n.cancel": "", + "i18n.decline": "", + "i18n.declined": "", + "i18n.delete": "", + "i18n.movies": "", + "i18n.partiallyavailable": "", + "i18n.pending": "リクエスト中", + "i18n.processing": "", + "i18n.tvshows": "", + "i18n.unavailable": "", + "pages.internalServerError": "", + "pages.oops": "ああ", + "pages.pageNotFound": "", + "pages.returnHome": "ホームへ戻る", + "pages.serviceUnavailable": "", + "pages.somethingWentWrong": "" +} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index d1878a1d..f2c71cf0 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -100,13 +100,11 @@ CoreApp.getInitialProps = async (initialProps) => { if (ctx.res) { // Check if app is initialized and redirect if necessary - let initialized = true; - const response = await axios.get<{ initialized: boolean }>( `http://localhost:${process.env.PORT || 3000}/api/v1/settings/public` ); - initialized = response.data.initialized; + const initialized = response.data.initialized; if (!initialized) { if (!router.pathname.match(/(setup|login\/plex)/)) { @@ -145,7 +143,7 @@ CoreApp.getInitialProps = async (initialProps) => { const cookies = parseCookies(ctx); - if (!!cookies.locale) { + if (cookies.locale) { locale = cookies.locale; } } diff --git a/src/pages/_error.tsx b/src/pages/_error.tsx index 0920d773..69463a9f 100644 --- a/src/pages/_error.tsx +++ b/src/pages/_error.tsx @@ -65,7 +65,7 @@ Error.getInitialProps = async ({ res, err }): Promise => { // Apologies for how gross ternary is but this is just temporary. Honestly, // blame the nextjs docs let statusCode: Undefinable; - if (!!res) { + if (res) { statusCode = res.statusCode; } else { statusCode = err ? err.statusCode : undefined; diff --git a/src/pages/requests/index.tsx b/src/pages/requests/index.tsx new file mode 100644 index 00000000..225331ed --- /dev/null +++ b/src/pages/requests/index.tsx @@ -0,0 +1,9 @@ +import React from 'react'; +import type { NextPage } from 'next'; +import RequestList from '../../components/RequestList'; + +const RequestsPage: NextPage = () => { + return ; +}; + +export default RequestsPage; diff --git a/src/pages/settings/index.tsx b/src/pages/settings/index.tsx index 534857f3..e67d53b4 100644 --- a/src/pages/settings/index.tsx +++ b/src/pages/settings/index.tsx @@ -6,7 +6,7 @@ import useRouteGuard from '../../hooks/useRouteGuard'; import { Permission } from '../../hooks/useUser'; const SettingsPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); + useRouteGuard(Permission.MANAGE_SETTINGS); return ( diff --git a/src/pages/settings/jobs.tsx b/src/pages/settings/jobs.tsx index 2ca87139..b0d03387 100644 --- a/src/pages/settings/jobs.tsx +++ b/src/pages/settings/jobs.tsx @@ -6,7 +6,7 @@ import { Permission } from '../../hooks/useUser'; import useRouteGuard from '../../hooks/useRouteGuard'; const SettingsMainPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); + useRouteGuard(Permission.MANAGE_SETTINGS); return ( diff --git a/src/pages/settings/main.tsx b/src/pages/settings/main.tsx index 3a84b823..7c450a37 100644 --- a/src/pages/settings/main.tsx +++ b/src/pages/settings/main.tsx @@ -6,7 +6,7 @@ import { Permission } from '../../hooks/useUser'; import useRouteGuard from '../../hooks/useRouteGuard'; const SettingsMainPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); + useRouteGuard(Permission.MANAGE_SETTINGS); return ( diff --git a/src/pages/settings/plex.tsx b/src/pages/settings/plex.tsx index ea10f444..d5beaeeb 100644 --- a/src/pages/settings/plex.tsx +++ b/src/pages/settings/plex.tsx @@ -6,7 +6,7 @@ import { Permission } from '../../hooks/useUser'; import useRouteGuard from '../../hooks/useRouteGuard'; const PlexSettingsPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); + useRouteGuard(Permission.MANAGE_SETTINGS); return ( diff --git a/src/pages/settings/services.tsx b/src/pages/settings/services.tsx index 52e55ddf..862b9b4d 100644 --- a/src/pages/settings/services.tsx +++ b/src/pages/settings/services.tsx @@ -6,7 +6,7 @@ import { Permission } from '../../hooks/useUser'; import useRouteGuard from '../../hooks/useRouteGuard'; const ServicesSettingsPage: NextPage = () => { - useRouteGuard(Permission.MANAGE_USERS); + useRouteGuard(Permission.MANAGE_SETTINGS); return ( diff --git a/src/utils/plex.ts b/src/utils/plex.ts index 25b58a6d..fe98ae46 100644 --- a/src/utils/plex.ts +++ b/src/utils/plex.ts @@ -57,19 +57,15 @@ class PlexOAuth { 'You must initialize the plex headers clientside to login' ); } - try { - const response = await axios.post( - 'https://plex.tv/api/v2/pins?strong=true', - undefined, - { headers: this.plexHeaders } - ); + const response = await axios.post( + 'https://plex.tv/api/v2/pins?strong=true', + undefined, + { headers: this.plexHeaders } + ); - this.pin = { id: response.data.id, code: response.data.code }; + this.pin = { id: response.data.id, code: response.data.code }; - return this.pin; - } catch (e) { - throw e; - } + return this.pin; } public preparePopup(): void { @@ -77,42 +73,38 @@ class PlexOAuth { } public async login(): Promise { - try { - this.initializeHeaders(); - await this.getPin(); + this.initializeHeaders(); + await this.getPin(); - if (!this.plexHeaders || !this.pin) { - throw new Error('Unable to call login if class is not initialized.'); - } - - const params = { - clientID: this.plexHeaders['X-Plex-Client-Identifier'], - 'context[device][product]': this.plexHeaders['X-Plex-Product'], - 'context[device][version]': this.plexHeaders['X-Plex-Version'], - 'context[device][platform]': this.plexHeaders['X-Plex-Platform'], - 'context[device][platformVersion]': this.plexHeaders[ - 'X-Plex-Platform-Version' - ], - 'context[device][device]': this.plexHeaders['X-Plex-Device'], - 'context[device][deviceName]': this.plexHeaders['X-Plex-Device-Name'], - 'context[device][model]': this.plexHeaders['X-Plex-Model'], - 'context[device][screenResolution]': this.plexHeaders[ - 'X-Plex-Device-Screen-Resolution' - ], - 'context[device][layout]': 'desktop', - code: this.pin.code, - }; - - if (this.popup) { - this.popup.location.href = `https://app.plex.tv/auth/#!?${this.encodeData( - params - )}`; - } - - return this.pinPoll(); - } catch (e) { - throw e; + if (!this.plexHeaders || !this.pin) { + throw new Error('Unable to call login if class is not initialized.'); } + + const params = { + clientID: this.plexHeaders['X-Plex-Client-Identifier'], + 'context[device][product]': this.plexHeaders['X-Plex-Product'], + 'context[device][version]': this.plexHeaders['X-Plex-Version'], + 'context[device][platform]': this.plexHeaders['X-Plex-Platform'], + 'context[device][platformVersion]': this.plexHeaders[ + 'X-Plex-Platform-Version' + ], + 'context[device][device]': this.plexHeaders['X-Plex-Device'], + 'context[device][deviceName]': this.plexHeaders['X-Plex-Device-Name'], + 'context[device][model]': this.plexHeaders['X-Plex-Model'], + 'context[device][screenResolution]': this.plexHeaders[ + 'X-Plex-Device-Screen-Resolution' + ], + 'context[device][layout]': 'desktop', + code: this.pin.code, + }; + + if (this.popup) { + this.popup.location.href = `https://app.plex.tv/auth/#!?${this.encodeData( + params + )}`; + } + + return this.pinPoll(); } private async pinPoll(): Promise { @@ -131,9 +123,9 @@ class PlexOAuth { ); if (response.data?.authToken) { - this.authToken = response.data.authToken; + this.authToken = response.data.authToken as string; this.closePopup(); - resolve(response.data.authToken); + resolve(this.authToken); } else if (!response.data?.authToken && !this.popup?.closed) { setTimeout(executePoll, 1000, resolve, reject); } else { diff --git a/stylelint.config.js b/stylelint.config.js index b5b8a6c1..79a28459 100644 --- a/stylelint.config.js +++ b/stylelint.config.js @@ -1,4 +1,5 @@ module.exports = { + ignoreFiles: ['**/*.js'], rules: { 'at-rule-no-unknown': [ true, diff --git a/yarn.lock b/yarn.lock index 9feb2dcf..ba988947 100644 --- a/yarn.lock +++ b/yarn.lock @@ -62,10 +62,10 @@ call-me-maybe "^1.0.1" js-yaml "^3.13.1" -"@babel/cli@^7.11.6": - version "7.11.6" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.11.6.tgz#1fcbe61c2a6900c3539c06ee58901141f3558482" - integrity sha512-+w7BZCvkewSmaRM6H4L2QM3RL90teqEIHDIFXAmrW33+0jhlymnDAEdqVeCZATvxhQuio1ifoGVlJJbIiH9Ffg== +"@babel/cli@^7.12.8": + version "7.12.8" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.12.8.tgz#3b24ed2fd5da353ee6f19e8935ff8c93b5fe8430" + integrity sha512-/6nQj11oaGhLmZiuRUfxsujiPDc9BBReemiXgIbxc+M5W+MIiFKYwvNDJvBfnGKNsJTKbUfEheKc9cwoPHAVQA== dependencies: commander "^4.0.1" convert-source-map "^1.1.0" @@ -76,7 +76,8 @@ slash "^2.0.0" source-map "^0.5.0" optionalDependencies: - chokidar "^2.1.8" + "@nicolo-ribaudo/chokidar-2" "2.1.8-no-fsevents" + chokidar "^3.4.0" "@babel/code-frame@7.10.4", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4": version "7.10.4" @@ -1310,10 +1311,10 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== -"@eslint/eslintrc@^0.1.3": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" - integrity sha512-4YVwPkANLeNtRjMekzux1ci8hIaH5eGKktGqR0d3LWsKNn5B2X/1Z6Trxy7jQXl9EBGE6Yj02O+t09FMeRllaA== +"@eslint/eslintrc@^0.2.2": + version "0.2.2" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.2.2.tgz#d01fc791e2fc33e88a29d6f3dc7e93d0cd784b76" + integrity sha512-EfB5OHNYp1F4px/LI/FEnGylop7nOqkQ1LRzCM0KccA2U8tvV8w01KBv37LbO7nW4H+YhKyo2LcJhRwjjV17QQ== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -1326,6 +1327,13 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" +"@formatjs/ecma402-abstract@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.5.0.tgz#759c8f11ff45e96f8fb58741e7fbdb41096d5ddd" + integrity sha512-wXv36yo+mfWllweN0Fq7sUs7PUiNopn7I0JpLTe3hGu6ZMR4CV7LqK1llhB18pndwpKoafQKb1et2DCJAOW20Q== + dependencies: + tslib "^2.0.1" + "@formatjs/ecma402-abstract@^1.2.1", "@formatjs/ecma402-abstract@^1.2.4": version "1.2.4" resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.2.4.tgz#0f11e0309bc885d53ddc823e36d04d520fda7674" @@ -1378,6 +1386,15 @@ intl-messageformat-parser "^6.0.9" tslib "^2.0.1" +"@formatjs/ts-transformer@2.12.10": + version "2.12.10" + resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.12.10.tgz#4f8758ea89e2536239b573da98f99454a4952ebf" + integrity sha512-H8mtPQcyXxLo3GJGkNVj3ZlmebeqxQfVTIvGsdpE1oXKZ/SxKqvC7ZeHlbZUyXUEiRwdJ4Hfsgw1QzsmTJnicw== + dependencies: + intl-messageformat-parser "6.0.18" + tslib "^2.0.1" + typescript "^4.0" + "@formatjs/ts-transformer@^2.10.0", "@formatjs/ts-transformer@^2.6.0": version "2.10.0" resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-2.10.0.tgz#06f292b6cbcea661e2cecf7b8945ac59f21b7c93" @@ -1477,6 +1494,23 @@ resolved "https://registry.yarnpkg.com/@next/react-refresh-utils/-/react-refresh-utils-10.0.3.tgz#276bec60eae18768f96baf8a52f668f657f50ab4" integrity sha512-XtzzPX2R4+MIyu1waEQUo2tiNwWVEkmObA6pboRCDTPOs4Ri8ckaIE08lN5A5opyF6GVN+IEq/J8KQrgsePsZQ== +"@nicolo-ribaudo/chokidar-2@2.1.8-no-fsevents": + version "2.1.8-no-fsevents" + resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/chokidar-2/-/chokidar-2-2.1.8-no-fsevents.tgz#da7c3996b8e6e19ebd14d82eaced2313e7769f9b" + integrity sha512-+nb9vWloHNNMFHjGofEam3wopE3m1yuambrrd/fnPc+lFOMB9ROTqQlche9ByFWNkdNqfSgR/kkQtQ8DzEWt2w== + dependencies: + anymatch "^2.0.0" + async-each "^1.0.1" + braces "^2.3.2" + glob-parent "^3.1.0" + inherits "^2.0.3" + is-binary-path "^1.0.0" + is-glob "^4.0.0" + normalize-path "^3.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.2.1" + upath "^1.1.1" + "@nodelib/fs.scandir@2.1.3": version "2.1.3" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" @@ -1927,11 +1961,6 @@ resolved "https://registry.yarnpkg.com/@types/emoji-regex/-/emoji-regex-8.0.0.tgz#df215c9ff818e071087fb8e7e6e74c4cb42a1303" integrity sha512-iacbaYN9IWWrGWTwlYLVOeUtN/e4cjN9Uh6v7Yo1Qa/vJzeSQeh10L/erBBSl53BTmbnQ07vsWp8mmNHGI4WbQ== -"@types/eslint-visitor-keys@^1.0.0": - version "1.0.0" - resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" - integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== - "@types/eslint@^7.2.0": version "7.2.2" resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.2.tgz#c88426b896efeb0b2732a92431ce8aa7ec0dee61" @@ -2002,10 +2031,10 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.5.tgz#dcce4430e64b443ba8945f0290fb564ad5bac6dd" integrity sha512-7+2BITlgjgDhH0vvwZU/HZJVyk+2XUlvxXe8dFMedNX/aMkaOq++rMAFXc0tM7ij15QaWlbdQASBR9dihi+bDQ== -"@types/lodash@^4.14.161": - version "4.14.161" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.161.tgz#a21ca0777dabc6e4f44f3d07f37b765f54188b18" - integrity sha512-EP6O3Jkr7bXvZZSZYlsgt5DIjiGr0dXP1/jVEwVLTFgg0d+3lWVQkRavYVQszV7dYUwvg0B8R0MBDpcmXg7XIA== +"@types/lodash@^4.14.165": + version "4.14.165" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.165.tgz#74d55d947452e2de0742bad65270433b63a8c30f" + integrity sha512-tjSSOTHhI5mCHTy/OOXYIhi2Wt1qcbHmuXD1Ha7q70CgI/I71afO4XtLb/cVexki1oVYchpul/TOuu3Arcdxrg== "@types/mime@*": version "2.0.3" @@ -2029,12 +2058,12 @@ dependencies: "@types/node" "*" -"@types/node@*", "@types/node@^14.10.0": +"@types/node@*": version "14.10.0" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.10.0.tgz#15815dff82c8dc30827f6b1286f865902945095a" integrity sha512-SOIyrdADB4cq6eY1F+9iU48iIomFAPltu11LCvA9PKcyEwHadjCFzNVPotAR+oEJA0bCP4Xvvgy+vwu1ZjVh8g== -"@types/node@>= 8": +"@types/node@>= 8", "@types/node@^14.14.10": version "14.14.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785" integrity sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ== @@ -2076,10 +2105,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== -"@types/react-dom@^16.9.8": - version "16.9.8" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423" - integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA== +"@types/react-dom@^17.0.0": + version "17.0.0" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.0.tgz#b3b691eb956c4b3401777ee67b900cb28415d95a" + integrity sha512-lUqY7OlkF/RbNtD5nIq7ot8NquXrdFrjSOR6+w9a9RFQevGi1oZO1dcJbXMeONAPKtZ2UrZOEJ5UOCVsxbLk/g== dependencies: "@types/react" "*" @@ -2097,7 +2126,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^16.9.49": +"@types/react@*": version "16.9.49" resolved "https://registry.yarnpkg.com/@types/react/-/react-16.9.49.tgz#09db021cf8089aba0cdb12a49f8021a69cce4872" integrity sha512-DtLFjSj0OYAdVLBbyjhuV9CdGVHCkHn2R+xr3XkBvK2rS1Y1tkc14XSGjYgm5Fjjr90AxH9tiSzc1pCFMGO06g== @@ -2105,6 +2134,14 @@ "@types/prop-types" "*" csstype "^3.0.2" +"@types/react@^17.0.0": + version "17.0.0" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.0.tgz#5af3eb7fad2807092f0046a1302b7823e27919b8" + integrity sha512-aj/L7RIMsRlWML3YB6KZiXB3fV2t41+5RBGYF8z+tAKU43Px8C3cYUZsDvf1/+Bm4FK21QWBrDutu8ZJ/70qOw== + dependencies: + "@types/prop-types" "*" + csstype "^3.0.2" + "@types/retry@^0.12.0": version "0.12.0" resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" @@ -2138,10 +2175,10 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== -"@types/xml2js@^0.4.5": - version "0.4.5" - resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.5.tgz#d21759b056f282d9c7066f15bbf5c19b908f22fa" - integrity sha512-yohU3zMn0fkhlape1nxXG2bLEGZRc1FeqF80RoHaYXJN7uibaauXfhzhOJr1Xh36sn+/tx21QAOf07b/xYVk1w== +"@types/xml2js@^0.4.7": + version "0.4.7" + resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.4.7.tgz#cd5b6c67bbec741ac625718a76e6cb99bc34365e" + integrity sha512-f5VOKSMEE0O+/L54FHwA/a7vcx9mHeSDM71844yHCOhh8Cin2xQa0UFw0b7Vc5hoZ3Ih6ZHaDobjfLih4tWPNw== dependencies: "@types/node" "*" @@ -2150,77 +2187,79 @@ resolved "https://registry.yarnpkg.com/@types/yamljs/-/yamljs-0.2.31.tgz#b1a620b115c96db7b3bfdf0cf54aee0c57139245" integrity sha512-QcJ5ZczaXAqbVD3o8mw/mEBhRvO5UAdTtbvgwL/OgoWubvNBh6/MxLBAigtcgIFaq3shon9m3POIxQaLQt4fxQ== -"@types/yup@^0.29.9": - version "0.29.9" - resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.9.tgz#e2015187ae5739fd3b791b3b7ab9094f2aa5a474" - integrity sha512-ZtjjlrHuHTYctHDz3c8XgInjj0v+Hahe32N/4cDa2banibf9w6aAgxwx0jZtBjKKzmGIU4NXhofEsBW1BbqrNg== +"@types/yup@^0.29.10": + version "0.29.10" + resolved "https://registry.yarnpkg.com/@types/yup/-/yup-0.29.10.tgz#1bfa4c4a47a6f57fcc8510948757b9e47c0d6ca3" + integrity sha512-kRKRZaWkxxnOK7H5C4oWqhCw9ID1QF3cBZ2oAPoXYsjIncwgpDGigWtXGjZ91t+hsc3cvPdBci9YoJo1A96CYg== -"@typescript-eslint/eslint-plugin@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.0.0.tgz#99349a501447fed91de18346705c0c65cf603bee" - integrity sha512-5e6q1TR7gS2P+8W2xndCu7gBh3BzmYEo70OyIdsmCmknHha/yNbz2vdevl+tP1uoaMOcrzg4gyrAijuV3DDBHA== +"@typescript-eslint/eslint-plugin@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.9.1.tgz#66758cbe129b965fe9c63b04b405d0cf5280868b" + integrity sha512-QRLDSvIPeI1pz5tVuurD+cStNR4sle4avtHhxA+2uyixWGFjKzJ+EaFVRW6dA/jOgjV5DTAjOxboQkRDE8cRlQ== dependencies: - "@typescript-eslint/experimental-utils" "4.0.0" - "@typescript-eslint/scope-manager" "4.0.0" + "@typescript-eslint/experimental-utils" "4.9.1" + "@typescript-eslint/scope-manager" "4.9.1" debug "^4.1.1" functional-red-black-tree "^1.0.1" regexpp "^3.0.0" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-3.10.1.tgz#e179ffc81a80ebcae2ea04e0332f8b251345a686" - integrity sha512-DewqIgscDzmAfd5nOGe4zm6Bl7PKtMG2Ad0KG8CUZAHlXfAKTF9Ol5PXhiMh39yRL2ChRH1cuuUGOcVyyrhQIw== +"@typescript-eslint/experimental-utils@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.9.1.tgz#86633e8395191d65786a808dc3df030a55267ae2" + integrity sha512-c3k/xJqk0exLFs+cWSJxIjqLYwdHCuLWhnpnikmPQD2+NGAx9KjLYlBDcSI81EArh9FDYSL6dslAUSwILeWOxg== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" + "@typescript-eslint/scope-manager" "4.9.1" + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/typescript-estree" "4.9.1" eslint-scope "^5.0.0" eslint-utils "^2.0.0" -"@typescript-eslint/experimental-utils@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.0.0.tgz#fbec21a3b5ab59127edb6ce2e139ed378cc50eb5" - integrity sha512-hbX6zR+a/vcpFVNJYN/Nbd7gmaMosDTxHEKcvmhWeWcq/0UDifrqmCfkkodbAKL46Fn4ekSBMTyq2zlNDzcQxw== +"@typescript-eslint/parser@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.9.1.tgz#2d74c4db5dd5117379a9659081a4d1ec02629055" + integrity sha512-Gv2VpqiomvQ2v4UL+dXlQcZ8zCX4eTkoIW+1aGVWT6yTO+6jbxsw7yQl2z2pPl/4B9qa5JXeIbhJpONKjXIy3g== dependencies: - "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.0.0" - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/typescript-estree" "4.0.0" - eslint-scope "^5.0.0" - eslint-utils "^2.0.0" + "@typescript-eslint/scope-manager" "4.9.1" + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/typescript-estree" "4.9.1" + debug "^4.1.1" -"@typescript-eslint/parser@^3.10.1": - version "3.10.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-3.10.1.tgz#1883858e83e8b442627e1ac6f408925211155467" - integrity sha512-Ug1RcWcrJP02hmtaXVS3axPPTTPnZjupqhgj+NnZ6BCkwSImWk/283347+x9wN+lqOdK9Eo3vsyiyDHgsmiEJw== +"@typescript-eslint/scope-manager@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.9.1.tgz#cc2fde310b3f3deafe8436a924e784eaab265103" + integrity sha512-sa4L9yUfD/1sg9Kl8OxPxvpUcqxKXRjBeZxBuZSSV1v13hjfEJkn84n0An2hN8oLQ1PmEl2uA6FkI07idXeFgQ== dependencies: - "@types/eslint-visitor-keys" "^1.0.0" - "@typescript-eslint/experimental-utils" "3.10.1" - "@typescript-eslint/types" "3.10.1" - "@typescript-eslint/typescript-estree" "3.10.1" - eslint-visitor-keys "^1.1.0" - -"@typescript-eslint/scope-manager@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.0.0.tgz#8c9e3b3b8cdf5a1fbe671d9fad73ff67bc027ea8" - integrity sha512-9gcWUPoWo7gk/+ZQPg7L1ySRmR5HLIy3Vu6/LfhQbuzIkGm6v2CGIjpVRISoDLFRovNRDImd4aP/sa8O4yIEBg== - dependencies: - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/visitor-keys" "4.0.0" + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/visitor-keys" "4.9.1" "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" integrity sha512-+3+FCUJIahE9q0lDi1WleYzjCwJs5hIsbugIgnbB+dSCYUxl8L6PwmsyOPFZde2hc1DlTo/xnkOgiTLSyAbHiQ== -"@typescript-eslint/types@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.0.0.tgz#ec1f9fc06b8558a1d5afa6e337182d08beece7f5" - integrity sha512-bK+c2VLzznX2fUWLK6pFDv3cXGTp7nHIuBMq1B9klA+QCsqLHOOqe5TQReAQDl7DN2RfH+neweo0oC5hYlG7Rg== +"@typescript-eslint/types@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.9.1.tgz#a1a7dd80e4e5ac2c593bc458d75dd1edaf77faa2" + integrity sha512-fjkT+tXR13ks6Le7JiEdagnwEFc49IkOyys7ueWQ4O8k4quKPwPJudrwlVOJCUQhXo45PrfIvIarcrEjFTNwUA== -"@typescript-eslint/typescript-estree@3.10.1", "@typescript-eslint/typescript-estree@^3.6.0": +"@typescript-eslint/typescript-estree@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.9.1.tgz#6e5b86ff5a5f66809e1f347469fadeec69ac50bf" + integrity sha512-bzP8vqwX6Vgmvs81bPtCkLtM/Skh36NE6unu6tsDeU/ZFoYthlTXbBmpIrvosgiDKlWTfb2ZpPELHH89aQjeQw== + dependencies: + "@typescript-eslint/types" "4.9.1" + "@typescript-eslint/visitor-keys" "4.9.1" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^7.3.2" + tsutils "^3.17.1" + +"@typescript-eslint/typescript-estree@^3.6.0": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" integrity sha512-QbcXOuq6WYvnB3XPsZpIwztBoquEYLXh2MtwVU+kO8jgYCiv4G5xrSP/1wg4tkvrEE+esZVquIPX/dxPlePk1w== @@ -2234,20 +2273,6 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/typescript-estree@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.0.0.tgz#2244c63de2f2190bc5718eb0fb3fd2c437d42097" - integrity sha512-ewFMPi2pMLDNIXGMPdf8r7El2oPSZw9PEYB0j+WcpKd7AX2ARmajGa7RUHTukllWX2bj4vWX6JLE1Oih2BMokA== - dependencies: - "@typescript-eslint/types" "4.0.0" - "@typescript-eslint/visitor-keys" "4.0.0" - debug "^4.1.1" - globby "^11.0.1" - is-glob "^4.0.1" - lodash "^4.17.15" - semver "^7.3.2" - tsutils "^3.17.1" - "@typescript-eslint/visitor-keys@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-3.10.1.tgz#cd4274773e3eb63b2e870ac602274487ecd1e931" @@ -2255,12 +2280,12 @@ dependencies: eslint-visitor-keys "^1.1.0" -"@typescript-eslint/visitor-keys@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.0.0.tgz#e2bbb69d98076d6a3f06abcb2048225a74362c33" - integrity sha512-sTouJbv6rjVJeTE4lpSBVYXq/u5K3gbB6LKt7ccFEZPTZB/VeQ0ssUz9q5Hx++sCqBbdF8PzrrgvEnicXAR6NQ== +"@typescript-eslint/visitor-keys@4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.9.1.tgz#d76374a58c4ead9e92b454d186fea63487b25ae1" + integrity sha512-9gspzc6UqLQHd7lXQS7oWs+hrYggspv/rk6zzEMhCbYwPE/sF7oxo7GAjkS35Tdlt7wguIG+ViWCPtVZHz/ybQ== dependencies: - "@typescript-eslint/types" "4.0.0" + "@typescript-eslint/types" "4.9.1" eslint-visitor-keys "^2.0.0" "@webassemblyjs/ast@1.9.0": @@ -2451,6 +2476,11 @@ acorn-jsx@^5.2.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.2.0.tgz#4c66069173d6fdd68ed85239fc256226182b2ebe" integrity sha512-HiUX/+K2YpkpJ+SzBffkM/AQ2YE03S0U1kjTLVpoJdhZMOWy8qvXVN9JdLqv2QsaQ6MPYQIuNmwD8zOiYUofLQ== +acorn-jsx@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" + integrity sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng== + acorn-node@^1.6.1: version "1.8.2" resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" @@ -2913,10 +2943,10 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.1.tgz#e1e82e4f3e999e2cfd61b161280d16a111f86428" integrity sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA== -axe-core@^3.5.4: - version "3.5.5" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-3.5.5.tgz#84315073b53fa3c0c51676c588d59da09a192227" - integrity sha512-5P0QZ6J5xGikH780pghEdbEKijCTrruK9KxtPZCFWUpef0f6GipO+xEZ5GKCb020mmqgbiNO6TcA55CriL784Q== +axe-core@^4.0.2: + version "4.1.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.1.1.tgz#70a7855888e287f7add66002211a423937063eaf" + integrity sha512-5Kgy8Cz6LPC9DJcNb3yjAXTu3XihQgEdnIg50c//zOC/MyLP0Clg+Y8Sh9ZjjnvBrDZU4DgXS9C3T9r4/scGZQ== axios@^0.20.0: version "0.20.0" @@ -2925,7 +2955,7 @@ axios@^0.20.0: dependencies: follow-redirects "^1.10.0" -axobject-query@^2.1.2: +axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== @@ -3582,7 +3612,7 @@ cheerio@^1.0.0-rc.3: lodash "^4.15.0" parse5 "^3.0.1" -chokidar@3.4.3: +chokidar@3.4.3, chokidar@^3.4.0: version "3.4.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.4.3.tgz#c1df38231448e45ca4ac588e6c79573ba6a57d5b" integrity sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ== @@ -3956,6 +3986,11 @@ commander@^6.0.0: resolved "https://registry.yarnpkg.com/commander/-/commander-6.1.0.tgz#f8d722b78103141006b66f4c7ba1e97315ba75bc" integrity sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA== +commander@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.0.tgz#b990bfb8ac030aedc6d11bc04d1488ffef56db75" + integrity sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q== + commitizen@^4.0.3, commitizen@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/commitizen/-/commitizen-4.2.1.tgz#3b098b16c6b1a37f0d129018dff6751b20cd3103" @@ -5391,70 +5426,69 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= -eslint-config-prettier@^6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.11.0.tgz#f6d2238c1290d01c859a8b5c1f7d352a0b0da8b1" - integrity sha512-oB8cpLWSAjOVFEJhhyMZh6NOEOtBVziaqdDQ86+qhDHFbZXoRTM7pNSvFRfW/W/L/LrQ38C99J5CGuRBBzBsdA== - dependencies: - get-stdin "^6.0.0" +eslint-config-prettier@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-7.0.0.tgz#c1ae4106f74e6c0357f44adb076771d032ac0e97" + integrity sha512-8Y8lGLVPPZdaNA7JXqnvETVC7IiVRgAP6afQu9gOQRn90YY3otMNh+x7Vr2vMePQntF+5erdSUBqSzCmU/AxaQ== -eslint-plugin-formatjs@^2.7.10: - version "2.7.10" - resolved "https://registry.yarnpkg.com/eslint-plugin-formatjs/-/eslint-plugin-formatjs-2.7.10.tgz#436bfe8283d5108c3e93617c8bea929cbbc8e35b" - integrity sha512-rqhw+AgicCWDD38jluqwLKqAEuVEBI3/XcUu/AWoWrhsyg692KmBdNl0hiKaN9bv+U837q0PYXcdcFwv5TuBeQ== +eslint-plugin-formatjs@^2.9.10: + version "2.9.10" + resolved "https://registry.yarnpkg.com/eslint-plugin-formatjs/-/eslint-plugin-formatjs-2.9.10.tgz#dc5b80792e4166f3b2c4ca927ca47a70c89f27d2" + integrity sha512-MFkJ6ZBs70Zdyeq2JdYn950jSgSROL4x9eWlxU/AzhNvDIiHiU0oXahx02X7wdAl1vzjCC7Ro4VWiGGecQ5cpA== dependencies: - "@formatjs/ts-transformer" "^2.10.0" + "@formatjs/ts-transformer" "2.12.10" "@types/emoji-regex" "^8.0.0" "@types/eslint" "^7.2.0" "@types/estree" "^0.0.45" "@typescript-eslint/typescript-estree" "^3.6.0" emoji-regex "^9.0.0" - intl-messageformat-parser "^6.0.6" + intl-messageformat-parser "6.0.18" + tslib "^2.0.1" -eslint-plugin-jsx-a11y@^6.3.1: - version "6.3.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.3.1.tgz#99ef7e97f567cc6a5b8dd5ab95a94a67058a2660" - integrity sha512-i1S+P+c3HOlBJzMFORRbC58tHa65Kbo8b52/TwCwSKLohwvpfT5rm2GjGWzOHTEuq4xxf2aRlHHTtmExDQOP+g== +eslint-plugin-jsx-a11y@^6.4.1: + version "6.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" + integrity sha512-0rGPJBbwHoGNPU73/QCLP/vveMlM1b1Z9PponxO87jfr6tuH5ligXbDT6nHSSzBC8ovX2Z+BQu7Bk5D/Xgq9zg== dependencies: - "@babel/runtime" "^7.10.2" + "@babel/runtime" "^7.11.2" aria-query "^4.2.2" array-includes "^3.1.1" ast-types-flow "^0.0.7" - axe-core "^3.5.4" - axobject-query "^2.1.2" + axe-core "^4.0.2" + axobject-query "^2.2.0" damerau-levenshtein "^1.0.6" emoji-regex "^9.0.0" has "^1.0.3" - jsx-ast-utils "^2.4.1" + jsx-ast-utils "^3.1.0" language-tags "^1.0.5" -eslint-plugin-prettier@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.4.tgz#168ab43154e2ea57db992a2cd097c828171f75c2" - integrity sha512-jZDa8z76klRqo+TdGDTFJSavwbnWK2ZpqGKNZ+VvweMW516pDUMmQ2koXvxEE4JhzNvTv+radye/bWGBmA6jmg== +eslint-plugin-prettier@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.2.0.tgz#af391b2226fa0e15c96f36c733f6e9035dbd952c" + integrity sha512-kOUSJnFjAUFKwVxuzy6sA5yyMx6+o9ino4gCdShzBNx4eyFRudWRYKCFolKjoM40PEiuU6Cn7wBLfq3WsGg7qg== dependencies: prettier-linter-helpers "^1.0.0" -eslint-plugin-react-hooks@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.1.2.tgz#2eb53731d11c95826ef7a7272303eabb5c9a271e" - integrity sha512-ykUeqkGyUGgwTtk78C0o8UG2fzwmgJ0qxBGPp2WqRKsTwcLuVf01kTDRAtOsd4u6whX2XOC8749n2vPydP82fg== +eslint-plugin-react-hooks@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.2.0.tgz#8c229c268d468956334c943bb45fc860280f5556" + integrity sha512-623WEiZJqxR7VdxFCKLI6d6LLpwJkGPYKODnkH3D7WpOG5KM8yWueBd8TLsNAetEJNF5iJmolaAKO3F8yzyVBQ== -eslint-plugin-react@^7.20.6: - version "7.20.6" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.20.6.tgz#4d7845311a93c463493ccfa0a19c9c5d0fd69f60" - integrity sha512-kidMTE5HAEBSLu23CUDvj8dc3LdBU0ri1scwHBZjI41oDv4tjsWZKU7MQccFzH1QYPYhsnTF2ovh7JlcIcmxgg== +eslint-plugin-react@^7.21.5: + version "7.21.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.21.5.tgz#50b21a412b9574bfe05b21db176e8b7b3b15bff3" + integrity sha512-8MaEggC2et0wSF6bUeywF7qQ46ER81irOdWS4QWxnnlAEsnzeBevk1sWh7fhpCghPpXb+8Ks7hvaft6L/xsR6g== dependencies: array-includes "^3.1.1" array.prototype.flatmap "^1.2.3" doctrine "^2.1.0" has "^1.0.3" - jsx-ast-utils "^2.4.1" + jsx-ast-utils "^2.4.1 || ^3.0.0" object.entries "^1.1.2" object.fromentries "^2.0.2" object.values "^1.1.1" prop-types "^15.7.2" - resolve "^1.17.0" + resolve "^1.18.1" string.prototype.matchall "^4.0.2" eslint-scope@^4.0.3: @@ -5490,13 +5524,13 @@ eslint-visitor-keys@^2.0.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8" integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ== -eslint@^7.10.0: - version "7.10.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.10.0.tgz#494edb3e4750fb791133ca379e786a8f648c72b9" - integrity sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA== +eslint@^7.15.0: + version "7.15.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.15.0.tgz#eb155fb8ed0865fcf5d903f76be2e5b6cd7e0bc7" + integrity sha512-Vr64xFDT8w30wFll643e7cGrIkPEU50yIiI36OdSIDoSGguIeaLzBo0vpGvzo9RECUqq7htURfwEtKqwytkqzA== dependencies: "@babel/code-frame" "^7.0.0" - "@eslint/eslintrc" "^0.1.3" + "@eslint/eslintrc" "^0.2.2" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -5505,11 +5539,11 @@ eslint@^7.10.0: enquirer "^2.3.5" eslint-scope "^5.1.1" eslint-utils "^2.1.0" - eslint-visitor-keys "^1.3.0" - espree "^7.3.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" esquery "^1.2.0" esutils "^2.0.2" - file-entry-cache "^5.0.1" + file-entry-cache "^6.0.0" functional-red-black-tree "^1.0.1" glob-parent "^5.0.0" globals "^12.1.0" @@ -5542,6 +5576,15 @@ espree@^7.3.0: acorn-jsx "^5.2.0" eslint-visitor-keys "^1.3.0" +espree@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + esprima@^4.0.0, esprima@~4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -5632,7 +5675,7 @@ execa@^0.7.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^4.0.0: +execa@^4.0.0, execa@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -5647,21 +5690,6 @@ execa@^4.0.0: signal-exit "^3.0.2" strip-final-newline "^2.0.0" -execa@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.3.tgz#0a34dabbad6d66100bd6f2c576c8669403f317f2" - integrity sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -5915,12 +5943,12 @@ figures@^3.0.0, figures@^3.2.0: dependencies: escape-string-regexp "^1.0.5" -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== +file-entry-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.0.tgz#7921a89c391c6d93efec2169ac6bf300c527ea0a" + integrity sha512-fqoO76jZ3ZnYrXLDRxBR1YvOvc0k844kcOg40bgsPrE25LAb/PDqTY+ho64Xh2c8ZXgIKldchCFHczG2UVRcWA== dependencies: - flat-cache "^2.0.1" + flat-cache "^3.0.4" file-uri-to-path@1.0.0: version "1.0.0" @@ -6040,24 +6068,23 @@ findup-sync@^3.0.0: micromatch "^3.0.4" resolve-dir "^1.0.1" -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" + flatted "^3.1.0" + rimraf "^3.0.2" flat@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== +flatted@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.1.0.tgz#a5d06b4a8b01e3a63771daa5cb7a1903e2e57067" + integrity sha512-tW+UkmtNg/jv9CSofAKvgVcO7c2URjhTdW1ZTkcAritblu8tajiYy7YisnIflEwtKssCtOxpnBRoCB7iap0/TA== flatten@^1.0.2: version "1.0.3" @@ -6335,11 +6362,6 @@ get-stdin@8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stdin@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" - integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== - get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -6846,10 +6868,10 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -husky@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.0.tgz#0b2ec1d66424e9219d359e26a51c58ec5278f0de" - integrity sha512-tTMeLCLqSBqnflBZnlVDhpaIMucSGaYyX6855jM4AguGeWCeSzNdb1mfyWduTZ3pe3SJVvVWGL0jO1iKZVPfTA== +husky@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.5.tgz#ab8d2a0eb6b62fef2853ee3d442c927d89290902" + integrity sha512-E5S/1HMoDDaqsH8kDF5zeKEQbYqe3wL9zJDyqyYqc8I4vHBtAoxkDBGXox0lZ9RI+k5GyB728vZdmnM4bYap+g== dependencies: chalk "^4.0.0" ci-info "^2.0.0" @@ -7061,6 +7083,14 @@ internal-slot@^1.0.2: has "^1.0.3" side-channel "^1.0.2" +intl-messageformat-parser@6.0.18: + version "6.0.18" + resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-6.0.18.tgz#bf2855b82b0749e1f34e452f0a15d08d3277c8c7" + integrity sha512-vLjACEunfi5uSUCWFLOR4PXQ9DGLpED3tM7o9zsYsOvjl0VIheoxyG0WZXnsnhn+S+Zu158M6CkuHXeNZfKRRg== + dependencies: + "@formatjs/ecma402-abstract" "1.5.0" + tslib "^2.0.1" + intl-messageformat-parser@^5.3.7: version "5.5.1" resolved "https://registry.yarnpkg.com/intl-messageformat-parser/-/intl-messageformat-parser-5.5.1.tgz#f09a692755813e6220081e3374df3fb1698bd0c6" @@ -7675,13 +7705,13 @@ jstransformer@1.0.0: is-promise "^2.0.0" promise "^7.0.1" -jsx-ast-utils@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.4.1.tgz#1114a4c1209481db06c690c2b4f488cc665f657e" - integrity sha512-z1xSldJ6imESSzOjd3NNkieVJKRlKYSOtMG8SFyCj2FIrvSaSuli/WjpBkEzCBoR9bYYYFgqJw61Xhu7Lcgk+w== +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.1.0.tgz#642f1d7b88aa6d7eb9d8f2210e166478444fa891" + integrity sha512-d4/UOjg+mxAWxCiF0c5UTSwyqbchkbqCvK87aBovhnh8GtysTjWmgC63tY0cJx/HzGgm9qnA147jVBdpOiQ2RA== dependencies: array-includes "^3.1.1" - object.assign "^4.1.0" + object.assign "^4.1.1" juice@^7.0.0: version "7.0.0" @@ -7994,20 +8024,20 @@ linkify-it@3.0.2: dependencies: uc.micro "^1.0.1" -lint-staged@^10.4.0: - version "10.4.0" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.4.0.tgz#d18628f737328e0bbbf87d183f4020930e9a984e" - integrity sha512-uaiX4U5yERUSiIEQc329vhCTDDwUcSvKdRLsNomkYLRzijk3v8V9GWm2Nz0RMVB87VcuzLvtgy6OsjoH++QHIg== +lint-staged@^10.5.3: + version "10.5.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.3.tgz#c682838b3eadd4c864d1022da05daa0912fb1da5" + integrity sha512-TanwFfuqUBLufxCc3RUtFEkFraSPNR3WzWcGF39R3f2J7S9+iF9W0KTVLfSy09lYGmZS5NDCxjNvhGMSJyFCWg== dependencies: chalk "^4.1.0" cli-truncate "^2.1.0" - commander "^6.0.0" + commander "^6.2.0" cosmiconfig "^7.0.0" - debug "^4.1.1" + debug "^4.2.0" dedent "^0.7.0" enquirer "^2.3.6" - execa "^4.0.3" - listr2 "^2.6.0" + execa "^4.1.0" + listr2 "^3.2.2" log-symbols "^4.0.0" micromatch "^4.0.2" normalize-path "^3.0.0" @@ -8015,10 +8045,10 @@ lint-staged@^10.4.0: string-argv "0.3.1" stringify-object "^3.3.0" -listr2@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-2.6.2.tgz#4912eb01e1e2dd72ec37f3895a56bf2622d6f36a" - integrity sha512-6x6pKEMs8DSIpA/tixiYY2m/GcbgMplMVmhQAaLFxEtNSKLeWTGjtmU57xvv6QCm2XcqzyNXL/cTSVf4IChCRA== +listr2@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.2.3.tgz#ef9e0d790862f038dde8a9837be552b1adfd1c07" + integrity sha512-vUb80S2dSUi8YxXahO8/I/s29GqnOL8ozgHVLjfWQXa03BNEeS1TpBLjh2ruaqq5ufx46BRGvfymdBSuoXET5w== dependencies: chalk "^4.1.0" cli-truncate "^2.1.0" @@ -8026,7 +8056,7 @@ listr2@^2.6.0: indent-string "^4.0.0" log-update "^4.0.0" p-map "^4.0.0" - rxjs "^6.6.2" + rxjs "^6.6.3" through "^2.3.8" load-json-file@^2.0.0: @@ -9221,10 +9251,10 @@ nodemailer@^6.4.16: resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.16.tgz#5cb6391b1d79ab7eff32d6f9f48366b5a7117293" integrity sha512-68K0LgZ6hmZ7PVmwL78gzNdjpj5viqBdFqKrTtr9bZbJYj6BRj5W6WGkxXrEnUl3Co3CBXi3CZBUlpV/foGnOQ== -nodemon@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" - integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ== +nodemon@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.6.tgz#1abe1937b463aaf62f0d52e2b7eaadf28cc2240d" + integrity sha512-4I3YDSKXg6ltYpcnZeHompqac4E6JeAMpGm8tJnB9Y3T0ehasLa4139dJOcCrB93HHrUMsCrKtoAlXTqT5n4AQ== dependencies: chokidar "^3.2.2" debug "^3.2.6" @@ -9234,8 +9264,8 @@ nodemon@^2.0.4: semver "^5.7.1" supports-color "^5.5.0" touch "^3.1.0" - undefsafe "^2.0.2" - update-notifier "^4.0.0" + undefsafe "^2.0.3" + update-notifier "^4.1.0" noms@0.0.0: version "0.0.0" @@ -11160,6 +11190,11 @@ react-fast-compare@^2.0.1: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9" integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw== +react-intersection-observer@^8.31.0: + version "8.31.0" + resolved "https://registry.yarnpkg.com/react-intersection-observer/-/react-intersection-observer-8.31.0.tgz#0ed21aaf93c4c0475b22b0ccaba6169076d01605" + integrity sha512-XraIC/tkrD9JtrmVA7ypEN1QIpKc52mXBH1u/bz/aicRLo8QQEJQAMUTb8mz4B6dqpPwyzgjrr7Ljv/2ACDtqw== + react-intl@^5.8.5: version "5.8.5" resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.8.5.tgz#bc5dfab259049830621e129b8bffb1ac33ef4124" @@ -11653,7 +11688,7 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.17.0, resolve@^1.3.2: dependencies: path-parse "^1.0.6" -resolve@^1.15.1, resolve@^1.19.0: +resolve@^1.15.1, resolve@^1.18.1, resolve@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.19.0.tgz#1af5bf630409734a067cae29318aac7fa29a267c" integrity sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg== @@ -11724,13 +11759,6 @@ rimraf@2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2. dependencies: glob "^7.1.3" -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -11763,13 +11791,20 @@ run-queue@^1.0.0, run-queue@^1.0.3: dependencies: aproba "^1.1.1" -rxjs@^6.4.0, rxjs@^6.6.2: +rxjs@^6.4.0: version "6.6.2" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.2.tgz#8096a7ac03f2cc4fe5860ef6e572810d9e01c0d2" integrity sha512-BHdBMVoWC2sL26w//BCu3YzKT4s2jip/WhwsGEDmeKYBhKDZeYezVUnHatYB7L85v5xs0BAQmg6BEYJEKxBabg== dependencies: tslib "^1.9.0" +rxjs@^6.6.3: + version "6.6.3" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.3.tgz#8ca84635c4daa900c0d3967a6ee7ac60271ee552" + integrity sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ== + dependencies: + tslib "^1.9.0" + safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -13361,7 +13396,7 @@ umask@^1.1.0, umask@~1.1.0: resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= -undefsafe@^2.0.2: +undefsafe@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== @@ -13508,10 +13543,10 @@ update-notifier@^2.2.0, update-notifier@^2.3.0, update-notifier@^2.5.0: semver-diff "^2.0.0" xdg-basedir "^3.0.0" -update-notifier@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3" - integrity sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew== +update-notifier@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" + integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== dependencies: boxen "^4.2.0" chalk "^3.0.0" @@ -13634,11 +13669,6 @@ uuid@^3.3.2, uuid@^3.3.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" - integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== - uuid@^8.3.1: version "8.3.1" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.1.tgz#2ba2e6ca000da60fce5a196954ab241131e05a31" @@ -13946,13 +13976,6 @@ write-json-file@^4.3.0: sort-keys "^4.0.0" write-file-atomic "^3.0.0" -write@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"