mirror of
https://github.com/stashapp/stash.git
synced 2025-12-17 04:14:39 +03:00
Rename Movie to Group in UI (#4963)
* Replace movies with groups in the UI * Massage menu items * Change view names * Rename Movie components to Group * Refactor movie to group variable names * Rename movie class names to group
This commit is contained in:
@@ -66,7 +66,7 @@ const Galleries = lazyComponent(
|
|||||||
() => import("./components/Galleries/Galleries")
|
() => import("./components/Galleries/Galleries")
|
||||||
);
|
);
|
||||||
|
|
||||||
const Movies = lazyComponent(() => import("./components/Movies/Movies"));
|
const Groups = lazyComponent(() => import("./components/Movies/Movies"));
|
||||||
const Tags = lazyComponent(() => import("./components/Tags/Tags"));
|
const Tags = lazyComponent(() => import("./components/Tags/Tags"));
|
||||||
const Images = lazyComponent(() => import("./components/Images/Images"));
|
const Images = lazyComponent(() => import("./components/Images/Images"));
|
||||||
const Setup = lazyComponent(() => import("./components/Setup/Setup"));
|
const Setup = lazyComponent(() => import("./components/Setup/Setup"));
|
||||||
@@ -312,7 +312,7 @@ export const App: React.FC = () => {
|
|||||||
<Route path="/performers" component={Performers} />
|
<Route path="/performers" component={Performers} />
|
||||||
<Route path="/tags" component={Tags} />
|
<Route path="/tags" component={Tags} />
|
||||||
<Route path="/studios" component={Studios} />
|
<Route path="/studios" component={Studios} />
|
||||||
<Route path="/movies" component={Movies} />
|
<Route path="/groups" component={Groups} />
|
||||||
<Route path="/stats" component={Stats} />
|
<Route path="/stats" component={Stats} />
|
||||||
<Route path="/settings" component={Settings} />
|
<Route path="/settings" component={Settings} />
|
||||||
<Route
|
<Route
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { ConfigurationContext } from "src/hooks/Config";
|
|||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { GalleryRecommendationRow } from "../Galleries/GalleryRecommendationRow";
|
import { GalleryRecommendationRow } from "../Galleries/GalleryRecommendationRow";
|
||||||
import { ImageRecommendationRow } from "../Images/ImageRecommendationRow";
|
import { ImageRecommendationRow } from "../Images/ImageRecommendationRow";
|
||||||
import { MovieRecommendationRow } from "../Movies/MovieRecommendationRow";
|
import { GroupRecommendationRow } from "../Movies/MovieRecommendationRow";
|
||||||
import { PerformerRecommendationRow } from "../Performers/PerformerRecommendationRow";
|
import { PerformerRecommendationRow } from "../Performers/PerformerRecommendationRow";
|
||||||
import { SceneRecommendationRow } from "../Scenes/SceneRecommendationRow";
|
import { SceneRecommendationRow } from "../Scenes/SceneRecommendationRow";
|
||||||
import { StudioRecommendationRow } from "../Studios/StudioRecommendationRow";
|
import { StudioRecommendationRow } from "../Studios/StudioRecommendationRow";
|
||||||
@@ -45,7 +45,7 @@ const RecommendationRow: React.FC<IFilter> = ({ mode, filter, header }) => {
|
|||||||
);
|
);
|
||||||
case GQL.FilterMode.Movies:
|
case GQL.FilterMode.Movies:
|
||||||
return (
|
return (
|
||||||
<MovieRecommendationRow
|
<GroupRecommendationRow
|
||||||
isTouch={isTouch}
|
isTouch={isTouch}
|
||||||
filter={filter}
|
filter={filter}
|
||||||
header={header}
|
header={header}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ interface IAddSavedFilterModalProps {
|
|||||||
const FilterModeToMessageID = {
|
const FilterModeToMessageID = {
|
||||||
[GQL.FilterMode.Galleries]: "galleries",
|
[GQL.FilterMode.Galleries]: "galleries",
|
||||||
[GQL.FilterMode.Images]: "images",
|
[GQL.FilterMode.Images]: "images",
|
||||||
[GQL.FilterMode.Movies]: "movies",
|
[GQL.FilterMode.Movies]: "groups",
|
||||||
[GQL.FilterMode.Performers]: "performers",
|
[GQL.FilterMode.Performers]: "performers",
|
||||||
[GQL.FilterMode.SceneMarkers]: "markers",
|
[GQL.FilterMode.SceneMarkers]: "markers",
|
||||||
[GQL.FilterMode.Scenes]: "scenes",
|
[GQL.FilterMode.Scenes]: "scenes",
|
||||||
|
|||||||
@@ -111,7 +111,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-skeleton {
|
.group-skeleton {
|
||||||
max-width: 240px;
|
max-width: 240px;
|
||||||
min-height: 540px;
|
min-height: 540px;
|
||||||
min-width: 240px;
|
min-width: 240px;
|
||||||
@@ -313,7 +313,7 @@
|
|||||||
width: 20rem;
|
width: 20rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.slick-list .movie-card.card {
|
.slick-list .group-card.card {
|
||||||
width: 16rem;
|
width: 16rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -193,7 +193,7 @@ const CriterionOptionList: React.FC<ICriterionList> = ({
|
|||||||
const FilterModeToConfigKey = {
|
const FilterModeToConfigKey = {
|
||||||
[FilterMode.Galleries]: "galleries",
|
[FilterMode.Galleries]: "galleries",
|
||||||
[FilterMode.Images]: "images",
|
[FilterMode.Images]: "images",
|
||||||
[FilterMode.Movies]: "movies",
|
[FilterMode.Movies]: "groups",
|
||||||
[FilterMode.Performers]: "performers",
|
[FilterMode.Performers]: "performers",
|
||||||
[FilterMode.SceneMarkers]: "sceneMarkers",
|
[FilterMode.SceneMarkers]: "sceneMarkers",
|
||||||
[FilterMode.Scenes]: "scenes",
|
[FilterMode.Scenes]: "scenes",
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export const LabeledIdFilter: React.FC<ILabeledIdFilterProps> = ({
|
|||||||
inputType !== "performer_tags" &&
|
inputType !== "performer_tags" &&
|
||||||
inputType !== "tags" &&
|
inputType !== "tags" &&
|
||||||
inputType !== "scenes" &&
|
inputType !== "scenes" &&
|
||||||
inputType !== "movies" &&
|
inputType !== "groups" &&
|
||||||
inputType !== "galleries"
|
inputType !== "galleries"
|
||||||
) {
|
) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ export enum View {
|
|||||||
Galleries = "galleries",
|
Galleries = "galleries",
|
||||||
Images = "images",
|
Images = "images",
|
||||||
Scenes = "scenes",
|
Scenes = "scenes",
|
||||||
Movies = "movies",
|
Groups = "groups",
|
||||||
Performers = "performers",
|
Performers = "performers",
|
||||||
Tags = "tags",
|
Tags = "tags",
|
||||||
SceneMarkers = "scene_markers",
|
SceneMarkers = "scene_markers",
|
||||||
@@ -17,7 +17,7 @@ export enum View {
|
|||||||
PerformerScenes = "performer_scenes",
|
PerformerScenes = "performer_scenes",
|
||||||
PerformerGalleries = "performer_galleries",
|
PerformerGalleries = "performer_galleries",
|
||||||
PerformerImages = "performer_images",
|
PerformerImages = "performer_images",
|
||||||
PerformerMovies = "performer_movies",
|
PerformerGroups = "performer_groups",
|
||||||
PerformerAppearsWith = "performer_appears_with",
|
PerformerAppearsWith = "performer_appears_with",
|
||||||
|
|
||||||
StudioGalleries = "studio_galleries",
|
StudioGalleries = "studio_galleries",
|
||||||
@@ -26,9 +26,9 @@ export enum View {
|
|||||||
GalleryImages = "gallery_images",
|
GalleryImages = "gallery_images",
|
||||||
|
|
||||||
StudioScenes = "studio_scenes",
|
StudioScenes = "studio_scenes",
|
||||||
StudioMovies = "studio_movies",
|
StudioGroups = "studio_groups",
|
||||||
StudioPerformers = "studio_performers",
|
StudioPerformers = "studio_performers",
|
||||||
StudioChildren = "studio_children",
|
StudioChildren = "studio_children",
|
||||||
|
|
||||||
MovieScenes = "movie_scenes",
|
GroupScenes = "group_scenes",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,10 @@
|
|||||||
import React, { useEffect, useRef, useState, useCallback } from "react";
|
import React, {
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
useCallback,
|
||||||
|
useMemo,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
defineMessages,
|
defineMessages,
|
||||||
FormattedMessage,
|
FormattedMessage,
|
||||||
@@ -52,9 +58,9 @@ const messages = defineMessages({
|
|||||||
id: "images",
|
id: "images",
|
||||||
defaultMessage: "Images",
|
defaultMessage: "Images",
|
||||||
},
|
},
|
||||||
movies: {
|
groups: {
|
||||||
id: "movies",
|
id: "groups",
|
||||||
defaultMessage: "Movies",
|
defaultMessage: "Groups",
|
||||||
},
|
},
|
||||||
markers: {
|
markers: {
|
||||||
id: "markers",
|
id: "markers",
|
||||||
@@ -107,9 +113,9 @@ const allMenuItems: IMenuItem[] = [
|
|||||||
hotkey: "g i",
|
hotkey: "g i",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "movies",
|
name: "groups",
|
||||||
message: messages.movies,
|
message: messages.groups,
|
||||||
href: "/movies",
|
href: "/groups",
|
||||||
icon: faFilm,
|
icon: faFilm,
|
||||||
hotkey: "g v",
|
hotkey: "g v",
|
||||||
userCreatable: true,
|
userCreatable: true,
|
||||||
@@ -179,20 +185,26 @@ export const MainNavbar: React.FC = () => {
|
|||||||
const { configuration, loading } = React.useContext(ConfigurationContext);
|
const { configuration, loading } = React.useContext(ConfigurationContext);
|
||||||
const { openManual } = React.useContext(ManualStateContext);
|
const { openManual } = React.useContext(ManualStateContext);
|
||||||
|
|
||||||
// Show all menu items by default, unless config says otherwise
|
|
||||||
const [menuItems, setMenuItems] = useState<IMenuItem[]>(allMenuItems);
|
|
||||||
|
|
||||||
const [expanded, setExpanded] = useState(false);
|
const [expanded, setExpanded] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
// Show all menu items by default, unless config says otherwise
|
||||||
const iCfg = configuration?.interface;
|
const menuItems = useMemo(() => {
|
||||||
if (iCfg?.menuItems) {
|
let cfgMenuItems = configuration?.interface.menuItems;
|
||||||
setMenuItems(
|
if (!cfgMenuItems) {
|
||||||
allMenuItems.filter((menuItem) =>
|
return allMenuItems;
|
||||||
iCfg.menuItems!.includes(menuItem.name)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// translate old movies menu item to groups
|
||||||
|
cfgMenuItems = cfgMenuItems.map((item) => {
|
||||||
|
if (item === "movies") {
|
||||||
|
return "groups";
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
|
||||||
|
return allMenuItems.filter((menuItem) =>
|
||||||
|
cfgMenuItems!.includes(menuItem.name)
|
||||||
|
);
|
||||||
}, [configuration]);
|
}, [configuration]);
|
||||||
|
|
||||||
// react-bootstrap typing bug
|
// react-bootstrap typing bug
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ interface IListOperationProps {
|
|||||||
onClose: (applied: boolean) => void;
|
onClose: (applied: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EditMoviesDialog: React.FC<IListOperationProps> = (
|
export const EditGroupsDialog: React.FC<IListOperationProps> = (
|
||||||
props: IListOperationProps
|
props: IListOperationProps
|
||||||
) => {
|
) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -69,7 +69,7 @@ export const EditMoviesDialog: React.FC<IListOperationProps> = (
|
|||||||
intl.formatMessage(
|
intl.formatMessage(
|
||||||
{ id: "toast.updated_entity" },
|
{ id: "toast.updated_entity" },
|
||||||
{
|
{
|
||||||
entity: intl.formatMessage({ id: "movies" }).toLocaleLowerCase(),
|
entity: intl.formatMessage({ id: "groups" }).toLocaleLowerCase(),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@@ -126,7 +126,7 @@ export const EditMoviesDialog: React.FC<IListOperationProps> = (
|
|||||||
icon={faPencilAlt}
|
icon={faPencilAlt}
|
||||||
header={intl.formatMessage(
|
header={intl.formatMessage(
|
||||||
{ id: "actions.edit_entity" },
|
{ id: "actions.edit_entity" },
|
||||||
{ entityType: intl.formatMessage({ id: "movies" }) }
|
{ entityType: intl.formatMessage({ id: "groups" }) }
|
||||||
)}
|
)}
|
||||||
accept={{
|
accept={{
|
||||||
onClick: onSave,
|
onClick: onSave,
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import { faPlayCircle, faTag } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import ScreenUtils from "src/utils/screen";
|
import ScreenUtils from "src/utils/screen";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
movie: GQL.MovieDataFragment;
|
group: GQL.MovieDataFragment;
|
||||||
containerWidth?: number;
|
containerWidth?: number;
|
||||||
sceneIndex?: number;
|
sceneIndex?: number;
|
||||||
selecting?: boolean;
|
selecting?: boolean;
|
||||||
@@ -20,8 +20,8 @@ interface IProps {
|
|||||||
onSelectedChanged?: (selected: boolean, shiftKey: boolean) => void;
|
onSelectedChanged?: (selected: boolean, shiftKey: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieCard: React.FC<IProps> = ({
|
export const GroupCard: React.FC<IProps> = ({
|
||||||
movie,
|
group,
|
||||||
sceneIndex,
|
sceneIndex,
|
||||||
containerWidth,
|
containerWidth,
|
||||||
selecting,
|
selecting,
|
||||||
@@ -47,7 +47,7 @@ export const MovieCard: React.FC<IProps> = ({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<hr />
|
<hr />
|
||||||
<span className="movie-scene-number">
|
<span className="group-scene-number">
|
||||||
<FormattedMessage id="scene" /> #{sceneIndex}
|
<FormattedMessage id="scene" /> #{sceneIndex}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -55,9 +55,9 @@ export const MovieCard: React.FC<IProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderScenesPopoverButton() {
|
function maybeRenderScenesPopoverButton() {
|
||||||
if (movie.scenes.length === 0) return;
|
if (group.scenes.length === 0) return;
|
||||||
|
|
||||||
const popoverContent = movie.scenes.map((scene) => (
|
const popoverContent = group.scenes.map((scene) => (
|
||||||
<SceneLink key={scene.id} scene={scene} />
|
<SceneLink key={scene.id} scene={scene} />
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -69,31 +69,31 @@ export const MovieCard: React.FC<IProps> = ({
|
|||||||
>
|
>
|
||||||
<Button className="minimal">
|
<Button className="minimal">
|
||||||
<Icon icon={faPlayCircle} />
|
<Icon icon={faPlayCircle} />
|
||||||
<span>{movie.scenes.length}</span>
|
<span>{group.scenes.length}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</HoverPopover>
|
</HoverPopover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderTagPopoverButton() {
|
function maybeRenderTagPopoverButton() {
|
||||||
if (movie.tags.length <= 0) return;
|
if (group.tags.length <= 0) return;
|
||||||
|
|
||||||
const popoverContent = movie.tags.map((tag) => (
|
const popoverContent = group.tags.map((tag) => (
|
||||||
<TagLink key={tag.id} linkType="movie" tag={tag} />
|
<TagLink key={tag.id} linkType="group" tag={tag} />
|
||||||
));
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<HoverPopover placement="bottom" content={popoverContent}>
|
<HoverPopover placement="bottom" content={popoverContent}>
|
||||||
<Button className="minimal tag-count">
|
<Button className="minimal tag-count">
|
||||||
<Icon icon={faTag} />
|
<Icon icon={faTag} />
|
||||||
<span>{movie.tags.length}</span>
|
<span>{group.tags.length}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</HoverPopover>
|
</HoverPopover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderPopoverButtonGroup() {
|
function maybeRenderPopoverButtonGroup() {
|
||||||
if (sceneIndex || movie.scenes.length > 0 || movie.tags.length > 0) {
|
if (sceneIndex || group.scenes.length > 0 || group.tags.length > 0) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{maybeRenderSceneNumber()}
|
{maybeRenderSceneNumber()}
|
||||||
@@ -109,28 +109,28 @@ export const MovieCard: React.FC<IProps> = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GridCard
|
<GridCard
|
||||||
className="movie-card"
|
className="group-card"
|
||||||
url={`/movies/${movie.id}`}
|
url={`/groups/${group.id}`}
|
||||||
width={cardWidth}
|
width={cardWidth}
|
||||||
title={movie.name}
|
title={group.name}
|
||||||
linkClassName="movie-card-header"
|
linkClassName="group-card-header"
|
||||||
image={
|
image={
|
||||||
<>
|
<>
|
||||||
<img
|
<img
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
className="movie-card-image"
|
className="group-card-image"
|
||||||
alt={movie.name ?? ""}
|
alt={group.name ?? ""}
|
||||||
src={movie.front_image_path ?? ""}
|
src={group.front_image_path ?? ""}
|
||||||
/>
|
/>
|
||||||
<RatingBanner rating={movie.rating100} />
|
<RatingBanner rating={group.rating100} />
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
details={
|
details={
|
||||||
<div className="movie-card__details">
|
<div className="group-card__details">
|
||||||
<span className="movie-card__date">{movie.date}</span>
|
<span className="group-card__date">{group.date}</span>
|
||||||
<TruncatedText
|
<TruncatedText
|
||||||
className="movie-card__description"
|
className="group-card__description"
|
||||||
text={movie.synopsis}
|
text={group.synopsis}
|
||||||
lineCount={3}
|
lineCount={3}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,27 +1,27 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { MovieCard } from "./MovieCard";
|
import { GroupCard } from "./MovieCard";
|
||||||
import { useContainerDimensions } from "../Shared/GridCard/GridCard";
|
import { useContainerDimensions } from "../Shared/GridCard/GridCard";
|
||||||
|
|
||||||
interface IMovieCardGrid {
|
interface IGroupCardGrid {
|
||||||
movies: GQL.MovieDataFragment[];
|
groups: GQL.MovieDataFragment[];
|
||||||
selectedIds: Set<string>;
|
selectedIds: Set<string>;
|
||||||
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void;
|
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieCardGrid: React.FC<IMovieCardGrid> = ({
|
export const GroupCardGrid: React.FC<IGroupCardGrid> = ({
|
||||||
movies,
|
groups,
|
||||||
selectedIds,
|
selectedIds,
|
||||||
onSelectChange,
|
onSelectChange,
|
||||||
}) => {
|
}) => {
|
||||||
const [componentRef, { width }] = useContainerDimensions();
|
const [componentRef, { width }] = useContainerDimensions();
|
||||||
return (
|
return (
|
||||||
<div className="row justify-content-center" ref={componentRef}>
|
<div className="row justify-content-center" ref={componentRef}>
|
||||||
{movies.map((p) => (
|
{groups.map((p) => (
|
||||||
<MovieCard
|
<GroupCard
|
||||||
key={p.id}
|
key={p.id}
|
||||||
containerWidth={width}
|
containerWidth={width}
|
||||||
movie={p}
|
group={p}
|
||||||
selecting={selectedIds.size > 0}
|
selecting={selectedIds.size > 0}
|
||||||
selected={selectedIds.has(p.id)}
|
selected={selectedIds.has(p.id)}
|
||||||
onSelectedChanged={(selected: boolean, shiftKey: boolean) =>
|
onSelectedChanged={(selected: boolean, shiftKey: boolean) =>
|
||||||
|
|||||||
@@ -17,12 +17,12 @@ import { LoadingIndicator } from "src/components/Shared/LoadingIndicator";
|
|||||||
import { useLightbox } from "src/hooks/Lightbox/hooks";
|
import { useLightbox } from "src/hooks/Lightbox/hooks";
|
||||||
import { ModalComponent } from "src/components/Shared/Modal";
|
import { ModalComponent } from "src/components/Shared/Modal";
|
||||||
import { useToast } from "src/hooks/Toast";
|
import { useToast } from "src/hooks/Toast";
|
||||||
import { MovieScenesPanel } from "./MovieScenesPanel";
|
import { GroupScenesPanel } from "./MovieScenesPanel";
|
||||||
import {
|
import {
|
||||||
CompressedMovieDetailsPanel,
|
CompressedMovieDetailsPanel,
|
||||||
MovieDetailsPanel,
|
GroupDetailsPanel,
|
||||||
} from "./MovieDetailsPanel";
|
} from "./MovieDetailsPanel";
|
||||||
import { MovieEditPanel } from "./MovieEditPanel";
|
import { GroupEditPanel } from "./MovieEditPanel";
|
||||||
import {
|
import {
|
||||||
faChevronDown,
|
faChevronDown,
|
||||||
faChevronUp,
|
faChevronUp,
|
||||||
@@ -38,14 +38,14 @@ import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
|||||||
import { ExternalLinksButton } from "src/components/Shared/ExternalLinksButton";
|
import { ExternalLinksButton } from "src/components/Shared/ExternalLinksButton";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
movie: GQL.MovieDataFragment;
|
group: GQL.MovieDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMovieParams {
|
interface IGroupParams {
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const MoviePage: React.FC<IProps> = ({ movie }) => {
|
const GroupPage: React.FC<IProps> = ({ group }) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
@@ -70,35 +70,35 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
const [encodingImage, setEncodingImage] = useState<boolean>(false);
|
const [encodingImage, setEncodingImage] = useState<boolean>(false);
|
||||||
|
|
||||||
const defaultImage =
|
const defaultImage =
|
||||||
movie.front_image_path && movie.front_image_path.includes("default=true")
|
group.front_image_path && group.front_image_path.includes("default=true")
|
||||||
? true
|
? true
|
||||||
: false;
|
: false;
|
||||||
|
|
||||||
const lightboxImages = useMemo(() => {
|
const lightboxImages = useMemo(() => {
|
||||||
const covers = [
|
const covers = [
|
||||||
...(movie.front_image_path && !defaultImage
|
...(group.front_image_path && !defaultImage
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
paths: {
|
paths: {
|
||||||
thumbnail: movie.front_image_path,
|
thumbnail: group.front_image_path,
|
||||||
image: movie.front_image_path,
|
image: group.front_image_path,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...(movie.back_image_path
|
...(group.back_image_path
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
paths: {
|
paths: {
|
||||||
thumbnail: movie.back_image_path,
|
thumbnail: group.back_image_path,
|
||||||
image: movie.back_image_path,
|
image: group.back_image_path,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
];
|
];
|
||||||
return covers;
|
return covers;
|
||||||
}, [movie.front_image_path, movie.back_image_path, defaultImage]);
|
}, [group.front_image_path, group.back_image_path, defaultImage]);
|
||||||
|
|
||||||
const index = lightboxImages.length;
|
const index = lightboxImages.length;
|
||||||
|
|
||||||
@@ -108,7 +108,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
|
|
||||||
const [updateMovie, { loading: updating }] = useMovieUpdate();
|
const [updateMovie, { loading: updating }] = useMovieUpdate();
|
||||||
const [deleteMovie, { loading: deleting }] = useMovieDestroy({
|
const [deleteMovie, { loading: deleting }] = useMovieDestroy({
|
||||||
id: movie.id,
|
id: group.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
// set up hotkeys
|
// set up hotkeys
|
||||||
@@ -135,7 +135,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
await updateMovie({
|
await updateMovie({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
id: movie.id,
|
id: group.id,
|
||||||
...input,
|
...input,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -144,7 +144,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
Toast.success(
|
Toast.success(
|
||||||
intl.formatMessage(
|
intl.formatMessage(
|
||||||
{ id: "toast.updated_entity" },
|
{ id: "toast.updated_entity" },
|
||||||
{ entity: intl.formatMessage({ id: "movie" }).toLocaleLowerCase() }
|
{ entity: intl.formatMessage({ id: "group" }).toLocaleLowerCase() }
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -157,7 +157,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// redirect to movies page
|
// redirect to movies page
|
||||||
history.push(`/movies`);
|
history.push(`/groups`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleEditing(value?: boolean) {
|
function toggleEditing(value?: boolean) {
|
||||||
@@ -187,8 +187,8 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
id="dialogs.delete_confirm"
|
id="dialogs.delete_confirm"
|
||||||
values={{
|
values={{
|
||||||
entityName:
|
entityName:
|
||||||
movie.name ??
|
group.name ??
|
||||||
intl.formatMessage({ id: "movie" }).toLocaleLowerCase(),
|
intl.formatMessage({ id: "group" }).toLocaleLowerCase(),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</p>
|
</p>
|
||||||
@@ -216,7 +216,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderFrontImage() {
|
function renderFrontImage() {
|
||||||
let image = movie.front_image_path;
|
let image = group.front_image_path;
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
if (frontImage === null && image) {
|
if (frontImage === null && image) {
|
||||||
const imageURL = new URL(image);
|
const imageURL = new URL(image);
|
||||||
@@ -229,14 +229,14 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
|
|
||||||
if (image && defaultImage) {
|
if (image && defaultImage) {
|
||||||
return (
|
return (
|
||||||
<div className="movie-image-container">
|
<div className="group-image-container">
|
||||||
<DetailImage alt="Front Cover" src={image} />
|
<DetailImage alt="Front Cover" src={image} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else if (image) {
|
} else if (image) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className="movie-image-container"
|
className="group-image-container"
|
||||||
variant="link"
|
variant="link"
|
||||||
onClick={() => showLightbox()}
|
onClick={() => showLightbox()}
|
||||||
>
|
>
|
||||||
@@ -247,7 +247,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderBackImage() {
|
function renderBackImage() {
|
||||||
let image = movie.back_image_path;
|
let image = group.back_image_path;
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
if (backImage === null) {
|
if (backImage === null) {
|
||||||
image = undefined;
|
image = undefined;
|
||||||
@@ -259,7 +259,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
if (image) {
|
if (image) {
|
||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className="movie-image-container"
|
className="group-image-container"
|
||||||
variant="link"
|
variant="link"
|
||||||
onClick={() => showLightbox(index - 1)}
|
onClick={() => showLightbox(index - 1)}
|
||||||
>
|
>
|
||||||
@@ -271,26 +271,26 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
|
|
||||||
const renderClickableIcons = () => (
|
const renderClickableIcons = () => (
|
||||||
<span className="name-icons">
|
<span className="name-icons">
|
||||||
{movie.urls.length > 0 && <ExternalLinksButton urls={movie.urls} />}
|
{group.urls.length > 0 && <ExternalLinksButton urls={group.urls} />}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
function maybeRenderAliases() {
|
function maybeRenderAliases() {
|
||||||
if (movie?.aliases) {
|
if (group?.aliases) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="alias-head">{movie?.aliases}</span>
|
<span className="alias-head">{group?.aliases}</span>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setRating(v: number | null) {
|
function setRating(v: number | null) {
|
||||||
if (movie.id) {
|
if (group.id) {
|
||||||
updateMovie({
|
updateMovie({
|
||||||
variables: {
|
variables: {
|
||||||
input: {
|
input: {
|
||||||
id: movie.id,
|
id: group.id,
|
||||||
rating100: v,
|
rating100: v,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -298,13 +298,13 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderTabs = () => <MovieScenesPanel active={true} movie={movie} />;
|
const renderTabs = () => <GroupScenesPanel active={true} group={group} />;
|
||||||
|
|
||||||
function maybeRenderDetails() {
|
function maybeRenderDetails() {
|
||||||
if (!isEditing) {
|
if (!isEditing) {
|
||||||
return (
|
return (
|
||||||
<MovieDetailsPanel
|
<GroupDetailsPanel
|
||||||
movie={movie}
|
group={group}
|
||||||
collapsed={collapsed}
|
collapsed={collapsed}
|
||||||
fullWidth={!collapsed && !compactExpandedDetails}
|
fullWidth={!collapsed && !compactExpandedDetails}
|
||||||
/>
|
/>
|
||||||
@@ -315,8 +315,8 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
function maybeRenderEditPanel() {
|
function maybeRenderEditPanel() {
|
||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
return (
|
return (
|
||||||
<MovieEditPanel
|
<GroupEditPanel
|
||||||
movie={movie}
|
group={group}
|
||||||
onSubmit={onSave}
|
onSubmit={onSave}
|
||||||
onCancel={() => toggleEditing()}
|
onCancel={() => toggleEditing()}
|
||||||
onDelete={onDelete}
|
onDelete={onDelete}
|
||||||
@@ -329,7 +329,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
{
|
{
|
||||||
return (
|
return (
|
||||||
<DetailsEditNavbar
|
<DetailsEditNavbar
|
||||||
objectName={movie.name}
|
objectName={group.name}
|
||||||
isNew={false}
|
isNew={false}
|
||||||
isEditing={isEditing}
|
isEditing={isEditing}
|
||||||
onToggleEdit={() => toggleEditing()}
|
onToggleEdit={() => toggleEditing()}
|
||||||
@@ -343,12 +343,12 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
|
|
||||||
function maybeRenderCompressedDetails() {
|
function maybeRenderCompressedDetails() {
|
||||||
if (!isEditing && loadStickyHeader) {
|
if (!isEditing && loadStickyHeader) {
|
||||||
return <CompressedMovieDetailsPanel movie={movie} />;
|
return <CompressedMovieDetailsPanel group={group} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderHeaderBackgroundImage() {
|
function maybeRenderHeaderBackgroundImage() {
|
||||||
let image = movie.front_image_path;
|
let image = group.front_image_path;
|
||||||
if (enableBackgroundImage && !isEditing && image) {
|
if (enableBackgroundImage && !isEditing && image) {
|
||||||
const imageURL = new URL(image);
|
const imageURL = new URL(image);
|
||||||
let isDefaultImage = imageURL.searchParams.get("default");
|
let isDefaultImage = imageURL.searchParams.get("default");
|
||||||
@@ -360,7 +360,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
<img
|
<img
|
||||||
className="background-image"
|
className="background-image"
|
||||||
src={image}
|
src={image}
|
||||||
alt={`${movie.name} background`}
|
alt={`${group.name} background`}
|
||||||
/>
|
/>
|
||||||
</picture>
|
</picture>
|
||||||
</div>
|
</div>
|
||||||
@@ -384,9 +384,9 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id="movie-page" className="row">
|
<div id="group-page" className="row">
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{movie?.name}</title>
|
<title>{group?.name}</title>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
|
|
||||||
<div className={headerClassName}>
|
<div className={headerClassName}>
|
||||||
@@ -399,7 +399,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
message={intl.formatMessage({ id: "actions.encoding_image" })}
|
message={intl.formatMessage({ id: "actions.encoding_image" })}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="movie-images">
|
<div className="group-images">
|
||||||
{renderFrontImage()}
|
{renderFrontImage()}
|
||||||
{renderBackImage()}
|
{renderBackImage()}
|
||||||
</div>
|
</div>
|
||||||
@@ -407,15 +407,15 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="movie-head col">
|
<div className="group-head col">
|
||||||
<h2>
|
<h2>
|
||||||
<span className="movie-name">{movie.name}</span>
|
<span className="group-name">{group.name}</span>
|
||||||
{maybeRenderShowCollapseButton()}
|
{maybeRenderShowCollapseButton()}
|
||||||
{renderClickableIcons()}
|
{renderClickableIcons()}
|
||||||
</h2>
|
</h2>
|
||||||
{maybeRenderAliases()}
|
{maybeRenderAliases()}
|
||||||
<RatingSystem
|
<RatingSystem
|
||||||
value={movie.rating100}
|
value={group.rating100}
|
||||||
onSetRating={(value) => setRating(value)}
|
onSetRating={(value) => setRating(value)}
|
||||||
clickToRate
|
clickToRate
|
||||||
withoutContext
|
withoutContext
|
||||||
@@ -428,8 +428,8 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
</div>
|
</div>
|
||||||
{maybeRenderCompressedDetails()}
|
{maybeRenderCompressedDetails()}
|
||||||
<div className="detail-body">
|
<div className="detail-body">
|
||||||
<div className="movie-body">
|
<div className="group-body">
|
||||||
<div className="movie-tabs">{maybeRenderTab()}</div>
|
<div className="group-tabs">{maybeRenderTab()}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{renderDeleteAlert()}
|
{renderDeleteAlert()}
|
||||||
@@ -437,7 +437,7 @@ const MoviePage: React.FC<IProps> = ({ movie }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieLoader: React.FC<RouteComponentProps<IMovieParams>> = ({
|
const GroupLoader: React.FC<RouteComponentProps<IGroupParams>> = ({
|
||||||
match,
|
match,
|
||||||
}) => {
|
}) => {
|
||||||
const { id } = match.params;
|
const { id } = match.params;
|
||||||
@@ -450,7 +450,7 @@ const MovieLoader: React.FC<RouteComponentProps<IMovieParams>> = ({
|
|||||||
if (!data?.findMovie)
|
if (!data?.findMovie)
|
||||||
return <ErrorMessage error={`No movie found with id ${id}.`} />;
|
return <ErrorMessage error={`No movie found with id ${id}.`} />;
|
||||||
|
|
||||||
return <MoviePage movie={data.findMovie} />;
|
return <GroupPage group={data.findMovie} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MovieLoader;
|
export default GroupLoader;
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import { useHistory, useLocation } from "react-router-dom";
|
|||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { LoadingIndicator } from "src/components/Shared/LoadingIndicator";
|
import { LoadingIndicator } from "src/components/Shared/LoadingIndicator";
|
||||||
import { useToast } from "src/hooks/Toast";
|
import { useToast } from "src/hooks/Toast";
|
||||||
import { MovieEditPanel } from "./MovieEditPanel";
|
import { GroupEditPanel } from "./MovieEditPanel";
|
||||||
|
|
||||||
const MovieCreate: React.FC = () => {
|
const GroupCreate: React.FC = () => {
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
|
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const query = useMemo(() => new URLSearchParams(location.search), [location]);
|
const query = useMemo(() => new URLSearchParams(location.search), [location]);
|
||||||
const movie = {
|
const group = {
|
||||||
name: query.get("q") ?? undefined,
|
name: query.get("q") ?? undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ const MovieCreate: React.FC = () => {
|
|||||||
variables: { input },
|
variables: { input },
|
||||||
});
|
});
|
||||||
if (result.data?.movieCreate?.id) {
|
if (result.data?.movieCreate?.id) {
|
||||||
history.push(`/movies/${result.data.movieCreate.id}`);
|
history.push(`/groups/${result.data.movieCreate.id}`);
|
||||||
Toast.success(
|
Toast.success(
|
||||||
intl.formatMessage(
|
intl.formatMessage(
|
||||||
{ id: "toast.created_entity" },
|
{ id: "toast.created_entity" },
|
||||||
@@ -43,7 +43,7 @@ const MovieCreate: React.FC = () => {
|
|||||||
function renderFrontImage() {
|
function renderFrontImage() {
|
||||||
if (frontImage) {
|
if (frontImage) {
|
||||||
return (
|
return (
|
||||||
<div className="movie-image-container">
|
<div className="group-image-container">
|
||||||
<img alt="Front Cover" src={frontImage} />
|
<img alt="Front Cover" src={frontImage} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,7 @@ const MovieCreate: React.FC = () => {
|
|||||||
function renderBackImage() {
|
function renderBackImage() {
|
||||||
if (backImage) {
|
if (backImage) {
|
||||||
return (
|
return (
|
||||||
<div className="movie-image-container">
|
<div className="group-image-container">
|
||||||
<img alt="Back Cover" src={backImage} />
|
<img alt="Back Cover" src={backImage} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -63,24 +63,24 @@ const MovieCreate: React.FC = () => {
|
|||||||
// TODO: CSS class
|
// TODO: CSS class
|
||||||
return (
|
return (
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="movie-details mb-3 col">
|
<div className="group-details mb-3 col">
|
||||||
<div className="logo w-100">
|
<div className="logo w-100">
|
||||||
{encodingImage ? (
|
{encodingImage ? (
|
||||||
<LoadingIndicator
|
<LoadingIndicator
|
||||||
message={intl.formatMessage({ id: "actions.encoding_image" })}
|
message={intl.formatMessage({ id: "actions.encoding_image" })}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="movie-images">
|
<div className="group-images">
|
||||||
{renderFrontImage()}
|
{renderFrontImage()}
|
||||||
{renderBackImage()}
|
{renderBackImage()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MovieEditPanel
|
<GroupEditPanel
|
||||||
movie={movie}
|
group={group}
|
||||||
onSubmit={onSave}
|
onSubmit={onSave}
|
||||||
onCancel={() => history.push("/movies")}
|
onCancel={() => history.push("/groups")}
|
||||||
onDelete={() => {}}
|
onDelete={() => {}}
|
||||||
setFrontImage={setFrontImage}
|
setFrontImage={setFrontImage}
|
||||||
setBackImage={setBackImage}
|
setBackImage={setBackImage}
|
||||||
@@ -91,4 +91,4 @@ const MovieCreate: React.FC = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MovieCreate;
|
export default GroupCreate;
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import { Link } from "react-router-dom";
|
|||||||
import { DirectorLink } from "src/components/Shared/Link";
|
import { DirectorLink } from "src/components/Shared/Link";
|
||||||
import { TagLink } from "src/components/Shared/TagLink";
|
import { TagLink } from "src/components/Shared/TagLink";
|
||||||
|
|
||||||
interface IMovieDetailsPanel {
|
interface IGroupDetailsPanel {
|
||||||
movie: GQL.MovieDataFragment;
|
group: GQL.MovieDataFragment;
|
||||||
collapsed?: boolean;
|
collapsed?: boolean;
|
||||||
fullWidth?: boolean;
|
fullWidth?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
export const GroupDetailsPanel: React.FC<IGroupDetailsPanel> = ({
|
||||||
movie,
|
group,
|
||||||
collapsed,
|
collapsed,
|
||||||
fullWidth,
|
fullWidth,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -22,13 +22,13 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
function renderTagsField() {
|
function renderTagsField() {
|
||||||
if (!movie.tags.length) {
|
if (!group.tags.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ul className="pl-0">
|
<ul className="pl-0">
|
||||||
{(movie.tags ?? []).map((tag) => (
|
{(group.tags ?? []).map((tag) => (
|
||||||
<TagLink key={tag.id} linkType="movie" tag={tag} />
|
<TagLink key={tag.id} linkType="group" tag={tag} />
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
);
|
);
|
||||||
@@ -40,7 +40,7 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
<>
|
<>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
id="synopsis"
|
id="synopsis"
|
||||||
value={movie.synopsis}
|
value={group.synopsis}
|
||||||
fullWidth={fullWidth}
|
fullWidth={fullWidth}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
@@ -58,21 +58,21 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
<DetailItem
|
<DetailItem
|
||||||
id="duration"
|
id="duration"
|
||||||
value={
|
value={
|
||||||
movie.duration ? TextUtils.secondsToTimestamp(movie.duration) : ""
|
group.duration ? TextUtils.secondsToTimestamp(group.duration) : ""
|
||||||
}
|
}
|
||||||
fullWidth={fullWidth}
|
fullWidth={fullWidth}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
id="date"
|
id="date"
|
||||||
value={movie.date ? TextUtils.formatDate(intl, movie.date) : ""}
|
value={group.date ? TextUtils.formatDate(intl, group.date) : ""}
|
||||||
fullWidth={fullWidth}
|
fullWidth={fullWidth}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
id="studio"
|
id="studio"
|
||||||
value={
|
value={
|
||||||
movie.studio?.id ? (
|
group.studio?.id ? (
|
||||||
<Link to={`/studios/${movie.studio?.id}`}>
|
<Link to={`/studios/${group.studio?.id}`}>
|
||||||
{movie.studio?.name}
|
{group.studio?.name}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
@@ -84,8 +84,8 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
<DetailItem
|
<DetailItem
|
||||||
id="director"
|
id="director"
|
||||||
value={
|
value={
|
||||||
movie.director ? (
|
group.director ? (
|
||||||
<DirectorLink director={movie.director} linkType="movie" />
|
<DirectorLink director={group.director} linkType="group" />
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
)
|
)
|
||||||
@@ -97,8 +97,8 @@ export const MovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CompressedMovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
export const CompressedMovieDetailsPanel: React.FC<IGroupDetailsPanel> = ({
|
||||||
movie,
|
group,
|
||||||
}) => {
|
}) => {
|
||||||
function scrollToTop() {
|
function scrollToTop() {
|
||||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||||
@@ -107,13 +107,13 @@ export const CompressedMovieDetailsPanel: React.FC<IMovieDetailsPanel> = ({
|
|||||||
return (
|
return (
|
||||||
<div className="sticky detail-header">
|
<div className="sticky detail-header">
|
||||||
<div className="sticky detail-header-group">
|
<div className="sticky detail-header-group">
|
||||||
<a className="movie-name" onClick={() => scrollToTop()}>
|
<a className="group-name" onClick={() => scrollToTop()}>
|
||||||
{movie.name}
|
{group.name}
|
||||||
</a>
|
</a>
|
||||||
{movie?.studio?.name ? (
|
{group?.studio?.name ? (
|
||||||
<>
|
<>
|
||||||
<span className="detail-divider">/</span>
|
<span className="detail-divider">/</span>
|
||||||
<span className="movie-studio">{movie?.studio?.name}</span>
|
<span className="group-studio">{group?.studio?.name}</span>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import TextUtils from "src/utils/text";
|
|||||||
import ImageUtils from "src/utils/image";
|
import ImageUtils from "src/utils/image";
|
||||||
import { useFormik } from "formik";
|
import { useFormik } from "formik";
|
||||||
import { Prompt } from "react-router-dom";
|
import { Prompt } from "react-router-dom";
|
||||||
import { MovieScrapeDialog } from "./MovieScrapeDialog";
|
import { GroupScrapeDialog } from "./MovieScrapeDialog";
|
||||||
import isEqual from "lodash-es/isEqual";
|
import isEqual from "lodash-es/isEqual";
|
||||||
import { handleUnsavedChanges } from "src/utils/navigation";
|
import { handleUnsavedChanges } from "src/utils/navigation";
|
||||||
import { formikUtils } from "src/utils/form";
|
import { formikUtils } from "src/utils/form";
|
||||||
@@ -27,8 +27,8 @@ import {
|
|||||||
import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
|
import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
|
||||||
import { useTagsEdit } from "src/hooks/tagsEdit";
|
import { useTagsEdit } from "src/hooks/tagsEdit";
|
||||||
|
|
||||||
interface IMovieEditPanel {
|
interface IGroupEditPanel {
|
||||||
movie: Partial<GQL.MovieDataFragment>;
|
group: Partial<GQL.MovieDataFragment>;
|
||||||
onSubmit: (movie: GQL.MovieCreateInput) => Promise<void>;
|
onSubmit: (movie: GQL.MovieCreateInput) => Promise<void>;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onDelete: () => void;
|
onDelete: () => void;
|
||||||
@@ -37,8 +37,8 @@ interface IMovieEditPanel {
|
|||||||
setEncodingImage: (loading: boolean) => void;
|
setEncodingImage: (loading: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
export const GroupEditPanel: React.FC<IGroupEditPanel> = ({
|
||||||
movie,
|
group,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
onDelete,
|
onDelete,
|
||||||
@@ -49,7 +49,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const Toast = useToast();
|
const Toast = useToast();
|
||||||
|
|
||||||
const isNew = movie.id === undefined;
|
const isNew = group.id === undefined;
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [isImageAlertOpen, setIsImageAlertOpen] = useState<boolean>(false);
|
const [isImageAlertOpen, setIsImageAlertOpen] = useState<boolean>(false);
|
||||||
@@ -57,7 +57,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
const [imageClipboard, setImageClipboard] = useState<string>();
|
const [imageClipboard, setImageClipboard] = useState<string>();
|
||||||
|
|
||||||
const Scrapers = useListMovieScrapers();
|
const Scrapers = useListMovieScrapers();
|
||||||
const [scrapedMovie, setScrapedMovie] = useState<GQL.ScrapedMovie>();
|
const [scrapedGroup, setScrapedGroup] = useState<GQL.ScrapedMovie>();
|
||||||
|
|
||||||
const [studio, setStudio] = useState<Studio | null>(null);
|
const [studio, setStudio] = useState<Studio | null>(null);
|
||||||
|
|
||||||
@@ -76,15 +76,15 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const initialValues = {
|
const initialValues = {
|
||||||
name: movie?.name ?? "",
|
name: group?.name ?? "",
|
||||||
aliases: movie?.aliases ?? "",
|
aliases: group?.aliases ?? "",
|
||||||
duration: movie?.duration ?? null,
|
duration: group?.duration ?? null,
|
||||||
date: movie?.date ?? "",
|
date: group?.date ?? "",
|
||||||
studio_id: movie?.studio?.id ?? null,
|
studio_id: group?.studio?.id ?? null,
|
||||||
tag_ids: (movie?.tags ?? []).map((t) => t.id),
|
tag_ids: (group?.tags ?? []).map((t) => t.id),
|
||||||
director: movie?.director ?? "",
|
director: group?.director ?? "",
|
||||||
urls: movie?.urls ?? [],
|
urls: group?.urls ?? [],
|
||||||
synopsis: movie?.synopsis ?? "",
|
synopsis: group?.synopsis ?? "",
|
||||||
};
|
};
|
||||||
|
|
||||||
type InputValues = yup.InferType<typeof schema>;
|
type InputValues = yup.InferType<typeof schema>;
|
||||||
@@ -97,7 +97,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { tags, updateTagsStateFromScraper, tagsControl } = useTagsEdit(
|
const { tags, updateTagsStateFromScraper, tagsControl } = useTagsEdit(
|
||||||
movie.tags,
|
group.tags,
|
||||||
(ids) => formik.setFieldValue("tag_ids", ids)
|
(ids) => formik.setFieldValue("tag_ids", ids)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -107,8 +107,8 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setStudio(movie.studio ?? null);
|
setStudio(group.studio ?? null);
|
||||||
}, [movie.studio]);
|
}, [group.studio]);
|
||||||
|
|
||||||
// set up hotkeys
|
// set up hotkeys
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -128,7 +128,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateMovieEditStateFromScraper(
|
function updateGroupEditStateFromScraper(
|
||||||
state: Partial<GQL.ScrapedMovieDataFragment>
|
state: Partial<GQL.ScrapedMovieDataFragment>
|
||||||
) {
|
) {
|
||||||
if (state.name) {
|
if (state.name) {
|
||||||
@@ -200,11 +200,11 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is a new movie, just dump the data
|
// if this is a new group, just dump the data
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
updateMovieEditStateFromScraper(result.data.scrapeMovieURL);
|
updateGroupEditStateFromScraper(result.data.scrapeMovieURL);
|
||||||
} else {
|
} else {
|
||||||
setScrapedMovie(result.data.scrapeMovieURL);
|
setScrapedGroup(result.data.scrapeMovieURL);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Toast.error(e);
|
Toast.error(e);
|
||||||
@@ -223,25 +223,25 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderScrapeDialog() {
|
function maybeRenderScrapeDialog() {
|
||||||
if (!scrapedMovie) {
|
if (!scrapedGroup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const currentMovie = {
|
const currentGroup = {
|
||||||
id: movie.id!,
|
id: group.id!,
|
||||||
...formik.values,
|
...formik.values,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get image paths for scrape gui
|
// Get image paths for scrape gui
|
||||||
currentMovie.front_image = movie?.front_image_path;
|
currentGroup.front_image = group?.front_image_path;
|
||||||
currentMovie.back_image = movie?.back_image_path;
|
currentGroup.back_image = group?.back_image_path;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MovieScrapeDialog
|
<GroupScrapeDialog
|
||||||
movie={currentMovie}
|
group={currentGroup}
|
||||||
movieStudio={studio}
|
groupStudio={studio}
|
||||||
movieTags={tags}
|
groupTags={tags}
|
||||||
scraped={scrapedMovie}
|
scraped={scrapedGroup}
|
||||||
onClose={(m) => {
|
onClose={(m) => {
|
||||||
onScrapeDialogClosed(m);
|
onScrapeDialogClosed(m);
|
||||||
}}
|
}}
|
||||||
@@ -251,9 +251,9 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
|
|
||||||
function onScrapeDialogClosed(p?: GQL.ScrapedMovieDataFragment) {
|
function onScrapeDialogClosed(p?: GQL.ScrapedMovieDataFragment) {
|
||||||
if (p) {
|
if (p) {
|
||||||
updateMovieEditStateFromScraper(p);
|
updateGroupEditStateFromScraper(p);
|
||||||
}
|
}
|
||||||
setScrapedMovie(undefined);
|
setScrapedGroup(undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
const encodingImage = ImageUtils.usePasteImage(showImageAlert);
|
const encodingImage = ImageUtils.usePasteImage(showImageAlert);
|
||||||
@@ -373,7 +373,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
<h2>
|
<h2>
|
||||||
{intl.formatMessage(
|
{intl.formatMessage(
|
||||||
{ id: "actions.add_entity" },
|
{ id: "actions.add_entity" },
|
||||||
{ entityType: intl.formatMessage({ id: "movie" }) }
|
{ entityType: intl.formatMessage({ id: "group" }) }
|
||||||
)}
|
)}
|
||||||
</h2>
|
</h2>
|
||||||
)}
|
)}
|
||||||
@@ -382,14 +382,14 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
when={formik.dirty}
|
when={formik.dirty}
|
||||||
message={(location, action) => {
|
message={(location, action) => {
|
||||||
// Check if it's a redirect after movie creation
|
// Check if it's a redirect after movie creation
|
||||||
if (action === "PUSH" && location.pathname.startsWith("/movies/"))
|
if (action === "PUSH" && location.pathname.startsWith("/groups/"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return handleUnsavedChanges(intl, "movies", movie.id)(location);
|
return handleUnsavedChanges(intl, "groups", group.id)(location);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Form noValidate onSubmit={formik.handleSubmit} id="movie-edit">
|
<Form noValidate onSubmit={formik.handleSubmit} id="group-edit">
|
||||||
{renderInputField("name")}
|
{renderInputField("name")}
|
||||||
{renderInputField("aliases")}
|
{renderInputField("aliases")}
|
||||||
{renderDurationField("duration")}
|
{renderDurationField("duration")}
|
||||||
@@ -402,7 +402,7 @@ export const MovieEditPanel: React.FC<IMovieEditPanel> = ({
|
|||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<DetailsEditNavbar
|
<DetailsEditNavbar
|
||||||
objectName={movie?.name ?? intl.formatMessage({ id: "movie" })}
|
objectName={group?.name ?? intl.formatMessage({ id: "group" })}
|
||||||
isNew={isNew}
|
isNew={isNew}
|
||||||
classNames="col-xl-9 mt-3"
|
classNames="col-xl-9 mt-3"
|
||||||
isEditing
|
isEditing
|
||||||
|
|||||||
@@ -5,17 +5,17 @@ import { ListFilterModel } from "src/models/list-filter/filter";
|
|||||||
import { SceneList } from "src/components/Scenes/SceneList";
|
import { SceneList } from "src/components/Scenes/SceneList";
|
||||||
import { View } from "src/components/List/views";
|
import { View } from "src/components/List/views";
|
||||||
|
|
||||||
interface IMovieScenesPanel {
|
interface IGroupScenesPanel {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
movie: GQL.MovieDataFragment;
|
group: GQL.MovieDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({
|
export const GroupScenesPanel: React.FC<IGroupScenesPanel> = ({
|
||||||
active,
|
active,
|
||||||
movie,
|
group,
|
||||||
}) => {
|
}) => {
|
||||||
function filterHook(filter: ListFilterModel) {
|
function filterHook(filter: ListFilterModel) {
|
||||||
const movieValue = { id: movie.id, label: movie.name };
|
const movieValue = { id: group.id, label: group.name };
|
||||||
// if movie is already present, then we modify it, otherwise add
|
// if movie is already present, then we modify it, otherwise add
|
||||||
let movieCriterion = filter.criteria.find((c) => {
|
let movieCriterion = filter.criteria.find((c) => {
|
||||||
return c.criterionOption.type === "movies";
|
return c.criterionOption.type === "movies";
|
||||||
@@ -29,7 +29,7 @@ export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({
|
|||||||
// add the movie if not present
|
// add the movie if not present
|
||||||
if (
|
if (
|
||||||
!movieCriterion.value.find((p) => {
|
!movieCriterion.value.find((p) => {
|
||||||
return p.id === movie.id;
|
return p.id === group.id;
|
||||||
})
|
})
|
||||||
) {
|
) {
|
||||||
movieCriterion.value.push(movieValue);
|
movieCriterion.value.push(movieValue);
|
||||||
@@ -46,13 +46,13 @@ export const MovieScenesPanel: React.FC<IMovieScenesPanel> = ({
|
|||||||
return filter;
|
return filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (movie && movie.id) {
|
if (group && group.id) {
|
||||||
return (
|
return (
|
||||||
<SceneList
|
<SceneList
|
||||||
filterHook={filterHook}
|
filterHook={filterHook}
|
||||||
defaultSort="movie_scene_number"
|
defaultSort="movie_scene_number"
|
||||||
alterQuery={active}
|
alterQuery={active}
|
||||||
view={View.MovieScenes}
|
view={View.GroupScenes}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,33 +20,33 @@ import { uniq } from "lodash-es";
|
|||||||
import { Tag } from "src/components/Tags/TagSelect";
|
import { Tag } from "src/components/Tags/TagSelect";
|
||||||
import { useScrapedTags } from "src/components/Shared/ScrapeDialog/scrapedTags";
|
import { useScrapedTags } from "src/components/Shared/ScrapeDialog/scrapedTags";
|
||||||
|
|
||||||
interface IMovieScrapeDialogProps {
|
interface IGroupScrapeDialogProps {
|
||||||
movie: Partial<GQL.MovieUpdateInput>;
|
group: Partial<GQL.MovieUpdateInput>;
|
||||||
movieStudio: Studio | null;
|
groupStudio: Studio | null;
|
||||||
movieTags: Tag[];
|
groupTags: Tag[];
|
||||||
scraped: GQL.ScrapedMovie;
|
scraped: GQL.ScrapedMovie;
|
||||||
|
|
||||||
onClose: (scrapedMovie?: GQL.ScrapedMovie) => void;
|
onClose: (scrapedMovie?: GQL.ScrapedMovie) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
export const GroupScrapeDialog: React.FC<IGroupScrapeDialogProps> = ({
|
||||||
movie,
|
group,
|
||||||
movieStudio,
|
groupStudio: groupStudio,
|
||||||
movieTags,
|
groupTags: groupTags,
|
||||||
scraped,
|
scraped,
|
||||||
onClose,
|
onClose,
|
||||||
}) => {
|
}) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const [name, setName] = useState<ScrapeResult<string>>(
|
const [name, setName] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.name, scraped.name)
|
new ScrapeResult<string>(group.name, scraped.name)
|
||||||
);
|
);
|
||||||
const [aliases, setAliases] = useState<ScrapeResult<string>>(
|
const [aliases, setAliases] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.aliases, scraped.aliases)
|
new ScrapeResult<string>(group.aliases, scraped.aliases)
|
||||||
);
|
);
|
||||||
const [duration, setDuration] = useState<ScrapeResult<string>>(
|
const [duration, setDuration] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(
|
new ScrapeResult<string>(
|
||||||
TextUtils.secondsToTimestamp(movie.duration || 0),
|
TextUtils.secondsToTimestamp(group.duration || 0),
|
||||||
// convert seconds to string if it's a number
|
// convert seconds to string if it's a number
|
||||||
scraped.duration && !isNaN(+scraped.duration)
|
scraped.duration && !isNaN(+scraped.duration)
|
||||||
? TextUtils.secondsToTimestamp(parseInt(scraped.duration, 10))
|
? TextUtils.secondsToTimestamp(parseInt(scraped.duration, 10))
|
||||||
@@ -54,20 +54,20 @@ export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
const [date, setDate] = useState<ScrapeResult<string>>(
|
const [date, setDate] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.date, scraped.date)
|
new ScrapeResult<string>(group.date, scraped.date)
|
||||||
);
|
);
|
||||||
const [director, setDirector] = useState<ScrapeResult<string>>(
|
const [director, setDirector] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.director, scraped.director)
|
new ScrapeResult<string>(group.director, scraped.director)
|
||||||
);
|
);
|
||||||
const [synopsis, setSynopsis] = useState<ScrapeResult<string>>(
|
const [synopsis, setSynopsis] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.synopsis, scraped.synopsis)
|
new ScrapeResult<string>(group.synopsis, scraped.synopsis)
|
||||||
);
|
);
|
||||||
const [studio, setStudio] = useState<ObjectScrapeResult<GQL.ScrapedStudio>>(
|
const [studio, setStudio] = useState<ObjectScrapeResult<GQL.ScrapedStudio>>(
|
||||||
new ObjectScrapeResult<GQL.ScrapedStudio>(
|
new ObjectScrapeResult<GQL.ScrapedStudio>(
|
||||||
movieStudio
|
groupStudio
|
||||||
? {
|
? {
|
||||||
stored_id: movieStudio.id,
|
stored_id: groupStudio.id,
|
||||||
name: movieStudio.name,
|
name: groupStudio.name,
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
scraped.studio?.stored_id ? scraped.studio : undefined
|
scraped.studio?.stored_id ? scraped.studio : undefined
|
||||||
@@ -75,17 +75,17 @@ export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
|||||||
);
|
);
|
||||||
const [urls, setURLs] = useState<ScrapeResult<string[]>>(
|
const [urls, setURLs] = useState<ScrapeResult<string[]>>(
|
||||||
new ScrapeResult<string[]>(
|
new ScrapeResult<string[]>(
|
||||||
movie.urls,
|
group.urls,
|
||||||
scraped.urls
|
scraped.urls
|
||||||
? uniq((movie.urls ?? []).concat(scraped.urls ?? []))
|
? uniq((group.urls ?? []).concat(scraped.urls ?? []))
|
||||||
: undefined
|
: undefined
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const [frontImage, setFrontImage] = useState<ScrapeResult<string>>(
|
const [frontImage, setFrontImage] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.front_image, scraped.front_image)
|
new ScrapeResult<string>(group.front_image, scraped.front_image)
|
||||||
);
|
);
|
||||||
const [backImage, setBackImage] = useState<ScrapeResult<string>>(
|
const [backImage, setBackImage] = useState<ScrapeResult<string>>(
|
||||||
new ScrapeResult<string>(movie.back_image, scraped.back_image)
|
new ScrapeResult<string>(group.back_image, scraped.back_image)
|
||||||
);
|
);
|
||||||
|
|
||||||
const [newStudio, setNewStudio] = useState<GQL.ScrapedStudio | undefined>(
|
const [newStudio, setNewStudio] = useState<GQL.ScrapedStudio | undefined>(
|
||||||
@@ -99,7 +99,7 @@ export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { tags, newTags, scrapedTagsRow } = useScrapedTags(
|
const { tags, newTags, scrapedTagsRow } = useScrapedTags(
|
||||||
movieTags,
|
groupTags,
|
||||||
scraped.tags
|
scraped.tags
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -194,13 +194,13 @@ export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
|||||||
{scrapedTagsRow}
|
{scrapedTagsRow}
|
||||||
<ScrapedImageRow
|
<ScrapedImageRow
|
||||||
title="Front Image"
|
title="Front Image"
|
||||||
className="movie-image"
|
className="group-image"
|
||||||
result={frontImage}
|
result={frontImage}
|
||||||
onChange={(value) => setFrontImage(value)}
|
onChange={(value) => setFrontImage(value)}
|
||||||
/>
|
/>
|
||||||
<ScrapedImageRow
|
<ScrapedImageRow
|
||||||
title="Back Image"
|
title="Back Image"
|
||||||
className="movie-image"
|
className="group-image"
|
||||||
result={backImage}
|
result={backImage}
|
||||||
onChange={(value) => setBackImage(value)}
|
onChange={(value) => setBackImage(value)}
|
||||||
/>
|
/>
|
||||||
@@ -212,7 +212,7 @@ export const MovieScrapeDialog: React.FC<IMovieScrapeDialogProps> = ({
|
|||||||
<ScrapeDialog
|
<ScrapeDialog
|
||||||
title={intl.formatMessage(
|
title={intl.formatMessage(
|
||||||
{ id: "dialogs.scrape_entity_title" },
|
{ id: "dialogs.scrape_entity_title" },
|
||||||
{ entity_type: intl.formatMessage({ id: "movie" }) }
|
{ entity_type: intl.formatMessage({ id: "group" }) }
|
||||||
)}
|
)}
|
||||||
renderScrapeRows={renderScrapeRows}
|
renderScrapeRows={renderScrapeRows}
|
||||||
onClose={(apply) => {
|
onClose={(apply) => {
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import {
|
|||||||
import { makeItemList, showWhenSelected } from "../List/ItemList";
|
import { makeItemList, showWhenSelected } from "../List/ItemList";
|
||||||
import { ExportDialog } from "../Shared/ExportDialog";
|
import { ExportDialog } from "../Shared/ExportDialog";
|
||||||
import { DeleteEntityDialog } from "../Shared/DeleteEntityDialog";
|
import { DeleteEntityDialog } from "../Shared/DeleteEntityDialog";
|
||||||
import { MovieCardGrid } from "./MovieCardGrid";
|
import { GroupCardGrid } from "./MovieCardGrid";
|
||||||
import { EditMoviesDialog } from "./EditMoviesDialog";
|
import { EditGroupsDialog } from "./EditMoviesDialog";
|
||||||
import { View } from "../List/views";
|
import { View } from "../List/views";
|
||||||
|
|
||||||
const MovieItemList = makeItemList({
|
const GroupItemList = makeItemList({
|
||||||
filterMode: GQL.FilterMode.Movies,
|
filterMode: GQL.FilterMode.Movies,
|
||||||
useResult: useFindMovies,
|
useResult: useFindMovies,
|
||||||
getItems(result: GQL.FindMoviesQueryResult) {
|
getItems(result: GQL.FindMoviesQueryResult) {
|
||||||
@@ -29,13 +29,13 @@ const MovieItemList = makeItemList({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
interface IMovieList {
|
interface IGroupList {
|
||||||
filterHook?: (filter: ListFilterModel) => ListFilterModel;
|
filterHook?: (filter: ListFilterModel) => ListFilterModel;
|
||||||
view?: View;
|
view?: View;
|
||||||
alterQuery?: boolean;
|
alterQuery?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieList: React.FC<IMovieList> = ({
|
export const GroupList: React.FC<IGroupList> = ({
|
||||||
filterHook,
|
filterHook,
|
||||||
alterQuery,
|
alterQuery,
|
||||||
view,
|
view,
|
||||||
@@ -90,7 +90,7 @@ export const MovieList: React.FC<IMovieList> = ({
|
|||||||
if (singleResult.data.findMovies.movies.length === 1) {
|
if (singleResult.data.findMovies.movies.length === 1) {
|
||||||
const { id } = singleResult.data.findMovies.movies[0];
|
const { id } = singleResult.data.findMovies.movies[0];
|
||||||
// navigate to the movie page
|
// navigate to the movie page
|
||||||
history.push(`/movies/${id}`);
|
history.push(`/groups/${id}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,7 +111,7 @@ export const MovieList: React.FC<IMovieList> = ({
|
|||||||
selectedIds: Set<string>,
|
selectedIds: Set<string>,
|
||||||
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void
|
onSelectChange: (id: string, selected: boolean, shiftKey: boolean) => void
|
||||||
) {
|
) {
|
||||||
function maybeRenderMovieExportDialog() {
|
function maybeRenderGroupExportDialog() {
|
||||||
if (isExportDialogOpen) {
|
if (isExportDialogOpen) {
|
||||||
return (
|
return (
|
||||||
<ExportDialog
|
<ExportDialog
|
||||||
@@ -127,13 +127,13 @@ export const MovieList: React.FC<IMovieList> = ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMovies() {
|
function renderGroups() {
|
||||||
if (!result.data?.findMovies) return;
|
if (!result.data?.findMovies) return;
|
||||||
|
|
||||||
if (filter.displayMode === DisplayMode.Grid) {
|
if (filter.displayMode === DisplayMode.Grid) {
|
||||||
return (
|
return (
|
||||||
<MovieCardGrid
|
<GroupCardGrid
|
||||||
movies={result.data.findMovies.movies}
|
groups={result.data.findMovies.movies}
|
||||||
selectedIds={selectedIds}
|
selectedIds={selectedIds}
|
||||||
onSelectChange={onSelectChange}
|
onSelectChange={onSelectChange}
|
||||||
/>
|
/>
|
||||||
@@ -145,36 +145,36 @@ export const MovieList: React.FC<IMovieList> = ({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{maybeRenderMovieExportDialog()}
|
{maybeRenderGroupExportDialog()}
|
||||||
{renderMovies()}
|
{renderGroups()}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderEditDialog(
|
function renderEditDialog(
|
||||||
selectedMovies: GQL.MovieDataFragment[],
|
selectedGroups: GQL.MovieDataFragment[],
|
||||||
onClose: (applied: boolean) => void
|
onClose: (applied: boolean) => void
|
||||||
) {
|
) {
|
||||||
return <EditMoviesDialog selected={selectedMovies} onClose={onClose} />;
|
return <EditGroupsDialog selected={selectedGroups} onClose={onClose} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderDeleteDialog(
|
function renderDeleteDialog(
|
||||||
selectedMovies: GQL.SlimMovieDataFragment[],
|
selectedGroups: GQL.SlimMovieDataFragment[],
|
||||||
onClose: (confirmed: boolean) => void
|
onClose: (confirmed: boolean) => void
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
<DeleteEntityDialog
|
<DeleteEntityDialog
|
||||||
selected={selectedMovies}
|
selected={selectedGroups}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
singularEntity={intl.formatMessage({ id: "movie" })}
|
singularEntity={intl.formatMessage({ id: "group" })}
|
||||||
pluralEntity={intl.formatMessage({ id: "movies" })}
|
pluralEntity={intl.formatMessage({ id: "groups" })}
|
||||||
destroyMutation={useMoviesDestroy}
|
destroyMutation={useMoviesDestroy}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MovieItemList
|
<GroupItemList
|
||||||
selectable
|
selectable
|
||||||
filterHook={filterHook}
|
filterHook={filterHook}
|
||||||
view={view}
|
view={view}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from "react";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { useFindMovies } from "src/core/StashService";
|
import { useFindMovies } from "src/core/StashService";
|
||||||
import Slider from "@ant-design/react-slick";
|
import Slider from "@ant-design/react-slick";
|
||||||
import { MovieCard } from "./MovieCard";
|
import { GroupCard } from "./MovieCard";
|
||||||
import { ListFilterModel } from "src/models/list-filter/filter";
|
import { ListFilterModel } from "src/models/list-filter/filter";
|
||||||
import { getSlickSliderSettings } from "src/core/recommendations";
|
import { getSlickSliderSettings } from "src/core/recommendations";
|
||||||
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
import { RecommendationRow } from "../FrontPage/RecommendationRow";
|
||||||
@@ -14,7 +14,7 @@ interface IProps {
|
|||||||
header: string;
|
header: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
export const GroupRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
||||||
const result = useFindMovies(props.filter);
|
const result = useFindMovies(props.filter);
|
||||||
const cardCount = result.data?.findMovies.count;
|
const cardCount = result.data?.findMovies.count;
|
||||||
|
|
||||||
@@ -24,10 +24,10 @@ export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RecommendationRow
|
<RecommendationRow
|
||||||
className="movie-recommendations"
|
className="group-recommendations"
|
||||||
header={props.header}
|
header={props.header}
|
||||||
link={
|
link={
|
||||||
<Link to={`/movies?${props.filter.makeQueryParameters()}`}>
|
<Link to={`/groups?${props.filter.makeQueryParameters()}`}>
|
||||||
<FormattedMessage id="view_all" />
|
<FormattedMessage id="view_all" />
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
@@ -40,10 +40,10 @@ export const MovieRecommendationRow: React.FC<IProps> = (props: IProps) => {
|
|||||||
>
|
>
|
||||||
{result.loading
|
{result.loading
|
||||||
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
? [...Array(props.filter.itemsPerPage)].map((i) => (
|
||||||
<div key={`_${i}`} className="movie-skeleton skeleton-card"></div>
|
<div key={`_${i}`} className="group-skeleton skeleton-card"></div>
|
||||||
))
|
))
|
||||||
: result.data?.findMovies.movies.map((m) => (
|
: result.data?.findMovies.movies.map((m) => (
|
||||||
<MovieCard key={m.id} movie={m} />
|
<GroupCard key={m.id} group={m} />
|
||||||
))}
|
))}
|
||||||
</Slider>
|
</Slider>
|
||||||
</RecommendationRow>
|
</RecommendationRow>
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ import { sortByRelevance } from "src/utils/query";
|
|||||||
import { PatchComponent, PatchFunction } from "src/patch";
|
import { PatchComponent, PatchFunction } from "src/patch";
|
||||||
import { TruncatedText } from "../Shared/TruncatedText";
|
import { TruncatedText } from "../Shared/TruncatedText";
|
||||||
|
|
||||||
export type Movie = Pick<
|
export type Group = Pick<
|
||||||
GQL.Movie,
|
GQL.Movie,
|
||||||
"id" | "name" | "date" | "front_image_path" | "aliases"
|
"id" | "name" | "date" | "front_image_path" | "aliases"
|
||||||
> & {
|
> & {
|
||||||
studio?: Pick<GQL.Studio, "name"> | null;
|
studio?: Pick<GQL.Studio, "name"> | null;
|
||||||
};
|
};
|
||||||
type Option = SelectOption<Movie>;
|
type Option = SelectOption<Group>;
|
||||||
|
|
||||||
type FindMoviesResult = Awaited<
|
type FindMoviesResult = Awaited<
|
||||||
ReturnType<typeof queryFindMoviesForSelect>
|
ReturnType<typeof queryFindMoviesForSelect>
|
||||||
@@ -56,9 +56,9 @@ const movieSelectSort = PatchFunction(
|
|||||||
sortMoviesByRelevance
|
sortMoviesByRelevance
|
||||||
);
|
);
|
||||||
|
|
||||||
const _MovieSelect: React.FC<
|
const _GroupSelect: React.FC<
|
||||||
IFilterProps &
|
IFilterProps &
|
||||||
IFilterValueProps<Movie> & {
|
IFilterValueProps<Group> & {
|
||||||
hoverPlacement?: Placement;
|
hoverPlacement?: Placement;
|
||||||
excludeIds?: string[];
|
excludeIds?: string[];
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ const _MovieSelect: React.FC<
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const MovieOption: React.FC<OptionProps<Option, boolean>> = (optionProps) => {
|
const GroupOption: React.FC<OptionProps<Option, boolean>> = (optionProps) => {
|
||||||
let thisOptionProps = optionProps;
|
let thisOptionProps = optionProps;
|
||||||
|
|
||||||
const { object } = optionProps.data;
|
const { object } = optionProps.data;
|
||||||
@@ -111,24 +111,24 @@ const _MovieSelect: React.FC<
|
|||||||
thisOptionProps = {
|
thisOptionProps = {
|
||||||
...optionProps,
|
...optionProps,
|
||||||
children: (
|
children: (
|
||||||
<span className="movie-select-option">
|
<span className="group-select-option">
|
||||||
<span className="movie-select-row">
|
<span className="group-select-row">
|
||||||
{object.front_image_path && (
|
{object.front_image_path && (
|
||||||
<img
|
<img
|
||||||
className="movie-select-image"
|
className="group-select-image"
|
||||||
src={object.front_image_path}
|
src={object.front_image_path}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<span className="movie-select-details">
|
<span className="group-select-details">
|
||||||
<TruncatedText
|
<TruncatedText
|
||||||
className="movie-select-title"
|
className="group-select-title"
|
||||||
text={
|
text={
|
||||||
<span>
|
<span>
|
||||||
{title}
|
{title}
|
||||||
{alias && (
|
{alias && (
|
||||||
<span className="movie-select-alias">{` (${alias})`}</span>
|
<span className="group-select-alias">{` (${alias})`}</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -136,13 +136,13 @@ const _MovieSelect: React.FC<
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{object.studio?.name && (
|
{object.studio?.name && (
|
||||||
<span className="movie-select-studio">
|
<span className="group-select-studio">
|
||||||
{object.studio?.name}
|
{object.studio?.name}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{object.date && (
|
{object.date && (
|
||||||
<span className="movie-select-date">{object.date}</span>
|
<span className="group-select-date">{object.date}</span>
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
@@ -153,7 +153,7 @@ const _MovieSelect: React.FC<
|
|||||||
return <reactSelectComponents.Option {...thisOptionProps} />;
|
return <reactSelectComponents.Option {...thisOptionProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieMultiValueLabel: React.FC<
|
const GroupMultiValueLabel: React.FC<
|
||||||
MultiValueGenericProps<Option, boolean>
|
MultiValueGenericProps<Option, boolean>
|
||||||
> = (optionProps) => {
|
> = (optionProps) => {
|
||||||
let thisOptionProps = optionProps;
|
let thisOptionProps = optionProps;
|
||||||
@@ -168,7 +168,7 @@ const _MovieSelect: React.FC<
|
|||||||
return <reactSelectComponents.MultiValueLabel {...thisOptionProps} />;
|
return <reactSelectComponents.MultiValueLabel {...thisOptionProps} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieValueLabel: React.FC<SingleValueProps<Option, boolean>> = (
|
const GroupValueLabel: React.FC<SingleValueProps<Option, boolean>> = (
|
||||||
optionProps
|
optionProps
|
||||||
) => {
|
) => {
|
||||||
let thisOptionProps = optionProps;
|
let thisOptionProps = optionProps;
|
||||||
@@ -190,7 +190,7 @@ const _MovieSelect: React.FC<
|
|||||||
return {
|
return {
|
||||||
value: result.data!.movieCreate!.id,
|
value: result.data!.movieCreate!.id,
|
||||||
item: result.data!.movieCreate!,
|
item: result.data!.movieCreate!,
|
||||||
message: "Created movie",
|
message: "Created group",
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ const _MovieSelect: React.FC<
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const isValidNewOption = (inputValue: string, options: Movie[]) => {
|
const isValidNewOption = (inputValue: string, options: Group[]) => {
|
||||||
if (!inputValue) {
|
if (!inputValue) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -221,12 +221,12 @@ const _MovieSelect: React.FC<
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FilterSelectComponent<Movie, boolean>
|
<FilterSelectComponent<Group, boolean>
|
||||||
{...props}
|
{...props}
|
||||||
className={cx(
|
className={cx(
|
||||||
"movie-select",
|
"group-select",
|
||||||
{
|
{
|
||||||
"movie-select-active": props.active,
|
"group-select-active": props.active,
|
||||||
},
|
},
|
||||||
props.className
|
props.className
|
||||||
)}
|
)}
|
||||||
@@ -234,9 +234,9 @@ const _MovieSelect: React.FC<
|
|||||||
getNamedObject={getNamedObject}
|
getNamedObject={getNamedObject}
|
||||||
isValidNewOption={isValidNewOption}
|
isValidNewOption={isValidNewOption}
|
||||||
components={{
|
components={{
|
||||||
Option: MovieOption,
|
Option: GroupOption,
|
||||||
MultiValueLabel: MovieMultiValueLabel,
|
MultiValueLabel: GroupMultiValueLabel,
|
||||||
SingleValue: MovieValueLabel,
|
SingleValue: GroupValueLabel,
|
||||||
}}
|
}}
|
||||||
isMulti={props.isMulti ?? false}
|
isMulti={props.isMulti ?? false}
|
||||||
creatable={props.creatable ?? defaultCreatable}
|
creatable={props.creatable ?? defaultCreatable}
|
||||||
@@ -247,7 +247,7 @@ const _MovieSelect: React.FC<
|
|||||||
{ id: "actions.select_entity" },
|
{ id: "actions.select_entity" },
|
||||||
{
|
{
|
||||||
entityType: intl.formatMessage({
|
entityType: intl.formatMessage({
|
||||||
id: props.isMulti ? "movies" : "movie",
|
id: props.isMulti ? "groups" : "group",
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -257,22 +257,22 @@ const _MovieSelect: React.FC<
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieSelect = PatchComponent("MovieSelect", _MovieSelect);
|
export const GroupSelect = PatchComponent("GroupSelect", _GroupSelect);
|
||||||
|
|
||||||
const _MovieIDSelect: React.FC<IFilterProps & IFilterIDProps<Movie>> = (
|
const _GroupIDSelect: React.FC<IFilterProps & IFilterIDProps<Group>> = (
|
||||||
props
|
props
|
||||||
) => {
|
) => {
|
||||||
const { ids, onSelect: onSelectValues } = props;
|
const { ids, onSelect: onSelectValues } = props;
|
||||||
|
|
||||||
const [values, setValues] = useState<Movie[]>([]);
|
const [values, setValues] = useState<Group[]>([]);
|
||||||
const idsChanged = useCompare(ids);
|
const idsChanged = useCompare(ids);
|
||||||
|
|
||||||
function onSelect(items: Movie[]) {
|
function onSelect(items: Group[]) {
|
||||||
setValues(items);
|
setValues(items);
|
||||||
onSelectValues?.(items);
|
onSelectValues?.(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadObjectsByID(idsToLoad: string[]): Promise<Movie[]> {
|
async function loadObjectsByID(idsToLoad: string[]): Promise<Group[]> {
|
||||||
const query = await queryFindMoviesByIDForSelect(idsToLoad);
|
const query = await queryFindMoviesByIDForSelect(idsToLoad);
|
||||||
const { movies: loadedMovies } = query.data.findMovies;
|
const { movies: loadedMovies } = query.data.findMovies;
|
||||||
|
|
||||||
@@ -303,7 +303,7 @@ const _MovieIDSelect: React.FC<IFilterProps & IFilterIDProps<Movie>> = (
|
|||||||
load();
|
load();
|
||||||
}, [ids, idsChanged, values]);
|
}, [ids, idsChanged, values]);
|
||||||
|
|
||||||
return <MovieSelect {...props} values={values} onSelect={onSelect} />;
|
return <GroupSelect {...props} values={values} onSelect={onSelect} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieIDSelect = PatchComponent("MovieIDSelect", _MovieIDSelect);
|
export const GroupIDSelect = PatchComponent("GroupIDSelect", _GroupIDSelect);
|
||||||
|
|||||||
@@ -2,30 +2,30 @@ import React from "react";
|
|||||||
import { Route, Switch } from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
import { Helmet } from "react-helmet";
|
import { Helmet } from "react-helmet";
|
||||||
import { useTitleProps } from "src/hooks/title";
|
import { useTitleProps } from "src/hooks/title";
|
||||||
import Movie from "./MovieDetails/Movie";
|
import Group from "./MovieDetails/Movie";
|
||||||
import MovieCreate from "./MovieDetails/MovieCreate";
|
import GroupCreate from "./MovieDetails/MovieCreate";
|
||||||
import { MovieList } from "./MovieList";
|
import { GroupList } from "./MovieList";
|
||||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||||
import { View } from "../List/views";
|
import { View } from "../List/views";
|
||||||
|
|
||||||
const Movies: React.FC = () => {
|
const Groups: React.FC = () => {
|
||||||
useScrollToTopOnMount();
|
useScrollToTopOnMount();
|
||||||
|
|
||||||
return <MovieList view={View.Movies} />;
|
return <GroupList view={View.Groups} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieRoutes: React.FC = () => {
|
const GroupRoutes: React.FC = () => {
|
||||||
const titleProps = useTitleProps({ id: "movies" });
|
const titleProps = useTitleProps({ id: "groups" });
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Helmet {...titleProps} />
|
<Helmet {...titleProps} />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route exact path="/movies" component={Movies} />
|
<Route exact path="/groups" component={Groups} />
|
||||||
<Route exact path="/movies/new" component={MovieCreate} />
|
<Route exact path="/groups/new" component={GroupCreate} />
|
||||||
<Route path="/movies/:id/:tab?" component={Movie} />
|
<Route path="/groups/:id/:tab?" component={Group} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default MovieRoutes;
|
export default GroupRoutes;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.movie-card {
|
.group-card {
|
||||||
width: 240px;
|
width: 240px;
|
||||||
|
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-scene-number {
|
.group-scene-number {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,14 +23,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-images {
|
.group-images {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-evenly;
|
justify-content: space-evenly;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
|
||||||
.movie-image-container {
|
.group-image-container {
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,17 +40,17 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#movie-page .rating-number .text-input {
|
#group-page .rating-number .text-input {
|
||||||
width: auto;
|
width: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-select-option {
|
.group-select-option {
|
||||||
.movie-select-row {
|
.group-select-row {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.movie-select-image {
|
.group-select-image {
|
||||||
background-color: $body-bg;
|
background-color: $body-bg;
|
||||||
margin-right: 0.4em;
|
margin-right: 0.4em;
|
||||||
max-height: 50px;
|
max-height: 50px;
|
||||||
@@ -59,26 +59,26 @@
|
|||||||
object-position: center;
|
object-position: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-select-details {
|
.group-select-details {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
max-height: 4.1rem;
|
max-height: 4.1rem;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.movie-select-title {
|
.group-select-title {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
|
||||||
.movie-select-alias {
|
.group-select-alias {
|
||||||
font-size: 0.8rem;
|
font-size: 0.8rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-select-date,
|
.group-select-date,
|
||||||
.movie-select-studio {
|
.group-select-studio {
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
|
|||||||
@@ -178,15 +178,15 @@ export const PerformerCard: React.FC<IPerformerCardProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderMoviesPopoverButton() {
|
function maybeRenderGroupsPopoverButton() {
|
||||||
if (!performer.movie_count) return;
|
if (!performer.movie_count) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverCountButton
|
<PopoverCountButton
|
||||||
className="movie-count"
|
className="group-count"
|
||||||
type="movie"
|
type="group"
|
||||||
count={performer.movie_count}
|
count={performer.movie_count}
|
||||||
url={NavUtils.makePerformerMoviesUrl(
|
url={NavUtils.makePerformerGroupsUrl(
|
||||||
performer,
|
performer,
|
||||||
extraCriteria?.performer,
|
extraCriteria?.performer,
|
||||||
extraCriteria?.movies
|
extraCriteria?.movies
|
||||||
@@ -209,7 +209,7 @@ export const PerformerCard: React.FC<IPerformerCardProps> = ({
|
|||||||
<hr />
|
<hr />
|
||||||
<ButtonGroup className="card-popovers">
|
<ButtonGroup className="card-popovers">
|
||||||
{maybeRenderScenesPopoverButton()}
|
{maybeRenderScenesPopoverButton()}
|
||||||
{maybeRenderMoviesPopoverButton()}
|
{maybeRenderGroupsPopoverButton()}
|
||||||
{maybeRenderImagesPopoverButton()}
|
{maybeRenderImagesPopoverButton()}
|
||||||
{maybeRenderGalleriesPopoverButton()}
|
{maybeRenderGalleriesPopoverButton()}
|
||||||
{maybeRenderTagPopoverButton()}
|
{maybeRenderTagPopoverButton()}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ import {
|
|||||||
} from "./PerformerDetailsPanel";
|
} from "./PerformerDetailsPanel";
|
||||||
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
||||||
import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
||||||
import { PerformerMoviesPanel } from "./PerformerMoviesPanel";
|
import { PerformerGroupsPanel } from "./PerformerMoviesPanel";
|
||||||
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
||||||
import { PerformerAppearsWithPanel } from "./performerAppearsWithPanel";
|
import { PerformerAppearsWithPanel } from "./performerAppearsWithPanel";
|
||||||
import { PerformerEditPanel } from "./PerformerEditPanel";
|
import { PerformerEditPanel } from "./PerformerEditPanel";
|
||||||
@@ -60,7 +60,7 @@ const validTabs = [
|
|||||||
"scenes",
|
"scenes",
|
||||||
"galleries",
|
"galleries",
|
||||||
"images",
|
"images",
|
||||||
"movies",
|
"groups",
|
||||||
"appearswith",
|
"appearswith",
|
||||||
] as const;
|
] as const;
|
||||||
type TabKey = (typeof validTabs)[number];
|
type TabKey = (typeof validTabs)[number];
|
||||||
@@ -146,7 +146,7 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||||||
} else if (performer.image_count != 0) {
|
} else if (performer.image_count != 0) {
|
||||||
ret = "images";
|
ret = "images";
|
||||||
} else if (performer.movie_count != 0) {
|
} else if (performer.movie_count != 0) {
|
||||||
ret = "movies";
|
ret = "groups";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,7 +191,7 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||||||
Mousetrap.bind("e", () => toggleEditing());
|
Mousetrap.bind("e", () => toggleEditing());
|
||||||
Mousetrap.bind("c", () => setTabKey("scenes"));
|
Mousetrap.bind("c", () => setTabKey("scenes"));
|
||||||
Mousetrap.bind("g", () => setTabKey("galleries"));
|
Mousetrap.bind("g", () => setTabKey("galleries"));
|
||||||
Mousetrap.bind("m", () => setTabKey("movies"));
|
Mousetrap.bind("m", () => setTabKey("groups"));
|
||||||
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
||||||
Mousetrap.bind(",", () => setCollapsed(!collapsed));
|
Mousetrap.bind(",", () => setCollapsed(!collapsed));
|
||||||
|
|
||||||
@@ -319,10 +319,10 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="movies"
|
eventKey="groups"
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
{intl.formatMessage({ id: "movies" })}
|
{intl.formatMessage({ id: "groups" })}
|
||||||
<Counter
|
<Counter
|
||||||
abbreviateCounter={abbreviateCounter}
|
abbreviateCounter={abbreviateCounter}
|
||||||
count={performer.movie_count}
|
count={performer.movie_count}
|
||||||
@@ -331,8 +331,8 @@ const PerformerPage: React.FC<IProps> = ({ performer, tabKey }) => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<PerformerMoviesPanel
|
<PerformerGroupsPanel
|
||||||
active={tabKey === "movies"}
|
active={tabKey === "groups"}
|
||||||
performer={performer}
|
performer={performer}
|
||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { MovieList } from "src/components/Movies/MovieList";
|
import { GroupList } from "src/components/Movies/MovieList";
|
||||||
import { usePerformerFilterHook } from "src/core/performers";
|
import { usePerformerFilterHook } from "src/core/performers";
|
||||||
import { View } from "src/components/List/views";
|
import { View } from "src/components/List/views";
|
||||||
|
|
||||||
@@ -9,16 +9,16 @@ interface IPerformerDetailsProps {
|
|||||||
performer: GQL.PerformerDataFragment;
|
performer: GQL.PerformerDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PerformerMoviesPanel: React.FC<IPerformerDetailsProps> = ({
|
export const PerformerGroupsPanel: React.FC<IPerformerDetailsProps> = ({
|
||||||
active,
|
active,
|
||||||
performer,
|
performer,
|
||||||
}) => {
|
}) => {
|
||||||
const filterHook = usePerformerFilterHook(performer);
|
const filterHook = usePerformerFilterHook(performer);
|
||||||
return (
|
return (
|
||||||
<MovieList
|
<GroupList
|
||||||
filterHook={filterHook}
|
filterHook={filterHook}
|
||||||
alterQuery={active}
|
alterQuery={active}
|
||||||
view={View.PerformerMovies}
|
view={View.PerformerGroups}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { HoverPopover } from "../Shared/HoverPopover";
|
|||||||
import { Icon } from "../Shared/Icon";
|
import { Icon } from "../Shared/Icon";
|
||||||
import {
|
import {
|
||||||
GalleryLink,
|
GalleryLink,
|
||||||
MovieLink,
|
GroupLink,
|
||||||
SceneMarkerLink,
|
SceneMarkerLink,
|
||||||
TagLink,
|
TagLink,
|
||||||
} from "../Shared/TagLink";
|
} from "../Shared/TagLink";
|
||||||
@@ -386,14 +386,14 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||||||
return <PerformerPopoverButton performers={scene.performers} />;
|
return <PerformerPopoverButton performers={scene.performers} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderMoviePopoverButton(scene: GQL.SlimSceneDataFragment) {
|
function maybeRenderGroupPopoverButton(scene: GQL.SlimSceneDataFragment) {
|
||||||
if (scene.movies.length <= 0) return;
|
if (scene.movies.length <= 0) return;
|
||||||
|
|
||||||
const popoverContent = scene.movies.map((sceneMovie) => (
|
const popoverContent = scene.movies.map((sceneMovie) => (
|
||||||
<div className="movie-tag-container row" key="movie">
|
<div className="group-tag-container row" key={sceneMovie.movie.id}>
|
||||||
<Link
|
<Link
|
||||||
to={`/movies/${sceneMovie.movie.id}`}
|
to={`/groups/${sceneMovie.movie.id}`}
|
||||||
className="movie-tag col m-auto zoom-2"
|
className="group-tag col m-auto zoom-2"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className="image-thumbnail"
|
className="image-thumbnail"
|
||||||
@@ -401,9 +401,9 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||||||
src={sceneMovie.movie.front_image_path ?? ""}
|
src={sceneMovie.movie.front_image_path ?? ""}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<MovieLink
|
<GroupLink
|
||||||
key={sceneMovie.movie.id}
|
key={sceneMovie.movie.id}
|
||||||
movie={sceneMovie.movie}
|
group={sceneMovie.movie}
|
||||||
className="d-block"
|
className="d-block"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -523,7 +523,7 @@ export const SceneDuplicateChecker: React.FC = () => {
|
|||||||
<ButtonGroup className="flex-wrap">
|
<ButtonGroup className="flex-wrap">
|
||||||
{maybeRenderTagPopoverButton(scene)}
|
{maybeRenderTagPopoverButton(scene)}
|
||||||
{maybeRenderPerformerPopoverButton(scene)}
|
{maybeRenderPerformerPopoverButton(scene)}
|
||||||
{maybeRenderMoviePopoverButton(scene)}
|
{maybeRenderGroupPopoverButton(scene)}
|
||||||
{maybeRenderSceneMarkerPopoverButton(scene)}
|
{maybeRenderSceneMarkerPopoverButton(scene)}
|
||||||
{maybeRenderOCounter(scene)}
|
{maybeRenderOCounter(scene)}
|
||||||
{maybeRenderGallery(scene)}
|
{maybeRenderGallery(scene)}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { RatingSystem } from "../Shared/Rating/RatingSystem";
|
|||||||
import {
|
import {
|
||||||
getAggregateInputIDs,
|
getAggregateInputIDs,
|
||||||
getAggregateInputValue,
|
getAggregateInputValue,
|
||||||
getAggregateMovieIds,
|
getAggregateGroupIds,
|
||||||
getAggregatePerformerIds,
|
getAggregatePerformerIds,
|
||||||
getAggregateRating,
|
getAggregateRating,
|
||||||
getAggregateStudioId,
|
getAggregateStudioId,
|
||||||
@@ -42,11 +42,11 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
);
|
);
|
||||||
const [tagIds, setTagIds] = useState<string[]>();
|
const [tagIds, setTagIds] = useState<string[]>();
|
||||||
const [existingTagIds, setExistingTagIds] = useState<string[]>();
|
const [existingTagIds, setExistingTagIds] = useState<string[]>();
|
||||||
const [movieMode, setMovieMode] = React.useState<GQL.BulkUpdateIdMode>(
|
const [groupMode, setGroupMode] = React.useState<GQL.BulkUpdateIdMode>(
|
||||||
GQL.BulkUpdateIdMode.Add
|
GQL.BulkUpdateIdMode.Add
|
||||||
);
|
);
|
||||||
const [movieIds, setMovieIds] = useState<string[]>();
|
const [groupIds, setGroupIds] = useState<string[]>();
|
||||||
const [existingMovieIds, setExistingMovieIds] = useState<string[]>();
|
const [existingGroupIds, setExistingGroupIds] = useState<string[]>();
|
||||||
const [organized, setOrganized] = useState<boolean | undefined>();
|
const [organized, setOrganized] = useState<boolean | undefined>();
|
||||||
|
|
||||||
const [updateScenes] = useBulkSceneUpdate(getSceneInput());
|
const [updateScenes] = useBulkSceneUpdate(getSceneInput());
|
||||||
@@ -62,7 +62,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
const aggregateStudioId = getAggregateStudioId(props.selected);
|
const aggregateStudioId = getAggregateStudioId(props.selected);
|
||||||
const aggregatePerformerIds = getAggregatePerformerIds(props.selected);
|
const aggregatePerformerIds = getAggregatePerformerIds(props.selected);
|
||||||
const aggregateTagIds = getAggregateTagIds(props.selected);
|
const aggregateTagIds = getAggregateTagIds(props.selected);
|
||||||
const aggregateMovieIds = getAggregateMovieIds(props.selected);
|
const aggregateGroupIds = getAggregateGroupIds(props.selected);
|
||||||
|
|
||||||
const sceneInput: GQL.BulkSceneUpdateInput = {
|
const sceneInput: GQL.BulkSceneUpdateInput = {
|
||||||
ids: props.selected.map((scene) => {
|
ids: props.selected.map((scene) => {
|
||||||
@@ -80,9 +80,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
);
|
);
|
||||||
sceneInput.tag_ids = getAggregateInputIDs(tagMode, tagIds, aggregateTagIds);
|
sceneInput.tag_ids = getAggregateInputIDs(tagMode, tagIds, aggregateTagIds);
|
||||||
sceneInput.movie_ids = getAggregateInputIDs(
|
sceneInput.movie_ids = getAggregateInputIDs(
|
||||||
movieMode,
|
groupMode,
|
||||||
movieIds,
|
groupIds,
|
||||||
aggregateMovieIds
|
aggregateGroupIds
|
||||||
);
|
);
|
||||||
|
|
||||||
if (organized !== undefined) {
|
if (organized !== undefined) {
|
||||||
@@ -115,7 +115,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
let updateStudioID: string | undefined;
|
let updateStudioID: string | undefined;
|
||||||
let updatePerformerIds: string[] = [];
|
let updatePerformerIds: string[] = [];
|
||||||
let updateTagIds: string[] = [];
|
let updateTagIds: string[] = [];
|
||||||
let updateMovieIds: string[] = [];
|
let updateGroupIds: string[] = [];
|
||||||
let updateOrganized: boolean | undefined;
|
let updateOrganized: boolean | undefined;
|
||||||
let first = true;
|
let first = true;
|
||||||
|
|
||||||
@@ -126,14 +126,14 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
.map((p) => p.id)
|
.map((p) => p.id)
|
||||||
.sort();
|
.sort();
|
||||||
const sceneTagIDs = (scene.tags ?? []).map((p) => p.id).sort();
|
const sceneTagIDs = (scene.tags ?? []).map((p) => p.id).sort();
|
||||||
const sceneMovieIDs = (scene.movies ?? []).map((m) => m.movie.id).sort();
|
const sceneGroupIDs = (scene.movies ?? []).map((m) => m.movie.id).sort();
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
updateRating = sceneRating ?? undefined;
|
updateRating = sceneRating ?? undefined;
|
||||||
updateStudioID = sceneStudioID;
|
updateStudioID = sceneStudioID;
|
||||||
updatePerformerIds = scenePerformerIDs;
|
updatePerformerIds = scenePerformerIDs;
|
||||||
updateTagIds = sceneTagIDs;
|
updateTagIds = sceneTagIDs;
|
||||||
updateMovieIds = sceneMovieIDs;
|
updateGroupIds = sceneGroupIDs;
|
||||||
first = false;
|
first = false;
|
||||||
updateOrganized = scene.organized;
|
updateOrganized = scene.organized;
|
||||||
} else {
|
} else {
|
||||||
@@ -149,8 +149,8 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
if (!isEqual(sceneTagIDs, updateTagIds)) {
|
if (!isEqual(sceneTagIDs, updateTagIds)) {
|
||||||
updateTagIds = [];
|
updateTagIds = [];
|
||||||
}
|
}
|
||||||
if (!isEqual(sceneMovieIDs, updateMovieIds)) {
|
if (!isEqual(sceneGroupIDs, updateGroupIds)) {
|
||||||
updateMovieIds = [];
|
updateGroupIds = [];
|
||||||
}
|
}
|
||||||
if (scene.organized !== updateOrganized) {
|
if (scene.organized !== updateOrganized) {
|
||||||
updateOrganized = undefined;
|
updateOrganized = undefined;
|
||||||
@@ -162,7 +162,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
setStudioId(updateStudioID);
|
setStudioId(updateStudioID);
|
||||||
setExistingPerformerIds(updatePerformerIds);
|
setExistingPerformerIds(updatePerformerIds);
|
||||||
setExistingTagIds(updateTagIds);
|
setExistingTagIds(updateTagIds);
|
||||||
setExistingMovieIds(updateMovieIds);
|
setExistingGroupIds(updateGroupIds);
|
||||||
setOrganized(updateOrganized);
|
setOrganized(updateOrganized);
|
||||||
}, [props.selected]);
|
}, [props.selected]);
|
||||||
|
|
||||||
@@ -173,7 +173,7 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
}, [organized, checkboxRef]);
|
}, [organized, checkboxRef]);
|
||||||
|
|
||||||
function renderMultiSelect(
|
function renderMultiSelect(
|
||||||
type: "performers" | "tags" | "movies",
|
type: "performers" | "tags" | "groups",
|
||||||
ids: string[] | undefined
|
ids: string[] | undefined
|
||||||
) {
|
) {
|
||||||
let mode = GQL.BulkUpdateIdMode.Add;
|
let mode = GQL.BulkUpdateIdMode.Add;
|
||||||
@@ -187,9 +187,9 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
mode = tagMode;
|
mode = tagMode;
|
||||||
existingIds = existingTagIds;
|
existingIds = existingTagIds;
|
||||||
break;
|
break;
|
||||||
case "movies":
|
case "groups":
|
||||||
mode = movieMode;
|
mode = groupMode;
|
||||||
existingIds = existingMovieIds;
|
existingIds = existingGroupIds;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -205,8 +205,8 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
case "tags":
|
case "tags":
|
||||||
setTagIds(itemIDs);
|
setTagIds(itemIDs);
|
||||||
break;
|
break;
|
||||||
case "movies":
|
case "groups":
|
||||||
setMovieIds(itemIDs);
|
setGroupIds(itemIDs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -218,8 +218,8 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
case "tags":
|
case "tags":
|
||||||
setTagMode(newMode);
|
setTagMode(newMode);
|
||||||
break;
|
break;
|
||||||
case "movies":
|
case "groups":
|
||||||
setMovieMode(newMode);
|
setGroupMode(newMode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
@@ -306,11 +306,11 @@ export const EditScenesDialog: React.FC<IListOperationProps> = (
|
|||||||
{renderMultiSelect("tags", tagIds)}
|
{renderMultiSelect("tags", tagIds)}
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group controlId="movies">
|
<Form.Group controlId="groups">
|
||||||
<Form.Label>
|
<Form.Label>
|
||||||
<FormattedMessage id="movies" />
|
<FormattedMessage id="groups" />
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
{renderMultiSelect("movies", movieIds)}
|
{renderMultiSelect("groups", groupIds)}
|
||||||
</Form.Group>
|
</Form.Group>
|
||||||
|
|
||||||
<Form.Group controlId="organized">
|
<Form.Group controlId="organized">
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { Icon } from "../Shared/Icon";
|
|||||||
import {
|
import {
|
||||||
GalleryLink,
|
GalleryLink,
|
||||||
TagLink,
|
TagLink,
|
||||||
MovieLink,
|
GroupLink,
|
||||||
SceneMarkerLink,
|
SceneMarkerLink,
|
||||||
} from "../Shared/TagLink";
|
} from "../Shared/TagLink";
|
||||||
import { HoverPopover } from "../Shared/HoverPopover";
|
import { HoverPopover } from "../Shared/HoverPopover";
|
||||||
@@ -143,24 +143,24 @@ const SceneCardPopovers = PatchComponent(
|
|||||||
return <PerformerPopoverButton performers={props.scene.performers} />;
|
return <PerformerPopoverButton performers={props.scene.performers} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderMoviePopoverButton() {
|
function maybeRenderGroupPopoverButton() {
|
||||||
if (props.scene.movies.length <= 0) return;
|
if (props.scene.movies.length <= 0) return;
|
||||||
|
|
||||||
const popoverContent = props.scene.movies.map((sceneMovie) => (
|
const popoverContent = props.scene.movies.map((sceneGroup) => (
|
||||||
<div className="movie-tag-container row" key="movie">
|
<div className="group-tag-container row" key={sceneGroup.movie.id}>
|
||||||
<Link
|
<Link
|
||||||
to={`/movies/${sceneMovie.movie.id}`}
|
to={`/groups/${sceneGroup.movie.id}`}
|
||||||
className="movie-tag col m-auto zoom-2"
|
className="group-tag col m-auto zoom-2"
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
className="image-thumbnail"
|
className="image-thumbnail"
|
||||||
alt={sceneMovie.movie.name ?? ""}
|
alt={sceneGroup.movie.name ?? ""}
|
||||||
src={sceneMovie.movie.front_image_path ?? ""}
|
src={sceneGroup.movie.front_image_path ?? ""}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
<MovieLink
|
<GroupLink
|
||||||
key={sceneMovie.movie.id}
|
key={sceneGroup.movie.id}
|
||||||
movie={sceneMovie.movie}
|
group={sceneGroup.movie}
|
||||||
className="d-block"
|
className="d-block"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,7 +170,7 @@ const SceneCardPopovers = PatchComponent(
|
|||||||
<HoverPopover
|
<HoverPopover
|
||||||
placement="bottom"
|
placement="bottom"
|
||||||
content={popoverContent}
|
content={popoverContent}
|
||||||
className="movie-count tag-tooltip"
|
className="group-count tag-tooltip"
|
||||||
>
|
>
|
||||||
<Button className="minimal">
|
<Button className="minimal">
|
||||||
<Icon icon={faFilm} />
|
<Icon icon={faFilm} />
|
||||||
@@ -291,7 +291,7 @@ const SceneCardPopovers = PatchComponent(
|
|||||||
<ButtonGroup className="card-popovers">
|
<ButtonGroup className="card-popovers">
|
||||||
{maybeRenderTagPopoverButton()}
|
{maybeRenderTagPopoverButton()}
|
||||||
{maybeRenderPerformerPopoverButton()}
|
{maybeRenderPerformerPopoverButton()}
|
||||||
{maybeRenderMoviePopoverButton()}
|
{maybeRenderGroupPopoverButton()}
|
||||||
{maybeRenderSceneMarkerPopoverButton()}
|
{maybeRenderSceneMarkerPopoverButton()}
|
||||||
{maybeRenderOCounter()}
|
{maybeRenderOCounter()}
|
||||||
{maybeRenderGallery()}
|
{maybeRenderGallery()}
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ const SceneMarkersPanel = lazyComponent(() => import("./SceneMarkersPanel"));
|
|||||||
const SceneFileInfoPanel = lazyComponent(() => import("./SceneFileInfoPanel"));
|
const SceneFileInfoPanel = lazyComponent(() => import("./SceneFileInfoPanel"));
|
||||||
const SceneDetailPanel = lazyComponent(() => import("./SceneDetailPanel"));
|
const SceneDetailPanel = lazyComponent(() => import("./SceneDetailPanel"));
|
||||||
const SceneHistoryPanel = lazyComponent(() => import("./SceneHistoryPanel"));
|
const SceneHistoryPanel = lazyComponent(() => import("./SceneHistoryPanel"));
|
||||||
const SceneMoviePanel = lazyComponent(() => import("./SceneMoviePanel"));
|
const SceneGroupPanel = lazyComponent(() => import("./SceneMoviePanel"));
|
||||||
const SceneGalleriesPanel = lazyComponent(
|
const SceneGalleriesPanel = lazyComponent(
|
||||||
() => import("./SceneGalleriesPanel")
|
() => import("./SceneGalleriesPanel")
|
||||||
);
|
);
|
||||||
@@ -443,9 +443,9 @@ const ScenePage: React.FC<IProps> = ({
|
|||||||
</Nav.Item>
|
</Nav.Item>
|
||||||
{scene.movies.length > 0 ? (
|
{scene.movies.length > 0 ? (
|
||||||
<Nav.Item>
|
<Nav.Item>
|
||||||
<Nav.Link eventKey="scene-movie-panel">
|
<Nav.Link eventKey="scene-group-panel">
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id="countables.movies"
|
id="countables.groups"
|
||||||
values={{ count: scene.movies.length }}
|
values={{ count: scene.movies.length }}
|
||||||
/>
|
/>
|
||||||
</Nav.Link>
|
</Nav.Link>
|
||||||
@@ -514,8 +514,8 @@ const ScenePage: React.FC<IProps> = ({
|
|||||||
isVisible={activeTabKey === "scene-markers-panel"}
|
isVisible={activeTabKey === "scene-markers-panel"}
|
||||||
/>
|
/>
|
||||||
</Tab.Pane>
|
</Tab.Pane>
|
||||||
<Tab.Pane eventKey="scene-movie-panel">
|
<Tab.Pane eventKey="scene-group-panel">
|
||||||
<SceneMoviePanel scene={scene} />
|
<SceneGroupPanel scene={scene} />
|
||||||
</Tab.Pane>
|
</Tab.Pane>
|
||||||
{scene.galleries.length >= 1 && (
|
{scene.galleries.length >= 1 && (
|
||||||
<Tab.Pane eventKey="scene-galleries-panel">
|
<Tab.Pane eventKey="scene-galleries-panel">
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import { useFormik } from "formik";
|
|||||||
import { Prompt } from "react-router-dom";
|
import { Prompt } from "react-router-dom";
|
||||||
import { ConfigurationContext } from "src/hooks/Config";
|
import { ConfigurationContext } from "src/hooks/Config";
|
||||||
import { stashboxDisplayName } from "src/utils/stashbox";
|
import { stashboxDisplayName } from "src/utils/stashbox";
|
||||||
import { IMovieEntry, SceneMovieTable } from "./SceneMovieTable";
|
import { IGroupEntry, SceneGroupTable } from "./SceneMovieTable";
|
||||||
import { faSearch, faSyncAlt } from "@fortawesome/free-solid-svg-icons";
|
import { faSearch, faSyncAlt } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { objectTitle } from "src/core/files";
|
import { objectTitle } from "src/core/files";
|
||||||
import { galleryTitle } from "src/core/galleries";
|
import { galleryTitle } from "src/core/galleries";
|
||||||
@@ -47,7 +47,7 @@ import {
|
|||||||
import { formikUtils } from "src/utils/form";
|
import { formikUtils } from "src/utils/form";
|
||||||
import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
|
import { Studio, StudioSelect } from "src/components/Studios/StudioSelect";
|
||||||
import { Gallery, GallerySelect } from "src/components/Galleries/GallerySelect";
|
import { Gallery, GallerySelect } from "src/components/Galleries/GallerySelect";
|
||||||
import { Movie } from "src/components/Movies/MovieSelect";
|
import { Group } from "src/components/Movies/MovieSelect";
|
||||||
import { useTagsEdit } from "src/hooks/tagsEdit";
|
import { useTagsEdit } from "src/hooks/tagsEdit";
|
||||||
|
|
||||||
const SceneScrapeDialog = lazyComponent(() => import("./SceneScrapeDialog"));
|
const SceneScrapeDialog = lazyComponent(() => import("./SceneScrapeDialog"));
|
||||||
@@ -75,7 +75,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
|
|
||||||
const [galleries, setGalleries] = useState<Gallery[]>([]);
|
const [galleries, setGalleries] = useState<Gallery[]>([]);
|
||||||
const [performers, setPerformers] = useState<Performer[]>([]);
|
const [performers, setPerformers] = useState<Performer[]>([]);
|
||||||
const [movies, setMovies] = useState<Movie[]>([]);
|
const [groups, setGroups] = useState<Group[]>([]);
|
||||||
const [studio, setStudio] = useState<Studio | null>(null);
|
const [studio, setStudio] = useState<Studio | null>(null);
|
||||||
|
|
||||||
const Scrapers = useListSceneScrapers();
|
const Scrapers = useListSceneScrapers();
|
||||||
@@ -104,7 +104,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
}, [scene.performers]);
|
}, [scene.performers]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMovies(scene.movies?.map((m) => m.movie) ?? []);
|
setGroups(scene.movies?.map((m) => m.movie) ?? []);
|
||||||
}, [scene.movies]);
|
}, [scene.movies]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -191,12 +191,12 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
return formik.values.movies
|
return formik.values.movies
|
||||||
.map((m) => {
|
.map((m) => {
|
||||||
return {
|
return {
|
||||||
movie: movies.find((mm) => mm.id === m.movie_id),
|
movie: groups.find((mm) => mm.id === m.movie_id),
|
||||||
scene_index: m.scene_index,
|
scene_index: m.scene_index,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.filter((m) => m.movie !== undefined) as IMovieEntry[];
|
.filter((m) => m.movie !== undefined) as IGroupEntry[];
|
||||||
}, [formik.values.movies, movies]);
|
}, [formik.values.movies, groups]);
|
||||||
|
|
||||||
function onSetGalleries(items: Gallery[]) {
|
function onSetGalleries(items: Gallery[]) {
|
||||||
setGalleries(items);
|
setGalleries(items);
|
||||||
@@ -253,8 +253,8 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
setQueryableScrapers(newQueryableScrapers);
|
setQueryableScrapers(newQueryableScrapers);
|
||||||
}, [Scrapers, stashConfig]);
|
}, [Scrapers, stashConfig]);
|
||||||
|
|
||||||
function onSetMovies(items: Movie[]) {
|
function onSetGroups(items: Group[]) {
|
||||||
setMovies(items);
|
setGroups(items);
|
||||||
|
|
||||||
const existingMovies = formik.values.movies;
|
const existingMovies = formik.values.movies;
|
||||||
|
|
||||||
@@ -386,7 +386,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
sceneStudio={studio}
|
sceneStudio={studio}
|
||||||
sceneTags={tags}
|
sceneTags={tags}
|
||||||
scenePerformers={performers}
|
scenePerformers={performers}
|
||||||
sceneMovies={movies}
|
sceneGroups={groups}
|
||||||
scraped={scrapedScene}
|
scraped={scrapedScene}
|
||||||
endpoint={endpoint}
|
endpoint={endpoint}
|
||||||
onClose={(s) => onScrapeDialogClosed(s)}
|
onClose={(s) => onScrapeDialogClosed(s)}
|
||||||
@@ -574,7 +574,7 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (idMovis.length > 0) {
|
if (idMovis.length > 0) {
|
||||||
onSetMovies(
|
onSetGroups(
|
||||||
idMovis.map((p) => {
|
idMovis.map((p) => {
|
||||||
return {
|
return {
|
||||||
id: p.stored_id!,
|
id: p.stored_id!,
|
||||||
@@ -725,8 +725,8 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
return renderField("performer_ids", title, control, fullWidthProps);
|
return renderField("performer_ids", title, control, fullWidthProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSetMovieEntries(input: IMovieEntry[]) {
|
function onSetMovieEntries(input: IGroupEntry[]) {
|
||||||
setMovies(input.map((m) => m.movie));
|
setGroups(input.map((m) => m.movie));
|
||||||
|
|
||||||
const newMovies = input.map((m) => ({
|
const newMovies = input.map((m) => ({
|
||||||
movie_id: m.movie.id,
|
movie_id: m.movie.id,
|
||||||
@@ -737,9 +737,9 @@ export const SceneEditPanel: React.FC<IProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renderMoviesField() {
|
function renderMoviesField() {
|
||||||
const title = intl.formatMessage({ id: "movies" });
|
const title = intl.formatMessage({ id: "groups" });
|
||||||
const control = (
|
const control = (
|
||||||
<SceneMovieTable value={movieEntries} onUpdate={onSetMovieEntries} />
|
<SceneGroupTable value={movieEntries} onUpdate={onSetMovieEntries} />
|
||||||
);
|
);
|
||||||
|
|
||||||
return renderField("movies", title, control, fullWidthProps);
|
return renderField("movies", title, control, fullWidthProps);
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { MovieCard } from "src/components/Movies/MovieCard";
|
import { GroupCard } from "src/components/Movies/MovieCard";
|
||||||
|
|
||||||
interface ISceneMoviePanelProps {
|
interface ISceneGroupPanelProps {
|
||||||
scene: GQL.SceneDataFragment;
|
scene: GQL.SceneDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SceneMoviePanel: React.FC<ISceneMoviePanelProps> = (
|
export const SceneGroupPanel: React.FC<ISceneGroupPanelProps> = (
|
||||||
props: ISceneMoviePanelProps
|
props: ISceneGroupPanelProps
|
||||||
) => {
|
) => {
|
||||||
const cards = props.scene.movies.map((sceneMovie) => (
|
const cards = props.scene.movies.map((sceneGroup) => (
|
||||||
<MovieCard
|
<GroupCard
|
||||||
key={sceneMovie.movie.id}
|
key={sceneGroup.movie.id}
|
||||||
movie={sceneMovie.movie}
|
group={sceneGroup.movie}
|
||||||
sceneIndex={sceneMovie.scene_index ?? undefined}
|
sceneIndex={sceneGroup.scene_index ?? undefined}
|
||||||
/>
|
/>
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -24,4 +24,4 @@ export const SceneMoviePanel: React.FC<ISceneMoviePanelProps> = (
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default SceneMoviePanel;
|
export default SceneGroupPanel;
|
||||||
|
|||||||
@@ -2,27 +2,27 @@ import React, { useMemo } from "react";
|
|||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { Form, Row, Col } from "react-bootstrap";
|
import { Form, Row, Col } from "react-bootstrap";
|
||||||
import { Movie, MovieSelect } from "src/components/Movies/MovieSelect";
|
import { Group, GroupSelect } from "src/components/Movies/MovieSelect";
|
||||||
import cx from "classnames";
|
import cx from "classnames";
|
||||||
|
|
||||||
export type MovieSceneIndexMap = Map<string, number | undefined>;
|
export type MovieSceneIndexMap = Map<string, number | undefined>;
|
||||||
|
|
||||||
export interface IMovieEntry {
|
export interface IGroupEntry {
|
||||||
movie: Movie;
|
movie: Group;
|
||||||
scene_index?: GQL.InputMaybe<number> | undefined;
|
scene_index?: GQL.InputMaybe<number> | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IProps {
|
export interface IProps {
|
||||||
value: IMovieEntry[];
|
value: IGroupEntry[];
|
||||||
onUpdate: (input: IMovieEntry[]) => void;
|
onUpdate: (input: IGroupEntry[]) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SceneMovieTable: React.FC<IProps> = (props) => {
|
export const SceneGroupTable: React.FC<IProps> = (props) => {
|
||||||
const { value, onUpdate } = props;
|
const { value, onUpdate } = props;
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const movieIDs = useMemo(() => value.map((m) => m.movie.id), [value]);
|
const groupIDs = useMemo(() => value.map((m) => m.movie.id), [value]);
|
||||||
|
|
||||||
const updateFieldChanged = (index: number, sceneIndex: number | null) => {
|
const updateFieldChanged = (index: number, sceneIndex: number | null) => {
|
||||||
const newValues = value.map((existing, i) => {
|
const newValues = value.map((existing, i) => {
|
||||||
@@ -38,21 +38,21 @@ export const SceneMovieTable: React.FC<IProps> = (props) => {
|
|||||||
onUpdate(newValues);
|
onUpdate(newValues);
|
||||||
};
|
};
|
||||||
|
|
||||||
function onMovieSet(index: number, movies: Movie[]) {
|
function onGroupSet(index: number, groups: Group[]) {
|
||||||
if (!movies.length) {
|
if (!groups.length) {
|
||||||
// remove this entry
|
// remove this entry
|
||||||
const newValues = value.filter((_, i) => i !== index);
|
const newValues = value.filter((_, i) => i !== index);
|
||||||
onUpdate(newValues);
|
onUpdate(newValues);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const movie = movies[0];
|
const group = groups[0];
|
||||||
|
|
||||||
const newValues = value.map((existing, i) => {
|
const newValues = value.map((existing, i) => {
|
||||||
if (i === index) {
|
if (i === index) {
|
||||||
return {
|
return {
|
||||||
...existing,
|
...existing,
|
||||||
movie: movie,
|
movie: group,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return existing;
|
return existing;
|
||||||
@@ -61,17 +61,17 @@ export const SceneMovieTable: React.FC<IProps> = (props) => {
|
|||||||
onUpdate(newValues);
|
onUpdate(newValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNewMovieSet(movies: Movie[]) {
|
function onNewGroupSet(groups: Group[]) {
|
||||||
if (!movies.length) {
|
if (!groups.length) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const movie = movies[0];
|
const group = groups[0];
|
||||||
|
|
||||||
const newValues = [
|
const newValues = [
|
||||||
...value,
|
...value,
|
||||||
{
|
{
|
||||||
movie: movie,
|
movie: group,
|
||||||
scene_index: null,
|
scene_index: null,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -83,12 +83,12 @@ export const SceneMovieTable: React.FC<IProps> = (props) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{value.map((m, i) => (
|
{value.map((m, i) => (
|
||||||
<Row key={m.movie.id} className="movie-row">
|
<Row key={m.movie.id} className="group-row">
|
||||||
<Col xs={9}>
|
<Col xs={9}>
|
||||||
<MovieSelect
|
<GroupSelect
|
||||||
onSelect={(items) => onMovieSet(i, items)}
|
onSelect={(items) => onGroupSet(i, items)}
|
||||||
values={[m.movie!]}
|
values={[m.movie!]}
|
||||||
excludeIds={movieIDs}
|
excludeIds={groupIDs}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={3}>
|
<Col xs={3}>
|
||||||
@@ -108,12 +108,12 @@ export const SceneMovieTable: React.FC<IProps> = (props) => {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
))}
|
))}
|
||||||
<Row className="movie-row">
|
<Row className="group-row">
|
||||||
<Col xs={12}>
|
<Col xs={12}>
|
||||||
<MovieSelect
|
<GroupSelect
|
||||||
onSelect={(items) => onNewMovieSet(items)}
|
onSelect={(items) => onNewGroupSet(items)}
|
||||||
values={[]}
|
values={[]}
|
||||||
excludeIds={movieIDs}
|
excludeIds={groupIDs}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@@ -122,11 +122,11 @@ export const SceneMovieTable: React.FC<IProps> = (props) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx("movie-table", { "no-movies": !value.length })}>
|
<div className={cx("group-table", { "no-groups": !value.length })}>
|
||||||
<Row className="movie-table-header">
|
<Row className="group-table-header">
|
||||||
<Col xs={9}></Col>
|
<Col xs={9}></Col>
|
||||||
<Form.Label column xs={3} className="movie-scene-number-header">
|
<Form.Label column xs={3} className="group-scene-number-header">
|
||||||
{intl.formatMessage({ id: "movie_scene_number" })}
|
{intl.formatMessage({ id: "group_scene_number" })}
|
||||||
</Form.Label>
|
</Form.Label>
|
||||||
</Row>
|
</Row>
|
||||||
{renderTableData()}
|
{renderTableData()}
|
||||||
|
|||||||
@@ -17,18 +17,18 @@ import {
|
|||||||
ScrapeResult,
|
ScrapeResult,
|
||||||
} from "src/components/Shared/ScrapeDialog/scrapeResult";
|
} from "src/components/Shared/ScrapeDialog/scrapeResult";
|
||||||
import {
|
import {
|
||||||
ScrapedMoviesRow,
|
ScrapedGroupsRow,
|
||||||
ScrapedPerformersRow,
|
ScrapedPerformersRow,
|
||||||
ScrapedStudioRow,
|
ScrapedStudioRow,
|
||||||
} from "src/components/Shared/ScrapeDialog/ScrapedObjectsRow";
|
} from "src/components/Shared/ScrapeDialog/ScrapedObjectsRow";
|
||||||
import {
|
import {
|
||||||
useCreateScrapedMovie,
|
useCreateScrapedGroup,
|
||||||
useCreateScrapedPerformer,
|
useCreateScrapedPerformer,
|
||||||
useCreateScrapedStudio,
|
useCreateScrapedStudio,
|
||||||
} from "src/components/Shared/ScrapeDialog/createObjects";
|
} from "src/components/Shared/ScrapeDialog/createObjects";
|
||||||
import { Tag } from "src/components/Tags/TagSelect";
|
import { Tag } from "src/components/Tags/TagSelect";
|
||||||
import { Studio } from "src/components/Studios/StudioSelect";
|
import { Studio } from "src/components/Studios/StudioSelect";
|
||||||
import { Movie } from "src/components/Movies/MovieSelect";
|
import { Group } from "src/components/Movies/MovieSelect";
|
||||||
import { useScrapedTags } from "src/components/Shared/ScrapeDialog/scrapedTags";
|
import { useScrapedTags } from "src/components/Shared/ScrapeDialog/scrapedTags";
|
||||||
|
|
||||||
interface ISceneScrapeDialogProps {
|
interface ISceneScrapeDialogProps {
|
||||||
@@ -36,7 +36,7 @@ interface ISceneScrapeDialogProps {
|
|||||||
sceneStudio: Studio | null;
|
sceneStudio: Studio | null;
|
||||||
scenePerformers: Performer[];
|
scenePerformers: Performer[];
|
||||||
sceneTags: Tag[];
|
sceneTags: Tag[];
|
||||||
sceneMovies: Movie[];
|
sceneGroups: Group[];
|
||||||
scraped: GQL.ScrapedScene;
|
scraped: GQL.ScrapedScene;
|
||||||
endpoint?: string;
|
endpoint?: string;
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
sceneStudio,
|
sceneStudio,
|
||||||
scenePerformers,
|
scenePerformers,
|
||||||
sceneTags,
|
sceneTags,
|
||||||
sceneMovies,
|
sceneGroups,
|
||||||
scraped,
|
scraped,
|
||||||
onClose,
|
onClose,
|
||||||
endpoint,
|
endpoint,
|
||||||
@@ -114,12 +114,12 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
scraped.performers?.filter((t) => !t.stored_id) ?? []
|
scraped.performers?.filter((t) => !t.stored_id) ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
const [movies, setMovies] = useState<
|
const [groups, setGroups] = useState<
|
||||||
ObjectListScrapeResult<GQL.ScrapedMovie>
|
ObjectListScrapeResult<GQL.ScrapedMovie>
|
||||||
>(
|
>(
|
||||||
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
||||||
sortStoredIdObjects(
|
sortStoredIdObjects(
|
||||||
sceneMovies.map((p) => ({
|
sceneGroups.map((p) => ({
|
||||||
stored_id: p.id,
|
stored_id: p.id,
|
||||||
name: p.name,
|
name: p.name,
|
||||||
}))
|
}))
|
||||||
@@ -127,7 +127,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
sortStoredIdObjects(scraped.movies ?? undefined)
|
sortStoredIdObjects(scraped.movies ?? undefined)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
const [newMovies, setNewMovies] = useState<GQL.ScrapedMovie[]>(
|
const [newGroups, setNewGroups] = useState<GQL.ScrapedMovie[]>(
|
||||||
scraped.movies?.filter((t) => !t.stored_id) ?? []
|
scraped.movies?.filter((t) => !t.stored_id) ?? []
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -157,11 +157,11 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
setNewObjects: setNewPerformers,
|
setNewObjects: setNewPerformers,
|
||||||
});
|
});
|
||||||
|
|
||||||
const createNewMovie = useCreateScrapedMovie({
|
const createNewGroup = useCreateScrapedGroup({
|
||||||
scrapeResult: movies,
|
scrapeResult: groups,
|
||||||
setScrapeResult: setMovies,
|
setScrapeResult: setGroups,
|
||||||
newObjects: newMovies,
|
newObjects: newGroups,
|
||||||
setNewObjects: setNewMovies,
|
setNewObjects: setNewGroups,
|
||||||
});
|
});
|
||||||
|
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
@@ -176,7 +176,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
director,
|
director,
|
||||||
studio,
|
studio,
|
||||||
performers,
|
performers,
|
||||||
movies,
|
groups,
|
||||||
tags,
|
tags,
|
||||||
details,
|
details,
|
||||||
image,
|
image,
|
||||||
@@ -184,7 +184,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
].every((r) => !r.scraped) &&
|
].every((r) => !r.scraped) &&
|
||||||
newTags.length === 0 &&
|
newTags.length === 0 &&
|
||||||
newPerformers.length === 0 &&
|
newPerformers.length === 0 &&
|
||||||
newMovies.length === 0 &&
|
newGroups.length === 0 &&
|
||||||
!newStudio
|
!newStudio
|
||||||
) {
|
) {
|
||||||
onClose();
|
onClose();
|
||||||
@@ -202,7 +202,7 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
director: director.getNewValue(),
|
director: director.getNewValue(),
|
||||||
studio: newStudioValue,
|
studio: newStudioValue,
|
||||||
performers: performers.getNewValue(),
|
performers: performers.getNewValue(),
|
||||||
movies: movies.getNewValue(),
|
movies: groups.getNewValue(),
|
||||||
tags: tags.getNewValue(),
|
tags: tags.getNewValue(),
|
||||||
details: details.getNewValue(),
|
details: details.getNewValue(),
|
||||||
image: image.getNewValue(),
|
image: image.getNewValue(),
|
||||||
@@ -253,12 +253,12 @@ export const SceneScrapeDialog: React.FC<ISceneScrapeDialogProps> = ({
|
|||||||
newObjects={newPerformers}
|
newObjects={newPerformers}
|
||||||
onCreateNew={createNewPerformer}
|
onCreateNew={createNewPerformer}
|
||||||
/>
|
/>
|
||||||
<ScrapedMoviesRow
|
<ScrapedGroupsRow
|
||||||
title={intl.formatMessage({ id: "movies" })}
|
title={intl.formatMessage({ id: "groups" })}
|
||||||
result={movies}
|
result={groups}
|
||||||
onChange={(value) => setMovies(value)}
|
onChange={(value) => setGroups(value)}
|
||||||
newObjects={newMovies}
|
newObjects={newGroups}
|
||||||
onCreateNew={createNewMovie}
|
onCreateNew={createNewGroup}
|
||||||
/>
|
/>
|
||||||
{scrapedTagsRow}
|
{scrapedTagsRow}
|
||||||
<ScrapedTextAreaRow
|
<ScrapedTextAreaRow
|
||||||
|
|||||||
@@ -124,12 +124,12 @@ export const SceneListTable: React.FC<ISceneListTableProps> = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const MovieCell = (scene: GQL.SlimSceneDataFragment) => (
|
const GroupCell = (scene: GQL.SlimSceneDataFragment) => (
|
||||||
<ul className="comma-list overflowable">
|
<ul className="comma-list overflowable">
|
||||||
{scene.movies.map((sceneMovie) => (
|
{scene.movies.map((sceneGroup) => (
|
||||||
<li key={sceneMovie.movie.id}>
|
<li key={sceneGroup.movie.id}>
|
||||||
<Link to={NavUtils.makeMovieScenesUrl(sceneMovie.movie)}>
|
<Link to={NavUtils.makeGroupScenesUrl(sceneGroup.movie)}>
|
||||||
<span className="ellips-data">{sceneMovie.movie.name}</span>
|
<span className="ellips-data">{sceneGroup.movie.name}</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
@@ -322,10 +322,10 @@ export const SceneListTable: React.FC<ISceneListTableProps> = (
|
|||||||
render: TagCell,
|
render: TagCell,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "movies",
|
value: "groups",
|
||||||
label: intl.formatMessage({ id: "movies" }),
|
label: intl.formatMessage({ id: "groups" }),
|
||||||
defaultShow: true,
|
defaultShow: true,
|
||||||
render: MovieCell,
|
render: GroupCell,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "galleries",
|
value: "galleries",
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import {
|
|||||||
hasScrapedValues,
|
hasScrapedValues,
|
||||||
} from "../Shared/ScrapeDialog/scrapeResult";
|
} from "../Shared/ScrapeDialog/scrapeResult";
|
||||||
import {
|
import {
|
||||||
ScrapedMoviesRow,
|
ScrapedGroupsRow,
|
||||||
ScrapedPerformersRow,
|
ScrapedPerformersRow,
|
||||||
ScrapedStudioRow,
|
ScrapedStudioRow,
|
||||||
ScrapedTagsRow,
|
ScrapedTagsRow,
|
||||||
@@ -100,7 +100,7 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function movieToStoredID(o: { movie: { id: string; name: string } }) {
|
function groupToStoredID(o: { movie: { id: string; name: string } }) {
|
||||||
return {
|
return {
|
||||||
stored_id: o.movie.id,
|
stored_id: o.movie.id,
|
||||||
name: o.movie.name,
|
name: o.movie.name,
|
||||||
@@ -141,11 +141,11 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
const [movies, setMovies] = useState<
|
const [groups, setGroups] = useState<
|
||||||
ObjectListScrapeResult<GQL.ScrapedMovie>
|
ObjectListScrapeResult<GQL.ScrapedMovie>
|
||||||
>(
|
>(
|
||||||
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
||||||
sortStoredIdObjects(dest.movies.map(movieToStoredID))
|
sortStoredIdObjects(dest.movies.map(groupToStoredID))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -252,10 +252,10 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
setMovies(
|
setGroups(
|
||||||
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
new ObjectListScrapeResult<GQL.ScrapedMovie>(
|
||||||
sortStoredIdObjects(dest.movies.map(movieToStoredID)),
|
sortStoredIdObjects(dest.movies.map(groupToStoredID)),
|
||||||
uniqIDStoredIDs(all.map((s) => s.movies.map(movieToStoredID)).flat())
|
uniqIDStoredIDs(all.map((s) => s.movies.map(groupToStoredID)).flat())
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
galleries,
|
galleries,
|
||||||
studio,
|
studio,
|
||||||
performers,
|
performers,
|
||||||
movies,
|
groups,
|
||||||
tags,
|
tags,
|
||||||
details,
|
details,
|
||||||
organized,
|
organized,
|
||||||
@@ -348,7 +348,7 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
galleries,
|
galleries,
|
||||||
studio,
|
studio,
|
||||||
performers,
|
performers,
|
||||||
movies,
|
groups,
|
||||||
tags,
|
tags,
|
||||||
details,
|
details,
|
||||||
organized,
|
organized,
|
||||||
@@ -508,10 +508,10 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
result={performers}
|
result={performers}
|
||||||
onChange={(value) => setPerformers(value)}
|
onChange={(value) => setPerformers(value)}
|
||||||
/>
|
/>
|
||||||
<ScrapedMoviesRow
|
<ScrapedGroupsRow
|
||||||
title={intl.formatMessage({ id: "movies" })}
|
title={intl.formatMessage({ id: "groups" })}
|
||||||
result={movies}
|
result={groups}
|
||||||
onChange={(value) => setMovies(value)}
|
onChange={(value) => setGroups(value)}
|
||||||
/>
|
/>
|
||||||
<ScrapedTagsRow
|
<ScrapedTagsRow
|
||||||
title={intl.formatMessage({ id: "tags" })}
|
title={intl.formatMessage({ id: "tags" })}
|
||||||
@@ -585,7 +585,7 @@ const SceneMergeDetails: React.FC<ISceneMergeDetailsProps> = ({
|
|||||||
gallery_ids: galleries.getNewValue(),
|
gallery_ids: galleries.getNewValue(),
|
||||||
studio_id: studio.getNewValue()?.stored_id,
|
studio_id: studio.getNewValue()?.stored_id,
|
||||||
performer_ids: performers.getNewValue()?.map((p) => p.stored_id!),
|
performer_ids: performers.getNewValue()?.map((p) => p.stored_id!),
|
||||||
movies: movies.getNewValue()?.map((m) => {
|
movies: groups.getNewValue()?.map((m) => {
|
||||||
// find the equivalent movie in the original scenes
|
// find the equivalent movie in the original scenes
|
||||||
const found = all
|
const found = all
|
||||||
.map((s) => s.movies)
|
.map((s) => s.movies)
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.performer-tag-container,
|
.performer-tag-container,
|
||||||
.movie-tag-container {
|
.group-tag-container {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.performer-tag.image,
|
.performer-tag.image,
|
||||||
.movie-tag.image {
|
.group-tag.image {
|
||||||
background-position: center;
|
background-position: center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
@@ -288,19 +288,19 @@ textarea.scene-description {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-image {
|
.group-image {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-table {
|
.group-table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.movie-row {
|
.group-row {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-scene-number-header {
|
.group-scene-number-header {
|
||||||
color: $text-muted;
|
color: $text-muted;
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
@@ -308,7 +308,7 @@ textarea.scene-description {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-table.no-movies .movie-table-header {
|
.group-table.no-groups .group-table-header {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useCallback, useMemo } from "react";
|
||||||
import { Button, Form } from "react-bootstrap";
|
import { Button, Form } from "react-bootstrap";
|
||||||
import { FormattedMessage, useIntl } from "react-intl";
|
import { FormattedMessage, useIntl } from "react-intl";
|
||||||
import { DurationInput } from "src/components/Shared/DurationInput";
|
import { DurationInput } from "src/components/Shared/DurationInput";
|
||||||
@@ -47,7 +47,7 @@ import { defaultMaxOptionsShown } from "src/core/config";
|
|||||||
const allMenuItems = [
|
const allMenuItems = [
|
||||||
{ id: "scenes", headingID: "scenes" },
|
{ id: "scenes", headingID: "scenes" },
|
||||||
{ id: "images", headingID: "images" },
|
{ id: "images", headingID: "images" },
|
||||||
{ id: "movies", headingID: "movies" },
|
{ id: "groups", headingID: "groups" },
|
||||||
{ id: "markers", headingID: "markers" },
|
{ id: "markers", headingID: "markers" },
|
||||||
{ id: "galleries", headingID: "galleries" },
|
{ id: "galleries", headingID: "galleries" },
|
||||||
{ id: "performers", headingID: "performers" },
|
{ id: "performers", headingID: "performers" },
|
||||||
@@ -67,6 +67,22 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
error,
|
error,
|
||||||
} = useSettings();
|
} = useSettings();
|
||||||
|
|
||||||
|
// convert old movies menu item to groups
|
||||||
|
const massageMenuItems = useCallback((menuItems: string[]) => {
|
||||||
|
return menuItems.map((item) => {
|
||||||
|
if (item === "movies") {
|
||||||
|
return "groups";
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const massagedMenuItems = useMemo(() => {
|
||||||
|
if (!iface.menuItems) return iface.menuItems;
|
||||||
|
|
||||||
|
return massageMenuItems(iface.menuItems);
|
||||||
|
}, [iface.menuItems, massageMenuItems]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
interactive,
|
interactive,
|
||||||
state: interactiveState,
|
state: interactiveState,
|
||||||
@@ -231,8 +247,8 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
<CheckboxGroup
|
<CheckboxGroup
|
||||||
groupId="menu-items"
|
groupId="menu-items"
|
||||||
items={allMenuItems}
|
items={allMenuItems}
|
||||||
checkedIds={iface.menuItems ?? undefined}
|
checkedIds={massagedMenuItems ?? undefined}
|
||||||
onChange={(v) => saveInterface({ menuItems: v })}
|
onChange={(v) => saveInterface({ menuItems: massageMenuItems(v) })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -563,7 +579,7 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
<BooleanSetting
|
<BooleanSetting
|
||||||
id="enableMovieBackgroundImage"
|
id="enableMovieBackgroundImage"
|
||||||
headingID="movie"
|
headingID="group"
|
||||||
checked={ui.enableMovieBackgroundImage ?? undefined}
|
checked={ui.enableMovieBackgroundImage ?? undefined}
|
||||||
onChange={(v) => saveUI({ enableMovieBackgroundImage: v })}
|
onChange={(v) => saveUI({ enableMovieBackgroundImage: v })}
|
||||||
/>
|
/>
|
||||||
@@ -659,8 +675,8 @@ export const SettingsInterfacePanel: React.FC = () => {
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<BooleanSetting
|
<BooleanSetting
|
||||||
id="disableDropdownCreate_movie"
|
id="disableDropdownCreate_group"
|
||||||
headingID="movie"
|
headingID="group"
|
||||||
checked={iface.disableDropdownCreate?.movie ?? undefined}
|
checked={iface.disableDropdownCreate?.movie ?? undefined}
|
||||||
onChange={(v) =>
|
onChange={(v) =>
|
||||||
saveInterface({
|
saveInterface({
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
useListSceneScrapers();
|
useListSceneScrapers();
|
||||||
const { data: galleryScrapers, loading: loadingGalleries } =
|
const { data: galleryScrapers, loading: loadingGalleries } =
|
||||||
useListGalleryScrapers();
|
useListGalleryScrapers();
|
||||||
const { data: movieScrapers, loading: loadingMovies } =
|
const { data: groupScrapers, loading: loadingGroups } =
|
||||||
useListMovieScrapers();
|
useListMovieScrapers();
|
||||||
|
|
||||||
const { general, scraping, loading, error, saveGeneral, saveScraping } =
|
const { general, scraping, loading, error, saveGeneral, saveScraping } =
|
||||||
@@ -158,13 +158,13 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMovieScrapeTypes(types: ScrapeType[]) {
|
function renderGroupScrapeTypes(types: ScrapeType[]) {
|
||||||
const typeStrings = types.map((t) => {
|
const typeStrings = types.map((t) => {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
case ScrapeType.Fragment:
|
case ScrapeType.Fragment:
|
||||||
return intl.formatMessage(
|
return intl.formatMessage(
|
||||||
{ id: "config.scraping.entity_metadata" },
|
{ id: "config.scraping.entity_metadata" },
|
||||||
{ entityType: intl.formatMessage({ id: "movie" }) }
|
{ entityType: intl.formatMessage({ id: "group" }) }
|
||||||
);
|
);
|
||||||
default:
|
default:
|
||||||
return t;
|
return t;
|
||||||
@@ -246,12 +246,12 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderMovieScrapers() {
|
function renderGroupScrapers() {
|
||||||
const elements = (movieScrapers?.listScrapers ?? []).map((scraper) => (
|
const elements = (groupScrapers?.listScrapers ?? []).map((scraper) => (
|
||||||
<tr key={scraper.id}>
|
<tr key={scraper.id}>
|
||||||
<td>{scraper.name}</td>
|
<td>{scraper.name}</td>
|
||||||
<td>
|
<td>
|
||||||
{renderMovieScrapeTypes(scraper.movie?.supported_scrapes ?? [])}
|
{renderGroupScrapeTypes(scraper.movie?.supported_scrapes ?? [])}
|
||||||
</td>
|
</td>
|
||||||
<td>{renderURLs(scraper.movie?.urls ?? [])}</td>
|
<td>{renderURLs(scraper.movie?.urls ?? [])}</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -260,7 +260,7 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
return renderTable(
|
return renderTable(
|
||||||
intl.formatMessage(
|
intl.formatMessage(
|
||||||
{ id: "config.scraping.entity_scrapers" },
|
{ id: "config.scraping.entity_scrapers" },
|
||||||
{ entityType: intl.formatMessage({ id: "movie" }) }
|
{ entityType: intl.formatMessage({ id: "group" }) }
|
||||||
),
|
),
|
||||||
elements
|
elements
|
||||||
);
|
);
|
||||||
@@ -297,7 +297,7 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
loadingScenes ||
|
loadingScenes ||
|
||||||
loadingGalleries ||
|
loadingGalleries ||
|
||||||
loadingPerformers ||
|
loadingPerformers ||
|
||||||
loadingMovies
|
loadingGroups
|
||||||
)
|
)
|
||||||
return <LoadingIndicator />;
|
return <LoadingIndicator />;
|
||||||
|
|
||||||
@@ -361,7 +361,7 @@ export const SettingsScrapingPanel: React.FC = () => {
|
|||||||
{renderSceneScrapers()}
|
{renderSceneScrapers()}
|
||||||
{renderGalleryScrapers()}
|
{renderGalleryScrapers()}
|
||||||
{renderPerformerScrapers()}
|
{renderPerformerScrapers()}
|
||||||
{renderMovieScrapers()}
|
{renderGroupScrapers()}
|
||||||
</div>
|
</div>
|
||||||
</SettingSection>
|
</SettingSection>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -6,14 +6,14 @@ import NavUtils from "src/utils/navigation";
|
|||||||
|
|
||||||
export const DirectorLink: React.FC<{
|
export const DirectorLink: React.FC<{
|
||||||
director: string;
|
director: string;
|
||||||
linkType: "scene" | "movie";
|
linkType: "scene" | "group";
|
||||||
}> = ({ director: director, linkType = "scene" }) => {
|
}> = ({ director: director, linkType = "scene" }) => {
|
||||||
const link = useMemo(() => {
|
const link = useMemo(() => {
|
||||||
switch (linkType) {
|
switch (linkType) {
|
||||||
case "scene":
|
case "scene":
|
||||||
return NavUtils.makeDirectorScenesUrl(director);
|
return NavUtils.makeDirectorScenesUrl(director);
|
||||||
case "movie":
|
case "group":
|
||||||
return NavUtils.makeDirectorMoviesUrl(director);
|
return NavUtils.makeDirectorGroupsUrl(director);
|
||||||
}
|
}
|
||||||
}, [director, linkType]);
|
}, [director, linkType]);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
} from "../Galleries/GallerySelect";
|
} from "../Galleries/GallerySelect";
|
||||||
|
|
||||||
interface IMultiSetProps {
|
interface IMultiSetProps {
|
||||||
type: "performers" | "studios" | "tags" | "movies" | "galleries";
|
type: "performers" | "studios" | "tags" | "groups" | "galleries";
|
||||||
existingIds?: string[];
|
existingIds?: string[];
|
||||||
ids?: string[];
|
ids?: string[];
|
||||||
mode: GQL.BulkUpdateIdMode;
|
mode: GQL.BulkUpdateIdMode;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type PopoverLinkType =
|
|||||||
| "image"
|
| "image"
|
||||||
| "gallery"
|
| "gallery"
|
||||||
| "marker"
|
| "marker"
|
||||||
| "movie"
|
| "group"
|
||||||
| "performer"
|
| "performer"
|
||||||
| "studio";
|
| "studio";
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ export const PopoverCountButton: React.FC<IProps> = ({
|
|||||||
return faImages;
|
return faImages;
|
||||||
case "marker":
|
case "marker":
|
||||||
return faMapMarkerAlt;
|
return faMapMarkerAlt;
|
||||||
case "movie":
|
case "group":
|
||||||
return faFilm;
|
return faFilm;
|
||||||
case "performer":
|
case "performer":
|
||||||
return faUser;
|
return faUser;
|
||||||
@@ -83,10 +83,10 @@ export const PopoverCountButton: React.FC<IProps> = ({
|
|||||||
one: "marker",
|
one: "marker",
|
||||||
other: "markers",
|
other: "markers",
|
||||||
};
|
};
|
||||||
case "movie":
|
case "group":
|
||||||
return {
|
return {
|
||||||
one: "movie",
|
one: "group",
|
||||||
other: "movies",
|
other: "groups",
|
||||||
};
|
};
|
||||||
case "performer":
|
case "performer":
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
} from "src/components/Shared/ScrapeDialog/scrapeResult";
|
} from "src/components/Shared/ScrapeDialog/scrapeResult";
|
||||||
import { TagSelect } from "src/components/Tags/TagSelect";
|
import { TagSelect } from "src/components/Tags/TagSelect";
|
||||||
import { StudioSelect } from "src/components/Studios/StudioSelect";
|
import { StudioSelect } from "src/components/Studios/StudioSelect";
|
||||||
import { MovieSelect } from "src/components/Movies/MovieSelect";
|
import { GroupSelect } from "src/components/Movies/MovieSelect";
|
||||||
|
|
||||||
interface IScrapedStudioRow {
|
interface IScrapedStudioRow {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -196,10 +196,10 @@ export const ScrapedPerformersRow: React.FC<
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScrapedMoviesRow: React.FC<
|
export const ScrapedGroupsRow: React.FC<
|
||||||
IScrapedObjectRowImpl<GQL.ScrapedMovie>
|
IScrapedObjectRowImpl<GQL.ScrapedMovie>
|
||||||
> = ({ title, result, onChange, newObjects, onCreateNew }) => {
|
> = ({ title, result, onChange, newObjects, onCreateNew }) => {
|
||||||
const moviesCopy = useMemo(() => {
|
const groupsCopy = useMemo(() => {
|
||||||
return (
|
return (
|
||||||
newObjects?.map((p) => {
|
newObjects?.map((p) => {
|
||||||
const name: string = p.name ?? "";
|
const name: string = p.name ?? "";
|
||||||
@@ -208,7 +208,7 @@ export const ScrapedMoviesRow: React.FC<
|
|||||||
);
|
);
|
||||||
}, [newObjects]);
|
}, [newObjects]);
|
||||||
|
|
||||||
function renderScrapedMovies(
|
function renderScrapedGroups(
|
||||||
scrapeResult: ScrapeResult<GQL.ScrapedMovie[]>,
|
scrapeResult: ScrapeResult<GQL.ScrapedMovie[]>,
|
||||||
isNew?: boolean,
|
isNew?: boolean,
|
||||||
onChangeFn?: (value: GQL.ScrapedMovie[]) => void
|
onChangeFn?: (value: GQL.ScrapedMovie[]) => void
|
||||||
@@ -228,7 +228,7 @@ export const ScrapedMoviesRow: React.FC<
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<MovieSelect
|
<GroupSelect
|
||||||
isMulti
|
isMulti
|
||||||
className="form-control react-select"
|
className="form-control react-select"
|
||||||
isDisabled={!isNew}
|
isDisabled={!isNew}
|
||||||
@@ -247,9 +247,9 @@ export const ScrapedMoviesRow: React.FC<
|
|||||||
<ScrapedObjectsRow<GQL.ScrapedMovie>
|
<ScrapedObjectsRow<GQL.ScrapedMovie>
|
||||||
title={title}
|
title={title}
|
||||||
result={result}
|
result={result}
|
||||||
renderObjects={renderScrapedMovies}
|
renderObjects={renderScrapedGroups}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
newObjects={moviesCopy}
|
newObjects={groupsCopy}
|
||||||
onCreateNew={onCreateNew}
|
onCreateNew={onCreateNew}
|
||||||
getName={(value) => value.name ?? ""}
|
getName={(value) => value.name ?? ""}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
import { ObjectScrapeResult, ScrapeResult } from "./scrapeResult";
|
import { ObjectScrapeResult, ScrapeResult } from "./scrapeResult";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { scrapedPerformerToCreateInput } from "src/core/performers";
|
import { scrapedPerformerToCreateInput } from "src/core/performers";
|
||||||
import { scrapedMovieToCreateInput } from "src/core/movies";
|
import { scrapedGroupToCreateInput } from "src/core/movies";
|
||||||
|
|
||||||
function useCreateObject<T>(
|
function useCreateObject<T>(
|
||||||
entityTypeID: string,
|
entityTypeID: string,
|
||||||
@@ -123,16 +123,16 @@ export function useCreateScrapedPerformer(
|
|||||||
return useCreateObject("performer", createNewPerformer);
|
return useCreateObject("performer", createNewPerformer);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCreateScrapedMovie(
|
export function useCreateScrapedGroup(
|
||||||
props: IUseCreateNewObjectProps<GQL.ScrapedMovie>
|
props: IUseCreateNewObjectProps<GQL.ScrapedMovie>
|
||||||
) {
|
) {
|
||||||
const { scrapeResult, setScrapeResult, newObjects, setNewObjects } = props;
|
const { scrapeResult, setScrapeResult, newObjects, setNewObjects } = props;
|
||||||
const [createMovie] = useMovieCreate();
|
const [createGroup] = useMovieCreate();
|
||||||
|
|
||||||
async function createNewMovie(toCreate: GQL.ScrapedMovie) {
|
async function createNewGroup(toCreate: GQL.ScrapedMovie) {
|
||||||
const input = scrapedMovieToCreateInput(toCreate);
|
const input = scrapedGroupToCreateInput(toCreate);
|
||||||
|
|
||||||
const result = await createMovie({
|
const result = await createGroup({
|
||||||
variables: { input: input },
|
variables: { input: input },
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -150,14 +150,14 @@ export function useCreateScrapedMovie(
|
|||||||
// remove the object from the list
|
// remove the object from the list
|
||||||
const newObjectsClone = newObjects.concat();
|
const newObjectsClone = newObjects.concat();
|
||||||
const pIndex = newObjectsClone.findIndex((p) => p.name === toCreate.name);
|
const pIndex = newObjectsClone.findIndex((p) => p.name === toCreate.name);
|
||||||
if (pIndex === -1) throw new Error("Could not find movie to remove");
|
if (pIndex === -1) throw new Error("Could not find group to remove");
|
||||||
|
|
||||||
newObjectsClone.splice(pIndex, 1);
|
newObjectsClone.splice(pIndex, 1);
|
||||||
|
|
||||||
setNewObjects(newObjectsClone);
|
setNewObjects(newObjectsClone);
|
||||||
}
|
}
|
||||||
|
|
||||||
return useCreateObject("movie", createNewMovie);
|
return useCreateObject("group", createNewGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCreateScrapedTag(
|
export function useCreateScrapedTag(
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import { faTableColumns } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import { TagIDSelect } from "../Tags/TagSelect";
|
import { TagIDSelect } from "../Tags/TagSelect";
|
||||||
import { StudioIDSelect } from "../Studios/StudioSelect";
|
import { StudioIDSelect } from "../Studios/StudioSelect";
|
||||||
import { GalleryIDSelect } from "../Galleries/GallerySelect";
|
import { GalleryIDSelect } from "../Galleries/GallerySelect";
|
||||||
import { MovieIDSelect } from "../Movies/MovieSelect";
|
import { GroupIDSelect } from "../Movies/MovieSelect";
|
||||||
import { SceneIDSelect } from "../Scenes/SceneSelect";
|
import { SceneIDSelect } from "../Scenes/SceneSelect";
|
||||||
|
|
||||||
export type SelectObject = {
|
export type SelectObject = {
|
||||||
@@ -44,7 +44,7 @@ interface ITypeProps {
|
|||||||
| "scene_tags"
|
| "scene_tags"
|
||||||
| "performer_tags"
|
| "performer_tags"
|
||||||
| "scenes"
|
| "scenes"
|
||||||
| "movies"
|
| "groups"
|
||||||
| "galleries";
|
| "galleries";
|
||||||
}
|
}
|
||||||
interface IFilterProps {
|
interface IFilterProps {
|
||||||
@@ -364,8 +364,8 @@ export const StudioSelect: React.FC<
|
|||||||
return <StudioIDSelect {...props} />;
|
return <StudioIDSelect {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const MovieSelect: React.FC<IFilterProps> = (props) => {
|
export const GroupSelect: React.FC<IFilterProps> = (props) => {
|
||||||
return <MovieIDSelect {...props} />;
|
return <GroupIDSelect {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TagSelect: React.FC<
|
export const TagSelect: React.FC<
|
||||||
@@ -382,8 +382,8 @@ export const FilterSelect: React.FC<IFilterProps & ITypeProps> = (props) => {
|
|||||||
return <StudioSelect {...props} creatable={false} />;
|
return <StudioSelect {...props} creatable={false} />;
|
||||||
case "scenes":
|
case "scenes":
|
||||||
return <SceneSelect {...props} creatable={false} />;
|
return <SceneSelect {...props} creatable={false} />;
|
||||||
case "movies":
|
case "groups":
|
||||||
return <MovieSelect {...props} creatable={false} />;
|
return <GroupSelect {...props} creatable={false} />;
|
||||||
case "galleries":
|
case "galleries":
|
||||||
return <GallerySelect {...props} />;
|
return <GallerySelect {...props} />;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -71,25 +71,25 @@ export const PerformerLink: React.FC<IPerformerLinkProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IMovieLinkProps {
|
interface IGroupLinkProps {
|
||||||
movie: INamedObject;
|
group: INamedObject;
|
||||||
linkType?: "scene";
|
linkType?: "scene";
|
||||||
className?: string;
|
className?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MovieLink: React.FC<IMovieLinkProps> = ({
|
export const GroupLink: React.FC<IGroupLinkProps> = ({
|
||||||
movie,
|
group,
|
||||||
linkType = "scene",
|
linkType = "scene",
|
||||||
className,
|
className,
|
||||||
}) => {
|
}) => {
|
||||||
const link = useMemo(() => {
|
const link = useMemo(() => {
|
||||||
switch (linkType) {
|
switch (linkType) {
|
||||||
case "scene":
|
case "scene":
|
||||||
return NavUtils.makeMovieScenesUrl(movie);
|
return NavUtils.makeGroupScenesUrl(group);
|
||||||
}
|
}
|
||||||
}, [movie, linkType]);
|
}, [group, linkType]);
|
||||||
|
|
||||||
const title = movie.name || "";
|
const title = group.name || "";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommonLinkComponent link={link} className={className}>
|
<CommonLinkComponent link={link} className={className}>
|
||||||
@@ -197,7 +197,7 @@ interface ITagLinkProps {
|
|||||||
| "image"
|
| "image"
|
||||||
| "details"
|
| "details"
|
||||||
| "performer"
|
| "performer"
|
||||||
| "movie"
|
| "group"
|
||||||
| "studio";
|
| "studio";
|
||||||
className?: string;
|
className?: string;
|
||||||
hoverPlacement?: Placement;
|
hoverPlacement?: Placement;
|
||||||
@@ -225,8 +225,8 @@ export const TagLink: React.FC<ITagLinkProps> = ({
|
|||||||
return NavUtils.makeTagGalleriesUrl(tag);
|
return NavUtils.makeTagGalleriesUrl(tag);
|
||||||
case "image":
|
case "image":
|
||||||
return NavUtils.makeTagImagesUrl(tag);
|
return NavUtils.makeTagImagesUrl(tag);
|
||||||
case "movie":
|
case "group":
|
||||||
return NavUtils.makeTagMoviesUrl(tag);
|
return NavUtils.makeTagGroupsUrl(tag);
|
||||||
case "details":
|
case "details":
|
||||||
return NavUtils.makeTagUrl(tag.id ?? "");
|
return NavUtils.makeTagUrl(tag.id ?? "");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export const Stats: React.FC = () => {
|
|||||||
<FormattedNumber value={data.stats.movie_count} />
|
<FormattedNumber value={data.stats.movie_count} />
|
||||||
</p>
|
</p>
|
||||||
<p className="heading">
|
<p className="heading">
|
||||||
<FormattedMessage id="movies" />
|
<FormattedMessage id="groups" />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="stats-element">
|
<div className="stats-element">
|
||||||
|
|||||||
@@ -142,15 +142,15 @@ export const StudioCard: React.FC<IProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderMoviesPopoverButton() {
|
function maybeRenderGroupsPopoverButton() {
|
||||||
if (!studio.movie_count) return;
|
if (!studio.movie_count) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverCountButton
|
<PopoverCountButton
|
||||||
className="movie-count"
|
className="group-count"
|
||||||
type="movie"
|
type="group"
|
||||||
count={studio.movie_count}
|
count={studio.movie_count}
|
||||||
url={NavUtils.makeStudioMoviesUrl(studio)}
|
url={NavUtils.makeStudioGroupsUrl(studio)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -199,7 +199,7 @@ export const StudioCard: React.FC<IProps> = ({
|
|||||||
<hr />
|
<hr />
|
||||||
<ButtonGroup className="card-popovers">
|
<ButtonGroup className="card-popovers">
|
||||||
{maybeRenderScenesPopoverButton()}
|
{maybeRenderScenesPopoverButton()}
|
||||||
{maybeRenderMoviesPopoverButton()}
|
{maybeRenderGroupsPopoverButton()}
|
||||||
{maybeRenderImagesPopoverButton()}
|
{maybeRenderImagesPopoverButton()}
|
||||||
{maybeRenderGalleriesPopoverButton()}
|
{maybeRenderGalleriesPopoverButton()}
|
||||||
{maybeRenderPerformersPopoverButton()}
|
{maybeRenderPerformersPopoverButton()}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
CompressedStudioDetailsPanel,
|
CompressedStudioDetailsPanel,
|
||||||
StudioDetailsPanel,
|
StudioDetailsPanel,
|
||||||
} from "./StudioDetailsPanel";
|
} from "./StudioDetailsPanel";
|
||||||
import { StudioMoviesPanel } from "./StudioMoviesPanel";
|
import { StudioGroupsPanel } from "./StudioMoviesPanel";
|
||||||
import {
|
import {
|
||||||
faTrashAlt,
|
faTrashAlt,
|
||||||
faLink,
|
faLink,
|
||||||
@@ -63,7 +63,7 @@ const validTabs = [
|
|||||||
"galleries",
|
"galleries",
|
||||||
"images",
|
"images",
|
||||||
"performers",
|
"performers",
|
||||||
"movies",
|
"groups",
|
||||||
"childstudios",
|
"childstudios",
|
||||||
] as const;
|
] as const;
|
||||||
type TabKey = (typeof validTabs)[number];
|
type TabKey = (typeof validTabs)[number];
|
||||||
@@ -108,7 +108,7 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||||||
(showAllCounts ? studio.image_count_all : studio.image_count) ?? 0;
|
(showAllCounts ? studio.image_count_all : studio.image_count) ?? 0;
|
||||||
const performerCount =
|
const performerCount =
|
||||||
(showAllCounts ? studio.performer_count_all : studio.performer_count) ?? 0;
|
(showAllCounts ? studio.performer_count_all : studio.performer_count) ?? 0;
|
||||||
const movieCount =
|
const groupCount =
|
||||||
(showAllCounts ? studio.movie_count_all : studio.movie_count) ?? 0;
|
(showAllCounts ? studio.movie_count_all : studio.movie_count) ?? 0;
|
||||||
|
|
||||||
const populatedDefaultTab = useMemo(() => {
|
const populatedDefaultTab = useMemo(() => {
|
||||||
@@ -120,8 +120,8 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||||||
ret = "images";
|
ret = "images";
|
||||||
} else if (performerCount != 0) {
|
} else if (performerCount != 0) {
|
||||||
ret = "performers";
|
ret = "performers";
|
||||||
} else if (movieCount != 0) {
|
} else if (groupCount != 0) {
|
||||||
ret = "movies";
|
ret = "groups";
|
||||||
} else if (studio.child_studios.length != 0) {
|
} else if (studio.child_studios.length != 0) {
|
||||||
ret = "childstudios";
|
ret = "childstudios";
|
||||||
}
|
}
|
||||||
@@ -133,7 +133,7 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||||||
galleryCount,
|
galleryCount,
|
||||||
imageCount,
|
imageCount,
|
||||||
performerCount,
|
performerCount,
|
||||||
movieCount,
|
groupCount,
|
||||||
studio,
|
studio,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -437,19 +437,19 @@ const StudioPage: React.FC<IProps> = ({ studio, tabKey }) => {
|
|||||||
/>
|
/>
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="movies"
|
eventKey="groups"
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
{intl.formatMessage({ id: "movies" })}
|
{intl.formatMessage({ id: "groups" })}
|
||||||
<Counter
|
<Counter
|
||||||
abbreviateCounter={abbreviateCounter}
|
abbreviateCounter={abbreviateCounter}
|
||||||
count={movieCount}
|
count={groupCount}
|
||||||
hideZero
|
hideZero
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<StudioMoviesPanel active={tabKey === "movies"} studio={studio} />
|
<StudioGroupsPanel active={tabKey === "groups"} studio={studio} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="childstudios"
|
eventKey="childstudios"
|
||||||
|
|||||||
@@ -1,24 +1,24 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { MovieList } from "src/components/Movies/MovieList";
|
import { GroupList } from "src/components/Movies/MovieList";
|
||||||
import { useStudioFilterHook } from "src/core/studios";
|
import { useStudioFilterHook } from "src/core/studios";
|
||||||
import { View } from "src/components/List/views";
|
import { View } from "src/components/List/views";
|
||||||
|
|
||||||
interface IStudioMoviesPanel {
|
interface IStudioGroupsPanel {
|
||||||
active: boolean;
|
active: boolean;
|
||||||
studio: GQL.StudioDataFragment;
|
studio: GQL.StudioDataFragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StudioMoviesPanel: React.FC<IStudioMoviesPanel> = ({
|
export const StudioGroupsPanel: React.FC<IStudioGroupsPanel> = ({
|
||||||
active,
|
active,
|
||||||
studio,
|
studio,
|
||||||
}) => {
|
}) => {
|
||||||
const filterHook = useStudioFilterHook(studio);
|
const filterHook = useStudioFilterHook(studio);
|
||||||
return (
|
return (
|
||||||
<MovieList
|
<GroupList
|
||||||
filterHook={filterHook}
|
filterHook={filterHook}
|
||||||
alterQuery={active}
|
alterQuery={active}
|
||||||
view={View.StudioMovies}
|
view={View.StudioGroups}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -236,15 +236,15 @@ export const TagCard: React.FC<IProps> = ({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function maybeRenderMoviesPopoverButton() {
|
function maybeRenderGroupsPopoverButton() {
|
||||||
if (!tag.movie_count) return;
|
if (!tag.movie_count) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PopoverCountButton
|
<PopoverCountButton
|
||||||
className="movie-count"
|
className="group-count"
|
||||||
type="movie"
|
type="group"
|
||||||
count={tag.movie_count}
|
count={tag.movie_count}
|
||||||
url={NavUtils.makeTagMoviesUrl(tag)}
|
url={NavUtils.makeTagGroupsUrl(tag)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -258,7 +258,7 @@ export const TagCard: React.FC<IProps> = ({
|
|||||||
{maybeRenderScenesPopoverButton()}
|
{maybeRenderScenesPopoverButton()}
|
||||||
{maybeRenderImagesPopoverButton()}
|
{maybeRenderImagesPopoverButton()}
|
||||||
{maybeRenderGalleriesPopoverButton()}
|
{maybeRenderGalleriesPopoverButton()}
|
||||||
{maybeRenderMoviesPopoverButton()}
|
{maybeRenderGroupsPopoverButton()}
|
||||||
{maybeRenderSceneMarkersPopoverButton()}
|
{maybeRenderSceneMarkersPopoverButton()}
|
||||||
{maybeRenderPerformersPopoverButton()}
|
{maybeRenderPerformersPopoverButton()}
|
||||||
{maybeRenderStudiosPopoverButton()}
|
{maybeRenderStudiosPopoverButton()}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ import {
|
|||||||
import { DetailImage } from "src/components/Shared/DetailImage";
|
import { DetailImage } from "src/components/Shared/DetailImage";
|
||||||
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
import { useLoadStickyHeader } from "src/hooks/detailsPanel";
|
||||||
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
import { useScrollToTopOnMount } from "src/hooks/scrollToTop";
|
||||||
import { TagMoviesPanel } from "./TagMoviesPanel";
|
import { TagGroupsPanel } from "./TagMoviesPanel";
|
||||||
|
|
||||||
interface IProps {
|
interface IProps {
|
||||||
tag: GQL.TagDataFragment;
|
tag: GQL.TagDataFragment;
|
||||||
@@ -59,7 +59,7 @@ const validTabs = [
|
|||||||
"scenes",
|
"scenes",
|
||||||
"images",
|
"images",
|
||||||
"galleries",
|
"galleries",
|
||||||
"movies",
|
"groups",
|
||||||
"markers",
|
"markers",
|
||||||
"performers",
|
"performers",
|
||||||
"studios",
|
"studios",
|
||||||
@@ -105,7 +105,7 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||||||
(showAllCounts ? tag.image_count_all : tag.image_count) ?? 0;
|
(showAllCounts ? tag.image_count_all : tag.image_count) ?? 0;
|
||||||
const galleryCount =
|
const galleryCount =
|
||||||
(showAllCounts ? tag.gallery_count_all : tag.gallery_count) ?? 0;
|
(showAllCounts ? tag.gallery_count_all : tag.gallery_count) ?? 0;
|
||||||
const movieCount =
|
const groupCount =
|
||||||
(showAllCounts ? tag.movie_count_all : tag.movie_count) ?? 0;
|
(showAllCounts ? tag.movie_count_all : tag.movie_count) ?? 0;
|
||||||
const sceneMarkerCount =
|
const sceneMarkerCount =
|
||||||
(showAllCounts ? tag.scene_marker_count_all : tag.scene_marker_count) ?? 0;
|
(showAllCounts ? tag.scene_marker_count_all : tag.scene_marker_count) ?? 0;
|
||||||
@@ -121,8 +121,8 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||||||
ret = "images";
|
ret = "images";
|
||||||
} else if (galleryCount != 0) {
|
} else if (galleryCount != 0) {
|
||||||
ret = "galleries";
|
ret = "galleries";
|
||||||
} else if (movieCount != 0) {
|
} else if (groupCount != 0) {
|
||||||
ret = "movies";
|
ret = "groups";
|
||||||
} else if (sceneMarkerCount != 0) {
|
} else if (sceneMarkerCount != 0) {
|
||||||
ret = "markers";
|
ret = "markers";
|
||||||
} else if (performerCount != 0) {
|
} else if (performerCount != 0) {
|
||||||
@@ -140,7 +140,7 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||||||
sceneMarkerCount,
|
sceneMarkerCount,
|
||||||
performerCount,
|
performerCount,
|
||||||
studioCount,
|
studioCount,
|
||||||
movieCount,
|
groupCount,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const setTabKey = useCallback(
|
const setTabKey = useCallback(
|
||||||
@@ -484,19 +484,19 @@ const TagPage: React.FC<IProps> = ({ tag, tabKey }) => {
|
|||||||
<TagGalleriesPanel active={tabKey === "galleries"} tag={tag} />
|
<TagGalleriesPanel active={tabKey === "galleries"} tag={tag} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="movies"
|
eventKey="groups"
|
||||||
title={
|
title={
|
||||||
<>
|
<>
|
||||||
{intl.formatMessage({ id: "movies" })}
|
{intl.formatMessage({ id: "groups" })}
|
||||||
<Counter
|
<Counter
|
||||||
abbreviateCounter={abbreviateCounter}
|
abbreviateCounter={abbreviateCounter}
|
||||||
count={movieCount}
|
count={groupCount}
|
||||||
hideZero
|
hideZero
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<TagMoviesPanel active={tabKey === "movies"} tag={tag} />
|
<TagGroupsPanel active={tabKey === "groups"} tag={tag} />
|
||||||
</Tab>
|
</Tab>
|
||||||
<Tab
|
<Tab
|
||||||
eventKey="markers"
|
eventKey="markers"
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import { useTagFilterHook } from "src/core/tags";
|
import { useTagFilterHook } from "src/core/tags";
|
||||||
import { MovieList } from "src/components/Movies/MovieList";
|
import { GroupList } from "src/components/Movies/MovieList";
|
||||||
|
|
||||||
export const TagMoviesPanel: React.FC<{
|
export const TagGroupsPanel: React.FC<{
|
||||||
active: boolean;
|
active: boolean;
|
||||||
tag: GQL.TagDataFragment;
|
tag: GQL.TagDataFragment;
|
||||||
}> = ({ active, tag }) => {
|
}> = ({ active, tag }) => {
|
||||||
const filterHook = useTagFilterHook(tag);
|
const filterHook = useTagFilterHook(tag);
|
||||||
return <MovieList filterHook={filterHook} alterQuery={active} />;
|
return <GroupList filterHook={filterHook} alterQuery={active} />;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ export function generateDefaultFrontPageContent(intl: IntlShape) {
|
|||||||
return [
|
return [
|
||||||
recentlyReleased(intl, FilterMode.Scenes, "scenes"),
|
recentlyReleased(intl, FilterMode.Scenes, "scenes"),
|
||||||
recentlyAdded(intl, FilterMode.Studios, "studios"),
|
recentlyAdded(intl, FilterMode.Studios, "studios"),
|
||||||
recentlyReleased(intl, FilterMode.Movies, "movies"),
|
recentlyReleased(intl, FilterMode.Movies, "groups"),
|
||||||
recentlyAdded(intl, FilterMode.Performers, "performers"),
|
recentlyAdded(intl, FilterMode.Performers, "performers"),
|
||||||
recentlyReleased(intl, FilterMode.Galleries, "galleries"),
|
recentlyReleased(intl, FilterMode.Galleries, "galleries"),
|
||||||
];
|
];
|
||||||
@@ -156,8 +156,8 @@ export function generatePremadeFrontPageContent(intl: IntlShape) {
|
|||||||
recentlyReleased(intl, FilterMode.Galleries, "galleries"),
|
recentlyReleased(intl, FilterMode.Galleries, "galleries"),
|
||||||
recentlyAdded(intl, FilterMode.Galleries, "galleries"),
|
recentlyAdded(intl, FilterMode.Galleries, "galleries"),
|
||||||
recentlyAdded(intl, FilterMode.Images, "images"),
|
recentlyAdded(intl, FilterMode.Images, "images"),
|
||||||
recentlyReleased(intl, FilterMode.Movies, "movies"),
|
recentlyReleased(intl, FilterMode.Movies, "groups"),
|
||||||
recentlyAdded(intl, FilterMode.Movies, "movies"),
|
recentlyAdded(intl, FilterMode.Movies, "groups"),
|
||||||
recentlyAdded(intl, FilterMode.Studios, "studios"),
|
recentlyAdded(intl, FilterMode.Studios, "studios"),
|
||||||
recentlyAdded(intl, FilterMode.Performers, "performers"),
|
recentlyAdded(intl, FilterMode.Performers, "performers"),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import * as GQL from "src/core/generated-graphql";
|
import * as GQL from "src/core/generated-graphql";
|
||||||
import TextUtils from "src/utils/text";
|
import TextUtils from "src/utils/text";
|
||||||
|
|
||||||
export const scrapedMovieToCreateInput = (toCreate: GQL.ScrapedMovie) => {
|
export const scrapedGroupToCreateInput = (toCreate: GQL.ScrapedMovie) => {
|
||||||
const input: GQL.MovieCreateInput = {
|
const input: GQL.MovieCreateInput = {
|
||||||
name: toCreate.name ?? "",
|
name: toCreate.name ?? "",
|
||||||
url: toCreate.url,
|
url: toCreate.url,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ body {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#movie-page,
|
#group-page,
|
||||||
#performer-page,
|
#performer-page,
|
||||||
#studio-page,
|
#studio-page,
|
||||||
#tag-page {
|
#tag-page {
|
||||||
@@ -83,7 +83,7 @@ dd {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-name,
|
.group-name,
|
||||||
.performer-name,
|
.performer-name,
|
||||||
.studio-name,
|
.studio-name,
|
||||||
.tag-name {
|
.tag-name {
|
||||||
@@ -93,7 +93,7 @@ dd {
|
|||||||
.sticky.detail-header-group {
|
.sticky.detail-header-group {
|
||||||
padding: 1rem 2.5rem;
|
padding: 1rem 2.5rem;
|
||||||
|
|
||||||
a.movie-name,
|
a.group-name,
|
||||||
a.performer-name,
|
a.performer-name,
|
||||||
a.studio-name,
|
a.studio-name,
|
||||||
a.tag-name {
|
a.tag-name {
|
||||||
@@ -313,7 +313,7 @@ dd {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 0 1rem;
|
padding: 0 1rem;
|
||||||
|
|
||||||
.movie-images {
|
.group-images {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +322,7 @@ dd {
|
|||||||
height: auto;
|
height: auto;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
|
||||||
.movie-images {
|
.group-images {
|
||||||
.img {
|
.img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
@@ -335,18 +335,18 @@ dd {
|
|||||||
transition: 0.5s;
|
transition: 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
.movie-images img {
|
.group-images img {
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#movie-page .detail-header-image .movie-images img {
|
#group-page .detail-header-image .group-images img {
|
||||||
max-width: 13rem;
|
max-width: 13rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
#movie-page .detail-header-image img,
|
#group-page .detail-header-image img,
|
||||||
#performer-page .detail-header-image img,
|
#performer-page .detail-header-image img,
|
||||||
#tag-page .detail-header-image img {
|
#tag-page .detail-header-image img {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
|
|||||||
@@ -798,9 +798,9 @@
|
|||||||
"countables": {
|
"countables": {
|
||||||
"files": "{count, plural, one {File} other {Files}}",
|
"files": "{count, plural, one {File} other {Files}}",
|
||||||
"galleries": "{count, plural, one {Gallery} other {Galleries}}",
|
"galleries": "{count, plural, one {Gallery} other {Galleries}}",
|
||||||
|
"groups": "{count, plural, one {Group} other {Groups}}",
|
||||||
"images": "{count, plural, one {Image} other {Images}}",
|
"images": "{count, plural, one {Image} other {Images}}",
|
||||||
"markers": "{count, plural, one {Marker} other {Markers}}",
|
"markers": "{count, plural, one {Marker} other {Markers}}",
|
||||||
"movies": "{count, plural, one {Movie} other {Movies}}",
|
|
||||||
"performers": "{count, plural, one {Performer} other {Performers}}",
|
"performers": "{count, plural, one {Performer} other {Performers}}",
|
||||||
"scenes": "{count, plural, one {Scene} other {Scenes}}",
|
"scenes": "{count, plural, one {Scene} other {Scenes}}",
|
||||||
"studios": "{count, plural, one {Studio} other {Studios}}",
|
"studios": "{count, plural, one {Studio} other {Studios}}",
|
||||||
@@ -1060,6 +1060,10 @@
|
|||||||
"TRANSGENDER_FEMALE": "Transgender Female",
|
"TRANSGENDER_FEMALE": "Transgender Female",
|
||||||
"TRANSGENDER_MALE": "Transgender Male"
|
"TRANSGENDER_MALE": "Transgender Male"
|
||||||
},
|
},
|
||||||
|
"group": "Group",
|
||||||
|
"group_count": "Group Count",
|
||||||
|
"group_scene_number": "Scene Number",
|
||||||
|
"groups": "Groups",
|
||||||
"hair_color": "Hair Colour",
|
"hair_color": "Hair Colour",
|
||||||
"handy_connection_status": {
|
"handy_connection_status": {
|
||||||
"connecting": "Connecting",
|
"connecting": "Connecting",
|
||||||
@@ -1117,10 +1121,6 @@
|
|||||||
},
|
},
|
||||||
"megabits_per_second": "{value} mbps",
|
"megabits_per_second": "{value} mbps",
|
||||||
"metadata": "Metadata",
|
"metadata": "Metadata",
|
||||||
"movie": "Movie",
|
|
||||||
"movie_count": "Movie Count",
|
|
||||||
"movie_scene_number": "Scene Number",
|
|
||||||
"movies": "Movies",
|
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"new": "New",
|
"new": "New",
|
||||||
"none": "None",
|
"none": "None",
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ export type InputType =
|
|||||||
| "performer_tags"
|
| "performer_tags"
|
||||||
| "scenes"
|
| "scenes"
|
||||||
| "scene_tags"
|
| "scene_tags"
|
||||||
| "movies"
|
| "groups"
|
||||||
| "galleries"
|
| "galleries"
|
||||||
| undefined;
|
| undefined;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import { ILabeledIdCriterion, ILabeledIdCriterionOption } from "./criterion";
|
import { ILabeledIdCriterion, ILabeledIdCriterionOption } from "./criterion";
|
||||||
|
|
||||||
const inputType = "movies";
|
const inputType = "groups";
|
||||||
|
|
||||||
export const MoviesCriterionOption = new ILabeledIdCriterionOption(
|
export const MoviesCriterionOption = new ILabeledIdCriterionOption(
|
||||||
"movies",
|
"groups",
|
||||||
"movies",
|
"movies",
|
||||||
false,
|
false,
|
||||||
inputType,
|
inputType,
|
||||||
|
|||||||
@@ -47,7 +47,6 @@ const sortByOptions = [
|
|||||||
"resume_time",
|
"resume_time",
|
||||||
"play_duration",
|
"play_duration",
|
||||||
"play_count",
|
"play_count",
|
||||||
"movie_scene_number",
|
|
||||||
"interactive",
|
"interactive",
|
||||||
"interactive_speed",
|
"interactive_speed",
|
||||||
"perceptual_similarity",
|
"perceptual_similarity",
|
||||||
@@ -59,6 +58,10 @@ const sortByOptions = [
|
|||||||
messageID: "o_count",
|
messageID: "o_count",
|
||||||
value: "o_counter",
|
value: "o_counter",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
messageID: "group_scene_number",
|
||||||
|
value: "movie_scene_number",
|
||||||
|
},
|
||||||
]);
|
]);
|
||||||
const displayModeOptions = [
|
const displayModeOptions = [
|
||||||
DisplayMode.Grid,
|
DisplayMode.Grid,
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ const sortByOptions = ["name", "random"]
|
|||||||
value: "scenes_count",
|
value: "scenes_count",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
messageID: "movie_count",
|
messageID: "group_count",
|
||||||
value: "movies_count",
|
value: "movies_count",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -62,7 +62,7 @@ const criterionOptions = [
|
|||||||
createMandatoryNumberCriterionOption("gallery_count"),
|
createMandatoryNumberCriterionOption("gallery_count"),
|
||||||
createMandatoryNumberCriterionOption("performer_count"),
|
createMandatoryNumberCriterionOption("performer_count"),
|
||||||
createMandatoryNumberCriterionOption("studio_count"),
|
createMandatoryNumberCriterionOption("studio_count"),
|
||||||
createMandatoryNumberCriterionOption("movie_count"),
|
createMandatoryNumberCriterionOption("movie_count", "group_count"),
|
||||||
createMandatoryNumberCriterionOption("marker_count"),
|
createMandatoryNumberCriterionOption("marker_count"),
|
||||||
ParentTagsCriterionOption,
|
ParentTagsCriterionOption,
|
||||||
new MandatoryNumberCriterionOption("parent_tag_count", "parent_count"),
|
new MandatoryNumberCriterionOption("parent_tag_count", "parent_count"),
|
||||||
|
|||||||
6
ui/v2.5/src/pluginApi.d.ts
vendored
6
ui/v2.5/src/pluginApi.d.ts
vendored
@@ -693,12 +693,12 @@ declare namespace PluginApi {
|
|||||||
function makePerformerScenesUrl(...args: any[]): any;
|
function makePerformerScenesUrl(...args: any[]): any;
|
||||||
function makePerformerImagesUrl(...args: any[]): any;
|
function makePerformerImagesUrl(...args: any[]): any;
|
||||||
function makePerformerGalleriesUrl(...args: any[]): any;
|
function makePerformerGalleriesUrl(...args: any[]): any;
|
||||||
function makePerformerMoviesUrl(...args: any[]): any;
|
function makePerformerGroupsUrl(...args: any[]): any;
|
||||||
function makePerformersCountryUrl(...args: any[]): any;
|
function makePerformersCountryUrl(...args: any[]): any;
|
||||||
function makeStudioScenesUrl(...args: any[]): any;
|
function makeStudioScenesUrl(...args: any[]): any;
|
||||||
function makeStudioImagesUrl(...args: any[]): any;
|
function makeStudioImagesUrl(...args: any[]): any;
|
||||||
function makeStudioGalleriesUrl(...args: any[]): any;
|
function makeStudioGalleriesUrl(...args: any[]): any;
|
||||||
function makeStudioMoviesUrl(...args: any[]): any;
|
function makeStudioGroupsUrl(...args: any[]): any;
|
||||||
function makeStudioPerformersUrl(...args: any[]): any;
|
function makeStudioPerformersUrl(...args: any[]): any;
|
||||||
function makeTagUrl(...args: any[]): any;
|
function makeTagUrl(...args: any[]): any;
|
||||||
function makeParentTagsUrl(...args: any[]): any;
|
function makeParentTagsUrl(...args: any[]): any;
|
||||||
@@ -710,7 +710,7 @@ declare namespace PluginApi {
|
|||||||
function makeTagImagesUrl(...args: any[]): any;
|
function makeTagImagesUrl(...args: any[]): any;
|
||||||
function makeScenesPHashMatchUrl(...args: any[]): any;
|
function makeScenesPHashMatchUrl(...args: any[]): any;
|
||||||
function makeSceneMarkerUrl(...args: any[]): any;
|
function makeSceneMarkerUrl(...args: any[]): any;
|
||||||
function makeMovieScenesUrl(...args: any[]): any;
|
function makeGroupScenesUrl(...args: any[]): any;
|
||||||
function makeChildStudiosUrl(...args: any[]): any;
|
function makeChildStudiosUrl(...args: any[]): any;
|
||||||
function makeGalleryImagesUrl(...args: any[]): any;
|
function makeGalleryImagesUrl(...args: any[]): any;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,11 +81,11 @@ export function getAggregateTagIds(state: { tags: IHasID[] }[]) {
|
|||||||
return getAggregateIds(sortedLists);
|
return getAggregateIds(sortedLists);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IMovie {
|
interface IGroup {
|
||||||
movie: IHasID;
|
movie: IHasID;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAggregateMovieIds(state: { movies: IMovie[] }[]) {
|
export function getAggregateGroupIds(state: { movies: IGroup[] }[]) {
|
||||||
const sortedLists = state.map((o) =>
|
const sortedLists = state.map((o) =>
|
||||||
o.movies.map((oo) => oo.movie.id).sort()
|
o.movies.map((oo) => oo.movie.id).sort()
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ const makePerformerGalleriesUrl = (
|
|||||||
return `/galleries?${filter.makeQueryParameters()}`;
|
return `/galleries?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makePerformerMoviesUrl = (
|
const makePerformerGroupsUrl = (
|
||||||
performer: Partial<GQL.PerformerDataFragment>,
|
performer: Partial<GQL.PerformerDataFragment>,
|
||||||
extraPerformer?: ILabeledId,
|
extraPerformer?: ILabeledId,
|
||||||
extraCriteria?: Criterion<CriterionValue>[]
|
extraCriteria?: Criterion<CriterionValue>[]
|
||||||
@@ -121,7 +121,7 @@ const makePerformerMoviesUrl = (
|
|||||||
|
|
||||||
filter.criteria.push(criterion);
|
filter.criteria.push(criterion);
|
||||||
addExtraCriteria(filter.criteria, extraCriteria);
|
addExtraCriteria(filter.criteria, extraCriteria);
|
||||||
return `/movies?${filter.makeQueryParameters()}`;
|
return `/groups?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makePerformersCountryUrl = (
|
const makePerformersCountryUrl = (
|
||||||
@@ -174,7 +174,7 @@ const makeStudioGalleriesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
|||||||
return `/galleries?${filter.makeQueryParameters()}`;
|
return `/galleries?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeStudioMoviesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
const makeStudioGroupsUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||||
if (!studio.id) return "#";
|
if (!studio.id) return "#";
|
||||||
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
|
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
|
||||||
const criterion = new StudiosCriterion();
|
const criterion = new StudiosCriterion();
|
||||||
@@ -184,7 +184,7 @@ const makeStudioMoviesUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
|||||||
depth: 0,
|
depth: 0,
|
||||||
};
|
};
|
||||||
filter.criteria.push(criterion);
|
filter.criteria.push(criterion);
|
||||||
return `/movies?${filter.makeQueryParameters()}`;
|
return `/groups?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeStudioPerformersUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
const makeStudioPerformersUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
||||||
@@ -211,12 +211,12 @@ const makeChildStudiosUrl = (studio: Partial<GQL.StudioDataFragment>) => {
|
|||||||
return `/studios?${filter.makeQueryParameters()}`;
|
return `/studios?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeMovieScenesUrl = (movie: Partial<GQL.MovieDataFragment>) => {
|
const makeGroupScenesUrl = (group: Partial<GQL.MovieDataFragment>) => {
|
||||||
if (!movie.id) return "#";
|
if (!group.id) return "#";
|
||||||
const filter = new ListFilterModel(GQL.FilterMode.Scenes, undefined);
|
const filter = new ListFilterModel(GQL.FilterMode.Scenes, undefined);
|
||||||
const criterion = new MoviesCriterion();
|
const criterion = new MoviesCriterion();
|
||||||
criterion.value = [
|
criterion.value = [
|
||||||
{ id: movie.id, label: movie.name || `Movie ${movie.id}` },
|
{ id: group.id, label: group.name || `Group ${group.id}` },
|
||||||
];
|
];
|
||||||
filter.criteria.push(criterion);
|
filter.criteria.push(criterion);
|
||||||
return `/scenes?${filter.makeQueryParameters()}`;
|
return `/scenes?${filter.makeQueryParameters()}`;
|
||||||
@@ -298,8 +298,8 @@ const makeTagImagesUrl = (tag: INamedObject) => {
|
|||||||
return `/images?${makeTagFilter(GQL.FilterMode.Images, tag)}`;
|
return `/images?${makeTagFilter(GQL.FilterMode.Images, tag)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeTagMoviesUrl = (tag: INamedObject) => {
|
const makeTagGroupsUrl = (tag: INamedObject) => {
|
||||||
return `/movies?${makeTagFilter(GQL.FilterMode.Movies, tag)}`;
|
return `/groups?${makeTagFilter(GQL.FilterMode.Movies, tag)}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
type SceneMarkerDataFragment = Pick<GQL.SceneMarker, "id" | "seconds"> & {
|
type SceneMarkerDataFragment = Pick<GQL.SceneMarker, "id" | "seconds"> & {
|
||||||
@@ -349,13 +349,13 @@ const makeDirectorScenesUrl = (director: string) => {
|
|||||||
return `/scenes?${filter.makeQueryParameters()}`;
|
return `/scenes?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makeDirectorMoviesUrl = (director: string) => {
|
const makeDirectorGroupsUrl = (director: string) => {
|
||||||
if (director.length == 0) return "#";
|
if (director.length == 0) return "#";
|
||||||
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
|
const filter = new ListFilterModel(GQL.FilterMode.Movies, undefined);
|
||||||
filter.criteria.push(
|
filter.criteria.push(
|
||||||
stringEqualsCriterion(createStringCriterionOption("director"), director)
|
stringEqualsCriterion(createStringCriterionOption("director"), director)
|
||||||
);
|
);
|
||||||
return `/movies?${filter.makeQueryParameters()}`;
|
return `/groups?${filter.makeQueryParameters()}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const makePhotographerGalleriesUrl = (photographer: string) => {
|
const makePhotographerGalleriesUrl = (photographer: string) => {
|
||||||
@@ -401,12 +401,12 @@ const NavUtils = {
|
|||||||
makePerformerScenesUrl,
|
makePerformerScenesUrl,
|
||||||
makePerformerImagesUrl,
|
makePerformerImagesUrl,
|
||||||
makePerformerGalleriesUrl,
|
makePerformerGalleriesUrl,
|
||||||
makePerformerMoviesUrl,
|
makePerformerGroupsUrl,
|
||||||
makePerformersCountryUrl,
|
makePerformersCountryUrl,
|
||||||
makeStudioScenesUrl,
|
makeStudioScenesUrl,
|
||||||
makeStudioImagesUrl,
|
makeStudioImagesUrl,
|
||||||
makeStudioGalleriesUrl,
|
makeStudioGalleriesUrl,
|
||||||
makeStudioMoviesUrl,
|
makeStudioGroupsUrl: makeStudioGroupsUrl,
|
||||||
makeStudioPerformersUrl,
|
makeStudioPerformersUrl,
|
||||||
makeTagUrl,
|
makeTagUrl,
|
||||||
makeParentTagsUrl,
|
makeParentTagsUrl,
|
||||||
@@ -417,16 +417,16 @@ const NavUtils = {
|
|||||||
makeTagStudiosUrl,
|
makeTagStudiosUrl,
|
||||||
makeTagGalleriesUrl,
|
makeTagGalleriesUrl,
|
||||||
makeTagImagesUrl,
|
makeTagImagesUrl,
|
||||||
makeTagMoviesUrl,
|
makeTagGroupsUrl,
|
||||||
makeScenesPHashMatchUrl,
|
makeScenesPHashMatchUrl,
|
||||||
makeSceneMarkerUrl,
|
makeSceneMarkerUrl,
|
||||||
makeMovieScenesUrl,
|
makeGroupScenesUrl,
|
||||||
makeChildStudiosUrl,
|
makeChildStudiosUrl,
|
||||||
makeGalleryImagesUrl,
|
makeGalleryImagesUrl,
|
||||||
makeDirectorScenesUrl,
|
makeDirectorScenesUrl,
|
||||||
makePhotographerGalleriesUrl,
|
makePhotographerGalleriesUrl,
|
||||||
makePhotographerImagesUrl,
|
makePhotographerImagesUrl,
|
||||||
makeDirectorMoviesUrl,
|
makeDirectorGroupsUrl,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NavUtils;
|
export default NavUtils;
|
||||||
|
|||||||
Reference in New Issue
Block a user