Add batch delete for performers/tags/studios/movies (#1053)

* Add batch delete for performers/tags/studios/movies
* Fix ListFilter styling bug
This commit is contained in:
InfiniteTF
2021-01-13 01:57:53 +01:00
committed by GitHub
parent 8a3d940aa7
commit aad4ddc46d
21 changed files with 353 additions and 56 deletions

View File

@@ -25,3 +25,7 @@ mutation MovieUpdate($input: MovieUpdateInput!) {
mutation MovieDestroy($id: ID!) { mutation MovieDestroy($id: ID!) {
movieDestroy(input: { id: $id }) movieDestroy(input: { id: $id })
} }
mutation MoviesDestroy($ids: [ID!]!) {
moviesDestroy(ids: $ids)
}

View File

@@ -55,3 +55,7 @@ mutation PerformerUpdate(
mutation PerformerDestroy($id: ID!) { mutation PerformerDestroy($id: ID!) {
performerDestroy(input: { id: $id }) performerDestroy(input: { id: $id })
} }
mutation PerformersDestroy($ids: [ID!]!) {
performersDestroy(ids: $ids)
}

View File

@@ -21,3 +21,7 @@ mutation StudioUpdate(
mutation StudioDestroy($id: ID!) { mutation StudioDestroy($id: ID!) {
studioDestroy(input: { id: $id }) studioDestroy(input: { id: $id })
} }
mutation StudiosDestroy($ids: [ID!]!) {
studiosDestroy(ids: $ids)
}

View File

@@ -8,6 +8,10 @@ mutation TagDestroy($id: ID!) {
tagDestroy(input: { id: $id }) tagDestroy(input: { id: $id })
} }
mutation TagsDestroy($ids: [ID!]!) {
tagsDestroy(ids: $ids)
}
mutation TagUpdate($input: TagUpdateInput!) { mutation TagUpdate($input: TagUpdateInput!) {
tagUpdate(input: $input) { tagUpdate(input: $input) {
...TagData ...TagData

View File

@@ -175,18 +175,22 @@ type Mutation {
performerCreate(input: PerformerCreateInput!): Performer performerCreate(input: PerformerCreateInput!): Performer
performerUpdate(input: PerformerUpdateInput!): Performer performerUpdate(input: PerformerUpdateInput!): Performer
performerDestroy(input: PerformerDestroyInput!): Boolean! performerDestroy(input: PerformerDestroyInput!): Boolean!
performersDestroy(ids: [ID!]!): Boolean!
studioCreate(input: StudioCreateInput!): Studio studioCreate(input: StudioCreateInput!): Studio
studioUpdate(input: StudioUpdateInput!): Studio studioUpdate(input: StudioUpdateInput!): Studio
studioDestroy(input: StudioDestroyInput!): Boolean! studioDestroy(input: StudioDestroyInput!): Boolean!
studiosDestroy(ids: [ID!]!): Boolean!
movieCreate(input: MovieCreateInput!): Movie movieCreate(input: MovieCreateInput!): Movie
movieUpdate(input: MovieUpdateInput!): Movie movieUpdate(input: MovieUpdateInput!): Movie
movieDestroy(input: MovieDestroyInput!): Boolean! movieDestroy(input: MovieDestroyInput!): Boolean!
moviesDestroy(ids: [ID!]!): Boolean!
tagCreate(input: TagCreateInput!): Tag tagCreate(input: TagCreateInput!): Tag
tagUpdate(input: TagUpdateInput!): Tag tagUpdate(input: TagUpdateInput!): Tag
tagDestroy(input: TagDestroyInput!): Boolean! tagDestroy(input: TagDestroyInput!): Boolean!
tagsDestroy(ids: [ID!]!): Boolean!
"""Change general configuration options""" """Change general configuration options"""
configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult! configureGeneral(input: ConfigGeneralInput!): ConfigGeneralResult!

View File

@@ -222,3 +222,18 @@ func (r *mutationResolver) MovieDestroy(ctx context.Context, input models.MovieD
} }
return true, nil return true, nil
} }
func (r *mutationResolver) MoviesDestroy(ctx context.Context, ids []string) (bool, error) {
qb := models.NewMovieQueryBuilder()
tx := database.DB.MustBeginTx(ctx, nil)
for _, id := range ids {
if err := qb.Destroy(id, tx); err != nil {
_ = tx.Rollback()
return false, err
}
}
if err := tx.Commit(); err != nil {
return false, err
}
return true, nil
}

View File

@@ -242,3 +242,18 @@ func (r *mutationResolver) PerformerDestroy(ctx context.Context, input models.Pe
} }
return true, nil return true, nil
} }
func (r *mutationResolver) PerformersDestroy(ctx context.Context, ids []string) (bool, error) {
qb := models.NewPerformerQueryBuilder()
tx := database.DB.MustBeginTx(ctx, nil)
for _, id := range ids {
if err := qb.Destroy(id, tx); err != nil {
_ = tx.Rollback()
return false, err
}
}
if err := tx.Commit(); err != nil {
return false, err
}
return true, nil
}

View File

@@ -182,3 +182,18 @@ func (r *mutationResolver) StudioDestroy(ctx context.Context, input models.Studi
} }
return true, nil return true, nil
} }
func (r *mutationResolver) StudiosDestroy(ctx context.Context, ids []string) (bool, error) {
qb := models.NewStudioQueryBuilder()
tx := database.DB.MustBeginTx(ctx, nil)
for _, id := range ids {
if err := qb.Destroy(id, tx); err != nil {
_ = tx.Rollback()
return false, err
}
}
if err := tx.Commit(); err != nil {
return false, err
}
return true, nil
}

