Skip to content

Commit

Permalink
Scene Marker grid view (#5443)
Browse files Browse the repository at this point in the history
* add bulk delete mutation
---------
Co-authored-by: WithoutPants <[email protected]>
  • Loading branch information
dogwithakeyboard authored Nov 29, 2024
1 parent 6ad0951 commit 7f83494
Show file tree
Hide file tree
Showing 16 changed files with 479 additions and 28 deletions.
1 change: 1 addition & 0 deletions graphql/schema/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ type Mutation {
sceneMarkerCreate(input: SceneMarkerCreateInput!): SceneMarker
sceneMarkerUpdate(input: SceneMarkerUpdateInput!): SceneMarker
sceneMarkerDestroy(id: ID!): Boolean!
sceneMarkersDestroy(ids: [ID!]!): Boolean!

sceneAssignFile(input: AssignSceneFileInput!): Boolean!

Expand Down
51 changes: 33 additions & 18 deletions internal/api/resolver_mutation_scene.go
Original file line number Diff line number Diff line change
Expand Up @@ -814,11 +814,16 @@ func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input SceneMar
}

func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) {
markerID, err := strconv.Atoi(id)
return r.SceneMarkersDestroy(ctx, []string{id})
}

func (r *mutationResolver) SceneMarkersDestroy(ctx context.Context, markerIDs []string) (bool, error) {
ids, err := stringslice.StringSliceToIntSlice(markerIDs)
if err != nil {
return false, fmt.Errorf("converting id: %w", err)
return false, fmt.Errorf("converting ids: %w", err)
}

var markers []*models.SceneMarker
fileNamingAlgo := manager.GetInstance().Config.GetVideoFileNamingAlgorithm()

fileDeleter := &scene.FileDeleter{
Expand All @@ -831,35 +836,45 @@ func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (b
qb := r.repository.SceneMarker
sqb := r.repository.Scene

marker, err := qb.Find(ctx, markerID)
for _, markerID := range ids {
marker, err := qb.Find(ctx, markerID)

if err != nil {
return err
}
if err != nil {
return err
}

if marker == nil {
return fmt.Errorf("scene marker with id %d not found", markerID)
}
if marker == nil {
return fmt.Errorf("scene marker with id %d not found", markerID)
}

s, err := sqb.Find(ctx, marker.SceneID)
if err != nil {
return err
}
s, err := sqb.Find(ctx, marker.SceneID)

if s == nil {
return fmt.Errorf("scene with id %d not found", marker.SceneID)
if err != nil {
return err
}

if s == nil {
return fmt.Errorf("scene with id %d not found", marker.SceneID)
}

markers = append(markers, marker)

if err := scene.DestroyMarker(ctx, s, marker, qb, fileDeleter); err != nil {
return err
}
}

return scene.DestroyMarker(ctx, s, marker, qb, fileDeleter)
return nil
}); err != nil {
fileDeleter.Rollback()
return false, err
}

// perform the post-commit actions
fileDeleter.Commit()

r.hookExecutor.ExecutePostHooks(ctx, markerID, hook.SceneMarkerDestroyPost, id, nil)
for _, marker := range markers {
r.hookExecutor.ExecutePostHooks(ctx, marker.ID, hook.SceneMarkerDestroyPost, markerIDs, nil)
}

return true, nil
}
Expand Down
17 changes: 16 additions & 1 deletion ui/v2.5/graphql/data/scene-marker.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ fragment SceneMarkerData on SceneMarker {
screenshot

scene {
id
...SceneMarkerSceneData
}

primary_tag {
Expand All @@ -21,3 +21,18 @@ fragment SceneMarkerData on SceneMarker {
name
}
}

fragment SceneMarkerSceneData on Scene {
id
title
files {
width
height
path
}
performers {
id
name
image_path
}
}
4 changes: 4 additions & 0 deletions ui/v2.5/graphql/mutations/scene-marker.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ mutation SceneMarkerUpdate(
mutation SceneMarkerDestroy($id: ID!) {
sceneMarkerDestroy(id: $id)
}

mutation SceneMarkersDestroy($ids: [ID!]!) {
sceneMarkersDestroy(ids: $ids)
}
83 changes: 83 additions & 0 deletions ui/v2.5/src/components/Scenes/DeleteSceneMarkersDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState } from "react";
import { useSceneMarkersDestroy } from "src/core/StashService";
import * as GQL from "src/core/generated-graphql";
import { ModalComponent } from "src/components/Shared/Modal";
import { useToast } from "src/hooks/Toast";
import { useIntl } from "react-intl";
import { faTrashAlt } from "@fortawesome/free-solid-svg-icons";

interface IDeleteSceneMarkersDialogProps {
selected: GQL.SceneMarkerDataFragment[];
onClose: (confirmed: boolean) => void;
}

export const DeleteSceneMarkersDialog: React.FC<
IDeleteSceneMarkersDialogProps
> = (props: IDeleteSceneMarkersDialogProps) => {
const intl = useIntl();
const singularEntity = intl.formatMessage({ id: "marker" });
const pluralEntity = intl.formatMessage({ id: "markers" });

const header = intl.formatMessage(
{ id: "dialogs.delete_object_title" },
{ count: props.selected.length, singularEntity, pluralEntity }
);
const toastMessage = intl.formatMessage(
{ id: "toast.delete_past_tense" },
{ count: props.selected.length, singularEntity, pluralEntity }
);
const message = intl.formatMessage(
{ id: "dialogs.delete_object_desc" },
{ count: props.selected.length, singularEntity, pluralEntity }
);

const Toast = useToast();
const [deleteSceneMarkers] = useSceneMarkersDestroy(
getSceneMarkersDeleteInput()
);

// Network state
const [isDeleting, setIsDeleting] = useState(false);

function getSceneMarkersDeleteInput(): GQL.SceneMarkersDestroyMutationVariables {
return {
ids: props.selected.map((marker) => marker.id),
};
}

async function onDelete() {
setIsDeleting(true);
try {
await deleteSceneMarkers();
Toast.success(toastMessage);
props.onClose(true);
} catch (e) {
Toast.error(e);
props.onClose(false);
}
setIsDeleting(false);
}

return (
<ModalComponent
show
icon={faTrashAlt}
header={header}
accept={{
variant: "danger",
onClick: onDelete,
text: intl.formatMessage({ id: "actions.delete" }),
}}
cancel={{
onClick: () => props.onClose(false),
text: intl.formatMessage({ id: "actions.cancel" }),
variant: "secondary",
}}
isRunning={isDeleting}
>
<p>{message}</p>
</ModalComponent>
);
};

export default DeleteSceneMarkersDialog;
2 changes: 1 addition & 1 deletion ui/v2.5/src/components/Scenes/PreviewScrubber.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export const PreviewScrubber: React.FC<IScenePreviewProps> = ({
onClick(s.start);
}

if (spriteInfo === null) return null;
if (spriteInfo === null || !vttPath) return null;

return (
<div className="preview-scrubber">
Expand Down
Loading

0 comments on commit 7f83494

Please sign in to comment.