diff --git a/ui/v2.5/.eslintrc.json b/ui/v2.5/.eslintrc.json index f26d60fca..07792d77a 100644 --- a/ui/v2.5/.eslintrc.json +++ b/ui/v2.5/.eslintrc.json @@ -1,4 +1,10 @@ { + "env": { + "browser": true + }, + "globals": { + "Mousetrap": "readonly" + }, "parser": "@typescript-eslint/parser", "parserOptions": { "project": "./tsconfig.json" @@ -16,11 +22,18 @@ "rules": { "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/no-explicit-any": 2, - "lines-between-class-members": "off", - "@typescript-eslint/interface-name-prefix": [ - "warn", - { "prefixWithI": "always" } + "@typescript-eslint/naming-convention": [ + "error", + { + "selector": "interface", + "format": ["PascalCase"], + "custom": { + "regex": "^I[A-Z]", + "match": true + } + } ], + "lines-between-class-members": "off", "import/extensions": [ "error", "ignorePackages", @@ -46,6 +59,7 @@ "@typescript-eslint/indent": "off", "react/prop-types": "off", "react/destructuring-assignment": "off", + "react/require-default-props": "off", "react/jsx-props-no-spreading": "off", "react/style-prop-object": ["error", { "allow": ["FormattedNumber"] diff --git a/ui/v2.5/codegen.yml b/ui/v2.5/codegen.yml index dbab06402..d648406a9 100644 --- a/ui/v2.5/codegen.yml +++ b/ui/v2.5/codegen.yml @@ -3,13 +3,12 @@ schema: "../../graphql/schema/**/*.graphql" documents: "../../graphql/documents/**/*.graphql" generates: src/core/generated-graphql.tsx: - config: - withHooks: true - withHOC: false - withComponents: false plugins: - - add: "/* eslint-disable */" + - add: + content: "/* eslint-disable */" - time - typescript - typescript-operations - typescript-react-apollo + config: + withRefetchFn: true diff --git a/ui/v2.5/package.json b/ui/v2.5/package.json index 164a6834d..5423cf023 100644 --- a/ui/v2.5/package.json +++ b/ui/v2.5/package.json @@ -25,66 +25,56 @@ "not op_mini all" ], "dependencies": { - "@apollo/react-hooks": "^3.1.5", - "@formatjs/intl-numberformat": "^4.2.1", - "@fortawesome/fontawesome-svg-core": "^1.2.28", - "@fortawesome/free-regular-svg-icons": "^5.13.0", - "@fortawesome/free-solid-svg-icons": "^5.13.0", - "@fortawesome/react-fontawesome": "^0.1.9", + "@apollo/client": "^3.1.4", + "@formatjs/intl-numberformat": "^5.6.0", + "@fortawesome/fontawesome-svg-core": "^1.2.30", + "@fortawesome/free-regular-svg-icons": "^5.14.0", + "@fortawesome/free-solid-svg-icons": "^5.14.0", + "@fortawesome/react-fontawesome": "^0.1.11", "@types/mousetrap": "^1.6.3", - "apollo-cache": "^1.3.4", - "apollo-cache-inmemory": "^1.6.5", - "apollo-client": "^2.6.8", - "apollo-link": "^1.2.14", - "apollo-link-error": "^1.1.13", - "apollo-link-http": "^1.5.17", - "apollo-link-ws": "^1.0.20", - "apollo-utilities": "^1.3.3", - "axios": "0.19.2", - "bootstrap": "^4.4.1", + "axios": "0.20.0", + "bootstrap": "^4.5.2", "classnames": "^2.2.6", - "flag-icon-css": "^3.4.6", - "formik": "^2.1.4", - "graphql": "^14.5.8", - "graphql-tag": "^2.10.3", - "i18n-iso-countries": "^5.2.0", - "jimp": "^0.12.1", - "localforage": "1.7.3", - "lodash": "^4.17.15", + "flag-icon-css": "^3.5.0", + "formik": "^2.1.5", + "graphql": "^15.3.0", + "graphql-tag": "^2.11.0", + "i18n-iso-countries": "^6.0.0", + "jimp": "^0.16.1", + "localforage": "1.9.0", + "lodash": "^4.17.20", "mousetrap": "^1.6.5", - "query-string": "6.12.1", + "query-string": "6.13.1", "react": "16.13.1", - "react-apollo": "^3.1.5", - "react-bootstrap": "1.0.1", + "react-bootstrap": "1.3.0", "react-dom": "16.13.1", "react-images": "0.5.19", - "react-intl": "^4.5.1", + "react-intl": "^5.8.0", "react-jw-player": "1.19.1", "react-markdown": "^4.3.1", "react-photo-gallery": "^8.0.0", "react-router-bootstrap": "^0.25.0", - "react-router-dom": "^5.1.2", + "react-router-dom": "^5.2.0", "react-select": "^3.1.0", - "subscriptions-transport-ws": "^0.9.16", + "subscriptions-transport-ws": "^0.9.18", "universal-cookie": "^4.0.3" }, "devDependencies": { - "@graphql-codegen/add": "^1.13.5", - "@graphql-codegen/cli": "^1.13.5", - "@graphql-codegen/time": "^1.13.5", - "@graphql-codegen/typescript": "^1.13.5", - "@graphql-codegen/typescript-compatibility": "^1.13.5", - "@graphql-codegen/typescript-operations": "^1.13.5", - "@graphql-codegen/typescript-react-apollo": "^1.13.5", + "@graphql-codegen/add": "^2.0.1", + "@graphql-codegen/cli": "^1.17.8", + "@graphql-codegen/time": "^2.0.1", + "@graphql-codegen/typescript": "^1.17.9", + "@graphql-codegen/typescript-operations": "^1.17.8", + "@graphql-codegen/typescript-react-apollo": "^2.0.6", "@types/classnames": "^2.2.10", - "@types/lodash": "^4.14.150", - "@types/node": "13.13.4", - "@types/react": "16.9.34", - "@types/react-dom": "^16.9.7", - "@types/react-images": "^0.5.1", + "@types/lodash": "^4.14.161", + "@types/node": "14.6.4", + "@types/react": "16.9.43", + "@types/react-dom": "^16.9.8", + "@types/react-images": "^0.5.3", "@types/react-router-bootstrap": "^0.24.5", "@types/react-router-dom": "5.1.5", - "@types/react-select": "^3.0.12", + "@types/react-select": "3.0.19", "@typescript-eslint/eslint-plugin": "^2.30.0", "@typescript-eslint/parser": "^2.30.0", "eslint": "^6.8.0", @@ -95,13 +85,13 @@ "eslint-plugin-react": "^7.19.0", "eslint-plugin-react-hooks": "^4.0.0", "extract-react-intl-messages": "^4.1.1", - "node-sass": "4.14.0", + "node-sass": "4.14.1", "postcss-safe-parser": "^4.0.2", - "prettier": "2.0.5", - "react-scripts": "^3.4.1", + "prettier": "2.1.1", + "react-scripts": "^3.4.3", "stylelint": "^13.3.3", "stylelint-config-prettier": "^8.0.1", "stylelint-order": "^4.0.0", - "typescript": "^3.8.3" + "typescript": "^3.9.7" } } diff --git a/ui/v2.5/src/App.tsx b/ui/v2.5/src/App.tsx index 92299389b..bdab5931d 100755 --- a/ui/v2.5/src/App.tsx +++ b/ui/v2.5/src/App.tsx @@ -5,8 +5,8 @@ import { ToastProvider } from "src/hooks/Toast"; import { library } from "@fortawesome/fontawesome-svg-core"; import { fas } from "@fortawesome/free-solid-svg-icons"; import "@formatjs/intl-numberformat/polyfill"; -import "@formatjs/intl-numberformat/dist/locale-data/en"; -import "@formatjs/intl-numberformat/dist/locale-data/en-GB"; +import "@formatjs/intl-numberformat/locale-data/en"; +import "@formatjs/intl-numberformat/locale-data/en-GB"; import locales from "src/locale"; import { useConfiguration } from "src/core/StashService"; diff --git a/ui/v2.5/src/components/Galleries/Gallery.tsx b/ui/v2.5/src/components/Galleries/Gallery.tsx index f58a591ae..3a57345b8 100644 --- a/ui/v2.5/src/components/Galleries/Gallery.tsx +++ b/ui/v2.5/src/components/Galleries/Gallery.tsx @@ -4,8 +4,12 @@ import { useFindGallery } from "src/core/StashService"; import { LoadingIndicator } from "src/components/Shared"; import { GalleryViewer } from "./GalleryViewer"; +interface IGalleryParams { + id: string; +} + export const Gallery: React.FC = () => { - const { id = "" } = useParams(); + const { id } = useParams(); const { data, error, loading } = useFindGallery(id); const gallery = data?.findGallery; diff --git a/ui/v2.5/src/components/Help/Manual.tsx b/ui/v2.5/src/components/Help/Manual.tsx index 038c31b52..ede75ff00 100644 --- a/ui/v2.5/src/components/Help/Manual.tsx +++ b/ui/v2.5/src/components/Help/Manual.tsx @@ -124,7 +124,7 @@ export const Manual: React.FC = ({ show, onClose }) => { setActiveTab(k)} + onSelect={(k) => k && setActiveTab(k)} id="manual-tabs" > diff --git a/ui/v2.5/src/components/List/ListFilter.tsx b/ui/v2.5/src/components/List/ListFilter.tsx index b6a0bf67c..78d27a2b9 100644 --- a/ui/v2.5/src/components/List/ListFilter.tsx +++ b/ui/v2.5/src/components/List/ListFilter.tsx @@ -9,7 +9,6 @@ import { Form, OverlayTrigger, Tooltip, - SafeAnchorProps, InputGroup, FormControl, ButtonToolbar, @@ -160,11 +159,9 @@ export const ListFilter: React.FC = ( props.onFilterUpdate(newFilter); } - function onChangeSortBy(event: React.MouseEvent) { - const target = event.currentTarget as HTMLAnchorElement; - + function onChangeSortBy(event: React.MouseEvent) { const newFilter = _.cloneDeep(props.filter); - newFilter.sortBy = target.text; + newFilter.sortBy = event.currentTarget.text; newFilter.currentPage = 1; props.onFilterUpdate(newFilter); } diff --git a/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx index 436456259..49bc6bc52 100644 --- a/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx +++ b/ui/v2.5/src/components/Movies/MovieDetails/Movie.tsx @@ -30,10 +30,14 @@ import { RatingStars } from "src/components/Scenes/SceneDetails/RatingStars"; import { MovieScenesPanel } from "./MovieScenesPanel"; import { MovieScrapeDialog } from "./MovieScrapeDialog"; +interface IMovieParams { + id?: string; +} + export const Movie: React.FC = () => { const history = useHistory(); const Toast = useToast(); - const { id = "new" } = useParams(); + const { id = "new" } = useParams(); const isNew = id === "new"; // Editing state diff --git a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx index 62856d8a3..1bf1fbb79 100644 --- a/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx +++ b/ui/v2.5/src/components/Performers/PerformerDetails/Performer.tsx @@ -17,10 +17,15 @@ import { PerformerDetailsPanel } from "./PerformerDetailsPanel"; import { PerformerOperationsPanel } from "./PerformerOperationsPanel"; import { PerformerScenesPanel } from "./PerformerScenesPanel"; +interface IPerformerParams { + id?: string; + tab?: string; +} + export const Performer: React.FC = () => { const Toast = useToast(); const history = useHistory(); - const { tab = "details", id = "new" } = useParams(); + const { tab = "details", id = "new" } = useParams(); const isNew = id === "new"; // Performer state @@ -51,7 +56,7 @@ export const Performer: React.FC = () => { tab === "scenes" || tab === "edit" || tab === "operations" ? tab : "details"; - const setActiveTabKey = (newTab: string) => { + const setActiveTabKey = (newTab: string | null) => { if (tab !== newTab) { const tabParam = newTab === "details" ? "" : `/${newTab}`; history.replace(`/performers/${id}${tabParam}`); diff --git a/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx b/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx index a5d28f717..c5133b3c9 100644 --- a/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx +++ b/ui/v2.5/src/components/SceneFilenameParser/SceneFilenameParser.tsx @@ -129,7 +129,7 @@ export const SceneFilenameParser: React.FC = () => { queryParseSceneFilenames(parserFilter, parserInputData) .then((response) => { - const result = response.data.parseSceneFilenames; + const result = response?.data?.parseSceneFilenames; if (result) { parseResults(result.results); setTotalItems(result.count); diff --git a/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx b/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx index b95308361..c922f1e69 100644 --- a/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx +++ b/ui/v2.5/src/components/SceneFilenameParser/SceneParserRow.tsx @@ -101,7 +101,6 @@ export class SceneParserResult { interface ISceneParserFieldProps { parserResult: ParserResult; className?: string; - fieldName: string; onSetChanged: (isSet: boolean) => void; onValueChanged: (value: T) => void; originalParserResult?: ParserResult; @@ -372,7 +371,6 @@ export const SceneParserRow = (props: ISceneParserRowProps) => { {props.showFields.get("Title") && ( @@ -386,7 +384,6 @@ export const SceneParserRow = (props: ISceneParserRowProps) => { {props.showFields.get("Date") && ( @@ -400,7 +397,6 @@ export const SceneParserRow = (props: ISceneParserRowProps) => { {props.showFields.get("Rating") && ( @@ -414,7 +410,6 @@ export const SceneParserRow = (props: ISceneParserRowProps) => { {props.showFields.get("Performers") && ( { {props.showFields.get("Tags") && ( { {props.showFields.get("Studio") && ( { - const { id = "new" } = useParams(); + const { id = "new" } = useParams(); const location = useLocation(); const history = useHistory(); const Toast = useToast(); @@ -210,7 +214,7 @@ export const Scene: React.FC = () => { return ( setActiveTabKey(k)} + onSelect={(k) => k && setActiveTabKey(k)} >