View File

@@ -152,3 +152,19 @@ func (r *mutationResolver) TagDestroy(ctx context.Context, input models.TagDestr
} }
return true, nil return true, nil
} }
func (r *mutationResolver) TagsDestroy(ctx context.Context, ids []string) (bool, error) {
qb := models.NewTagQueryBuilder()
tx := database.DB.MustBeginTx(ctx, nil)
for _, id := range ids {
if err := qb.Destroy(id, tx); err != nil {
_ = tx.Rollback()
return false, err
}
}
if err := tx.Commit(); err != nil {
return false, err
}
return true, nil
}

View File

@@ -6,6 +6,7 @@
* Allow configuration of visible navbar items. * Allow configuration of visible navbar items.
### 🎨 Improvements ### 🎨 Improvements
* Add batch deleting of performers, tags, studios, and movies.
* Reset cache after scan/clean to ensure scenes are updated. * Reset cache after scan/clean to ensure scenes are updated.
* Add more video/image resolution tags. * Add more video/image resolution tags.
* Add option to strip file extension from scene title when populating from scanning task. * Add option to strip file extension from scene title when populating from scanning task.

View File

@@ -76,11 +76,13 @@ export const DeleteImagesDialog: React.FC<IDeleteImageDialogProps> = (
</p> </p>
<Form> <Form>
<Form.Check <Form.Check
id="delete-image"
checked={deleteFile} checked={deleteFile}
label="Delete file" label="Delete file"
onChange={() => setDeleteFile(!deleteFile)} onChange={() => setDeleteFile(!deleteFile)}
/> />
<Form.Check <Form.Check
id="delete-image-generated"
checked={deleteGenerated} checked={deleteGenerated}
label="Delete generated supporting files" label="Delete generated supporting files"
onChange={() => setDeleteGenerated(!deleteGenerated)} onChange={() => setDeleteGenerated(!deleteGenerated)}

View File

@@ -426,29 +426,25 @@ export const ListFilter: React.FC<IListFilterProps> = (
} }
function maybeRenderSelectedButtons() { function maybeRenderSelectedButtons() {
if (props.itemsSelected) { if (props.itemsSelected && (props.onEdit || props.onDelete)) {
return ( return (
<> <ButtonGroup className="ml-2">
{props.onEdit ? ( {props.onEdit && (
<ButtonGroup className="mr-1">
<OverlayTrigger overlay={<Tooltip id="edit">Edit</Tooltip>}> <OverlayTrigger overlay={<Tooltip id="edit">Edit</Tooltip>}>
<Button variant="secondary" onClick={onEdit}> <Button variant="secondary" onClick={onEdit}>
<Icon icon="pencil-alt" /> <Icon icon="pencil-alt" />
</Button> </Button>
</OverlayTrigger> </OverlayTrigger>
</ButtonGroup> )}
) : undefined}
{props.onDelete ? ( {props.onDelete && (
<ButtonGroup className="mr-1">
<OverlayTrigger overlay={<Tooltip id="delete">Delete</Tooltip>}> <OverlayTrigger overlay={<Tooltip id="delete">Delete</Tooltip>}>
<Button variant="danger" onClick={onDelete}> <Button variant="danger" onClick={onDelete}>
<Icon icon="trash" /> <Icon icon="trash" />
</Button> </Button>
</OverlayTrigger> </OverlayTrigger>
)}
</ButtonGroup> </ButtonGroup>
) : undefined}
</>
); );
} }
} }
@@ -456,8 +452,8 @@ export const ListFilter: React.FC<IListFilterProps> = (
function render() { function render() {
return ( return (
<> <>
<ButtonToolbar className="align-items-center justify-content-center"> <ButtonToolbar className="align-items-center justify-content-center mb-2">
<div className="my-1 d-flex"> <div className="d-flex">
<InputGroup className="mr-2 flex-grow-1"> <InputGroup className="mr-2 flex-grow-1">
<FormControl <FormControl
ref={queryRef} ref={queryRef}
@@ -530,18 +526,15 @@ export const ListFilter: React.FC<IListFilterProps> = (
))} ))}
</Form.Control> </Form.Control>
<ButtonGroup className="mx-3 my-1">
{maybeRenderSelectedButtons()} {maybeRenderSelectedButtons()}
{renderMore()}
</ButtonGroup>
<ButtonGroup className="my-1"> <div className="mx-2">{renderMore()}</div>
{renderDisplayModeOptions()}
</ButtonGroup> <ButtonGroup>{renderDisplayModeOptions()}</ButtonGroup>
{maybeRenderZoom()} {maybeRenderZoom()}
</ButtonToolbar> </ButtonToolbar>
<div className="d-flex justify-content-center mt-1"> <div className="d-flex justify-content-center">
{renderFilterTags()} {renderFilterTags()}
</div> </div>
</> </>

