Switch to biome for frontend lint/format (#980)

This commit is contained in:
InfiniteStash
2025-08-26 08:59:20 +02:00
committed by GitHub
parent 0b9299948f
commit c5a31be447
180 changed files with 2097 additions and 70190 deletions

View File

@@ -1,2 +0,0 @@
generated-graphql/
definitions/

View File

@@ -1,13 +0,0 @@
{
"plugins": [
"stylelint-scss"
],
"extends": [
"stylelint-config-standard",
"stylelint-config-standard-scss"
],
"rules": {
"selector-class-pattern": null,
"property-no-vendor-prefix": null
},
}

View File

@@ -1,28 +0,0 @@
const path = require("path");
const globule = require("globule");
const schemaPath = path.resolve(__dirname, "../graphql/schema");
/** @type {import("apollo").ApolloConfig} */
module.exports = {
client: {
service: {
name: "stash-box",
localSchemaFile: [
...globule.find({
src: "**/*.graphql",
cwd: schemaPath,
prefixBase: true,
ignore: "schema.graphql",
}),
path.join(schemaPath, "./schema.graphql"),
],
},
excludes: [
"**/queries/**/_*",
"**/mutations/**/_*",
"**/__tests__/**/*",
"**/node_modules",
],
},
};

24
frontend/biome.json Normal file
View File

@@ -0,0 +1,24 @@
{
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
"files": {
"ignoreUnknown": false,
"includes": ["src/**", "!src/graphql/types.ts"]
},
"formatter": { "enabled": true, "indentStyle": "space", "indentWidth": 2 },
"javascript": { "formatter": { "quoteStyle": "double" }, "globals": [] },
"linter": {
"rules": {
"a11y": {
"useSemanticElements": "off"
},
"correctness": {
"useUniqueElementIds": "off"
}
}
},
"assist": {
"enabled": true,
"actions": { "source": { "organizeImports": "on" } }
}
}

View File

@@ -17,6 +17,3 @@ generates:
namingConvention:
enumValues: change-case-all#upperCase
nonOptionalTypename: true
hooks:
afterAllFileWrite:
- prettier --write

View File

@@ -1,70 +0,0 @@
import tseslint from 'typescript-eslint';
import reactRecommendedConfig from "eslint-plugin-react/configs/recommended.js"
import reactJSXConfig from "eslint-plugin-react/configs/jsx-runtime.js"
import reactHooks from "eslint-plugin-react-hooks";
import importPlugin from 'eslint-plugin-import';
import jsxA11y from 'eslint-plugin-jsx-a11y';
import eslintConfigPrettier from "eslint-config-prettier";
export default tseslint.config(
tseslint.configs.recommended,
tseslint.configs.recommendedTypeChecked,
reactRecommendedConfig,
reactJSXConfig,
importPlugin.flatConfigs.recommended,
jsxA11y.flatConfigs.recommended,
eslintConfigPrettier,
{
ignores: ["**/vite.config.js"],
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname,
},
},
plugins: {
"react-hooks": reactHooks,
},
settings: {
react: {
version: "detect",
},
},
rules: {
...reactHooks.configs.recommended.rules,
"react/prop-types": "off",
"@typescript-eslint/no-use-before-define": ["error", {
functions: false,
classes: true,
}],
"@typescript-eslint/no-floating-promises": "off",
"@typescript-eslint/restrict-template-expressions": "off",
"@typescript-eslint/no-unused-vars": ["error", {
"vars": "all",
"args": "after-used",
"ignoreRestSiblings": true,
}],
"prefer-destructuring": ["error", {
object: true,
array: false,
}],
"import/named": "off",
"import/namespace": "off",
"import/no-unresolved": "off",
"@typescript-eslint/no-misused-promises": ["error", {
checksVoidReturn: false,
}],
"jsx-a11y/no-autofocus": "off",
},
});

View File

@@ -7,12 +7,10 @@
"start": "vite --host",
"build": "vite build",
"validate": "pnpm lint && pnpm format-check && tsc --noEmit",
"lint": "pnpm lint:css && pnpm lint:js",
"lint:js": "eslint --cache src/**/*.{ts,tsx}",
"lint:css": "stylelint \"src/**/*.scss\"",
"lint": "pnpm biome lint src",
"generate": "graphql-codegen --config codegen.yml",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,scss,gql}\"",
"format-check": "prettier --check \"src/**/*.{js,jsx,ts,tsx,scss,gql}\"",
"format": "pnpm biome format --write",
"format-check": "pnpm biome format",
"analyze": "analyze=true vite build"
},
"engines": {
@@ -22,6 +20,7 @@
},
"packageManager": "pnpm@9.0.5",
"devDependencies": {
"@biomejs/biome": "^2.2.0",
"@graphql-codegen/cli": "^5.0.3",
"@graphql-codegen/typed-document-node": "^5.0.11",
"@graphql-codegen/typescript": "^4.1.1",
@@ -35,22 +34,10 @@
"@types/react-dom": "^18.3.1",
"@types/react-helmet": "^6.1.11",
"@vitejs/plugin-react-swc": "^3.7.1",
"eslint": "^9.15.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react": "^7.37.2",
"eslint-plugin-react-hooks": "^5.0.0",
"globule": "^1.3.4",
"prettier": "3.3.3",
"rollup-plugin-analyzer": "^4.0.0",
"sass": "~1.77.6",
"stylelint": "^16.10.0",
"stylelint-config-standard": "^36.0.1",
"stylelint-config-standard-scss": "^13.1.0",
"stylelint-scss": "^6.9.0",
"typescript": "~5.6.3",
"typescript-eslint": "^8.15.0",
"vite": "^5.4.19",
"vite-tsconfig-paths": "^5.1.3"
},

2310
frontend/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { ApolloProvider } from "@apollo/client";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { config as fontAwesomeConfig } from "@fortawesome/fontawesome-svg-core";

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { useForm } from "react-hook-form";
import { Button, Col, Form, Row } from "react-bootstrap";

View File

@@ -1,4 +1,4 @@
import { FC, useEffect } from "react";
import { type FC, useEffect } from "react";
import { Navbar, Nav, Button, Badge } from "react-bootstrap";
import { NavLink, useLocation, useNavigate, Link } from "react-router-dom";
import { faBell, faBook, faUser } from "@fortawesome/free-solid-svg-icons";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Col, Row } from "react-bootstrap";
import cx from "classnames";
@@ -29,8 +29,6 @@ const ChangeRow: FC<ChangeRowProps> = ({
</div>
</Col>
</Row>
) : (
<></>
);
) : null;
export default ChangeRow;

View File

