From 1fc67365f05cb21c2465877b9ebfcb7c9e2ee9d2 Mon Sep 17 00:00:00 2001 From: Lukas Heiligenbrunner Date: Sun, 14 Mar 2021 14:51:53 +0000 Subject: [PATCH] use eslint to lint project drop code quality job --- .eslintrc.js | 291 +++++++++++++++++ .gitlab-ci.yml | 21 +- .prettierrc.js | 10 + package.json | 18 +- src/App.tsx | 133 ++++---- src/elements/ActorTile/ActorTile.tsx | 31 +- src/elements/FilterButton/FilterButton.tsx | 98 +++--- .../InfoHeaderItem/InfoHeaderItem.tsx | 44 ++- src/elements/PageTitle/PageTitle.tsx | 8 +- .../AddActorPopup/AddActorPopup.test.js | 2 +- .../Popups/AddActorPopup/AddActorPopup.tsx | 88 ++++-- .../Popups/AddTagPopup/AddTagPopup.tsx | 20 +- .../Popups/NewActorPopup/NewActorPopup.tsx | 21 +- .../Popups/NewTagPopup/NewTagPopup.tsx | 25 +- .../NoBackendConnectionPopup.tsx | 17 +- src/elements/Popups/PopupBase.tsx | 44 +-- .../Popups/SubmitPopup/SubmitPopup.tsx | 9 +- src/elements/Preview/Preview.tsx | 33 +- src/elements/Preview/Previw.test.js | 6 +- src/elements/SideBar/SideBar.tsx | 22 +- src/elements/Tag/Tag.tsx | 15 +- .../VideoContainer/VideoContainer.tsx | 24 +- src/index.tsx | 4 +- .../ActorOverviewPage/ActorOverviewPage.tsx | 32 +- src/pages/ActorPage/ActorPage.tsx | 43 ++- .../AuthenticationPage/AuthenticationPage.tsx | 41 +-- src/pages/CategoryPage/CategoryPage.tsx | 4 +- src/pages/CategoryPage/CategoryView.tsx | 94 +++--- src/pages/CategoryPage/TagView.tsx | 57 ++-- src/pages/HomePage/HomePage.tsx | 133 ++++---- src/pages/HomePage/SearchHandling.tsx | 16 +- src/pages/Player/Player.tsx | 296 ++++++++++-------- src/pages/RandomPage/RandomPage.tsx | 24 +- src/pages/SettingsPage/GeneralSettings.tsx | 216 +++++++------ src/pages/SettingsPage/MovieSettings.tsx | 43 ++- src/pages/SettingsPage/SettingsPage.tsx | 16 +- src/types/ApiTypes.ts | 44 +-- src/types/GeneralTypes.ts | 4 +- src/types/VideoTypes.ts | 4 +- src/utils/Api.ts | 197 ++++++------ src/utils/GlobalInfos.ts | 10 +- yarn.lock | 199 +++++++++++- 42 files changed, 1614 insertions(+), 843 deletions(-) create mode 100644 .eslintrc.js create mode 100644 .prettierrc.js diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..0a3364a --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,291 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + */ + +module.exports = { + env: { + es6: true + }, + + parserOptions: { + sourceType: 'module' + }, + + extends: [ + 'plugin:prettier/recommended', // https://github.com/prettier/eslint-plugin-prettier#recommended-configuration + 'prettier' + ], + + plugins: ['eslint-comments', 'react', 'react-hooks', 'jest'], + + settings: { + react: { + version: 'detect' + } + }, + + ignorePatterns: ['node_modules/', '**/*.js'], + + overrides: [ + { + files: ['*.ts', '*.tsx'], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint/eslint-plugin'], + rules: { + '@typescript-eslint/no-unused-vars': ['error', {argsIgnorePattern: '^_'}], + 'no-unused-vars': 'off' + } + } + ], + + // Map from global var to bool specifying if it can be redefined + globals: { + jest: true, + __DEV__: true, + __dirname: false, + __fbBatchedBridgeConfig: false, + AbortController: false, + alert: false, + cancelAnimationFrame: false, + cancelIdleCallback: false, + clearImmediate: true, + clearInterval: false, + clearTimeout: false, + console: false, + document: false, + ErrorUtils: false, + escape: false, + Event: false, + EventTarget: false, + exports: false, + fetch: false, + FileReader: false, + FormData: false, + global: false, + Headers: false, + Intl: false, + Map: true, + module: false, + navigator: false, + process: false, + Promise: true, + requestAnimationFrame: true, + requestIdleCallback: true, + require: false, + Set: true, + setImmediate: true, + setInterval: false, + setTimeout: false, + URL: false, + URLSearchParams: false, + WebSocket: true, + window: false, + XMLHttpRequest: false, + JSX: true, + KeyboardEvent: true, + MouseEvent: true, + Node: true, + HTMLDivElement: true, + HTMLInputElement: true + }, + + rules: { + // 'multiline-ternary': [1, 'always-multiline'], + + // General + 'comma-dangle': [1, 'never'], // allow or disallow trailing commas + 'no-cond-assign': 1, // disallow assignment in conditional expressions + 'no-console': 0, // disallow use of console (off by default in the node environment) + 'no-const-assign': 2, // disallow assignment to const-declared variables + 'no-constant-condition': 0, // disallow use of constant expressions in conditions + 'no-control-regex': 1, // disallow control characters in regular expressions + 'no-debugger': 1, // disallow use of debugger + 'no-dupe-class-members': 2, // Disallow duplicate name in class members + 'no-dupe-keys': 2, // disallow duplicate keys when creating object literals + 'no-empty': 0, // disallow empty statements + 'no-ex-assign': 1, // disallow assigning to the exception in a catch block + 'no-extra-boolean-cast': 1, // disallow double-negation boolean casts in a boolean context + 'no-extra-parens': 0, // disallow unnecessary parentheses (off by default) + 'no-extra-semi': 1, // disallow unnecessary semicolons + 'no-func-assign': 1, // disallow overwriting functions written as function declarations + 'no-inner-declarations': 0, // disallow function or variable declarations in nested blocks + 'no-invalid-regexp': 1, // disallow invalid regular expression strings in the RegExp constructor + 'no-negated-in-lhs': 1, // disallow negation of the left operand of an in expression + 'no-obj-calls': 1, // disallow the use of object properties of the global object (Math and JSON) as functions + 'no-regex-spaces': 1, // disallow multiple spaces in a regular expression literal + 'no-reserved-keys': 0, // disallow reserved words being used as object literal keys (off by default) + 'no-sparse-arrays': 1, // disallow sparse arrays + 'no-unreachable': 2, // disallow unreachable statements after a return, throw, continue, or break statement + 'use-isnan': 1, // disallow comparisons with the value NaN + 'valid-jsdoc': 0, // Ensure JSDoc comments are valid (off by default) + 'valid-typeof': 1, // Ensure that the results of typeof are compared against a valid string + + // Best Practices + // These are rules designed to prevent you from making mistakes. They either prescribe a better way of doing something or help you avoid footguns. + + 'block-scoped-var': 0, // treat var statements as if they were block scoped (off by default) + complexity: 0, // specify the maximum cyclomatic complexity allowed in a program (off by default) + 'consistent-return': 0, // require return statements to either always or never specify values + curly: 1, // specify curly brace conventions for all control statements + 'default-case': 0, // require default case in switch statements (off by default) + 'dot-notation': 1, // encourages use of dot notation whenever possible + eqeqeq: [1, 'allow-null'], // require the use of === and !== + 'guard-for-in': 0, // make sure for-in loops have an if statement (off by default) + 'no-alert': 1, // disallow the use of alert, confirm, and prompt + 'no-caller': 1, // disallow use of arguments.caller or arguments.callee + 'no-div-regex': 1, // disallow division operators explicitly at beginning of regular expression (off by default) + 'no-else-return': 0, // disallow else after a return in an if (off by default) + 'no-eq-null': 0, // disallow comparisons to null without a type-checking operator (off by default) + 'no-eval': 2, // disallow use of eval() + 'no-extend-native': 1, // disallow adding to native types + 'no-extra-bind': 1, // disallow unnecessary function binding + 'no-fallthrough': 1, // disallow fallthrough of case statements + 'no-floating-decimal': 1, // disallow the use of leading or trailing decimal points in numeric literals (off by default) + 'no-implied-eval': 1, // disallow use of eval()-like methods + 'no-labels': 1, // disallow use of labeled statements + 'no-iterator': 1, // disallow usage of __iterator__ property + 'no-lone-blocks': 1, // disallow unnecessary nested blocks + 'no-loop-func': 0, // disallow creation of functions within loops + 'no-multi-str': 0, // disallow use of multiline strings + 'no-native-reassign': 0, // disallow reassignments of native objects + 'no-new': 1, // disallow use of new operator when not part of the assignment or comparison + 'no-new-func': 2, // disallow use of new operator for Function object + 'no-new-wrappers': 1, // disallows creating new instances of String,Number, and Boolean + 'no-octal': 1, // disallow use of octal literals + 'no-octal-escape': 1, // disallow use of octal escape sequences in string literals, such as var foo = "Copyright \251"; + 'no-proto': 1, // disallow usage of __proto__ property + 'no-redeclare': 0, // disallow declaring the same variable more then once + 'no-return-assign': 1, // disallow use of assignment in return statement + 'no-script-url': 1, // disallow use of javascript: urls. + 'no-self-compare': 1, // disallow comparisons where both sides are exactly the same (off by default) + 'no-sequences': 1, // disallow use of comma operator + 'no-unused-expressions': 0, // disallow usage of expressions in statement position + 'no-useless-escape': 1, // disallow escapes that don't have any effect in literals + 'no-void': 1, // disallow use of void operator (off by default) + 'no-warning-comments': 0, // disallow usage of configurable warning terms in comments": 1, // e.g. TODO or FIXME (off by default) + 'no-with': 1, // disallow use of the with statement + radix: 1, // require use of the second argument for parseInt() (off by default) + 'semi-spacing': 1, // require a space after a semi-colon + 'vars-on-top': 0, // requires to declare all vars on top of their containing scope (off by default) + 'wrap-iife': 0, // require immediate function invocation to be wrapped in parentheses (off by default) + yoda: 1, // require or disallow Yoda conditions + + // Variables + // These rules have to do with variable declarations. + + 'no-catch-shadow': 1, // disallow the catch clause parameter name being the same as a variable in the outer scope (off by default in the node environment) + 'no-delete-var': 1, // disallow deletion of variables + 'no-label-var': 1, // disallow labels that share a name with a variable + 'no-shadow': 1, // disallow declaration of variables already declared in the outer scope + 'no-shadow-restricted-names': 1, // disallow shadowing of names such as arguments + 'no-undef': 2, // disallow use of undeclared variables unless mentioned in a /*global */ block + 'no-undefined': 0, // disallow use of undefined variable (off by default) + 'no-undef-init': 1, // disallow use of undefined when initializing variables + 'no-unused-vars': [1, {vars: 'all', args: 'none', ignoreRestSiblings: true}], // disallow declaration of variables that are not used in the code + 'no-use-before-define': 0, // disallow use of variables before they are defined + + // Node.js + // These rules are specific to JavaScript running on Node.js. + + 'handle-callback-err': 1, // enforces error handling in callbacks (off by default) (on by default in the node environment) + 'no-mixed-requires': 1, // disallow mixing regular variable and require declarations (off by default) (on by default in the node environment) + 'no-new-require': 1, // disallow use of new operator with the require function (off by default) (on by default in the node environment) + 'no-path-concat': 1, // disallow string concatenation with __dirname and __filename (off by default) (on by default in the node environment) + 'no-process-exit': 0, // disallow process.exit() (on by default in the node environment) + 'no-restricted-modules': 1, // restrict usage of specified node modules (off by default) + 'no-sync': 0, // disallow use of synchronous methods (off by default) + + // ESLint Comments Plugin + // The following rules are made available via `eslint-plugin-eslint-comments` + 'eslint-comments/no-aggregating-enable': 1, // disallows eslint-enable comments for multiple eslint-disable comments + 'eslint-comments/no-unlimited-disable': 1, // disallows eslint-disable comments without rule names + 'eslint-comments/no-unused-disable': 1, // disallow disables that don't cover any errors + 'eslint-comments/no-unused-enable': 1, // // disallow enables that don't enable anything or enable rules that weren't disabled + + // Stylistic Issues + // These rules are purely matters of style and are quite subjective. + + 'key-spacing': 0, + 'keyword-spacing': 1, // enforce spacing before and after keywords + 'jsx-quotes': [1, 'prefer-single'], // enforces the usage of double quotes for all JSX attribute values which doesn’t contain a double quote + 'comma-spacing': 0, + 'no-multi-spaces': 0, + 'brace-style': 0, // enforce one true brace style (off by default) + camelcase: 1, // require camel case names + 'consistent-this': 1, // enforces consistent naming when capturing the current execution context (off by default) + 'eol-last': 1, // enforce newline at the end of file, with no multiple empty lines + 'func-names': 0, // require function expressions to have a name (off by default) + 'func-style': 0, // enforces use of function declarations or expressions (off by default) + 'new-cap': 0, // require a capital letter for constructors + 'new-parens': 1, // disallow the omission of parentheses when invoking a constructor with no arguments + 'no-nested-ternary': 0, // disallow nested ternary expressions (off by default) + 'no-array-constructor': 1, // disallow use of the Array constructor + 'no-empty-character-class': 1, // disallow the use of empty character classes in regular expressions + 'no-lonely-if': 0, // disallow if as the only statement in an else block (off by default) + 'no-new-object': 1, // disallow use of the Object constructor + 'no-spaced-func': 1, // disallow space between function identifier and application + 'no-ternary': 0, // disallow the use of ternary operators (off by default) + 'no-trailing-spaces': 1, // disallow trailing whitespace at the end of lines + 'no-underscore-dangle': 0, // disallow dangling underscores in identifiers + 'no-mixed-spaces-and-tabs': 1, // disallow mixed spaces and tabs for indentation + quotes: [1, 'single', 'avoid-escape'], // specify whether double or single quotes should be used + 'quote-props': 0, // require quotes around object literal property names (off by default) + semi: 1, // require or disallow use of semicolons instead of ASI + 'sort-vars': 0, // sort variables within the same declaration block (off by default) + 'space-in-brackets': 0, // require or disallow spaces inside brackets (off by default) + 'space-in-parens': 0, // require or disallow spaces inside parentheses (off by default) + 'space-infix-ops': 1, // require spaces around operators + 'space-unary-ops': [1, {words: true, nonwords: false}], // require or disallow spaces before/after unary operators (words on by default, nonwords off by default) + 'max-nested-callbacks': 0, // specify the maximum depth callbacks can be nested (off by default) + 'one-var': 0, // allow just one var statement per function (off by default) + 'wrap-regex': 0, // require regex literals to be wrapped in parentheses (off by default) + + // Legacy + // The following rules are included for compatibility with JSHint and JSLint. While the names of the rules may not match up with the JSHint/JSLint counterpart, the functionality is the same. + + 'max-depth': 0, // specify the maximum depth that blocks can be nested (off by default) + 'max-len': 0, // specify the maximum length of a line in your program (off by default) + 'max-params': 0, // limits the number of parameters that can be used in the function declaration. (off by default) + 'max-statements': 0, // specify the maximum number of statement allowed in a function (off by default) + 'no-bitwise': 1, // disallow use of bitwise operators (off by default) + 'no-plusplus': 0, // disallow use of unary operators, ++ and -- (off by default) + + // React Plugin + // The following rules are made available via `eslint-plugin-react`. + + 'react/display-name': 0, + 'react/jsx-boolean-value': 0, + 'react/jsx-no-comment-textnodes': 2, + 'react/jsx-no-duplicate-props': 2, + 'react/jsx-no-undef': 2, + 'react/jsx-sort-props': 0, + 'react/jsx-uses-react': 1, + 'react/jsx-uses-vars': 1, + 'react/no-did-mount-set-state': 1, + 'react/no-did-update-set-state': 1, + 'react/no-multi-comp': 0, + 'react/no-string-refs': 1, + 'react/no-unknown-property': 0, + 'react/prop-types': 0, + 'react/react-in-jsx-scope': 1, + 'react/self-closing-comp': 1, + 'react/wrap-multilines': 0, + + // React-Hooks Plugin + // The following rules are made available via `eslint-plugin-react-hooks` + 'react-hooks/rules-of-hooks': 'error', + 'react-hooks/exhaustive-deps': 'error', + + // Jest Plugin + // The following rules are made available via `eslint-plugin-jest`. + 'jest/no-disabled-tests': 1, + 'jest/no-focused-tests': 1, + 'jest/no-identical-title': 1, + 'jest/valid-expect': 1 + } +}; diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 24c2ca1..5109cf2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,9 +6,6 @@ stages: - packaging - deploy -include: - - template: Code-Quality.gitlab-ci.yml - variables: SAST_DISABLE_DIND: "true" @@ -68,9 +65,21 @@ Backend_Tests: reports: junit: ./apiGo/report.xml -code_quality: - tags: - - dind +lint: + stage: test + before_script: + - yarn install --cache-folder .yarn + script: + - yarn run lint + cache: + key: ${CI_COMMIT_REF_SLUG} + paths: + - .yarn/ + - ./node_modules/ + artifacts: + reports: + codequality: gl-codequality.json + needs: [] Debian_Server: stage: packaging diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..2d3c936 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,10 @@ +module.exports = { + bracketSpacing: false, + jsxBracketSameLine: true, + singleQuote: true, + tabWidth: 4, + trailingComma: 'none', + printWidth: 135, + semi: true, + jsxSingleQuote: true +}; diff --git a/package.json b/package.json index 6b2f9fd..e15b6e5 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,6 @@ "name": "openmediacenter", "version": "0.1.2", "private": true, - "main": "public/electron.js", "author": { "email": "lukas.heiligenbrunner@gmail.com", "name": "Lukas Heiligenbrunner", @@ -24,8 +23,9 @@ }, "scripts": { "start": "react-scripts start", - "build": "react-scripts build", - "test": "CI=true react-scripts test --reporters=jest-junit --verbose --silent --coverage --reporters=default" + "build": "CI=false react-scripts build", + "test": "CI=true react-scripts test --reporters=jest-junit --verbose --silent --coverage --reporters=default", + "lint": "eslint --format gitlab src/" }, "jest": { "collectCoverageFrom": [ @@ -78,9 +78,21 @@ "@types/react-dom": "^17.0.1", "@types/react-router": "5.1.12", "@types/react-router-dom": "^5.1.6", + "@typescript-eslint/eslint-plugin": "^4.17.0", + "@typescript-eslint/parser": "^4.17.0", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.5", + "eslint": "^7.22.0", + "eslint-config-prettier": "^8.1.0", + "eslint-formatter-gitlab": "^2.2.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-jest": "^24.3.1", + "eslint-plugin-prettier": "^3.3.1", + "eslint-plugin-react": "^7.22.0", + "eslint-plugin-react-hooks": "^4.2.0", "jest-junit": "^12.0.0", + "prettier": "^2.2.1", + "prettier-config": "^1.0.0", "react-scripts": "4.0.3" } } diff --git a/src/App.tsx b/src/App.tsx index fa0448c..47f927f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -17,7 +17,7 @@ import Player from './pages/Player/Player'; import ActorOverviewPage from './pages/ActorOverviewPage/ActorOverviewPage'; import ActorPage from './pages/ActorPage/ActorPage'; import {SettingsTypes} from './types/ApiTypes'; -import AuthenticationPage from "./pages/AuthenticationPage/AuthenticationPage"; +import AuthenticationPage from './pages/AuthenticationPage/AuthenticationPage'; interface state { password: boolean | null; // null if uninitialized - true if pwd needed false if not needed @@ -39,13 +39,13 @@ class App extends React.Component<{}, state> { } else { refreshAPIToken((err) => { if (err === 'invalid_client') { - this.setState({password: true}) + this.setState({password: true}); } else if (err === '') { - this.setState({password: false}) + this.setState({password: false}); } else { - console.log("unimplemented token error: " + err) + console.log('unimplemented token error: ' + err); } - }) + }); } this.state = { @@ -56,33 +56,37 @@ class App extends React.Component<{}, state> { GlobalInfos.onThemeChange(() => { this.forceUpdate(); - }) + }); } initialAPICall(): void { // this is the first api call so if it fails we know there is no connection to backend - callApiUnsafe(APINode.Init, {action: 'loadInitialData'}, (result: SettingsTypes.initialApiCallData) => { - // set theme - GlobalInfos.enableDarkTheme(result.DarkMode); + callApiUnsafe( + APINode.Init, + {action: 'loadInitialData'}, + (result: SettingsTypes.initialApiCallData) => { + // set theme + GlobalInfos.enableDarkTheme(result.DarkMode); - GlobalInfos.setVideoPath(result.VideoPath); + GlobalInfos.setVideoPath(result.VideoPath); - this.setState({ - mediacentername: result.MediacenterName, - onapierror: false - }); - // set tab title to received mediacenter name - document.title = result.MediacenterName; - }, error => { - this.setState({onapierror: true}); - }); + this.setState({ + mediacentername: result.MediacenterName, + onapierror: false + }); + // set tab title to received mediacenter name + document.title = result.MediacenterName; + }, + () => { + this.setState({onapierror: true}); + } + ); } componentDidMount(): void { this.initialAPICall(); } - render(): JSX.Element { const themeStyle = GlobalInfos.getThemeStyle(); // add the main theme to the page body @@ -90,33 +94,52 @@ class App extends React.Component<{}, state> { if (this.state.password === true) { return ( - { - refreshAPIToken((error) => { - if (error !== '') { - console.log("wrong password!!!"); - } else { - this.setState({password: false}); - } - }, password); - }}/> + { + refreshAPIToken((error) => { + if (error !== '') { + console.log('wrong password!!!'); + } else { + this.setState({password: false}); + } + }, password); + }} + /> ); } else if (this.state.password === false) { return (
+ className={[style.navcontainer, themeStyle.backgroundcolor, themeStyle.textcolor, themeStyle.hrcolor].join( + ' ' + )}>
{this.state.mediacentername}
- Home - Random - Video + + Home + + + Random Video + - Categories - Settings + + Categories + + + Settings +
{this.routing()}
@@ -124,33 +147,33 @@ class App extends React.Component<{}, state> {
); } else { - return (<>still loading...); + return <>still loading...; } } routing(): JSX.Element { return ( - - + + - - + + - - + + - - + + - - + + - - + + - - + + ); @@ -158,7 +181,7 @@ class App extends React.Component<{}, state> { ApiError(): JSX.Element { // on api error show popup and retry and show again if failing.. - return ( this.initialAPICall()}/>); + return this.initialAPICall()} />; } } diff --git a/src/elements/ActorTile/ActorTile.tsx b/src/elements/ActorTile/ActorTile.tsx index 742bc8d..96b590c 100644 --- a/src/elements/ActorTile/ActorTile.tsx +++ b/src/elements/ActorTile/ActorTile.tsx @@ -5,13 +5,13 @@ import React from 'react'; import {Link} from 'react-router-dom'; import {ActorType} from '../../types/VideoTypes'; -interface props { +interface Props { actor: ActorType; - onClick?: (actor: ActorType) => void + onClick?: (actor: ActorType) => void; } -class ActorTile extends React.Component { - constructor(props: props) { +class ActorTile extends React.Component { + constructor(props: Props) { super(props); this.state = {}; @@ -21,12 +21,7 @@ class ActorTile extends React.Component { if (this.props.onClick) { return this.renderActorTile(this.props.onClick); } else { - return ( - - {this.renderActorTile(() => { - })} - - ); + return {this.renderActorTile(() => {})}; } } @@ -34,9 +29,19 @@ class ActorTile extends React.Component { return (
customclickhandler(this.props.actor)}>
- {this.props.actor.Thumbnail === '' ? : 'dfdf' /* todo render picture provided here! */} + { + this.props.actor.Thumbnail === '' ? ( + + ) : ( + 'dfdf' + ) /* todo render picture provided here! */ + }
{this.props.actor.Name}
diff --git a/src/elements/FilterButton/FilterButton.tsx b/src/elements/FilterButton/FilterButton.tsx index 146bb23..0315984 100644 --- a/src/elements/FilterButton/FilterButton.tsx +++ b/src/elements/FilterButton/FilterButton.tsx @@ -1,12 +1,12 @@ -import React from "react"; -import style from "../Popups/AddActorPopup/AddActorPopup.module.css"; -import {Button} from "../GPElements/Button"; -import {FontAwesomeIcon} from "@fortawesome/react-fontawesome"; -import {faFilter, faTimes} from "@fortawesome/free-solid-svg-icons"; -import {addKeyHandler, removeKeyHandler} from "../../utils/ShortkeyHandler"; +import React from 'react'; +import style from '../Popups/AddActorPopup/AddActorPopup.module.css'; +import {Button} from '../GPElements/Button'; +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faFilter, faTimes} from '@fortawesome/free-solid-svg-icons'; +import {addKeyHandler, removeKeyHandler} from '../../utils/ShortkeyHandler'; -interface props { - onFilterChange: (filter: string) => void +interface Props { + onFilterChange: (filter: string) => void; } interface state { @@ -14,18 +14,17 @@ interface state { filter: string; } -class FilterButton extends React.Component { +class FilterButton extends React.Component { // filterfield anchor, needed to focus after filter btn click private filterfield: HTMLInputElement | null | undefined; - - constructor(props: props) { + constructor(props: Props) { super(props); this.state = { filtervisible: false, filter: '' - } + }; this.keypress = this.keypress.bind(this); this.enableFilterField = this.enableFilterField.bind(this); @@ -43,34 +42,57 @@ class FilterButton extends React.Component { if (this.state.filtervisible) { return ( <> - { - this.props.onFilterChange(e.target.value); - this.setState({filter: e.target.value}); - }} - ref={(input): void => { - this.filterfield = input; - }}/> - } ParentSubmit={this.parentSubmit}> + { + this.setState({contentDefault: false}); + }}> + Create new Actor + + } + ParentSubmit={this.parentSubmit}> {this.resolvePage()} @@ -65,11 +72,18 @@ class AddActorPopup extends React.Component { * @returns {JSX.Element} */ resolvePage(): JSX.Element { - if (this.state.contentDefault) return (this.getContent()); - else return ( { - this.loadActors(); - this.setState({contentDefault: true}); - }}/>); + if (this.state.contentDefault) { + return this.getContent(); + } else { + return ( + { + this.loadActors(); + this.setState({contentDefault: true}); + }} + /> + ); + } } /** @@ -81,15 +95,19 @@ class AddActorPopup extends React.Component { return ( <>
- { - this.setState({filter: filter}) - }}/> + { + this.setState({filter: filter}); + }} + />
- {this.state.actors.filter(this.filterSearch).map((el) => ())} + {this.state.actors.filter(this.filterSearch).map((el) => ( + + ))} ); } else { - return (
somekind of loading
); + return
somekind of loading
; } } @@ -98,25 +116,29 @@ class AddActorPopup extends React.Component { */ tileClickHandler(actor: ActorType): void { // fetch the available actors - callAPI(APINode.Actor, { - action: 'addActorToVideo', - ActorId: actor.ActorId, - MovieId: this.props.movie_id - }, result => { - if (result.result === 'success') { - // return back to player page - this.props.onHide(); - } else { - console.error('an error occured while fetching actors: ' + result); + callAPI( + APINode.Actor, + { + action: 'addActorToVideo', + ActorId: actor.ActorId, + MovieId: this.props.movieId + }, + (result) => { + if (result.result === 'success') { + // return back to player page + this.props.onHide(); + } else { + console.error('an error occured while fetching actors: ' + result); + } } - }); + ); } /** * load the actors from backend and set state */ loadActors(): void { - callAPI(APINode.Actor, {action: 'getAllActors'}, result => { + callAPI(APINode.Actor, {action: 'getAllActors'}, (result) => { this.setState({actors: result}); }); } diff --git a/src/elements/Popups/AddTagPopup/AddTagPopup.tsx b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx index c35fbff..79fa135 100644 --- a/src/elements/Popups/AddTagPopup/AddTagPopup.tsx +++ b/src/elements/Popups/AddTagPopup/AddTagPopup.tsx @@ -3,10 +3,10 @@ import Tag from '../../Tag/Tag'; import PopupBase from '../PopupBase'; import {APINode, callAPI} from '../../../utils/Api'; import {TagType} from '../../../types/VideoTypes'; -import FilterButton from "../../FilterButton/FilterButton"; -import styles from './AddTagPopup.module.css' +import FilterButton from '../../FilterButton/FilterButton'; +import styles from './AddTagPopup.module.css'; -interface props { +interface Props { onHide: () => void; submit: (tagId: number, tagName: string) => void; } @@ -19,8 +19,8 @@ interface state { /** * component creates overlay to add a new tag to a video */ -class AddTagPopup extends React.Component { - constructor(props: props) { +class AddTagPopup extends React.Component { + constructor(props: Props) { super(props); this.state = {items: [], filter: ''}; @@ -42,13 +42,11 @@ class AddTagPopup extends React.Component { return (
- this.setState({filter: filter})}/> + this.setState({filter: filter})} />
- {this.state.items ? - this.state.items.filter(this.tagFilter).map((i) => ( - this.onItemClick(i)}/> - )) : null} + {this.state.items + ? this.state.items.filter(this.tagFilter).map((i) => this.onItemClick(i)} />) + : null}
); } diff --git a/src/elements/Popups/NewActorPopup/NewActorPopup.tsx b/src/elements/Popups/NewActorPopup/NewActorPopup.tsx index 086e2b2..cce7387 100644 --- a/src/elements/Popups/NewActorPopup/NewActorPopup.tsx +++ b/src/elements/Popups/NewActorPopup/NewActorPopup.tsx @@ -15,7 +15,7 @@ class NewActorPopup extends React.Component { render(): JSX.Element { return ( - + ); } @@ -28,10 +28,17 @@ export class NewActorPopupContent extends React.Component { return ( <>
- { - this.value = v.target.value; - }}/>
- + { + this.value = v.target.value; + }} + /> + + ); } @@ -41,7 +48,9 @@ export class NewActorPopupContent extends React.Component { */ storeselection(): void { // check if user typed in name - if (this.value === '' || this.value === undefined) return; + if (this.value === '' || this.value === undefined) { + return; + } callAPI(APINode.Actor, {action: 'createActor', actorname: this.value}, (result: GeneralSuccess) => { if (result.result !== 'success') { diff --git a/src/elements/Popups/NewTagPopup/NewTagPopup.tsx b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx index 488df13..11bbc75 100644 --- a/src/elements/Popups/NewTagPopup/NewTagPopup.tsx +++ b/src/elements/Popups/NewTagPopup/NewTagPopup.tsx @@ -5,7 +5,7 @@ import {APINode, callAPI} from '../../../utils/Api'; import {GeneralSuccess} from '../../../types/GeneralTypes'; interface props { - onHide: () => void + onHide: () => void; } /** @@ -16,11 +16,24 @@ class NewTagPopup extends React.Component { render(): JSX.Element { return ( - this.storeselection()}> -
{ - this.value = v.target.value; - }}/>
- + this.storeselection()}> +
+ { + this.value = v.target.value; + }} + /> +
+
); } diff --git a/src/elements/Popups/NoBackendConnectionPopup/NoBackendConnectionPopup.tsx b/src/elements/Popups/NoBackendConnectionPopup/NoBackendConnectionPopup.tsx index be4b160..3b3f28e 100644 --- a/src/elements/Popups/NoBackendConnectionPopup/NoBackendConnectionPopup.tsx +++ b/src/elements/Popups/NoBackendConnectionPopup/NoBackendConnectionPopup.tsx @@ -4,17 +4,24 @@ import style from '../NewActorPopup/NewActorPopup.module.css'; import {setCustomBackendDomain} from '../../../utils/Api'; interface NBCProps { - onHide: (_: void) => void + onHide: (_: void) => void; } export function NoBackendConnectionPopup(props: NBCProps): JSX.Element { return (
- { - setCustomBackendDomain(v.target.value); - }}/>
- + { + setCustomBackendDomain(v.target.value); + }} + /> + +
); } diff --git a/src/elements/Popups/PopupBase.tsx b/src/elements/Popups/PopupBase.tsx index 451daf2..0aae75c 100644 --- a/src/elements/Popups/PopupBase.tsx +++ b/src/elements/Popups/PopupBase.tsx @@ -4,7 +4,7 @@ import {Line} from '../PageTitle/PageTitle'; import React, {RefObject} from 'react'; import {addKeyHandler, removeKeyHandler} from '../../utils/ShortkeyHandler'; -interface props { +interface Props { width?: string; height?: string; banner?: JSX.Element; @@ -16,11 +16,11 @@ interface props { /** * wrapper class for generic types of popups */ -class PopupBase extends React.Component { +class PopupBase extends React.Component { private wrapperRef: RefObject; - private framedimensions: { minHeight: string | undefined; width: string | undefined; height: string | undefined }; + private framedimensions: {minHeight: string | undefined; width: string | undefined; height: string | undefined}; - constructor(props: props) { + constructor(props: Props) { super(props); this.state = {items: []}; @@ -32,9 +32,9 @@ class PopupBase extends React.Component { // parse style props this.framedimensions = { - width: (this.props.width ? this.props.width : undefined), - height: (this.props.height ? this.props.height : undefined), - minHeight: (this.props.height ? this.props.height : undefined) + width: this.props.width ? this.props.width : undefined, + height: this.props.height ? this.props.height : undefined, + minHeight: this.props.height ? this.props.height : undefined }; } @@ -63,10 +63,8 @@ class PopupBase extends React.Component {
{this.props.banner}
- -
- {this.props.children} -
+ +
{this.props.children}
); } @@ -90,7 +88,9 @@ class PopupBase extends React.Component { this.props.onHide(); } else if (event.key === 'Enter') { // call a parentsubmit if defined - if (this.props.ParentSubmit) this.props.ParentSubmit(); + if (this.props.ParentSubmit) { + this.props.ParentSubmit(); + } } } @@ -98,15 +98,19 @@ class PopupBase extends React.Component { * make the element drag and droppable */ dragElement(): void { - let xOld = 0, yOld = 0; + let xOld = 0, + yOld = 0; const elmnt = this.wrapperRef.current; - if (elmnt === null) return; - if (elmnt.firstChild === null) return; + if (elmnt === null) { + return; + } + if (elmnt.firstChild === null) { + return; + } (elmnt.firstChild as HTMLDivElement).onmousedown = dragMouseDown; - function dragMouseDown(e: MouseEvent): void { e.preventDefault(); // get the mouse cursor position at startup: @@ -125,9 +129,11 @@ class PopupBase extends React.Component { xOld = e.clientX; yOld = e.clientY; // set the element's new position: - if (elmnt === null) return; - elmnt.style.top = (elmnt.offsetTop - dy) + 'px'; - elmnt.style.left = (elmnt.offsetLeft - dx) + 'px'; + if (elmnt === null) { + return; + } + elmnt.style.top = elmnt.offsetTop - dy + 'px'; + elmnt.style.left = elmnt.offsetLeft - dx + 'px'; } function closeDragElement(): void { diff --git a/src/elements/Popups/SubmitPopup/SubmitPopup.tsx b/src/elements/Popups/SubmitPopup/SubmitPopup.tsx index e6723d1..18127ed 100644 --- a/src/elements/Popups/SubmitPopup/SubmitPopup.tsx +++ b/src/elements/Popups/SubmitPopup/SubmitPopup.tsx @@ -2,17 +2,16 @@ import React from 'react'; import PopupBase from '../PopupBase'; import {Button} from '../../GPElements/Button'; -interface props { +interface Props { onHide: (_: void) => void; submit: (_: void) => void; } -export default function SubmitPopup(props: props): JSX.Element { +export default function SubmitPopup(props: Props): JSX.Element { return ( - + ); } diff --git a/src/elements/VideoContainer/VideoContainer.tsx b/src/elements/VideoContainer/VideoContainer.tsx index e03a344..01fb205 100644 --- a/src/elements/VideoContainer/VideoContainer.tsx +++ b/src/elements/VideoContainer/VideoContainer.tsx @@ -3,8 +3,8 @@ import Preview from '../Preview/Preview'; import style from './VideoContainer.module.css'; import {VideoTypes} from '../../types/ApiTypes'; -interface props { - data: VideoTypes.VideoUnloadedType[] +interface Props { + data: VideoTypes.VideoUnloadedType[]; } interface state { @@ -16,11 +16,11 @@ interface state { * A videocontainer storing lots of Preview elements * includes scroll handling and loading of preview infos */ -class VideoContainer extends React.Component { +class VideoContainer extends React.Component { // stores current index of loaded elements loadindex: number = 0; - constructor(props: props) { + constructor(props: Props) { super(props); this.state = { @@ -38,15 +38,11 @@ class VideoContainer extends React.Component { render(): JSX.Element { return (
- {this.state.loadeditems.map(elem => ( - + {this.state.loadeditems.map((elem) => ( + ))} {/*todo css for no items to show*/} - {this.state.loadeditems.length === 0 ? - 'no items to show!' : null} + {this.state.loadeditems.length === 0 ? 'no items to show!' : null} {this.props.children}
); @@ -73,13 +69,9 @@ class VideoContainer extends React.Component { } this.setState({ - loadeditems: [ - ...this.state.loadeditems, - ...ret - ] + loadeditems: [...this.state.loadeditems, ...ret] }); - this.loadindex += nr; } diff --git a/src/index.tsx b/src/index.tsx index 2a553e3..78e0469 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,11 +3,11 @@ import ReactDOM from 'react-dom'; import App from './App'; // don't allow console logs within production env -global.console.log = process.env.NODE_ENV !== 'development' ? (s: string | number | boolean): void => {} : global.console.log; +global.console.log = process.env.NODE_ENV !== 'development' ? (_: string | number | boolean): void => {} : global.console.log; ReactDOM.render( - + , document.getElementById('root') ); diff --git a/src/pages/ActorOverviewPage/ActorOverviewPage.tsx b/src/pages/ActorOverviewPage/ActorOverviewPage.tsx index a9b31de..0e74a37 100644 --- a/src/pages/ActorOverviewPage/ActorOverviewPage.tsx +++ b/src/pages/ActorOverviewPage/ActorOverviewPage.tsx @@ -8,16 +8,15 @@ import style from './ActorOverviewPage.module.css'; import {Button} from '../../elements/GPElements/Button'; import NewActorPopup from '../../elements/Popups/NewActorPopup/NewActorPopup'; -interface props { -} +interface Props {} interface state { actors: ActorType[]; - NActorPopupVisible: boolean + NActorPopupVisible: boolean; } -class ActorOverviewPage extends React.Component { - constructor(props: props) { +class ActorOverviewPage extends React.Component { + constructor(props: Props) { super(props); this.state = { @@ -33,24 +32,29 @@ class ActorOverviewPage extends React.Component { render(): JSX.Element { return ( <> - + - {this.handlePopups()} @@ -78,9 +87,14 @@ export class CategoryView extends React.Component this.setState({submitForceDelete: false})} - submit={(): void => {this.deleteTag(true);}}/>); + return ( + this.setState({submitForceDelete: false})} + submit={(): void => { + this.deleteTag(true); + }} + /> + ); } else { return <>; } @@ -91,7 +105,7 @@ export class CategoryView extends React.Component(APINode.Video, {action: 'getMovies', tag: id}, result => { + callAPI(APINode.Video, {action: 'getMovies', tag: id}, (result) => { this.videodata = result; this.setState({loaded: true}); }); @@ -101,19 +115,23 @@ export class CategoryView extends React.Component(APINode.Tags, { - action: 'deleteTag', - TagId: parseInt(this.props.match.params.id), - Force: force - }, result => { - console.log(result.result); - if (result.result === 'success') { - this.props.history.push('/categories'); - } else if (result.result === 'not empty tag') { - // show submisison tag to ask if really delete - this.setState({submitForceDelete: true}); + callAPI( + APINode.Tags, + { + action: 'deleteTag', + TagId: parseInt(this.props.match.params.id, 10), + Force: force + }, + (result) => { + console.log(result.result); + if (result.result === 'success') { + this.props.history.push('/categories'); + } else if (result.result === 'not empty tag') { + // show submisison tag to ask if really delete + this.setState({submitForceDelete: true}); + } } - }); + ); } } diff --git a/src/pages/CategoryPage/TagView.tsx b/src/pages/CategoryPage/TagView.tsx index af71a35..616b698 100644 --- a/src/pages/CategoryPage/TagView.tsx +++ b/src/pages/CategoryPage/TagView.tsx @@ -15,10 +15,10 @@ interface TagViewState { popupvisible: boolean; } -interface props {} +interface Props {} -class TagView extends React.Component { - constructor(props: props) { +class TagView extends React.Component { + constructor(props: Props) { super(props); this.state = { @@ -34,30 +34,33 @@ class TagView extends React.Component { render(): JSX.Element { return ( <> - + Default Tags: - - - - + + + + - -
- {this.state.loadedtags ? - this.state.loadedtags.map((m) => ( - - - )) : - 'loading'} + {this.state.loadedtags + ? this.state.loadedtags.map((m) => ( + + + + )) + : 'loading'}
{this.handlePopups()} @@ -68,7 +71,7 @@ class TagView extends React.Component { * load all available tags from db. */ loadTags(): void { - callAPI(APINode.Tags, {action: 'getAllTags'}, result => { + callAPI(APINode.Tags, {action: 'getAllTags'}, (result) => { this.setState({loadedtags: result}); }); } @@ -76,13 +79,15 @@ class TagView extends React.Component { private handlePopups(): JSX.Element { if (this.state.popupvisible) { return ( - { - this.setState({popupvisible: false}); - this.loadTags(); - }}/> + { + this.setState({popupvisible: false}); + this.loadTags(); + }} + /> ); } else { - return (<>); + return <>; } } } diff --git a/src/pages/HomePage/HomePage.tsx b/src/pages/HomePage/HomePage.tsx index 3b51274..b7af48e 100644 --- a/src/pages/HomePage/HomePage.tsx +++ b/src/pages/HomePage/HomePage.tsx @@ -10,25 +10,25 @@ import {Route, Switch, withRouter} from 'react-router-dom'; import {RouteComponentProps} from 'react-router'; import SearchHandling from './SearchHandling'; import {VideoTypes} from '../../types/ApiTypes'; -import {DefaultTags} from "../../types/GeneralTypes"; +import {DefaultTags} from '../../types/GeneralTypes'; -interface props extends RouteComponentProps {} +interface Props extends RouteComponentProps {} interface state { - sideinfo: VideoTypes.startDataType - subtitle: string, - data: VideoTypes.VideoUnloadedType[], - selectionnr: number + sideinfo: VideoTypes.startDataType; + subtitle: string; + data: VideoTypes.VideoUnloadedType[]; + selectionnr: number; } /** * The home page component showing on the initial pageload */ -export class HomePage extends React.Component { +export class HomePage extends React.Component { /** keyword variable needed temporary store search keyword */ keyword = ''; - constructor(props: props) { + constructor(props: Props) { super(props); this.state = { @@ -38,7 +38,7 @@ export class HomePage extends React.Component { HDNr: 0, SDNr: 0, DifferentTags: 0, - Tagged: 0, + Tagged: 0 }, subtitle: 'All Videos', data: [], @@ -65,7 +65,7 @@ export class HomePage extends React.Component { }); this.setState({ data: result, - selectionnr: result.length, + selectionnr: result.length }); }); } @@ -79,65 +79,86 @@ export class HomePage extends React.Component { }); } - render(): JSX.Element { return ( <> - + - -
{ - e.preventDefault(); - this.props.history.push('/search/' + this.keyword); - }}> - { - this.keyword = e.target.value; - }}/> - + + { + e.preventDefault(); + this.props.history.push('/search/' + this.keyword); + }}> + { + this.keyword = e.target.value; + }} + /> +
Infos: - - {this.state.sideinfo.VideoNr} Videos Total! - {this.state.sideinfo.FullHdNr} FULL-HD Videos! - {this.state.sideinfo.HDNr} HD Videos! - {this.state.sideinfo.SDNr} SD Videos! - {this.state.sideinfo.DifferentTags} different Tags! - + + + {this.state.sideinfo.VideoNr} Videos Total! + + + {this.state.sideinfo.FullHdNr} FULL-HD Videos! + + + {this.state.sideinfo.HDNr} HD Videos! + + + {this.state.sideinfo.SDNr} SD Videos! + + + {this.state.sideinfo.DifferentTags} different Tags! + + Default Tags: - { - this.fetchVideoData(DefaultTags.all.TagId); - this.setState({subtitle: `All Videos`}); - }}/> - { - this.fetchVideoData(DefaultTags.fullhd.TagId); - this.setState({subtitle: `Full Hd Videos`}); - }}/> - { - this.fetchVideoData(DefaultTags.lowq.TagId); - this.setState({subtitle: `Low Quality Videos`}); - }}/> - { - this.fetchVideoData(DefaultTags.hd.TagId); - this.setState({subtitle: `HD Videos`}); - }}/> + { + this.fetchVideoData(DefaultTags.all.TagId); + this.setState({subtitle: 'All Videos'}); + }} + /> + { + this.fetchVideoData(DefaultTags.fullhd.TagId); + this.setState({subtitle: 'Full Hd Videos'}); + }} + /> + { + this.fetchVideoData(DefaultTags.lowq.TagId); + this.setState({subtitle: 'Low Quality Videos'}); + }} + /> + { + this.fetchVideoData(DefaultTags.hd.TagId); + this.setState({subtitle: 'HD Videos'}); + }} + /> - {this.state.data.length !== 0 ? - : -
No Data found!
} -
- -
+ {this.state.data.length !== 0 ? :
No Data found!
} +
diff --git a/src/pages/HomePage/SearchHandling.tsx b/src/pages/HomePage/SearchHandling.tsx index a1f2452..7064c23 100644 --- a/src/pages/HomePage/SearchHandling.tsx +++ b/src/pages/HomePage/SearchHandling.tsx @@ -11,14 +11,14 @@ interface params { name: string; } -interface props extends RouteComponentProps {} +interface Props extends RouteComponentProps {} interface state { data: VideoTypes.VideoUnloadedType[]; } -export class SearchHandling extends React.Component { - constructor(props: props) { +export class SearchHandling extends React.Component { + constructor(props: Props) { super(props); this.state = { @@ -33,8 +33,8 @@ export class SearchHandling extends React.Component { render(): JSX.Element { return ( <> - - + + {this.getVideoData()} ); @@ -45,11 +45,9 @@ export class SearchHandling extends React.Component { */ getVideoData(): JSX.Element { if (this.state.data.length !== 0) { - return ( - - ); + return ; } else { - return (
No Data found!
); + return
No Data found!
; } } diff --git a/src/pages/Player/Player.tsx b/src/pages/Player/Player.tsx index 3784fc0..516c1e8 100644 --- a/src/pages/Player/Player.tsx +++ b/src/pages/Player/Player.tsx @@ -20,22 +20,22 @@ import {ActorType, TagType} from '../../types/VideoTypes'; import PlyrJS from 'plyr'; import {Button} from '../../elements/GPElements/Button'; import {VideoTypes} from '../../types/ApiTypes'; -import GlobalInfos from "../../utils/GlobalInfos"; +import GlobalInfos from '../../utils/GlobalInfos'; -interface myprops extends RouteComponentProps<{ id: string }> {} +interface myprops extends RouteComponentProps<{id: string}> {} interface mystate { - sources?: PlyrJS.SourceInfo, - movie_id: number, - movie_name: string, - likes: number, - quality: number, - length: number, - tags: TagType[], - suggesttag: TagType[], - popupvisible: boolean, - actorpopupvisible: boolean, - actors: ActorType[] + sources?: PlyrJS.SourceInfo; + movieId: number; + movieName: string; + likes: number; + quality: number; + length: number; + tags: TagType[]; + suggesttag: TagType[]; + popupvisible: boolean; + actorpopupvisible: boolean; + actors: ActorType[]; } /** @@ -64,8 +64,8 @@ export class Player extends React.Component { super(props); this.state = { - movie_id: -1, - movie_name: '', + movieId: -1, + movieName: '', likes: 0, quality: 0, length: 0, @@ -87,27 +87,37 @@ export class Player extends React.Component { render(): JSX.Element { return (
- + {this.assembleSideBar()}
{/* video component is added here */} - {this.state.sources ? : -
not loaded yet
} + {this.state.sources ? ( + + ) : ( +
not loaded yet
+ )}
-
{this.assembleActorTiles()}
- + { // handle the popovers switched on and off according to state changes this.handlePopOvers() @@ -123,18 +133,26 @@ export class Player extends React.Component { return ( Infos: - - {this.state.likes} Likes! - {this.state.quality !== 0 ? - {this.state.quality}p Quality! : null} - {this.state.length !== 0 ? - {Math.round(this.state.length / 60)} Minutes of length! : null} - + + + {this.state.likes} Likes! + + {this.state.quality !== 0 ? ( + + {this.state.quality}p Quality! + + ) : null} + {this.state.length !== 0 ? ( + + {Math.round(this.state.length / 60)} Minutes of length! + + ) : null} + Tags: {this.state.tags.map((m: TagType) => ( - + ))} - + Tag Quickadd: {this.state.suggesttag.map((m: TagType) => ( { key={m.TagName} onclick={(): void => { this.quickAddTag(m.TagId, m.TagName); - }}/> + }} + /> ))} ); @@ -154,18 +173,20 @@ export class Player extends React.Component { private assembleActorTiles(): JSX.Element { return (
- {this.state.actors ? - this.state.actors.map((actr: ActorType) => ( - - )) : <> - } -
{ - this.addActor(); - }}> + {this.state.actors ? this.state.actors.map((actr: ActorType) => ) : <>} +
{ + this.addActor(); + }}>
- +
Add Actor
@@ -173,7 +194,6 @@ export class Player extends React.Component { ); } - /** * handle the popovers generated according to state changes * @returns {JSX.Element} @@ -181,18 +201,18 @@ export class Player extends React.Component { handlePopOvers(): JSX.Element { return ( <> - { - this.state.popupvisible ? - this.setState({popupvisible: false})} - submit={this.quickAddTag}/> : null - } - { - this.state.actorpopupvisible ? - { + {this.state.popupvisible ? ( + this.setState({popupvisible: false})} submit={this.quickAddTag} /> + ) : null} + {this.state.actorpopupvisible ? ( + { this.refetchActors(); this.setState({actorpopupvisible: false}); - }} movie_id={this.state.movie_id}/> : null - } + }} + movieId={this.state.movieId} + /> + ) : null} ); } @@ -203,82 +223,93 @@ export class Player extends React.Component { * @param tagName name of tag to add */ quickAddTag(tagId: number, tagName: string): void { - callAPI(APINode.Tags, { - action: 'addTag', - TagId: tagId, - MovieId: parseInt(this.props.match.params.id) - }, (result: GeneralSuccess) => { - if (result.result !== 'success') { - console.error('error occured while writing to db -- todo error handling'); - console.error(result.result); - } else { - // check if tag has already been added - const tagIndex = this.state.tags.map(function (e: TagType) { - return e.TagName; - }).indexOf(tagName); + callAPI( + APINode.Tags, + { + action: 'addTag', + TagId: tagId, + MovieId: parseInt(this.props.match.params.id, 10) + }, + (result: GeneralSuccess) => { + if (result.result !== 'success') { + console.error('error occured while writing to db -- todo error handling'); + console.error(result.result); + } else { + // check if tag has already been added + const tagIndex = this.state.tags + .map(function (e: TagType) { + return e.TagName; + }) + .indexOf(tagName); - // only add tag if it isn't already there - if (tagIndex === -1) { - // update tags if successful - let array = [...this.state.suggesttag]; // make a separate copy of the array (because of setState) - const quickaddindex = this.state.suggesttag.map(function (e: TagType) { - return e.TagId; - }).indexOf(tagId); + // only add tag if it isn't already there + if (tagIndex === -1) { + // update tags if successful + let array = [...this.state.suggesttag]; // make a separate copy of the array (because of setState) + const quickaddindex = this.state.suggesttag + .map(function (e: TagType) { + return e.TagId; + }) + .indexOf(tagId); - // check if tag is available in quickadds - if (quickaddindex !== -1) { - array.splice(quickaddindex, 1); + // check if tag is available in quickadds + if (quickaddindex !== -1) { + array.splice(quickaddindex, 1); - this.setState({ - tags: [...this.state.tags, {TagName: tagName, TagId: tagId}], - suggesttag: array - }); - } else { - this.setState({ - tags: [...this.state.tags, {TagName: tagName, TagId: tagId}] - }); + this.setState({ + tags: [...this.state.tags, {TagName: tagName, TagId: tagId}], + suggesttag: array + }); + } else { + this.setState({ + tags: [...this.state.tags, {TagName: tagName, TagId: tagId}] + }); + } } } } - }); + ); } /** * fetch all the required infos of a video from backend */ fetchMovieData(): void { - callAPI(APINode.Video, {action: 'loadVideo', MovieId: parseInt(this.props.match.params.id)}, (result: VideoTypes.loadVideoType) => { - console.log(result) - this.setState({ - sources: { - type: 'video', - sources: [ - { - src: getBackendDomain() + GlobalInfos.getVideoPath() + result.MovieUrl, - type: 'video/mp4', - size: 1080 - } - ], - poster: result.Poster - }, - movie_id: result.MovieId, - movie_name: result.MovieName, - likes: result.Likes, - quality: result.Quality, - length: result.Length, - tags: result.Tags, - suggesttag: result.SuggestedTag, - actors: result.Actors - }); - }); + callAPI( + APINode.Video, + {action: 'loadVideo', MovieId: parseInt(this.props.match.params.id, 10)}, + (result: VideoTypes.loadVideoType) => { + console.log(result); + this.setState({ + sources: { + type: 'video', + sources: [ + { + src: getBackendDomain() + GlobalInfos.getVideoPath() + result.MovieUrl, + type: 'video/mp4', + size: 1080 + } + ], + poster: result.Poster + }, + movieId: result.MovieId, + movieName: result.MovieName, + likes: result.Likes, + quality: result.Quality, + length: result.Length, + tags: result.Tags, + suggesttag: result.SuggestedTag, + actors: result.Actors + }); + } + ); } - /** * click handler for the like btn */ likebtn(): void { - callAPI(APINode.Video, {action: 'addLike', MovieId: parseInt(this.props.match.params.id)}, (result: GeneralSuccess) => { + callAPI(APINode.Video, {action: 'addLike', MovieId: parseInt(this.props.match.params.id, 10)}, (result: GeneralSuccess) => { if (result.result === 'success') { // likes +1 --> avoid reload of all data this.setState({likes: this.state.likes + 1}); @@ -301,15 +332,19 @@ export class Player extends React.Component { * delete the current video and return to last page */ deleteVideo(): void { - callAPI(APINode.Video, {action: 'deleteVideo', MovieId: parseInt(this.props.match.params.id)}, (result: GeneralSuccess) => { - if (result.result === 'success') { - // return to last element if successful - this.props.history.goBack(); - } else { - console.error('an error occured while liking'); - console.error(result); + callAPI( + APINode.Video, + {action: 'deleteVideo', MovieId: parseInt(this.props.match.params.id, 10)}, + (result: GeneralSuccess) => { + if (result.result === 'success') { + // return to last element if successful + this.props.history.goBack(); + } else { + console.error('an error occured while liking'); + console.error(result); + } } - }); + ); } /** @@ -323,11 +358,14 @@ export class Player extends React.Component { * fetch the available video actors again */ refetchActors(): void { - callAPI(APINode.Actor, {action: 'getActorsOfVideo', MovieId: parseInt(this.props.match.params.id)}, result => { - this.setState({actors: result}); - }); + callAPI( + APINode.Actor, + {action: 'getActorsOfVideo', MovieId: parseInt(this.props.match.params.id, 10)}, + (result) => { + this.setState({actors: result}); + } + ); } } export default withRouter(Player); - diff --git a/src/pages/RandomPage/RandomPage.tsx b/src/pages/RandomPage/RandomPage.tsx index e02b36e..ffd3a79 100644 --- a/src/pages/RandomPage/RandomPage.tsx +++ b/src/pages/RandomPage/RandomPage.tsx @@ -47,26 +47,26 @@ class RandomPage extends React.Component<{}, state> { render(): JSX.Element { return (
- + Visible Tags: {this.state.tags.map((m) => ( - + ))} - {this.state.videos.length !== 0 ? - + {this.state.videos.length !== 0 ? ( +
- +
- : -
No Data found!
} - + ) : ( +
No Data found!
+ )}
); } @@ -83,8 +83,8 @@ class RandomPage extends React.Component<{}, state> { * @param nr number of videos to load */ loadShuffledvideos(nr: number): void { - callAPI(APINode.Video, {action: 'getRandomMovies', number: nr}, result => { - console.log(result) + callAPI(APINode.Video, {action: 'getRandomMovies', number: nr}, (result) => { + console.log(result); this.setState({videos: []}); // needed to trigger rerender of main videoview this.setState({ videos: result.Videos, diff --git a/src/pages/SettingsPage/GeneralSettings.tsx b/src/pages/SettingsPage/GeneralSettings.tsx index b31b6f4..df2b6a7 100644 --- a/src/pages/SettingsPage/GeneralSettings.tsx +++ b/src/pages/SettingsPage/GeneralSettings.tsx @@ -11,20 +11,19 @@ import {SettingsTypes} from '../../types/ApiTypes'; import {GeneralSuccess} from '../../types/GeneralTypes'; interface state { - customapi: boolean - apipath: string - generalSettings: SettingsTypes.loadGeneralSettingsType + customapi: boolean; + apipath: string; + generalSettings: SettingsTypes.loadGeneralSettingsType; } -interface props { -} +interface Props {} /** * Component for Generalsettings tag on Settingspage * handles general settings of mediacenter which concerns to all pages */ -class GeneralSettings extends React.Component { - constructor(props: props) { +class GeneralSettings extends React.Component { + constructor(props: Props) { super(props); this.state = { @@ -34,14 +33,14 @@ class GeneralSettings extends React.Component { DarkMode: true, DBSize: 0, DifferentTags: 0, - EpisodePath: "", - MediacenterName: "", - Password: "", + EpisodePath: '', + MediacenterName: '', + Password: '', PasswordEnabled: false, TagsAdded: 0, TMDBGrabbing: false, VideoNr: 0, - VideoPath: "" + VideoPath: '' } }; } @@ -55,51 +54,71 @@ class GeneralSettings extends React.Component { return ( <>
- - - - + + + +
-
{ - e.preventDefault(); - this.saveSettings(); - }}> + { + e.preventDefault(); + this.saveSettings(); + }}> Video Path - this.setState({ - generalSettings: { - ...this.state.generalSettings, - VideoPath: ee.target.value - } - })}/> + + this.setState({ + generalSettings: { + ...this.state.generalSettings, + VideoPath: ee.target.value + } + }) + } + /> TV Show Path - this.setState({ - generalSettings: { - ...this.state.generalSettings, - EpisodePath: e.target.value - } - })}/> + + this.setState({ + generalSettings: { + ...this.state.generalSettings, + EpisodePath: e.target.value + } + }) + } + /> @@ -116,17 +135,20 @@ class GeneralSettings extends React.Component { this.setState({customapi: !this.state.customapi}); }} /> - {this.state.customapi ? + {this.state.customapi ? ( API Backend url - { - this.setState({apipath: e.target.value}); - setCustomBackendDomain(e.target.value); - }}/> - : null} - + { + this.setState({apipath: e.target.value}); + setCustomBackendDomain(e.target.value); + }} + /> + + ) : null} { }} /> - {this.state.generalSettings.PasswordEnabled ? + {this.state.generalSettings.PasswordEnabled ? ( Password - this.setState({ - generalSettings: { - ...this.state.generalSettings, - Password: e.target.value - } - })}/> - : null - } + + this.setState({ + generalSettings: { + ...this.state.generalSettings, + Password: e.target.value + } + }) + } + /> + + ) : null} { The name of the Mediacenter - this.setState({ - generalSettings: { - ...this.state.generalSettings, - MediacenterName: e.target.value - } - })}/> + + this.setState({ + generalSettings: { + ...this.state.generalSettings, + MediacenterName: e.target.value + } + }) + } + />
-
- Version: {version} -
+
Version: {version}
); } @@ -225,23 +255,27 @@ class GeneralSettings extends React.Component { */ saveSettings(): void { let settings = this.state.generalSettings; - if(!this.state.generalSettings.PasswordEnabled){ + if (!this.state.generalSettings.PasswordEnabled) { settings.Password = '-1'; } - settings.DarkMode = GlobalInfos.isDarkTheme() + settings.DarkMode = GlobalInfos.isDarkTheme(); - callAPI(APINode.Settings, { - action: 'saveGeneralSettings', - Settings: settings - }, (result: GeneralSuccess) => { - if (result.result) { - console.log('successfully saved settings'); - // todo 2020-07-10: popup success - } else { - console.log('failed to save settings'); - // todo 2020-07-10: popup error + callAPI( + APINode.Settings, + { + action: 'saveGeneralSettings', + Settings: settings + }, + (result: GeneralSuccess) => { + if (result.result) { + console.log('successfully saved settings'); + // todo 2020-07-10: popup success + } else { + console.log('failed to save settings'); + // todo 2020-07-10: popup error + } } - }); + ); } } diff --git a/src/pages/SettingsPage/MovieSettings.tsx b/src/pages/SettingsPage/MovieSettings.tsx index d667d02..ba610de 100644 --- a/src/pages/SettingsPage/MovieSettings.tsx +++ b/src/pages/SettingsPage/MovieSettings.tsx @@ -5,20 +5,20 @@ import {GeneralSuccess} from '../../types/GeneralTypes'; import {SettingsTypes} from '../../types/ApiTypes'; interface state { - text: string[] - startbtnDisabled: boolean + text: string[]; + startbtnDisabled: boolean; } -interface props {} +interface Props {} /** * Component for MovieSettings on Settingspage * handles settings concerning to movies in general */ -class MovieSettings extends React.Component { +class MovieSettings extends React.Component { myinterval: number = -1; - constructor(props: props) { + constructor(props: Props) { super(props); this.state = { @@ -32,23 +32,36 @@ class MovieSettings extends React.Component { } componentWillUnmount(): void { - if (this.myinterval !== -1) + if (this.myinterval !== -1) { clearInterval(this.myinterval); + } } render(): JSX.Element { return ( <> - - -
{this.state.text.map(m => ( -
{m}
- ))}
+
+ {this.state.text.map((m) => ( +
+ {m} +
+ ))} +
); } @@ -99,7 +112,7 @@ class MovieSettings extends React.Component { * send request to cleanup db gravity */ cleanupGravity(): void { - callAPI(APINode.Settings, {action: 'cleanupGravity'}, (result) => { + callAPI(APINode.Settings, {action: 'cleanupGravity'}, () => { this.setState({ text: ['successfully cleaned up gravity!'] }); diff --git a/src/pages/SettingsPage/SettingsPage.tsx b/src/pages/SettingsPage/SettingsPage.tsx index bcaa0b3..9835e34 100644 --- a/src/pages/SettingsPage/SettingsPage.tsx +++ b/src/pages/SettingsPage/SettingsPage.tsx @@ -28,17 +28,17 @@ class SettingsPage extends React.Component {
- - + + - - + + - - + + - - + +
diff --git a/src/types/ApiTypes.ts b/src/types/ApiTypes.ts index 1895a44..25f1e88 100644 --- a/src/types/ApiTypes.ts +++ b/src/types/ApiTypes.ts @@ -2,16 +2,16 @@ import {ActorType, TagType} from './VideoTypes'; export namespace VideoTypes { export interface loadVideoType { - MovieUrl: string - Poster: string - MovieId: number - MovieName: string - Likes: number - Quality: number - Length: number - Tags: TagType[] - SuggestedTag: TagType[] - Actors: ActorType[] + MovieUrl: string; + Poster: string; + MovieId: number; + MovieName: string; + Likes: number; + Quality: number; + Length: number; + Tags: TagType[]; + SuggestedTag: TagType[]; + Actors: ActorType[]; } export interface startDataType { @@ -25,7 +25,7 @@ export namespace VideoTypes { export interface VideoUnloadedType { MovieId: number; - MovieName: string + MovieName: string; } } @@ -38,18 +38,18 @@ export namespace SettingsTypes { } export interface loadGeneralSettingsType { - VideoPath: string, - EpisodePath: string, - MediacenterName: string, - Password: string, - PasswordEnabled: boolean, - TMDBGrabbing: boolean, - DarkMode: boolean, + VideoPath: string; + EpisodePath: string; + MediacenterName: string; + Password: string; + PasswordEnabled: boolean; + TMDBGrabbing: boolean; + DarkMode: boolean; - VideoNr: number, - DBSize: number, - DifferentTags: number, - TagsAdded: number + VideoNr: number; + DBSize: number; + DifferentTags: number; + TagsAdded: number; } export interface getStatusMessageType { diff --git a/src/types/GeneralTypes.ts b/src/types/GeneralTypes.ts index d763f16..443ff15 100644 --- a/src/types/GeneralTypes.ts +++ b/src/types/GeneralTypes.ts @@ -1,11 +1,11 @@ import {TagType} from './VideoTypes'; export interface GeneralSuccess { - result: string + result: string; } interface TagarrayType { - [_: string]: TagType + [_: string]: TagType; } export const DefaultTags: TagarrayType = { diff --git a/src/types/VideoTypes.ts b/src/types/VideoTypes.ts index f3a963e..763fb8e 100644 --- a/src/types/VideoTypes.ts +++ b/src/types/VideoTypes.ts @@ -2,8 +2,8 @@ * type accepted by Tag component */ export interface TagType { - TagName: string - TagId: number + TagName: string; + TagId: number; } export interface ActorType { diff --git a/src/utils/Api.ts b/src/utils/Api.ts index c0ae974..b40f9c5 100644 --- a/src/utils/Api.ts +++ b/src/utils/Api.ts @@ -8,13 +8,13 @@ export function getBackendDomain(): string { let userAgent = navigator.userAgent.toLowerCase(); if (userAgent.indexOf(' electron/') > -1) { // Electron-specific code - force a custom backendurl - return (customBackendURL); + return customBackendURL; } else { // use custom only if defined if (customBackendURL) { - return (customBackendURL); + return customBackendURL; } else { - return (window.location.origin); + return window.location.origin; } } } @@ -38,29 +38,21 @@ function getAPIDomain(): string { * interface how an api request should look like */ interface ApiBaseRequest { - action: string | number, + action: string | number; - [_: string]: string | number | boolean | object + [_: string]: string | number | boolean | object; } // store api token - empty if not set -let apiToken = '' +let apiToken = ''; // a callback que to be called after api token refresh -let callQue: ((error: string) => void)[] = [] +let callQue: ((error: string) => void)[] = []; // flag to check wheter a api refresh is currently pending let refreshInProcess = false; // store the expire seconds of token let expireSeconds = -1; -interface APIToken { - error?: string; - access_token: string; - expires_in: number; - scope: string; - token_type: string; -} - /** * refresh the api token or use that one in cookie if still valid * @param callback to be called after successful refresh @@ -79,34 +71,44 @@ export function refreshAPIToken(callback: (error: string) => void, password?: st } if (apiTokenValid()) { - console.log("token still valid...") + console.log('token still valid...'); callFuncQue(''); return; } const formData = new FormData(); - formData.append("grant_type", "client_credentials"); - formData.append("client_id", "openmediacenter"); - formData.append("client_secret", password ? password : 'openmediacenter'); - formData.append("scope", 'all'); + formData.append('grant_type', 'client_credentials'); + formData.append('client_id', 'openmediacenter'); + formData.append('client_secret', password ? password : 'openmediacenter'); + formData.append('scope', 'all'); + interface APIToken { + error?: string; + // eslint-disable-next-line camelcase + access_token: string; // no camel case allowed because of backendlib + // eslint-disable-next-line camelcase + expires_in: number; // no camel case allowed because of backendlib + scope: string; + // eslint-disable-next-line camelcase + token_type: string; // no camel case allowed because of backendlib + } - fetch(getBackendDomain() + '/token', {method: 'POST', body: formData}) - .then((response) => response.json() - .then((result: APIToken) => { - if (result.error) { - callFuncQue(result.error); - return; - } - console.log(result) - // set api token - apiToken = result.access_token; - // set expire time - expireSeconds = (new Date().getTime() / 1000) + result.expires_in; - setTokenCookie(apiToken, expireSeconds); - // call all handlers and release flag - callFuncQue(''); - })); + fetch(getBackendDomain() + '/token', {method: 'POST', body: formData}).then((response) => + response.json().then((result: APIToken) => { + if (result.error) { + callFuncQue(result.error); + return; + } + console.log(result); + // set api token + apiToken = result.access_token; + // set expire time + expireSeconds = new Date().getTime() / 1000 + result.expires_in; + setTokenCookie(apiToken, expireSeconds); + // call all handlers and release flag + callFuncQue(''); + }) + ); } export function apiTokenValid(): boolean { @@ -114,7 +116,7 @@ export function apiTokenValid(): boolean { const token = getTokenCookie(); if (token !== null) { // check if token is at least valid for the next minute - if (token.expire > (new Date().getTime() / 1000) + 60) { + if (token.expire > new Date().getTime() / 1000 + 60) { apiToken = token.token; expireSeconds = token.expire; @@ -129,11 +131,11 @@ export function apiTokenValid(): boolean { */ function callFuncQue(error: string): void { // call all pending handlers - callQue.map(func => { + callQue.map((func) => { return func(error); - }) + }); // reset pending que - callQue = [] + callQue = []; // release flag to be able to start new refresh refreshInProcess = false; } @@ -146,24 +148,24 @@ function callFuncQue(error: string): void { function setTokenCookie(token: string, validSec: number): void { let d = new Date(); d.setTime(validSec * 1000); - console.log("token set" + d.toUTCString()) - let expires = "expires=" + d.toUTCString(); - document.cookie = "token=" + token + ";" + expires + ";path=/"; - document.cookie = "token_expire=" + validSec + ";" + expires + ";path=/"; + console.log('token set' + d.toUTCString()); + let expires = 'expires=' + d.toUTCString(); + document.cookie = 'token=' + token + ';' + expires + ';path=/'; + document.cookie = 'token_expire=' + validSec + ';' + expires + ';path=/'; } /** * get all required cookies for the token */ -function getTokenCookie(): { token: string, expire: number } | null { +function getTokenCookie(): {token: string; expire: number} | null { const token = decodeCookie('token'); const expireInString = decodeCookie('token_expire'); - const expireIn = parseInt(expireInString, 10) | 0; + const expireIn = parseInt(expireInString, 10); if (expireIn !== 0 && token !== '') { return {token: token, expire: expireIn}; } else { - return null + return null; } } @@ -172,7 +174,7 @@ function getTokenCookie(): { token: string, expire: number } | null { * @param key cookie key */ function decodeCookie(key: string): string { - let name = key + "="; + let name = key + '='; let decodedCookie = decodeURIComponent(document.cookie); let ca = decodedCookie.split(';'); for (let i = 0; i < ca.length; i++) { @@ -184,7 +186,7 @@ function decodeCookie(key: string): string { return c.substring(name.length, c.length); } } - return ""; + return ''; } /** @@ -196,10 +198,10 @@ function checkAPITokenValid(callback: () => void): void { // check if token is valid and set if (apiToken === '' || expireSeconds <= new Date().getTime() / 1000) { refreshAPIToken(() => { - callback() - }) + callback(); + }); } else { - callback() + callback(); } } @@ -210,28 +212,34 @@ function checkAPITokenValid(callback: () => void): void { * @param callback the callback with json reply from backend * @param errorcallback a optional callback if an error occured */ -export function callAPI(apinode: APINode, - fd: ApiBaseRequest, - callback: (_: T) => void, - errorcallback: (_: string) => void = (_: string): void => { - }): void { +export function callAPI( + apinode: APINode, + fd: ApiBaseRequest, + callback: (_: T) => void, + errorcallback: (_: string) => void = (_: string): void => {} +): void { checkAPITokenValid(() => { + console.log(apiToken); fetch(getAPIDomain() + apinode, { - method: 'POST', body: JSON.stringify(fd), headers: new Headers({ + method: 'POST', + body: JSON.stringify(fd), + headers: new Headers({ 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + apiToken, - }), - }).then((response) => { - if (response.status !== 200) { - console.log('Error: ' + response.statusText); - // todo place error popup here - } else { - response.json().then((result: T) => { - callback(result); - }) - } - }).catch(reason => errorcallback(reason)); - }) + Authorization: 'Bearer ' + apiToken + }) + }) + .then((response) => { + if (response.status !== 200) { + console.log('Error: ' + response.statusText); + // todo place error popup here + } else { + response.json().then((result: T) => { + callback(result); + }); + } + }) + .catch((reason) => errorcallback(reason)); + }); } /** @@ -239,18 +247,26 @@ export function callAPI(apinode: APINode, * @param apinode * @param fd * @param callback + * @param errorcallback */ -export function callApiUnsafe(apinode: APINode, fd: ApiBaseRequest, callback: (_: T) => void, errorcallback?: (_: string) => void): void { - fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd),}).then((response) => { - if (response.status !== 200) { - console.log('Error: ' + response.statusText); - // todo place error popup here - } else { - response.json().then((result: T) => { - callback(result); - }) - } - }).catch(reason => errorcallback ? errorcallback(reason) : {}) +export function callApiUnsafe( + apinode: APINode, + fd: ApiBaseRequest, + callback: (_: T) => void, + errorcallback?: (_: string) => void +): void { + fetch(getAPIDomain() + apinode, {method: 'POST', body: JSON.stringify(fd)}) + .then((response) => { + if (response.status !== 200) { + console.log('Error: ' + response.statusText); + // todo place error popup here + } else { + response.json().then((result: T) => { + callback(result); + }); + } + }) + .catch((reason) => (errorcallback ? errorcallback(reason) : {})); } /** @@ -262,21 +278,24 @@ export function callApiUnsafe(apinode: APINode, fd: ApiBaseRequest, callback: export function callAPIPlain(apinode: APINode, fd: ApiBaseRequest, callback: (_: string) => void): void { checkAPITokenValid(() => { fetch(getAPIDomain() + apinode, { - method: 'POST', body: JSON.stringify(fd), headers: new Headers({ + method: 'POST', + body: JSON.stringify(fd), + headers: new Headers({ 'Content-Type': 'application/json', - 'Authorization': 'Bearer ' + apiToken, + Authorization: 'Bearer ' + apiToken }) - }) - .then((response) => response.text() - .then((result) => { - callback(result); - })); + }).then((response) => + response.text().then((result) => { + callback(result); + }) + ); }); } /** * API nodes definitions */ +// eslint-disable-next-line no-shadow export enum APINode { Settings = 'settings', Tags = 'tags', diff --git a/src/utils/GlobalInfos.ts b/src/utils/GlobalInfos.ts index 8c9a7c4..f9789c4 100644 --- a/src/utils/GlobalInfos.ts +++ b/src/utils/GlobalInfos.ts @@ -7,7 +7,7 @@ import lighttheme from '../AppLightTheme.module.css'; */ class StaticInfos { private darktheme: boolean = true; - private videopath: string = "" + private videopath: string = ''; /** * check if the current theme is the dark theme @@ -15,7 +15,7 @@ class StaticInfos { */ isDarkTheme(): boolean { return this.darktheme; - }; + } /** * setter to enable or disable the dark or light theme @@ -23,16 +23,16 @@ class StaticInfos { */ enableDarkTheme(enable = true): void { this.darktheme = enable; - this.handlers.map(func => { + this.handlers.map((func) => { return func(); - }) + }); } /** * get the currently selected theme stylesheet * @returns {*} the style object of the current active theme */ - getThemeStyle(): { [_: string]: string } { + getThemeStyle(): {[_: string]: string} { return this.isDarkTheme() ? darktheme : lighttheme; } diff --git a/yarn.lock b/yarn.lock index 3b87a3b..de35c11 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1977,6 +1977,20 @@ dependencies: "@types/yargs-parser" "*" +"@typescript-eslint/eslint-plugin@^4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.17.0.tgz#6f856eca4e6a52ce9cf127dfd349096ad936aa2d" + integrity sha512-/fKFDcoHg8oNan39IKFOb5WmV7oWhQe1K6CDaAVfJaNWEhmfqlA24g+u1lqU5bMH7zuNasfMId4LaYWC5ijRLw== + dependencies: + "@typescript-eslint/experimental-utils" "4.17.0" + "@typescript-eslint/scope-manager" "4.17.0" + debug "^4.1.1" + functional-red-black-tree "^1.0.1" + lodash "^4.17.15" + regexpp "^3.0.0" + semver "^7.3.2" + tsutils "^3.17.1" + "@typescript-eslint/eslint-plugin@^4.5.0": version "4.16.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.16.1.tgz#2caf6a79dd19c3853b8d39769a27fccb24e4e651" @@ -2003,6 +2017,18 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/experimental-utils@4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.17.0.tgz#762c44aaa1a6a3c05b6d63a8648fb89b89f84c80" + integrity sha512-ZR2NIUbnIBj+LGqCFGQ9yk2EBQrpVVFOh9/Kd0Lm6gLpSAcCuLLe5lUCibKGCqyH9HPwYC0GIJce2O1i8VYmWA== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/scope-manager" "4.17.0" + "@typescript-eslint/types" "4.17.0" + "@typescript-eslint/typescript-estree" "4.17.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + "@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" @@ -2014,6 +2040,16 @@ eslint-scope "^5.0.0" eslint-utils "^2.0.0" +"@typescript-eslint/parser@^4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.17.0.tgz#141b647ffc72ebebcbf9b0fe6087f65b706d3215" + integrity sha512-KYdksiZQ0N1t+6qpnl6JeK9ycCFprS9xBAiIrw4gSphqONt8wydBw4BXJi3C11ywZmyHulvMaLjWsxDjUSDwAw== + dependencies: + "@typescript-eslint/scope-manager" "4.17.0" + "@typescript-eslint/types" "4.17.0" + "@typescript-eslint/typescript-estree" "4.17.0" + debug "^4.1.1" + "@typescript-eslint/parser@^4.5.0": version "4.16.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.16.1.tgz#3bbd3234dd3c5b882b2bcd9899bc30e1e1586d2a" @@ -2032,6 +2068,14 @@ "@typescript-eslint/types" "4.16.1" "@typescript-eslint/visitor-keys" "4.16.1" +"@typescript-eslint/scope-manager@4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.17.0.tgz#f4edf94eff3b52a863180f7f89581bf963e3d37d" + integrity sha512-OJ+CeTliuW+UZ9qgULrnGpPQ1bhrZNFpfT/Bc0pzNeyZwMik7/ykJ0JHnQ7krHanFN9wcnPK89pwn84cRUmYjw== + dependencies: + "@typescript-eslint/types" "4.17.0" + "@typescript-eslint/visitor-keys" "4.17.0" + "@typescript-eslint/types@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-3.10.1.tgz#1d7463fa7c32d8a23ab508a803ca2fe26e758727" @@ -2042,6 +2086,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.16.1.tgz#5ba2d3e38b1a67420d2487519e193163054d9c15" integrity sha512-nnKqBwMgRlhzmJQF8tnFDZWfunXmJyuXj55xc8Kbfup4PbkzdoDXZvzN8//EiKR27J6vUSU8j4t37yUuYPiLqA== +"@typescript-eslint/types@4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.17.0.tgz#f57d8fc7f31b348db946498a43050083d25f40ad" + integrity sha512-RN5z8qYpJ+kXwnLlyzZkiJwfW2AY458Bf8WqllkondQIcN2ZxQowAToGSd9BlAUZDB5Ea8I6mqL2quGYCLT+2g== + "@typescript-eslint/typescript-estree@3.10.1": version "3.10.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-3.10.1.tgz#fd0061cc38add4fad45136d654408569f365b853" @@ -2069,6 +2118,19 @@ semver "^7.3.2" tsutils "^3.17.1" +"@typescript-eslint/typescript-estree@4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.17.0.tgz#b835d152804f0972b80dbda92477f9070a72ded1" + integrity sha512-lRhSFIZKUEPPWpWfwuZBH9trYIEJSI0vYsrxbvVvNyIUDoKWaklOAelsSkeh3E2VBSZiNe9BZ4E5tYBZbUczVQ== + dependencies: + "@typescript-eslint/types" "4.17.0" + "@typescript-eslint/visitor-keys" "4.17.0" + debug "^4.1.1" + globby "^11.0.1" + is-glob "^4.0.1" + 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" @@ -2084,6 +2146,14 @@ "@typescript-eslint/types" "4.16.1" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.17.0": + version "4.17.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.17.0.tgz#9c304cfd20287c14a31d573195a709111849b14d" + integrity sha512-WfuMN8mm5SSqXuAr9NM+fItJ0SVVphobWYkWOwQ1odsfC014Vdxk/92t4JwS1Q6fCA/ABfCKpa3AVtpUKTNKGQ== + dependencies: + "@typescript-eslint/types" "4.17.0" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.9.0": version "1.9.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" @@ -2430,6 +2500,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -4719,6 +4794,11 @@ escodegen@^1.14.1: optionalDependencies: source-map "~0.6.1" +eslint-config-prettier@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.1.0.tgz#4ef1eaf97afe5176e6a75ddfb57c335121abc5a6" + integrity sha512-oKMhGv3ihGbCIimCAjqkdzx2Q+jthoqnXSP+d86M9tptwugycmTFdVR4IpLgq2c4SHifbwO90z2fQ8/Aio73yw== + eslint-config-react-app@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/eslint-config-react-app/-/eslint-config-react-app-6.0.0.tgz#ccff9fc8e36b322902844cbd79197982be355a0e" @@ -4726,6 +4806,13 @@ eslint-config-react-app@^6.0.0: dependencies: confusing-browser-globals "^1.0.10" +eslint-formatter-gitlab@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/eslint-formatter-gitlab/-/eslint-formatter-gitlab-2.2.0.tgz#e91bf9e22d04ae54561bf84788ed509c32a26e01" + integrity sha512-iLQB4Fp8CFAB2PiHVGMx58Zukzx5ZiNZa8MUKWzEkYwohkv6ZoutMi1JQWG89x1I+26EsvleTMoF2QkZco/XKA== + dependencies: + js-yaml "^4.0.0" + eslint-import-resolver-node@^0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz#85ffa81942c25012d8231096ddf679c03042c717" @@ -4742,6 +4829,14 @@ eslint-module-utils@^2.6.0: debug "^2.6.9" pkg-dir "^2.0.0" +eslint-plugin-eslint-comments@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz#9e1cd7b4413526abb313933071d7aba05ca12ffa" + integrity sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ== + dependencies: + escape-string-regexp "^1.0.5" + ignore "^5.0.5" + eslint-plugin-flowtype@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/eslint-plugin-flowtype/-/eslint-plugin-flowtype-5.3.1.tgz#df6227e28c61d967b825c1327a27818bbb2ad325" @@ -4776,6 +4871,13 @@ eslint-plugin-jest@^24.1.0: dependencies: "@typescript-eslint/experimental-utils" "^4.0.1" +eslint-plugin-jest@^24.3.1: + version "24.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-24.3.1.tgz#c8df037847b83397940bef7fbc2cc168ab466bcc" + integrity sha512-RQt59rfMSHyvedImT72iaf8JcvCcR4P7Uq499dALtjY8mrCjbwWrFi1UceG4sid2wVIeDi+0tjxXZ8CZEVO7Zw== + dependencies: + "@typescript-eslint/experimental-utils" "^4.0.1" + eslint-plugin-jsx-a11y@^6.3.1: version "6.4.1" resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.4.1.tgz#a2d84caa49756942f42f1ffab9002436391718fd" @@ -4793,12 +4895,19 @@ eslint-plugin-jsx-a11y@^6.3.1: jsx-ast-utils "^3.1.0" language-tags "^1.0.5" +eslint-plugin-prettier@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz#7079cfa2497078905011e6f82e8dd8453d1371b7" + integrity sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ== + dependencies: + prettier-linter-helpers "^1.0.0" + 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.21.5: +eslint-plugin-react@^7.21.5, eslint-plugin-react@^7.22.0: version "7.22.0" resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.22.0.tgz#3d1c542d1d3169c45421c1215d9470e341707269" integrity sha512-p30tuX3VS+NWv9nQot9xIGAHBXR0+xJVaZriEsHoJrASGCJZDJ8JLNM0YqKqI0AKm6Uxaa1VUHoNEibxRCMQHA== @@ -4909,6 +5018,49 @@ eslint@^7.11.0: text-table "^0.2.0" v8-compile-cache "^2.0.3" +eslint@^7.22.0: + version "7.22.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.22.0.tgz#07ecc61052fec63661a2cab6bd507127c07adc6f" + integrity sha512-3VawOtjSJUQiiqac8MQc+w457iGLfuNGLFn8JmF051tTKbh5/x/0vlcEj8OgDCaw7Ysa2Jn8paGshV7x2abKXg== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.0.0" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash "^4.17.21" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.4" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + espree@^7.3.0, espree@^7.3.1: version "7.3.1" resolved "https://registry.yarnpkg.com/espree/-/espree-7.3.1.tgz#f2df330b752c6f55019f8bd89b7660039c1bbbb6" @@ -5147,6 +5299,11 @@ fast-deep-equal@^3.1.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-glob@^3.1.1: version "3.2.5" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.5.tgz#7939af2a656de79a4f1901903ee8adcaa7cb9661" @@ -5576,6 +5733,13 @@ globals@^12.1.0: dependencies: type-fest "^0.8.1" +globals@^13.6.0: + version "13.6.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.6.0.tgz#d77138e53738567bb96a3916ff6f6b487af20ef7" + integrity sha512-YFKCX0SiPg7l5oKYCJ2zZGxcXprVXHcSnVuvzrT3oSENQonVLqM5pf9fN5dLGZGyCjhw8TN8Btwe/jKnZ0pjvQ== + dependencies: + type-fest "^0.20.2" + globby@11.0.1: version "11.0.1" resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.1.tgz#9a2bf107a068f3ffeabc49ad702c79ede8cfd357" @@ -5991,7 +6155,7 @@ ignore@^4.0.6: resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== -ignore@^5.1.4: +ignore@^5.0.5, ignore@^5.1.4: version "5.1.8" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== @@ -7013,6 +7177,13 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" + integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" @@ -7363,7 +7534,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -9202,6 +9373,23 @@ prepend-http@^1.0.0: resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= +prettier-config@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-config/-/prettier-config-1.0.0.tgz#f8eed3916369b81678acaa33dc0298147d1958c8" + integrity sha1-+O7TkWNpuBZ4rKoz3AKYFH0ZWMg= + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" + integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== + pretty-bytes@^5.3.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" @@ -11280,6 +11468,11 @@ type-fest@^0.11.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1"