diff --git a/graphql/schema/types/filters.graphql b/graphql/schema/types/filters.graphql index d1b169769..1ca8c1fb0 100644 --- a/graphql/schema/types/filters.graphql +++ b/graphql/schema/types/filters.graphql @@ -191,6 +191,8 @@ input SceneMarkerFilterType { scene_tags: HierarchicalMultiCriterionInput "Filter to only include scene markers with these performers" performers: MultiCriterionInput + "Filter to only include scene markers from these scenes" + scenes: MultiCriterionInput "Filter by creation time" created_at: TimestampCriterionInput "Filter by last update time" diff --git a/pkg/models/scene_marker.go b/pkg/models/scene_marker.go index 59186ca59..8c4598a6d 100644 --- a/pkg/models/scene_marker.go +++ b/pkg/models/scene_marker.go @@ -9,6 +9,8 @@ type SceneMarkerFilterType struct { SceneTags *HierarchicalMultiCriterionInput `json:"scene_tags"` // Filter to only include scene markers with these performers Performers *MultiCriterionInput `json:"performers"` + // Filter to only include scene markers from these scenes + Scenes *MultiCriterionInput `json:"scenes"` // Filter by created at CreatedAt *TimestampCriterionInput `json:"created_at"` // Filter by updated at diff --git a/pkg/sqlite/scene_marker_filter.go b/pkg/sqlite/scene_marker_filter.go index 94147ed80..d5e044e85 100644 --- a/pkg/sqlite/scene_marker_filter.go +++ b/pkg/sqlite/scene_marker_filter.go @@ -40,6 +40,7 @@ func (qb *sceneMarkerFilterHandler) criterionHandler() criterionHandler { qb.tagsCriterionHandler(sceneMarkerFilter.Tags), qb.sceneTagsCriterionHandler(sceneMarkerFilter.SceneTags), qb.performersCriterionHandler(sceneMarkerFilter.Performers), + qb.scenesCriterionHandler(sceneMarkerFilter.Scenes), ×tampCriterionHandler{sceneMarkerFilter.CreatedAt, "scene_markers.created_at", nil}, ×tampCriterionHandler{sceneMarkerFilter.UpdatedAt, "scene_markers.updated_at", nil}, &dateCriterionHandler{sceneMarkerFilter.SceneDate, "scenes.date", qb.joinScenes}, @@ -187,3 +188,18 @@ func (qb *sceneMarkerFilterHandler) performersCriterionHandler(performers *model handler(ctx, f) } } + +func (qb *sceneMarkerFilterHandler) scenesCriterionHandler(scenes *models.MultiCriterionInput) criterionHandlerFunc { + addJoinsFunc := func(f *filterBuilder) { + f.addLeftJoin(sceneTable, "markers_scenes", "markers_scenes.id = scene_markers.scene_id") + } + h := multiCriterionHandlerBuilder{ + primaryTable: sceneMarkerTable, + foreignTable: "markers_scenes", + joinTable: "", + primaryFK: sceneIDColumn, + foreignFK: sceneIDColumn, + addJoinsFunc: addJoinsFunc, + } + return h.handler(scenes) +} diff --git a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx index 792c4a7e7..888cfe401 100644 --- a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Form } from "react-bootstrap"; import { FilterSelect, SelectObject } from "src/components/Shared/Select"; +import { objectTitle } from "src/core/files"; import { galleryTitle } from "src/core/galleries"; import { Criterion } from "src/models/list-filter/criteria/criterion"; import { ILabeledId } from "src/models/list-filter/types"; @@ -31,8 +32,11 @@ export const LabeledIdFilter: React.FC = ({ } function getLabel(i: SelectObject) { - if (inputType === "galleries") { - return galleryTitle(i); + switch (inputType) { + case "galleries": + return galleryTitle(i); + case "scenes": + return objectTitle(i); } return i.name ?? i.title ?? ""; diff --git a/ui/v2.5/src/models/list-filter/criteria/scenes.ts b/ui/v2.5/src/models/list-filter/criteria/scenes.ts index 365cc7f86..346838279 100644 --- a/ui/v2.5/src/models/list-filter/criteria/scenes.ts +++ b/ui/v2.5/src/models/list-filter/criteria/scenes.ts @@ -1,4 +1,9 @@ -import { ILabeledIdCriterion, ILabeledIdCriterionOption } from "./criterion"; +import { + CriterionOption, + ILabeledIdCriterion, + ILabeledIdCriterionOption, +} from "./criterion"; +import { CriterionModifier } from "src/core/generated-graphql"; const inputType = "scenes"; @@ -15,3 +20,25 @@ export class ScenesCriterion extends ILabeledIdCriterion { super(ScenesCriterionOption); } } + +const modifierOptions = [ + CriterionModifier.Includes, + CriterionModifier.Excludes, +]; + +const defaultModifier = CriterionModifier.Includes; + +export const MarkersScenesCriterionOption = new CriterionOption({ + messageID: "scenes", + type: "scenes", + modifierOptions, + defaultModifier, + inputType, + makeCriterion: () => new MarkersScenesCriterion(), +}); + +export class MarkersScenesCriterion extends ILabeledIdCriterion { + constructor() { + super(MarkersScenesCriterionOption); + } +} diff --git a/ui/v2.5/src/models/list-filter/scene-markers.ts b/ui/v2.5/src/models/list-filter/scene-markers.ts index 3de42b2a1..7f6e555cc 100644 --- a/ui/v2.5/src/models/list-filter/scene-markers.ts +++ b/ui/v2.5/src/models/list-filter/scene-markers.ts @@ -1,4 +1,5 @@ import { PerformersCriterionOption } from "./criteria/performers"; +import { MarkersScenesCriterionOption } from "./criteria/scenes"; import { SceneTagsCriterionOption, TagsCriterionOption } from "./criteria/tags"; import { ListFilterOptions } from "./filter-options"; import { DisplayMode } from "./types"; @@ -18,6 +19,7 @@ const sortByOptions = [ const displayModeOptions = [DisplayMode.Wall]; const criterionOptions = [ TagsCriterionOption, + MarkersScenesCriterionOption, SceneTagsCriterionOption, PerformersCriterionOption, createMandatoryTimestampCriterionOption("created_at"),