Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scene Marker grid view #5443

Merged
merged 8 commits into from
Nov 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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