@@ -1,5 +1,6 @@
import { FC, useState } from "react";
import Select, { OnChangeValue } from "react-select";
// biome-ignore-all lint/correctness/noNestedComponentDefinitions: Necessary for react-select
import { type FC, useState } from "react";
import Select, { type OnChangeValue } from "react-select";
import { Form } from "react-bootstrap";
import { uniq } from "lodash-es";
@@ -28,7 +29,7 @@ const CheckboxSelect: FC<MultiSelectProps> = ({
const handleChange = (vals: OnChangeValue<IOptionType, true>) => {
const selected = uniq(
vals.map((v) => [v.value, ...(v.subValues ?? [])]).flat(),
vals.flatMap((v) => [v.value, ...(v.subValues ?? [])]),
);
setUnselected(selected);

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Button } from "react-bootstrap";
import Modal from "src/components/modal";

View File

@@ -1,6 +1,6 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Button, Form } from "react-bootstrap";
import { GraphQLFormattedError } from "graphql";
import type { GraphQLFormattedError } from "graphql";
import { useEditComment } from "src/graphql";
import cx from "classnames";

View File

@@ -1,11 +1,11 @@
import { FC } from "react";
import type { FC } from "react";
import { Card, Col, Row } from "react-bootstrap";
import { Link } from "react-router-dom";
import cx from "classnames";
import { faRobot } from "@fortawesome/free-solid-svg-icons";
import { Icon, Tooltip } from "src/components/fragments";
import { OperationEnum, EditFragment } from "src/graphql";
import { OperationEnum, type EditFragment } from "src/graphql";
import { formatDateTime, editHref, userHref, formatOrdinals } from "src/utils";
import ModifyEdit from "./ModifyEdit";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Card } from "react-bootstrap";
import { Link } from "react-router-dom";

View File

