diff --git a/graphql/documents/queries/misc.graphql b/graphql/documents/queries/misc.graphql index 19d0d2b8b..e653635dc 100644 --- a/graphql/documents/queries/misc.graphql +++ b/graphql/documents/queries/misc.graphql @@ -8,18 +8,25 @@ query MarkerStrings($q: String, $sort: String) { query AllPerformersForFilter { allPerformers { - ...SlimPerformerData + id + name + disambiguation + alias_list } } query AllStudiosForFilter { allStudios { - ...SlimStudioData + id + name + aliases } } + query AllMoviesForFilter { allMovies { - ...SlimMovieData + id + name } } diff --git a/graphql/schema/schema.graphql b/graphql/schema/schema.graphql index 3bdcba5aa..9964b7d5d 100644 --- a/graphql/schema/schema.graphql +++ b/graphql/schema/schema.graphql @@ -144,6 +144,10 @@ type Query { # Get everything + allScenes: [Scene!]! + allSceneMarkers: [SceneMarker!]! + allImages: [Image!]! + allGalleries: [Gallery!]! allPerformers: [Performer!]! allStudios: [Studio!]! allMovies: [Movie!]! diff --git a/internal/api/resolver_query_find_gallery.go b/internal/api/resolver_query_find_gallery.go index 43a71f4d9..db1fcafaf 100644 --- a/internal/api/resolver_query_find_gallery.go +++ b/internal/api/resolver_query_find_gallery.go @@ -43,3 +43,14 @@ func (r *queryResolver) FindGalleries(ctx context.Context, galleryFilter *models return ret, nil } + +func (r *queryResolver) AllGalleries(ctx context.Context) (ret []*models.Gallery, err error) { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + ret, err = r.repository.Gallery.All(ctx) + return err + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/internal/api/resolver_query_find_image.go b/internal/api/resolver_query_find_image.go index 360f4fff9..e979f3f11 100644 --- a/internal/api/resolver_query_find_image.go +++ b/internal/api/resolver_query_find_image.go @@ -86,3 +86,14 @@ func (r *queryResolver) FindImages(ctx context.Context, imageFilter *models.Imag return ret, nil } + +func (r *queryResolver) AllImages(ctx context.Context) (ret []*models.Image, err error) { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + ret, err = r.repository.Image.All(ctx) + return err + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/internal/api/resolver_query_find_scene.go b/internal/api/resolver_query_find_scene.go index fa322d804..1eaa2dc03 100644 --- a/internal/api/resolver_query_find_scene.go +++ b/internal/api/resolver_query_find_scene.go @@ -234,3 +234,14 @@ func (r *queryResolver) FindDuplicateScenes(ctx context.Context, distance *int) return ret, nil } + +func (r *queryResolver) AllScenes(ctx context.Context) (ret []*models.Scene, err error) { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + ret, err = r.repository.Scene.All(ctx) + return err + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/internal/api/resolver_query_find_scene_marker.go b/internal/api/resolver_query_find_scene_marker.go index 4bd70e658..895ebc057 100644 --- a/internal/api/resolver_query_find_scene_marker.go +++ b/internal/api/resolver_query_find_scene_marker.go @@ -24,3 +24,14 @@ func (r *queryResolver) FindSceneMarkers(ctx context.Context, sceneMarkerFilter return ret, nil } + +func (r *queryResolver) AllSceneMarkers(ctx context.Context) (ret []*models.SceneMarker, err error) { + if err := r.withReadTxn(ctx, func(ctx context.Context) error { + ret, err = r.repository.SceneMarker.All(ctx) + return err + }); err != nil { + return nil, err + } + + return ret, nil +} diff --git a/pkg/models/mocks/SceneMarkerReaderWriter.go b/pkg/models/mocks/SceneMarkerReaderWriter.go index 695a54391..ef6e9cc78 100644 --- a/pkg/models/mocks/SceneMarkerReaderWriter.go +++ b/pkg/models/mocks/SceneMarkerReaderWriter.go @@ -14,6 +14,50 @@ type SceneMarkerReaderWriter struct { mock.Mock } +// All provides a mock function with given fields: ctx +func (_m *SceneMarkerReaderWriter) All(ctx context.Context) ([]*models.SceneMarker, error) { + ret := _m.Called(ctx) + + var r0 []*models.SceneMarker + if rf, ok := ret.Get(0).(func(context.Context) []*models.SceneMarker); ok { + r0 = rf(ctx) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).([]*models.SceneMarker) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + +// Count provides a mock function with given fields: ctx +func (_m *SceneMarkerReaderWriter) Count(ctx context.Context) (int, error) { + ret := _m.Called(ctx) + + var r0 int + if rf, ok := ret.Get(0).(func(context.Context) int); ok { + r0 = rf(ctx) + } else { + r0 = ret.Get(0).(int) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context) error); ok { + r1 = rf(ctx) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // CountByTagID provides a mock function with given fields: ctx, tagID func (_m *SceneMarkerReaderWriter) CountByTagID(ctx context.Context, tagID int) (int, error) { ret := _m.Called(ctx, tagID) diff --git a/pkg/models/mocks/SceneReaderWriter.go b/pkg/models/mocks/SceneReaderWriter.go index 74ad7dc4b..bb6e6d4a5 100644 --- a/pkg/models/mocks/SceneReaderWriter.go +++ b/pkg/models/mocks/SceneReaderWriter.go @@ -638,29 +638,8 @@ func (_m *SceneReaderWriter) GetTagIDs(ctx context.Context, relatedID int) ([]in return r0, r1 } -// SaveActivity provides a mock function with given fields: ctx, id, resumeTime, playDuration -func (_m *SceneReaderWriter) SaveActivity(ctx context.Context, id int, resumeTime *float64, playDuration *float64) (bool, error) { - ret := _m.Called(ctx, id, resumeTime, playDuration) - - var r0 bool - if rf, ok := ret.Get(0).(func(context.Context, int, *float64, *float64) bool); ok { - r0 = rf(ctx, id, resumeTime, playDuration) - } else { - r0 = ret.Get(0).(bool) - } - - var r1 error - if rf, ok := ret.Get(1).(func(context.Context, int, *float64, *float64) error); ok { - r1 = rf(ctx, id, resumeTime, playDuration) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// IncrementWatchCount provides a mock function with given fields: ctx, id -func (_m *SceneReaderWriter) IncrementWatchCount(ctx context.Context, id int) (int, error) { +// IncrementOCounter provides a mock function with given fields: ctx, id +func (_m *SceneReaderWriter) IncrementOCounter(ctx context.Context, id int) (int, error) { ret := _m.Called(ctx, id) var r0 int @@ -680,8 +659,8 @@ func (_m *SceneReaderWriter) IncrementWatchCount(ctx context.Context, id int) (i return r0, r1 } -// IncrementOCounter provides a mock function with given fields: ctx, id -func (_m *SceneReaderWriter) IncrementOCounter(ctx context.Context, id int) (int, error) { +// IncrementWatchCount provides a mock function with given fields: ctx, id +func (_m *SceneReaderWriter) IncrementWatchCount(ctx context.Context, id int) (int, error) { ret := _m.Called(ctx, id) var r0 int @@ -745,6 +724,27 @@ func (_m *SceneReaderWriter) ResetOCounter(ctx context.Context, id int) (int, er return r0, r1 } +// SaveActivity provides a mock function with given fields: ctx, id, resumeTime, playDuration +func (_m *SceneReaderWriter) SaveActivity(ctx context.Context, id int, resumeTime *float64, playDuration *float64) (bool, error) { + ret := _m.Called(ctx, id, resumeTime, playDuration) + + var r0 bool + if rf, ok := ret.Get(0).(func(context.Context, int, *float64, *float64) bool); ok { + r0 = rf(ctx, id, resumeTime, playDuration) + } else { + r0 = ret.Get(0).(bool) + } + + var r1 error + if rf, ok := ret.Get(1).(func(context.Context, int, *float64, *float64) error); ok { + r1 = rf(ctx, id, resumeTime, playDuration) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} + // Size provides a mock function with given fields: ctx func (_m *SceneReaderWriter) Size(ctx context.Context) (float64, error) { ret := _m.Called(ctx) diff --git a/pkg/models/scene_marker.go b/pkg/models/scene_marker.go index 3251f6a00..2ae8c3343 100644 --- a/pkg/models/scene_marker.go +++ b/pkg/models/scene_marker.go @@ -36,6 +36,8 @@ type SceneMarkerReader interface { CountByTagID(ctx context.Context, tagID int) (int, error) GetMarkerStrings(ctx context.Context, q *string, sort *string) ([]*MarkerStringsResultType, error) Wall(ctx context.Context, q *string) ([]*SceneMarker, error) + Count(ctx context.Context) (int, error) + All(ctx context.Context) ([]*SceneMarker, error) Query(ctx context.Context, sceneMarkerFilter *SceneMarkerFilterType, findFilter *FindFilterType) ([]*SceneMarker, int, error) GetTagIDs(ctx context.Context, imageID int) ([]int, error) } diff --git a/pkg/sqlite/scene_marker.go b/pkg/sqlite/scene_marker.go index d3f520be8..df3c73030 100644 --- a/pkg/sqlite/scene_marker.go +++ b/pkg/sqlite/scene_marker.go @@ -346,3 +346,11 @@ func (qb *sceneMarkerQueryBuilder) UpdateTags(ctx context.Context, id int, tagID // Delete the existing joins and then create new ones return qb.tagsRepository().replace(ctx, id, tagIDs) } + +func (qb *sceneMarkerQueryBuilder) Count(ctx context.Context) (int, error) { + return qb.runCountQuery(ctx, qb.buildCountQuery("SELECT scene_markers.id FROM scene_markers"), nil) +} + +func (qb *sceneMarkerQueryBuilder) All(ctx context.Context) ([]*models.SceneMarker, error) { + return qb.querySceneMarkers(ctx, selectAll("scene_markers")+qb.getSceneMarkerSort(nil, nil), nil) +} diff --git a/pkg/sqlite/scene_marker_test.go b/pkg/sqlite/scene_marker_test.go index 76a4dd845..9c5ae866f 100644 --- a/pkg/sqlite/scene_marker_test.go +++ b/pkg/sqlite/scene_marker_test.go @@ -222,4 +222,6 @@ func queryMarkers(ctx context.Context, t *testing.T, sqb models.SceneMarkerReade // TODO Find // TODO GetMarkerStrings // TODO Wall +// TODO Count +// TODO All // TODO Query diff --git a/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx b/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx index f43317aa4..8ea26bae5 100644 --- a/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/HierarchicalLabelValueFilter.tsx @@ -1,7 +1,7 @@ import React from "react"; import { Form } from "react-bootstrap"; import { defineMessages, MessageDescriptor, useIntl } from "react-intl"; -import { FilterSelect, ValidTypes } from "src/components/Shared/Select"; +import { FilterSelect, SelectObject } from "src/components/Shared/Select"; import { Criterion } from "src/models/list-filter/criteria/criterion"; import { IHierarchicalLabelValue } from "src/models/list-filter/types"; @@ -35,11 +35,11 @@ export const HierarchicalLabelValueFilter: React.FC< }, }); - function onSelectionChanged(items: ValidTypes[]) { + function onSelectionChanged(items: SelectObject[]) { const { value } = criterion; value.items = items.map((i) => ({ id: i.id, - label: i.name!, + label: i.name ?? i.title ?? "", })); onValueChanged(value); } diff --git a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx index 12e49ca1c..b859f8345 100644 --- a/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx +++ b/ui/v2.5/src/components/List/Filters/LabeledIdFilter.tsx @@ -1,6 +1,6 @@ import React from "react"; import { Form } from "react-bootstrap"; -import { FilterSelect, ValidTypes } from "src/components/Shared/Select"; +import { FilterSelect, SelectObject } from "src/components/Shared/Select"; import { Criterion } from "src/models/list-filter/criteria/criterion"; import { ILabeledId } from "src/models/list-filter/types"; @@ -26,11 +26,11 @@ export const LabeledIdFilter: React.FC = ({ ) return null; - function onSelectionChanged(items: ValidTypes[]) { + function onSelectionChanged(items: SelectObject[]) { onValueChanged( items.map((i) => ({ id: i.id, - label: i.name!, + label: i.name ?? i.title ?? "", })) ); } diff --git a/ui/v2.5/src/components/Shared/MultiSet.tsx b/ui/v2.5/src/components/Shared/MultiSet.tsx index 641035188..c19922683 100644 --- a/ui/v2.5/src/components/Shared/MultiSet.tsx +++ b/ui/v2.5/src/components/Shared/MultiSet.tsx @@ -3,13 +3,7 @@ import { useIntl } from "react-intl"; import * as GQL from "src/core/generated-graphql"; import { Button, ButtonGroup } from "react-bootstrap"; -import { FilterSelect } from "./Select"; - -type ValidTypes = - | GQL.SlimPerformerDataFragment - | GQL.SlimTagDataFragment - | GQL.SlimStudioDataFragment - | GQL.SlimMovieDataFragment; +import { FilterSelect, SelectObject } from "./Select"; interface IMultiSetProps { type: "performers" | "studios" | "tags" | "movies"; @@ -29,7 +23,7 @@ export const MultiSet: React.FC = (props) => { GQL.BulkUpdateIdMode.Remove, ]; - function onUpdate(items: ValidTypes[]) { + function onUpdate(items: SelectObject[]) { props.onUpdate(items.map((i) => i.id)); } diff --git a/ui/v2.5/src/components/Shared/Select.tsx b/ui/v2.5/src/components/Shared/Select.tsx index 32a3fde8b..bb7b371af 100644 --- a/ui/v2.5/src/components/Shared/Select.tsx +++ b/ui/v2.5/src/components/Shared/Select.tsx @@ -31,11 +31,11 @@ import { objectTitle } from "src/core/files"; import { galleryTitle } from "src/core/galleries"; import { TagPopover } from "../Tags/TagPopover"; -export type ValidTypes = - | GQL.SlimPerformerDataFragment - | GQL.SlimTagDataFragment - | GQL.SlimStudioDataFragment - | GQL.SlimMovieDataFragment; +export type SelectObject = { + id: string; + name?: string | null; + title?: string | null; +}; type Option = { value: string; label: string }; interface ITypeProps { @@ -53,7 +53,7 @@ interface ITypeProps { interface IFilterProps { ids?: string[]; initialIds?: string[]; - onSelect?: (item: ValidTypes[]) => void; + onSelect?: (item: SelectObject[]) => void; noSelectionString?: string; className?: string; isMulti?: boolean; @@ -90,9 +90,9 @@ interface ISelectProps { noOptionsMessage?: string | null; } interface IFilterComponentProps extends IFilterProps { - items: Array; - toOption?: (item: ValidTypes) => Option; - onCreate?: (name: string) => Promise<{ item: ValidTypes; message: string }>; + items: SelectObject[]; + toOption?: (item: SelectObject) => Option; + onCreate?: (name: string) => Promise<{ item: SelectObject; message: string }>; } interface IFilterSelectProps extends Pick< @@ -284,7 +284,7 @@ const FilterSelectComponent = ( } return { value: i.id, - label: i.name ?? "", + label: i.name ?? i.title ?? "", }; }); diff --git a/ui/v2.5/src/components/Tagger/scenes/PerformerResult.tsx b/ui/v2.5/src/components/Tagger/scenes/PerformerResult.tsx index e0ceb6188..c1334fa11 100755 --- a/ui/v2.5/src/components/Tagger/scenes/PerformerResult.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/PerformerResult.tsx @@ -6,7 +6,7 @@ import cx from "classnames"; import * as GQL from "src/core/generated-graphql"; import { Icon } from "src/components/Shared/Icon"; import { OperationButton } from "src/components/Shared/OperationButton"; -import { PerformerSelect, ValidTypes } from "src/components/Shared/Select"; +import { PerformerSelect, SelectObject } from "src/components/Shared/Select"; import { OptionalField } from "../IncludeButton"; import { faSave } from "@fortawesome/free-solid-svg-icons"; @@ -38,7 +38,7 @@ const PerformerResult: React.FC = ({ (stashID) => stashID.endpoint === endpoint && stashID.stash_id ); - const handlePerformerSelect = (performers: ValidTypes[]) => { + const handlePerformerSelect = (performers: SelectObject[]) => { if (performers.length) { setSelectedID(performers[0].id); } else { diff --git a/ui/v2.5/src/components/Tagger/scenes/StudioResult.tsx b/ui/v2.5/src/components/Tagger/scenes/StudioResult.tsx index b63f92361..ed76e5e70 100755 --- a/ui/v2.5/src/components/Tagger/scenes/StudioResult.tsx +++ b/ui/v2.5/src/components/Tagger/scenes/StudioResult.tsx @@ -5,7 +5,7 @@ import cx from "classnames"; import { Icon } from "src/components/Shared/Icon"; import { OperationButton } from "src/components/Shared/OperationButton"; -import { StudioSelect, ValidTypes } from "src/components/Shared/Select"; +import { StudioSelect, SelectObject } from "src/components/Shared/Select"; import * as GQL from "src/core/generated-graphql"; import { OptionalField } from "../IncludeButton"; @@ -38,7 +38,7 @@ const StudioResult: React.FC = ({ (stashID) => stashID.endpoint === endpoint && stashID.stash_id ); - const handleSelect = (studios: ValidTypes[]) => { + const handleSelect = (studios: SelectObject[]) => { if (studios.length) { setSelectedID(studios[0].id); } else {