View File

@@ -1,14 +1,17 @@
import React, { useState } from "react"; import React, { useState } from "react";
import _ from "lodash"; import _ from "lodash";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { FindMoviesQueryResult } from "src/core/generated-graphql"; import { useHistory } from "react-router-dom";
import {
FindMoviesQueryResult,
SlimMovieDataFragment,
} from "src/core/generated-graphql";
import { ListFilterModel } from "src/models/list-filter/filter"; import { ListFilterModel } from "src/models/list-filter/filter";
import { DisplayMode } from "src/models/list-filter/types"; import { DisplayMode } from "src/models/list-filter/types";
import { queryFindMovies } from "src/core/StashService"; import { queryFindMovies, useMoviesDestroy } from "src/core/StashService";
import { showWhenSelected, useMoviesList } from "src/hooks/ListHook"; import { showWhenSelected, useMoviesList } from "src/hooks/ListHook";
import { useHistory } from "react-router-dom"; import { ExportDialog, DeleteEntityDialog } from "src/components/Shared";
import { MovieCard } from "./MovieCard"; import { MovieCard } from "./MovieCard";
import { ExportDialog } from "../Shared/ExportDialog";
export const MovieList: React.FC = () => { export const MovieList: React.FC = () => {
const history = useHistory(); const history = useHistory();
@@ -44,12 +47,26 @@ export const MovieList: React.FC = () => {
}; };
}; };
const renderDeleteDialog = (
selectedMovies: SlimMovieDataFragment[],
onClose: (confirmed: boolean) => void
) => (
<DeleteEntityDialog
selected={selectedMovies}
onClose={onClose}
singularEntity="movie"
pluralEntity="movies"
destroyMutation={useMoviesDestroy}
/>
);
const listData = useMoviesList({ const listData = useMoviesList({
renderContent, renderContent,
addKeybinds, addKeybinds,
otherOperations, otherOperations,
selectable: true, selectable: true,
persistState: true, persistState: true,
renderDeleteDialog,
}); });
async function viewRandom( async function viewRandom(

View File

@@ -2,13 +2,19 @@ import _ from "lodash";
import React, { useState } from "react"; import React, { useState } from "react";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { FindPerformersQueryResult } from "src/core/generated-graphql"; import {
import { queryFindPerformers } from "src/core/StashService"; FindPerformersQueryResult,
SlimPerformerDataFragment,
} from "src/core/generated-graphql";
import {
queryFindPerformers,
usePerformersDestroy,
} from "src/core/StashService";
import { usePerformersList } from "src/hooks"; import { usePerformersList } from "src/hooks";
import { showWhenSelected } from "src/hooks/ListHook"; import { showWhenSelected } from "src/hooks/ListHook";
import { ListFilterModel } from "src/models/list-filter/filter"; import { ListFilterModel } from "src/models/list-filter/filter";
import { DisplayMode } from "src/models/list-filter/types"; import { DisplayMode } from "src/models/list-filter/types";
import { ExportDialog } from "src/components/Shared/ExportDialog"; import { ExportDialog, DeleteEntityDialog } from "src/components/Shared";
import { PerformerCard } from "./PerformerCard"; import { PerformerCard } from "./PerformerCard";
import { PerformerListTable } from "./PerformerListTable"; import { PerformerListTable } from "./PerformerListTable";
@@ -76,12 +82,26 @@ export const PerformerList: React.FC = () => {
} }
} }
const renderDeleteDialog = (
selectedPerformers: SlimPerformerDataFragment[],
onClose: (confirmed: boolean) => void
) => (
<DeleteEntityDialog
selected={selectedPerformers}
onClose={onClose}
singularEntity="performer"
pluralEntity="performers"
destroyMutation={usePerformersDestroy}
/>
);
const listData = usePerformersList({ const listData = usePerformersList({
otherOperations, otherOperations,
renderContent, renderContent,
addKeybinds, addKeybinds,
selectable: true, selectable: true,
persistState: true, persistState: true,
renderDeleteDialog,
}); });
async function getRandom( async function getRandom(

View File

@@ -76,11 +76,13 @@ export const DeleteScenesDialog: React.FC<IDeleteSceneDialogProps> = (
</p> </p>
<Form> <Form>
<Form.Check <Form.Check
id="delete-file"
checked={deleteFile} checked={deleteFile}
label="Delete file" label="Delete file"
onChange={() => setDeleteFile(!deleteFile)} onChange={() => setDeleteFile(!deleteFile)}
/> />
<Form.Check <Form.Check
id="delete-generated"
checked={deleteGenerated} checked={deleteGenerated}
label="Delete generated supporting files" label="Delete generated supporting files"
onChange={() => setDeleteGenerated(!deleteGenerated)} onChange={() => setDeleteGenerated(!deleteGenerated)}

View File

@@ -68,13 +68,18 @@ export const SceneList: React.FC<ISceneList> = ({
}; };
}; };
const renderDeleteDialog = (
selectedScenes: SlimSceneDataFragment[],
onClose: (confirmed: boolean) => void
) => <DeleteScenesDialog selected={selectedScenes} onClose={onClose} />;
const listData = useScenesList({ const listData = useScenesList({
zoomable: true, zoomable: true,
selectable: true, selectable: true,
otherOperations, otherOperations,
renderContent, renderContent,
renderEditDialog: renderEditScenesDialog, renderEditDialog: renderEditScenesDialog,
renderDeleteDialog: renderDeleteScenesDialog, renderDeleteDialog,
filterHook, filterHook,
addKeybinds, addKeybinds,
persistState, persistState,
@@ -166,17 +171,6 @@ export const SceneList: React.FC<ISceneList> = ({
); );
} }
function renderDeleteScenesDialog(
selectedScenes: SlimSceneDataFragment[],
onClose: (confirmed: boolean) => void
) {
return (
<>
<DeleteScenesDialog selected={selectedScenes} onClose={onClose} />
</>
);
}
function renderSceneCard( function renderSceneCard(
scene: SlimSceneDataFragment, scene: SlimSceneDataFragment,
selectedIds: Set<string>, selectedIds: Set<string>,

View File

@@ -0,0 +1,123 @@
import React, { useState } from "react";
import { defineMessages, FormattedMessage, useIntl } from "react-intl";
import { FetchResult } from "@apollo/client";
import { Modal } from "src/components/Shared";
import { useToast } from "src/hooks";
interface IDeletionEntity {
id: string;
name?: string | null;
}
type DestroyMutation = (input: {
ids: string[];
}) => [() => Promise<FetchResult>, {}];
interface IDeleteEntityDialogProps {
selected: IDeletionEntity[];
onClose: (confirmed: boolean) => void;
singularEntity: string;
pluralEntity: string;
destroyMutation: DestroyMutation;
}
const messages = defineMessages({
deleteHeader: {
id: "delete-header",
defaultMessage:
"Delete {count, plural, =1 {{singularEntity}} other {{pluralEntity}}}",
},
deleteToast: {
id: "delete-toast",
defaultMessage:
"Deleted {count, plural, =1 {{singularEntity}} other {{pluralEntity}}}",
},
deleteMessage: {
id: "delete-message",
defaultMessage:
"Are you sure you want to delete {count, plural, =1 {this {singularEntity}} other {these {pluralEntity}}}?",
},
overflowMessage: {
id: "overflow-message",
defaultMessage:
"...and {count} other {count, plural, =1 {{ singularEntity}} other {{ pluralEntity }}}.",
},
});
const DeleteEntityDialog: React.FC<IDeleteEntityDialogProps> = ({
selected,
onClose,
singularEntity,
pluralEntity,
destroyMutation,
}) => {
const intl = useIntl();
const Toast = useToast();
const [deleteEntities] = destroyMutation({ ids: selected.map((p) => p.id) });
const count = selected.length;
// Network state
const [isDeleting, setIsDeleting] = useState(false);
async function onDelete() {
setIsDeleting(true);
try {
await deleteEntities();
Toast.success({
content: intl.formatMessage(messages.deleteToast, {
count,
singularEntity,
pluralEntity,
}),
});
} catch (e) {
Toast.error(e);
}
setIsDeleting(false);
onClose(true);
}
return (
<Modal
show
icon="trash-alt"
header={intl.formatMessage(messages.deleteHeader, {
count,
singularEntity,
pluralEntity,
})}
accept={{ variant: "danger", onClick: onDelete, text: "Delete" }}
cancel={{
onClick: () => onClose(false),
text: "Cancel",
variant: "secondary",
}}
isRunning={isDeleting}
>
<p>
<FormattedMessage
values={{ count, singularEntity, pluralEntity }}
{...messages.deleteMessage}
/>
</p>
<ul>
{selected.slice(0, 10).map((s) => (
<li>{s.name}</li>
))}
{selected.length > 10 && (
<FormattedMessage
values={{
count: selected.length - 10,
singularEntity,
pluralEntity,
}}
{...messages.overflowMessage}
/>
)}
</ul>
</Modal>
);
};
export default DeleteEntityDialog;

View File

@@ -24,3 +24,5 @@ export { default as ErrorMessage } from "./ErrorMessage";
export { default as TruncatedText } from "./TruncatedText"; export { default as TruncatedText } from "./TruncatedText";
export { BasicCard } from "./BasicCard"; export { BasicCard } from "./BasicCard";
export { RatingStars } from "./RatingStars"; export { RatingStars } from "./RatingStars";
export { ExportDialog } from "./ExportDialog";
export { default as DeleteEntityDialog } from "./DeleteEntityDialog";

View File

@@ -2,13 +2,16 @@ import React, { useState } from "react";
import _ from "lodash"; import _ from "lodash";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { FindStudiosQueryResult } from "src/core/generated-graphql"; import {
FindStudiosQueryResult,
SlimStudioDataFragment,
} from "src/core/generated-graphql";
import { useStudiosList } from "src/hooks"; import { useStudiosList } from "src/hooks";
import { showWhenSelected } from "src/hooks/ListHook"; import { showWhenSelected } from "src/hooks/ListHook";
import { ListFilterModel } from "src/models/list-filter/filter"; import { ListFilterModel } from "src/models/list-filter/filter";
import { DisplayMode } from "src/models/list-filter/types"; import { DisplayMode } from "src/models/list-filter/types";
import { queryFindStudios } from "src/core/StashService"; import { queryFindStudios, useStudiosDestroy } from "src/core/StashService";
import { ExportDialog } from "../Shared/ExportDialog"; import { ExportDialog, DeleteEntityDialog } from "src/components/Shared";
import { StudioCard } from "./StudioCard"; import { StudioCard } from "./StudioCard";
interface IStudioList { interface IStudioList {
@@ -109,6 +112,19 @@ export const StudioList: React.FC<IStudioList> = ({
} }
} }
const renderDeleteDialog = (
selectedStudios: SlimStudioDataFragment[],
onClose: (confirmed: boolean) => void
) => (
<DeleteEntityDialog
selected={selectedStudios}
onClose={onClose}
singularEntity="studio"
pluralEntity="studios"
destroyMutation={useStudiosDestroy}
/>
);
const listData = useStudiosList({ const listData = useStudiosList({
renderContent, renderContent,
filterHook, filterHook,
@@ -116,6 +132,7 @@ export const StudioList: React.FC<IStudioList> = ({
otherOperations, otherOperations,
selectable: true, selectable: true,
persistState: !fromParent, persistState: !fromParent,
renderDeleteDialog,
}); });
function renderStudios( function renderStudios(

View File

@@ -12,11 +12,12 @@ import {
queryFindTags, queryFindTags,
mutateMetadataAutoTag, mutateMetadataAutoTag,
useTagDestroy, useTagDestroy,
useTagsDestroy,
} from "src/core/StashService"; } from "src/core/StashService";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { FormattedNumber } from "react-intl"; import { FormattedNumber } from "react-intl";
import { NavUtils } from "src/utils"; import { NavUtils } from "src/utils";
import { Icon, Modal } from "src/components/Shared"; import { Icon, Modal, DeleteEntityDialog } from "src/components/Shared";
import { TagCard } from "./TagCard"; import { TagCard } from "./TagCard";
import { ExportDialog } from "../Shared/ExportDialog"; import { ExportDialog } from "../Shared/ExportDialog";
@@ -121,6 +122,19 @@ export const TagList: React.FC<ITagList> = ({ filterHook }) => {
} }
} }
const renderDeleteDialog = (
selectedTags: GQL.TagDataFragment[],
onClose: (confirmed: boolean) => void
) => (
<DeleteEntityDialog
selected={selectedTags}
onClose={onClose}
singularEntity="tag"
pluralEntity="tags"
destroyMutation={useTagsDestroy}
/>
);
const listData = useTagsList({ const listData = useTagsList({
renderContent, renderContent,
filterHook, filterHook,
@@ -130,6 +144,7 @@ export const TagList: React.FC<ITagList> = ({ filterHook }) => {
zoomable: true, zoomable: true,
defaultZoomIndex: 0, defaultZoomIndex: 0,
persistState: true, persistState: true,
renderDeleteDialog,
}); });
function getDeleteTagInput() { function getDeleteTagInput() {

View File

@@ -309,6 +309,18 @@ export const usePerformerDestroy = () =>
update: deleteCache(performerMutationImpactedQueries), update: deleteCache(performerMutationImpactedQueries),
}); });
export const usePerformersDestroy = (
variables: GQL.PerformersDestroyMutationVariables
) =>
GQL.usePerformersDestroyMutation({
variables,
refetchQueries: getQueryNames([
GQL.FindPerformersDocument,
GQL.AllPerformersForFilterDocument,
]),
update: deleteCache(performerMutationImpactedQueries),
});
const sceneMutationImpactedQueries = [ const sceneMutationImpactedQueries = [
GQL.FindPerformerDocument, GQL.FindPerformerDocument,
GQL.FindPerformersDocument, GQL.FindPerformersDocument,
@@ -562,6 +574,12 @@ export const useStudioDestroy = (input: GQL.StudioDestroyInput) =>
update: deleteCache(studioMutationImpactedQueries), update: deleteCache(studioMutationImpactedQueries),
}); });
export const useStudiosDestroy = (input: GQL.StudiosDestroyMutationVariables) =>
GQL.useStudiosDestroyMutation({
variables: input,
update: deleteCache(studioMutationImpactedQueries),
});
export const movieMutationImpactedQueries = [ export const movieMutationImpactedQueries = [
GQL.FindSceneDocument, GQL.FindSceneDocument,
GQL.FindScenesDocument, GQL.FindScenesDocument,
@@ -589,6 +607,12 @@ export const useMovieDestroy = (input: GQL.MovieDestroyInput) =>
update: deleteCache(movieMutationImpactedQueries), update: deleteCache(movieMutationImpactedQueries),
}); });
export const useMoviesDestroy = (input: GQL.MoviesDestroyMutationVariables) =>
GQL.useMoviesDestroyMutation({
variables: input,
update: deleteCache(movieMutationImpactedQueries),
});
export const tagMutationImpactedQueries = [ export const tagMutationImpactedQueries = [
GQL.FindSceneDocument, GQL.FindSceneDocument,
GQL.FindScenesDocument, GQL.FindScenesDocument,
@@ -622,6 +646,12 @@ export const useTagDestroy = (input: GQL.TagDestroyInput) =>
update: deleteCache(tagMutationImpactedQueries), update: deleteCache(tagMutationImpactedQueries),
}); });
export const useTagsDestroy = (input: GQL.TagsDestroyMutationVariables) =>
GQL.useTagsDestroyMutation({
variables: input,
update: deleteCache(tagMutationImpactedQueries),
});
export const useConfigureGeneral = (input: GQL.ConfigGeneralInput) => export const useConfigureGeneral = (input: GQL.ConfigGeneralInput) =>
GQL.useConfigureGeneralMutation({ GQL.useConfigureGeneralMutation({
variables: { input }, variables: { input },