@@ -1,8 +1,8 @@
import { FC } from "react";
import type { FC } from "react";
import { formatDistance } from "date-fns";
import { Tooltip } from "src/components/fragments";
import { useConfig, VoteStatusEnum, EditFragment } from "src/graphql";
import { useConfig, VoteStatusEnum, type EditFragment } from "src/graphql";
interface Props {
edit: EditFragment;
@@ -28,7 +28,7 @@ const ExpirationNotification: FC<Props> = ({ edit }) => {
edit.status !== VoteStatusEnum.PENDING ||
!edit.expires
)
return <></>;
return null;
// Pending edits that have reached the voting threshold have shorter voting periods.
// This will happen for destructive edits, or when votes are not unanimous.

View File

@@ -1,9 +1,9 @@
import { FC, useMemo } from "react";
import { type FC, useMemo } from "react";
import { Link } from "react-router-dom";
import { Col, Row } from "react-bootstrap";
import { faCheck, faXmark, faVideo } from "@fortawesome/free-solid-svg-icons";
import { OperationEnum, EditFragment } from "src/graphql";
import { OperationEnum, type EditFragment } from "src/graphql";
import {
isValidEditTarget,
getEditTargetRoute,

View File

@@ -1,5 +1,5 @@
import { FC } from "react";
import { Badge, BadgeProps } from "react-bootstrap";
import type { FC } from "react";
import { Badge, type BadgeProps } from "react-bootstrap";
import { VoteStatusEnum } from "src/graphql";
import { EditStatusTypes } from "src/constants/enums";

View File

@@ -1,8 +1,8 @@
import { FC } from "react";
import type { FC } from "react";
import { Col, Row } from "react-bootstrap";
import { faCheck, faXmark, faEdit } from "@fortawesome/free-solid-svg-icons";
import {
import type {
FingerprintAlgorithm,
PerformerFragment,
GenderEnum,
@@ -34,7 +34,7 @@ import {
import { Icon } from "src/components/fragments";
import ChangeRow from "src/components/changeRow";
import ImageChangeRow from "src/components/imageChangeRow";
import URLChangeRow, { URL } from "src/components/urlChangeRow";
import URLChangeRow, { type URL } from "src/components/urlChangeRow";
import LinkedChangeRow from "../linkedChangeRow";
import ListChangeRow from "../listChangeRow";
import { renderPerformer, renderTag, renderFingerprint } from "./renderEntity";

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Button, Form } from "react-bootstrap";
import { faCheck } from "@fortawesome/free-solid-svg-icons";
import cx from "classnames";
@@ -7,7 +7,7 @@ import {
VoteStatusEnum,
VoteTypeEnum,
useVote,
EditFragment,
type EditFragment,
} from "src/graphql";
import { Icon } from "src/components/fragments";
import { useCurrentUser } from "src/hooks";
@@ -27,7 +27,7 @@ const VoteBar: FC<Props> = ({ edit }) => {
const [vote, setVote] = useState<VoteTypeEnum | null>(userVote?.vote ?? null);
const [submitVote, { loading: savingVote }] = useVote();
if (edit.status !== VoteStatusEnum.PENDING) return <></>;
if (edit.status !== VoteStatusEnum.PENDING) return null;
const currentVote = (
<h6>

View File

@@ -1,8 +1,8 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import { sortBy } from "lodash-es";
import { VoteTypeEnum, EditFragment } from "src/graphql";
import { VoteTypeEnum, type EditFragment } from "src/graphql";
import { userHref, formatDateTime } from "src/utils";
import { VoteTypes } from "src/constants/enums";
import { Tooltip } from "src/components/fragments";

View File

@@ -1,6 +1,6 @@
import { Link } from "react-router-dom";
import { FingerprintAlgorithm, PerformerFragment } from "src/graphql";
import type { FingerprintAlgorithm, PerformerFragment } from "src/graphql";
import { performerHref, tagHref, createHref, formatDuration } from "src/utils";
import { GenderIcon, PerformerName, TagLink } from "src/components/fragments";

View File

@@ -1,4 +1,4 @@
import { FC, ChangeEvent, useState } from "react";
import { type FC, type ChangeEvent, useState } from "react";
import { Button, Col, Form, Row } from "react-bootstrap";
import { useFieldArray } from "react-hook-form";
import type { Control } from "react-hook-form";
@@ -6,7 +6,7 @@ import { isApolloError } from "@apollo/client";
import { faImages } from "@fortawesome/free-solid-svg-icons";
import cx from "classnames";
import { ImageFragment as Image, useAddImage } from "src/graphql";
import { type ImageFragment as Image, useAddImage } from "src/graphql";
import { Image as ImageInput } from "src/components/form";
import { Icon, LoadingIndicator } from "src/components/fragments";
@@ -24,7 +24,7 @@ type ControlType =
| undefined;
interface EditImagesProps {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: Awkward react-hook-form type
control: Control<any>;
file: File | undefined;
setFile: (f: File | undefined) => void;

View File

@@ -1,4 +1,5 @@
import { FC, ChangeEvent } from "react";
// biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select
import type { FC, ChangeEvent } from "react";
import Creatable from "react-select/creatable";
import { components } from "react-select";
import { Button, Col, Form, InputGroup, Row } from "react-bootstrap";
@@ -7,7 +8,7 @@ import type { Control } from "react-hook-form";
interface BodyModificationProps {
name: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: Awkward react-hook-form type
control: Control<any>;
locationPlaceholder: string;
descriptionPlaceholder: string;
@@ -83,7 +84,7 @@ const BodyModification: FC<BodyModificationProps> = ({
components={{
DropdownIndicator: () => null,
Menu: (data) =>
data.options.length > 0 ? <components.Menu {...data} /> : <></>,
data.options.length > 0 ? <components.Menu {...data} /> : null,
}}
/>
</Col>

View File

@@ -1,12 +1,12 @@
import { FC } from "react";
import type { FC } from "react";
import { Form } from "react-bootstrap";
import cx from "classnames";
import { FieldError, UseFormRegister } from "react-hook-form";
import type { FieldError, UseFormRegister } from "react-hook-form";
import NoteInput from "./NoteInput";
interface Props {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
// biome-ignore lint/suspicious/noExplicitAny: Awkward react-hook-form type
register: UseFormRegister<any>;
error?: FieldError;
}

View File

@@ -1,10 +1,10 @@
import { FC } from "react";
import type { FC } from "react";
import { Button } from "react-bootstrap";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { Icon } from "src/components/fragments";
import Image from "src/components/image";
import { ImageFragment } from "src/graphql";
import type { ImageFragment } from "src/graphql";
interface ImageProps {
image: Pick<ImageFragment, "id" | "url" | "width" | "height">;

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Button } from "react-bootstrap";
import { useNavigate } from "react-router-dom";

View File

@@ -1,16 +1,15 @@
import { FC, ChangeEvent, useState } from "react";
import { type FC, type ChangeEvent, useState } from "react";
import { Form, Tabs, Tab } from "react-bootstrap";
import cx from "classnames";
import EditComment from "src/components/editCard/EditComment";
import { UseFormRegister } from "react-hook-form";
import type { UseFormRegister } from "react-hook-form";
import { useCurrentUser } from "src/hooks";
interface IProps {
onChange?: (text: string) => void;
className?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
register?: UseFormRegister<any>;
register?: UseFormRegister<{ note: string }>;
hasError?: boolean;
}

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Button } from "react-bootstrap";
import { useNavigate } from "react-router-dom";

View File

@@ -1,4 +1,4 @@
import { FC, ReactNode } from "react";
import type { FC, ReactNode } from "react";
interface IProps {
error: string | ReactNode;

View File

@@ -1,4 +1,4 @@
import { FC, MouseEvent } from "react";
import type { FC, MouseEvent } from "react";
import { faStar } from "@fortawesome/free-solid-svg-icons";
import { faStar as farStar } from "@fortawesome/free-regular-svg-icons";
import { Button } from "react-bootstrap";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import {
faVenus,
faTransgender,
@@ -6,7 +6,7 @@ import {
faVenusMars,
} from "@fortawesome/free-solid-svg-icons";
import Icon from "./Icon";
import { GenderEnum } from "src/graphql";
import type { GenderEnum } from "src/graphql";
import { GenderTypes } from "src/constants";
interface IconProps {

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Button, OverlayTrigger, Popover } from "react-bootstrap";
import { Icon } from "src/components/fragments";
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";

View File

@@ -1,7 +1,7 @@
import { FC } from "react";
import type { FC } from "react";
import cx from "classnames";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
interface Props {
icon: IconDefinition;

View File

@@ -1,4 +1,4 @@
import { FC, useEffect, useState } from "react";
import { type FC, useEffect, useState } from "react";
import { Spinner } from "react-bootstrap";
import cx from "classnames";

View File

@@ -1,5 +1,5 @@
import { FC } from "react";
import { PerformerFragment } from "src/graphql";
import type { FC } from "react";
import type { PerformerFragment } from "src/graphql";
interface PerformerNameProps {
performer: Pick<PerformerFragment, "name" | "disambiguation" | "deleted">;

View File

@@ -1,4 +1,4 @@
import React from "react";
import type React from "react";
import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons";
import { Icon, Tooltip } from "src/components/fragments";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import cx from "classnames";
import { siteHref } from "src/utils/route";
@@ -19,7 +19,7 @@ interface Props {
}
const SiteLink: FC<Props> = ({ site, hideName = false, noMargin = false }) =>
site ? (
site && (
<Link to={siteHref(site)} className={CLASSNAME}>
<img className={CLASSNAME_ICON} src={site.icon} alt="" />
{!hideName && (
@@ -30,8 +30,6 @@ const SiteLink: FC<Props> = ({ site, hideName = false, noMargin = false }) =>
</span>
)}
</Link>
) : (
<></>
);
export default SiteLink;

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Badge, Button } from "react-bootstrap";
import { Link } from "react-router-dom";
import { Icon } from "src/components/fragments";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import cx from "classnames";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import Icon from "./Icon";

View File

@@ -1,8 +1,8 @@
import { FC, ReactElement } from "react";
import type { FC, ReactElement } from "react";
import {
OverlayTrigger,
Tooltip as BSTooltip,
PopoverProps,
type PopoverProps,
} from "react-bootstrap";
interface Props {

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import cx from "classnames";
import { faXmark } from "@fortawesome/free-solid-svg-icons";
import { sortImageURLs } from "src/utils";

View File

@@ -1,11 +1,11 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Button } from "react-bootstrap";
import {
faChevronLeft,
faChevronRight,
} from "@fortawesome/free-solid-svg-icons";
import { ImageFragment } from "src/graphql";
import type { ImageFragment } from "src/graphql";
import Image from "src/components/image";
import { Icon } from "src/components/fragments";
import { sortImageURLs } from "src/utils";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Col, Row } from "react-bootstrap";
import ImageComponent from "src/components/image";
@@ -25,6 +25,7 @@ const Images: FC<{
<>
{(images ?? []).map((image, i) =>
image === null ? (
// biome-ignore lint/suspicious/noArrayIndexKey: Image is deleted, no other key
<img className={CLASSNAME_IMAGE} alt="Deleted" key={`deleted-${i}`} />
) : (
<div key={image.id} className={CLASSNAME_IMAGE}>
@@ -70,8 +71,6 @@ const ImageChangeRow: FC<ImageChangeRowProps> = ({
)}
</Col>
</Row>
) : (
<></>
);
) : null;
export default ImageChangeRow;

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import { Col, Row } from "react-bootstrap";
import cx from "classnames";

View File

@@ -1,14 +1,14 @@
import { FC } from "react";
import type { FC } from "react";
import { useEditFilter, usePagination } from "src/hooks";
import {
useEdits,
TargetTypeEnum,
SortDirectionEnum,
VoteStatusEnum,
OperationEnum,
EditSortEnum,
UserVotedFilterEnum,
type TargetTypeEnum,
type SortDirectionEnum,
type VoteStatusEnum,
type OperationEnum,
type EditSortEnum,
type UserVotedFilterEnum,
} from "src/graphql";
import { ErrorMessage } from "src/components/fragments";
import EditCard from "src/components/editCard";

View File

@@ -1,4 +1,4 @@
import { FC, ReactNode, useEffect, useState } from "react";
import { type FC, type ReactNode, useEffect, useState } from "react";
import { LoadingIndicator } from "src/components/fragments";
import Pagination from "src/components/pagination";
@@ -51,9 +51,7 @@ const List: FC<Props> = ({
children
) : currentCount === 0 ? (
<h4 className="m-4 p-4 text-center">No results</h4>
) : (
<></>
)}
) : null}
<div className="d-flex">
<Pagination
onClick={setPage}

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import Select from "react-select";
import { Button, Col, Form, InputGroup, Row } from "react-bootstrap";
import {
@@ -9,7 +9,7 @@ import {
import {
useScenes,
FavoriteFilter,
SceneQueryInput,
type SceneQueryInput,
SortDirectionEnum,
SceneSortEnum,
CriterionModifier,

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import { Card, Form, Row } from "react-bootstrap";
import { debounce } from "lodash-es";
@@ -7,7 +7,7 @@ import {
useTags,
SortDirectionEnum,
TagSortEnum,
TagQueryInput,
type TagQueryInput,
} from "src/graphql";
import { usePagination, useQueryParams } from "src/hooks";
import { ErrorMessage } from "src/components/fragments";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { SiteLink } from "src/components/fragments";
interface URLListProps {

View File

@@ -1,4 +1,4 @@
import { PropsWithChildren } from "react";
import type { PropsWithChildren } from "react";
import { Col, Row } from "react-bootstrap";
@@ -14,7 +14,7 @@ interface ListChangeRowProps<T> {
const CLASSNAME = "ListChangeRow";
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
const ListChangeRow = <T extends unknown>({
const ListChangeRow = <T,>({
added,
removed,
name,
@@ -56,8 +56,6 @@ const ListChangeRow = <T extends unknown>({
)}
</Col>
</Row>
) : (
<></>
);
) : null;
export default ListChangeRow;

View File

@@ -1,4 +1,4 @@
import { ReactNode, FC } from "react";
import type { ReactNode, FC } from "react";
import { Modal, Button } from "react-bootstrap";
interface ModalProps {

View File

@@ -1,6 +1,7 @@
import { FC } from "react";
// biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select
import type { FC } from "react";
import CreatableSelect from "react-select/creatable";
import { OnChangeValue } from "react-select";
import type { OnChangeValue } from "react-select";
interface MultiSelectProps {
initialValues: string[];

View File

@@ -1,4 +1,4 @@
import { FC, MouseEvent } from "react";
import type { FC, MouseEvent } from "react";
import { Pagination } from "react-bootstrap";
interface PaginationProps {

View File

@@ -1,9 +1,9 @@
import { FC } from "react";
import type { FC } from "react";
import { Card } from "react-bootstrap";
import { Link } from "react-router-dom";
import cx from "classnames";
import { Performer } from "src/graphql";
import type { Performer } from "src/graphql";
import {
GenderIcon,

View File

@@ -1,10 +1,10 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { TagLink } from "src/components/fragments";
import SearchField, { SearchType } from "src/components/searchField";
import { performerHref } from "src/utils";
import { formatDisambiguation, performerHref } from "src/utils";
import { SearchPerformersQuery } from "src/graphql";
import type { SearchPerformersQuery } from "src/graphql";
type Performer = NonNullable<SearchPerformersQuery["searchPerformer"]>[number];
@@ -43,10 +43,7 @@ const PerformerSelect: FC<PerformerSelectProps> = ({
.sort((a, b) => (a.name > b.name ? 1 : a.name < b.name ? -1 : 0))
.map((performer) => (
<TagLink
title={
performer.name +
(performer.disambiguation ? ` (${performer.disambiguation})` : "")
}
title={`${performer.name}${formatDisambiguation(performer)}`}
link={performerHref(performer)}
onRemove={() => removePerformer(performer.id)}
key={performer.id}

View File

@@ -1,9 +1,9 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import { Card } from "react-bootstrap";
import { faVideo } from "@fortawesome/free-solid-svg-icons";
import { Scene, Studio } from "src/graphql";
import type { Scene, Studio } from "src/graphql";
import {
getImage,
sceneHref,

View File

@@ -1,10 +1,11 @@
import { FC, KeyboardEvent, useRef, useState } from "react";
// biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select
import { type FC, type KeyboardEvent, useRef, useState } from "react";
import { useApolloClient } from "@apollo/client";
import {
OnChangeValue,
type OnChangeValue,
components,
SelectInstance,
GroupBase,
type SelectInstance,
type GroupBase,
} from "react-select";
import Async from "react-select/async";
import debounce from "p-debounce";
@@ -13,8 +14,13 @@ import { useNavigate } from "react-router-dom";
import SearchAllGQL from "src/graphql/queries/SearchAll.gql";
import SearchPerformersGQL from "src/graphql/queries/SearchPerformers.gql";
import { SearchAllQuery, SearchPerformersQuery } from "src/graphql";
import { createHref, filterData, getImage } from "src/utils";
import type { SearchAllQuery, SearchPerformersQuery } from "src/graphql";
import {
createHref,
filterData,
getImage,
formatDisambiguation,
} from "src/utils";
import { ROUTE_SEARCH } from "src/constants/route";
import { GenderIcon, SearchHint, Thumbnail } from "src/components/fragments";
@@ -103,9 +109,7 @@ function handleResult(
.map((performer) => ({
type: "performer",
value: performer,
label: `${performer.name}${
performer.disambiguation ? " (" + performer.disambiguation + ")" : ""
}`,
label: `${performer.name}${formatDisambiguation(performer)}`,
sublabel: [
performer?.birth_date ? `Born: ${performer.birth_date}` : null,
performer?.aliases.length
@@ -141,9 +145,7 @@ function handleResult(
.map((performer) => ({
type: "performer",
value: performer,
label: `${performer.name}${
performer.disambiguation ? " (" + performer.disambiguation + ")" : ""
}`,
label: `${performer.name}${formatDisambiguation(performer)}`,
sublabel: [
performer.birth_date ? `Born: ${performer.birth_date}` : null,
performer.aliases.length

View File

@@ -1,4 +1,5 @@
import { FC } from "react";
// biome-ignore-all lint/correctness/noNestedComponentDefinitions: react-select
import type { FC } from "react";
import { components } from "react-select";
import Async from "react-select/async";
import { useApolloClient } from "@apollo/client";
@@ -11,10 +12,10 @@ import StudioGQL from "src/graphql/queries/Studio.gql";
import {
SortDirectionEnum,
StudioSortEnum,
StudiosQuery,
StudiosQueryVariables,
StudioQuery,
StudioQueryVariables,
type StudiosQuery,
type StudiosQueryVariables,
type StudioQuery,
type StudioQueryVariables,
} from "src/graphql";
import { isUUID } from "src/utils";

View File

@@ -1,12 +1,16 @@
import { FC } from "react";
import type { FC } from "react";
import Async from "react-select/async";
import { OnChangeValue, MenuPlacement } from "react-select";
import type { OnChangeValue, MenuPlacement } from "react-select";
import { useApolloClient } from "@apollo/client";
import debounce from "p-debounce";
import SearchTagsGQL from "src/graphql/queries/SearchTags.gql";
import { SearchTagsQuery, SearchTagsQueryVariables, useTag } from "src/graphql";
import {
type SearchTagsQuery,
type SearchTagsQueryVariables,
useTag,
} from "src/graphql";
type Tag = NonNullable<SearchTagsQuery["query"][number]>;

View File

@@ -1,12 +1,12 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import Async from "react-select/async";
import { OnChangeValue, MenuPlacement } from "react-select";
import type { OnChangeValue, MenuPlacement } from "react-select";
import { useApolloClient } from "@apollo/client";
import debounce from "p-debounce";
import SearchTagsGQL from "src/graphql/queries/SearchTags.gql";
import { SearchTagsQuery, SearchTagsQueryVariables } from "src/graphql";
import type { SearchTagsQuery, SearchTagsQueryVariables } from "src/graphql";
import { TagLink } from "src/components/fragments";
import { tagHref } from "src/utils/route";
import { compareByName } from "src/utils";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Helmet } from "react-helmet";
// Title is only injected in production, so default to Stash-Box in dev
@@ -10,8 +10,6 @@ interface Props {
}
const Title: FC<Props> = ({ page }) => (
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
/* @ts-ignore */
<Helmet>
<title>{page ? `${page} | ${INSTANCE_TITLE}` : INSTANCE_TITLE}</title>
</Helmet>

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Col, Row } from "react-bootstrap";
import { SiteLink } from "src/components/fragments";
@@ -62,8 +62,6 @@ const URLChangeRow: FC<URLChangeRowProps> = ({ newURLs, oldURLs, showDiff }) =>
)}
</Col>
</Row>
) : (
<></>
);
) : null;
export default URLChangeRow;

View File

@@ -1,4 +1,4 @@
import { FC, useRef, useState } from "react";
import { type FC, useRef, useState } from "react";
import { Button, Form, InputGroup } from "react-bootstrap";
import { Icon } from "src/components/fragments";
import type {
@@ -10,7 +10,7 @@ import type {
import { useFieldArray } from "react-hook-form";
import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons";
import { useSites, ValidSiteTypeEnum, SiteQuery } from "src/graphql";
import { useSites, type ValidSiteTypeEnum, type SiteQuery } from "src/graphql";
import { cleanURL } from "src/utils";
type Site = NonNullable<SiteQuery["findSite"]>;
@@ -33,8 +33,8 @@ type ErrorsType = Merge<
>;
interface URLInputProps {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
control: any;
// biome-ignore lint/suspicious/noExplicitAny: Awkward react-hooks type
control: Control<any>;
type: ValidSiteTypeEnum;
errors?: ErrorsType;
}
@@ -55,7 +55,7 @@ const URLInput: FC<URLInputProps> = ({ control, type, errors }) => {
const inputRef = useRef<HTMLInputElement | null>(null);
const { data, loading } = useSites();
if (loading) return <></>;
if (loading) return null;
const sites = (data?.querySites.sites ?? []).filter((s) =>
s.valid_types.includes(type),
);

View File

@@ -1,6 +1,6 @@
import { createContext, useContext } from "react";
import { RoleEnum } from "src/graphql";
import type { RoleEnum } from "src/graphql";
export interface User {
id: string;

View File

@@ -1,93 +1,93 @@
import { useMutation, MutationHookOptions } from "@apollo/client";
import { useMutation, type MutationHookOptions } from "@apollo/client";
import MeGql from "../queries/Me.gql";
import {
ActivateNewUserMutation,
ActivateNewUserMutationVariables,
AddUserMutation,
AddUserMutationVariables,
NewUserMutation,
NewUserMutationVariables,
UpdateUserMutation,
UpdateUserMutationVariables,
DeleteUserMutation,
DeleteUserMutationVariables,
AddTagCategoryMutation,
AddTagCategoryMutationVariables,
DeleteTagCategoryMutation,
DeleteTagCategoryMutationVariables,
UpdateTagCategoryMutation,
UpdateTagCategoryMutationVariables,
AddImageMutation,
AddImageMutationVariables,
PerformerEditMutation,
PerformerEditMutationVariables,
PerformerEditUpdateMutation,
PerformerEditUpdateMutationVariables,
TagEditMutation,
TagEditMutationVariables,
TagEditUpdateMutation,
TagEditUpdateMutationVariables,
AddSceneMutation,
AddSceneMutationVariables,
DeleteSceneMutation,
DeleteSceneMutationVariables,
UpdateSceneMutation,
UpdateSceneMutationVariables,
AddStudioMutation,
AddStudioMutationVariables,
DeleteStudioMutation,
DeleteStudioMutationVariables,
UpdateStudioMutation,
UpdateStudioMutationVariables,
ApplyEditMutation,
ApplyEditMutationVariables,
CancelEditMutation,
CancelEditMutationVariables,
ChangePasswordMutation,
ChangePasswordMutationVariables,
ResetPasswordMutation,
ResetPasswordMutationVariables,
RegenerateApiKeyMutation,
RegenerateApiKeyMutationVariables,
GenerateInviteCodesMutation,
GrantInviteMutation,
GrantInviteMutationVariables,
RescindInviteCodeMutation,
RescindInviteCodeMutationVariables,
RevokeInviteMutation,
RevokeInviteMutationVariables,
EditCommentMutation,
EditCommentMutationVariables,
StudioEditMutation,
StudioEditMutationVariables,
StudioEditUpdateMutation,
StudioEditUpdateMutationVariables,
SceneEditMutation,
SceneEditMutationVariables,
SceneEditUpdateMutation,
SceneEditUpdateMutationVariables,
VoteMutation,
VoteMutationVariables,
AddSiteMutation,
AddSiteMutationVariables,
DeleteSiteMutation,
DeleteSiteMutationVariables,
UpdateSiteMutation,
UpdateSiteMutationVariables,
FavoriteStudioMutation,
FavoriteStudioMutationVariables,
FavoritePerformerMutation,
FavoritePerformerMutationVariables,
DeleteDraftMutation,
DeleteDraftMutationVariables,
UnmatchFingerprintMutation,
UnmatchFingerprintMutationVariables,
ValidateChangeEmailMutation,
ValidateChangeEmailMutationVariables,
ConfirmChangeEmailMutation,
ConfirmChangeEmailMutationVariables,
RequestChangeEmailMutation,
type ActivateNewUserMutation,
type ActivateNewUserMutationVariables,
type AddUserMutation,
type AddUserMutationVariables,
type NewUserMutation,
type NewUserMutationVariables,
type UpdateUserMutation,
type UpdateUserMutationVariables,
type DeleteUserMutation,
type DeleteUserMutationVariables,
type AddTagCategoryMutation,
type AddTagCategoryMutationVariables,
type DeleteTagCategoryMutation,
type DeleteTagCategoryMutationVariables,
type UpdateTagCategoryMutation,
type UpdateTagCategoryMutationVariables,
type AddImageMutation,
type AddImageMutationVariables,
type PerformerEditMutation,
type PerformerEditMutationVariables,
type PerformerEditUpdateMutation,
type PerformerEditUpdateMutationVariables,
type TagEditMutation,
type TagEditMutationVariables,
type TagEditUpdateMutation,
type TagEditUpdateMutationVariables,
type AddSceneMutation,
type AddSceneMutationVariables,
type DeleteSceneMutation,
type DeleteSceneMutationVariables,
type UpdateSceneMutation,
type UpdateSceneMutationVariables,
type AddStudioMutation,
type AddStudioMutationVariables,
type DeleteStudioMutation,
type DeleteStudioMutationVariables,
type UpdateStudioMutation,
type UpdateStudioMutationVariables,
type ApplyEditMutation,
type ApplyEditMutationVariables,
type CancelEditMutation,
type CancelEditMutationVariables,
type ChangePasswordMutation,
type ChangePasswordMutationVariables,
type ResetPasswordMutation,
type ResetPasswordMutationVariables,
type RegenerateApiKeyMutation,
type RegenerateApiKeyMutationVariables,
type GenerateInviteCodesMutation,
type GrantInviteMutation,
type GrantInviteMutationVariables,
type RescindInviteCodeMutation,
type RescindInviteCodeMutationVariables,
type RevokeInviteMutation,
type RevokeInviteMutationVariables,
type EditCommentMutation,
type EditCommentMutationVariables,
type StudioEditMutation,
type StudioEditMutationVariables,
type StudioEditUpdateMutation,
type StudioEditUpdateMutationVariables,
type SceneEditMutation,
type SceneEditMutationVariables,
type SceneEditUpdateMutation,
type SceneEditUpdateMutationVariables,
type VoteMutation,
type VoteMutationVariables,
type AddSiteMutation,
type AddSiteMutationVariables,
type DeleteSiteMutation,
type DeleteSiteMutationVariables,
type UpdateSiteMutation,
type UpdateSiteMutationVariables,
type FavoriteStudioMutation,
type FavoriteStudioMutationVariables,
type FavoritePerformerMutation,
type FavoritePerformerMutationVariables,
type DeleteDraftMutation,
type DeleteDraftMutationVariables,
type UnmatchFingerprintMutation,
type UnmatchFingerprintMutationVariables,
type ValidateChangeEmailMutation,
type ValidateChangeEmailMutationVariables,
type ConfirmChangeEmailMutation,
type ConfirmChangeEmailMutationVariables,
type RequestChangeEmailMutation,
ActivateNewUserDocument,
AddUserDocument,
NewUserDocument,
@@ -132,14 +132,14 @@ import {
ValidateChangeEmailDocument,
ConfirmChangeEmailDocument,
RequestChangeEmailDocument,
RequestChangeEmailMutationVariables,
type RequestChangeEmailMutationVariables,
UpdateNotificationSubscriptionsDocument,
UpdateNotificationSubscriptionsMutation,
UpdateNotificationSubscriptionsMutationVariables,
type UpdateNotificationSubscriptionsMutation,
type UpdateNotificationSubscriptionsMutationVariables,
MarkNotificationsReadDocument,
MarkNotificationReadDocument,
MarkNotificationReadMutationVariables,
MeQuery,
type MarkNotificationReadMutationVariables,
type MeQuery,
} from "../types";
export const useActivateUser = (

View File

@@ -36,7 +36,8 @@ query ScenePairings(
...ImageFragment
}
scenes(input: { performed_with: $performerId })
@include(if: $fetchScenes) {
@include(if: $fetchScenes)
{
id
title
date

View File

@@ -1,78 +1,78 @@
import {
useQuery,
useLazyQuery,
QueryHookOptions,
LazyQueryHookOptions,
type QueryHookOptions,
type LazyQueryHookOptions,
} from "@apollo/client";
import {
CategoryDocument,
CategoryQueryVariables,
type CategoryQueryVariables,
CategoriesDocument,
EditDocument,
EditQueryVariables,
type EditQueryVariables,
EditUpdateDocument,
EditsDocument,
EditsQueryVariables,
type EditsQueryVariables,
MeDocument,
MeQuery,
type MeQuery,
PerformerDocument,
PerformerQueryVariables,
type PerformerQueryVariables,
FullPerformerDocument,
PerformersDocument,
PerformersQueryVariables,
type PerformersQueryVariables,
SceneDocument,
SceneQueryVariables,
type SceneQueryVariables,
ScenesDocument,
ScenesQueryVariables,
type ScenesQueryVariables,
ScenesWithFingerprintsDocument,
ScenesWithFingerprintsQueryVariables,
type ScenesWithFingerprintsQueryVariables,
ScenesWithoutCountDocument,
SearchAllDocument,
SearchAllQuery,
SearchAllQueryVariables,
type SearchAllQuery,
type SearchAllQueryVariables,
SearchPerformersDocument,
SearchPerformersQuery,
SearchPerformersQueryVariables,
type SearchPerformersQuery,
type SearchPerformersQueryVariables,
SearchTagsDocument,
SearchTagsQueryVariables,
type SearchTagsQueryVariables,
StudioDocument,
StudioQueryVariables,
type StudioQueryVariables,
StudiosDocument,
StudiosQuery,
StudiosQueryVariables,
type StudiosQuery,
type StudiosQueryVariables,
TagDocument,
TagQueryVariables,
type TagQueryVariables,
TagsDocument,
TagsQuery,
TagsQueryVariables,
type TagsQuery,
type TagsQueryVariables,
UserDocument,
UserQueryVariables,
type UserQueryVariables,
UsersDocument,
UsersQueryVariables,
type UsersQueryVariables,
PublicUserDocument,
PublicUserQueryVariables,
type PublicUserQueryVariables,
ConfigDocument,
PendingEditsCountDocument,
PendingEditsCountQueryVariables,
type PendingEditsCountQueryVariables,
SiteDocument,
SiteQueryVariables,
type SiteQueryVariables,
SitesDocument,
DraftDocument,
DraftQueryVariables,
type DraftQueryVariables,
DraftsDocument,
QueryExistingSceneDocument,
QueryExistingSceneQueryVariables,
type QueryExistingSceneQueryVariables,
QueryExistingPerformerDocument,
QueryExistingPerformerQueryVariables,
type QueryExistingPerformerQueryVariables,
ScenePairingsDocument,
ScenePairingsQueryVariables,
type ScenePairingsQueryVariables,
StudioPerformersDocument,
StudioPerformersQueryVariables,
type StudioPerformersQueryVariables,
VersionDocument,
MeQueryVariables,
type MeQueryVariables,
NotificationsDocument,
NotificationsQueryVariables,
type NotificationsQueryVariables,
UnreadNotificationCountDocument,
} from "../types";
import { useCurrentUser } from "src/hooks";

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
import { useMe } from "src/graphql";
import { getCachedUser, setCachedUser } from "src/utils";
import { User } from "../context";
import type { User } from "../context";
interface AuthResult {
loading: boolean;

View File

@@ -1,10 +1,11 @@
import { useEffect } from "react";
const unloadListener = (event: BeforeUnloadEvent) => {
event.preventDefault();
event.returnValue = true;
};
export const useBeforeUnload = () => {
const unloadListener = (event: BeforeUnloadEvent) => {
event.preventDefault();
event.returnValue = true;
};
useEffect(() => {
window.addEventListener("beforeunload", unloadListener);
return () => window.removeEventListener("beforeunload", unloadListener);

View File

@@ -1,3 +1,4 @@
// biome-ignore-all lint/performance/noAccumulatingSpread: Necessary for types
import { useCallback, useMemo } from "react";
import { useNavigate, useLocation } from "react-router-dom";
import querystring from "query-string";
@@ -90,13 +91,16 @@ export const useQueryParams = <T extends QueryParamConfig>(
const allParams = useMemo(() => {
const rawQueryParams = querystring.parse(location.search.replace("?", ""));
const parsedParams = Object.keys(queryParams).reduce((map, key) => {
const config = queryParams[key];
const rawValue = rawQueryParams[config.name];
rawQueryParams[config.name] = null;
const value = getParamValue(config, rawValue || "");
return { ...map, [key]: value };
}, {} as QueryParams<T>);
const parsedParams = Object.keys(queryParams).reduce(
(map, key) => {
const config = queryParams[key];
const rawValue = rawQueryParams[config.name];
rawQueryParams[config.name] = null;
const value = getParamValue(config, rawValue || "");
return { ...map, [key]: value };
},
{} as QueryParams<T>,
);
return {
...rawQueryParams,

View File

@@ -1,5 +1,5 @@
import { FC, useState } from "react";
import { ApolloError } from "@apollo/client";
import { type FC, useState } from "react";
import type { ApolloError } from "@apollo/client";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
import { useNavigate, useLocation } from "react-router-dom";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Link } from "react-router-dom";
import { Button, Card } from "react-bootstrap";
import { sortBy, groupBy } from "lodash-es";

View File

@@ -1,8 +1,8 @@
import { FC } from "react";
import type { FC } from "react";
import { Link, useNavigate } from "react-router-dom";
import { Button, Row } from "react-bootstrap";
import { useDeleteCategory, CategoryQuery } from "src/graphql";
import { useDeleteCategory, type CategoryQuery } from "src/graphql";
import { createHref } from "src/utils";
import DeleteButton from "src/components/deleteButton";
import { TagList } from "src/components/list";

View File

@@ -1,7 +1,7 @@
import { FC } from "react";
import type { FC } from "react";
import { useNavigate } from "react-router-dom";
import { useAddCategory, TagCategoryCreateInput } from "src/graphql";
import { useAddCategory, type TagCategoryCreateInput } from "src/graphql";
import { categoryHref } from "src/utils";
import CategoryForm from "./categoryForm";

View File

@@ -1,10 +1,10 @@
import { FC } from "react";
import type { FC } from "react";
import { useNavigate } from "react-router-dom";
import {
useUpdateCategory,
TagCategoryCreateInput,
CategoryQuery,
type TagCategoryCreateInput,
type CategoryQuery,
} from "src/graphql";
import { categoryHref } from "src/utils";
import CategoryForm from "./categoryForm";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { useNavigate, Link } from "react-router-dom";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
@@ -8,8 +8,8 @@ import { Button, Form } from "react-bootstrap";
import {
TagGroupEnum,
TagCategoryCreateInput,
CategoryQuery,
type TagCategoryCreateInput,
type CategoryQuery,
} from "src/graphql";
import { createHref } from "src/utils";
import { ROUTE_CATEGORIES, ROUTE_CATEGORY } from "src/constants/route";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { useParams, Route, Routes } from "react-router-dom";
import { ErrorMessage, LoadingIndicator } from "src/components/fragments";
import Title from "src/components/title";

View File

@@ -1,4 +1,4 @@
import { DraftQuery } from "src/graphql";
import type { DraftQuery } from "src/graphql";
import SceneDraft from "./SceneDraft";
import PerformerDraft from "./PerformerDraft";

View File

@@ -1,4 +1,4 @@
import React from "react";
import type React from "react";
import { Button, Card } from "react-bootstrap";
import { sortBy } from "lodash-es";
import { Link } from "react-router-dom";

View File

@@ -1,12 +1,12 @@
import { FC } from "react";
import type { FC } from "react";
import { Link, useNavigate } from "react-router-dom";
import {
usePerformer,
usePerformerEdit,
OperationEnum,
PerformerEditDetailsInput,
DraftQuery,
type PerformerEditDetailsInput,
type DraftQuery,
useSites,
} from "src/graphql";
import { LoadingIndicator } from "src/components/fragments";

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { useNavigate, Link } from "react-router-dom";
import { Alert, Col, Row } from "react-bootstrap";
@@ -7,9 +7,9 @@ import {
useScene,
useSceneEdit,
OperationEnum,
SceneEditDetailsInput,
type SceneEditDetailsInput,
FingerprintAlgorithm,
DraftQuery,
type DraftQuery,
useSites,
} from "src/graphql";
import { LoadingIndicator } from "src/components/fragments";

View File

@@ -1,7 +1,7 @@
import React from "react";
import type React from "react";
import { Route, Routes, useParams } from "react-router-dom";
import { useDraft, DraftQuery } from "src/graphql";
import { useDraft, type DraftQuery } from "src/graphql";
import { ErrorMessage, LoadingIndicator } from "src/components/fragments";
import Title from "src/components/title";

View File

@@ -1,17 +1,17 @@
import { InitialScene } from "src/pages/scenes/sceneForm";
import { InitialPerformer } from "src/pages/performers/performerForm";
import type { InitialScene } from "src/pages/scenes/sceneForm";
import type { InitialPerformer } from "src/pages/performers/performerForm";
import {
GenderEnum,
HairColorEnum,
EyeColorEnum,
EthnicityEnum,
SceneFragment,
PerformerFragment,
DraftQuery,
SceneQuery,
type SceneFragment,
type PerformerFragment,
type DraftQuery,
type SceneQuery,
BreastTypeEnum,
ValidSiteTypeEnum,
Site,
type Site,
} from "src/graphql";
import { uniqBy } from "lodash-es";
@@ -73,7 +73,7 @@ const parseUrls = (
const remainder = [];
for (const url of urls) {
if (url == "") continue;
if (url === "") continue;
const matchedSite = sites.find((site) => {
if (!site.valid_types.includes(type) || !site.regex) return false;
@@ -132,23 +132,18 @@ export const parseSceneDraft = (
duration: draft.fingerprints?.[0]?.duration ?? null,
images: draft.image ? [draft.image] : existingScene?.images,
tags: joinTags(
(draft.tags ?? []).reduce<Tag[]>(
(res, t) => (t.__typename === "Tag" ? [...res, t] : res),
[],
),
(draft.tags ?? []).reduce<Tag[]>((res, t) => {
if (t.__typename === "Tag") res.push(t);
return res;
}, []),
existingScene?.tags,
),
performers: joinPerformers(
(draft.performers ?? []).reduce<ScenePerformer[]>(
(res, p) =>
p.__typename === "Performer"
? [
...res,
{ performer: p, as: "", __typename: "PerformerAppearance" },
]
: res,
[],
),
(draft.performers ?? []).reduce<ScenePerformer[]>((res, p) => {
if (p.__typename === "Performer")
res.push({ performer: p, as: "", __typename: "PerformerAppearance" });
return res;
}, []),
existingScene?.performers,
),
};
@@ -157,15 +152,17 @@ export const parseSceneDraft = (
Studio:
draft.studio?.__typename === "DraftEntity" ? draft.studio.name : null,
Performers: (draft.performers ?? [])
.reduce<
string[]
>((res, p) => (p.__typename === "DraftEntity" ? [...res, p.name] : res), [])
.reduce<string[]>((res, p) => {
if (p.__typename === "DraftEntity") res.push(p.name);
return res;
}, [])
.join(", "),
Urls: remainingUrls.join(", "),
Tags: (draft.tags ?? [])
.reduce<
string[]
>((res, t) => (t.__typename === "DraftEntity" ? [...res, t.name] : res), [])
.reduce<string[]>((res, t) => {
if (t.__typename === "DraftEntity") res.push(t.name);
return res;
}, [])
.join(", "),
};
@@ -196,13 +193,13 @@ const parseMeasurements = (value: string | null | undefined) => {
const parsedMeasurements = value?.match(
/^(\d\d)([a-zA-Z]+)(?:-|\s)(\d\d)(?:-|\s)(\d\d)$/,
);
if (!parsedMeasurements || parsedMeasurements?.length != 5) return null;
if (!parsedMeasurements || parsedMeasurements?.length !== 5) return null;
return {
band: Number.parseInt(parsedMeasurements[1]),
band: Number.parseInt(parsedMeasurements[1], 10),
cup: parsedMeasurements[2],
waist: Number.parseInt(parsedMeasurements[3]),
hip: Number.parseInt(parsedMeasurements[4]),
waist: Number.parseInt(parsedMeasurements[3], 10),
hip: Number.parseInt(parsedMeasurements[4], 10),
};
};
@@ -243,7 +240,7 @@ export const parsePerformerDraft = (
) as HairColorEnum | null,
birthdate: draft.birthdate,
deathdate: draft.deathdate,
height: Number.parseInt(draft.height ?? "") || null,
height: Number.parseInt(draft.height ?? "", 10) || null,
country: draft?.country?.length === 2 ? draft.country : null,
aliases: draftAliases ?? existingPerformer?.aliases,
career_start_year:

View File

@@ -1,4 +1,4 @@
import { FC, useState } from "react";
import { type FC, useState } from "react";
import { Button } from "react-bootstrap";
import { useParams, Link } from "react-router-dom";
import { UpdateCount } from "./components/UpdateCount";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { useParams } from "react-router-dom";
import { useEditUpdate, TargetTypeEnum } from "src/graphql";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { VoteStatusEnum, UserVotedFilterEnum } from "src/graphql";
import { EditList } from "src/components/list";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { useConfig } from "src/graphql";
interface Props {

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Route, Routes } from "react-router-dom";
import Edit from "./Edit";

View File

@@ -1,5 +1,5 @@
import { FC, useState } from "react";
import { ApolloError } from "@apollo/client";
import { type FC, useState } from "react";
import type { ApolloError } from "@apollo/client";
import { yupResolver } from "@hookform/resolvers/yup";
import { useForm } from "react-hook-form";
import { useNavigate } from "react-router-dom";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Col, Row } from "react-bootstrap";
import { Link } from "react-router-dom";
import cx from "classnames";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Route, Routes } from "react-router-dom";
import {

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import type { CommentNotificationType } from "./types";
import EditComment from "src/components/editCard/EditComment";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import EditCard from "src/components/editCard";
import type { EditNotificationType } from "./types";

View File

@@ -1,4 +1,4 @@
import React from "react";
import type React from "react";
import { Button } from "react-bootstrap";
import { Link } from "react-router-dom";
import { faEnvelope, faEnvelopeOpen } from "@fortawesome/free-solid-svg-icons";
@@ -6,7 +6,7 @@ import { Icon } from "src/components/fragments";
import { editHref } from "src/utils";
import { useMarkNotificationRead, NotificationEnum } from "src/graphql";
import {
NotificationType,
type NotificationType,
isSceneNotification,
isEditNotification,
isCommentNotification,

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import { Button, Form } from "react-bootstrap";
import { Link } from "react-router-dom";
import { faEdit } from "@fortawesome/free-solid-svg-icons";

View File

@@ -1,4 +1,4 @@
import { FC } from "react";
import type { FC } from "react";
import SceneCard from "src/components/sceneCard";
import type { SceneNotificationType } from "./types";

Some files were not shown because too many files have changed in this diff Show More