mirror of https://github.com/stashapp/stash.git
Add missing gallery components (#969)
* add gallery scrapers to settings page * add galleries to performers page * add galleries to studios page
This commit is contained in:
parent
a96ab9ce6f
commit
c45780dc59
|
@ -1,4 +1,6 @@
|
||||||
### 🎨 Improvements
|
### 🎨 Improvements
|
||||||
|
* Add gallery tabs to performer and studio pages.
|
||||||
|
* Add gallery scrapers to scraper page.
|
||||||
* Add support for setting cookies in scrapers.
|
* Add support for setting cookies in scrapers.
|
||||||
* Truncate long text and show on hover.
|
* Truncate long text and show on hover.
|
||||||
* Show scene studio as text where image is missing.
|
* Show scene studio as text where image is missing.
|
||||||
|
|
|
@ -22,6 +22,7 @@ import FsLightbox from "fslightbox-react";
|
||||||
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
import { PerformerDetailsPanel } from "./PerformerDetailsPanel";
|
||||||
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
import { PerformerOperationsPanel } from "./PerformerOperationsPanel";
|
||||||
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
import { PerformerScenesPanel } from "./PerformerScenesPanel";
|
||||||
|
import { PerformerGalleriesPanel } from "./PerformerGalleriesPanel";
|
||||||
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
import { PerformerImagesPanel } from "./PerformerImagesPanel";
|
||||||
|
|
||||||
interface IPerformerParams {
|
interface IPerformerParams {
|
||||||
|
@ -60,6 +61,7 @@ export const Performer: React.FC = () => {
|
||||||
|
|
||||||
const activeTabKey =
|
const activeTabKey =
|
||||||
tab === "scenes" ||
|
tab === "scenes" ||
|
||||||
|
tab === "galleries" ||
|
||||||
tab === "images" ||
|
tab === "images" ||
|
||||||
tab === "edit" ||
|
tab === "edit" ||
|
||||||
tab === "operations"
|
tab === "operations"
|
||||||
|
@ -81,6 +83,7 @@ export const Performer: React.FC = () => {
|
||||||
Mousetrap.bind("a", () => setActiveTabKey("details"));
|
Mousetrap.bind("a", () => setActiveTabKey("details"));
|
||||||
Mousetrap.bind("e", () => setActiveTabKey("edit"));
|
Mousetrap.bind("e", () => setActiveTabKey("edit"));
|
||||||
Mousetrap.bind("c", () => setActiveTabKey("scenes"));
|
Mousetrap.bind("c", () => setActiveTabKey("scenes"));
|
||||||
|
Mousetrap.bind("g", () => setActiveTabKey("galleries"));
|
||||||
Mousetrap.bind("o", () => setActiveTabKey("operations"));
|
Mousetrap.bind("o", () => setActiveTabKey("operations"));
|
||||||
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
Mousetrap.bind("f", () => setFavorite(!performer.favorite));
|
||||||
|
|
||||||
|
@ -163,6 +166,9 @@ export const Performer: React.FC = () => {
|
||||||
<Tab eventKey="scenes" title="Scenes">
|
<Tab eventKey="scenes" title="Scenes">
|
||||||
<PerformerScenesPanel performer={performer} />
|
<PerformerScenesPanel performer={performer} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
<Tab eventKey="galleries" title="Galleries">
|
||||||
|
<PerformerGalleriesPanel performer={performer} />
|
||||||
|
</Tab>
|
||||||
<Tab eventKey="images" title="Images">
|
<Tab eventKey="images" title="Images">
|
||||||
<PerformerImagesPanel performer={performer} />
|
<PerformerImagesPanel performer={performer} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import * as GQL from "src/core/generated-graphql";
|
||||||
|
import { GalleryList } from "src/components/Galleries/GalleryList";
|
||||||
|
import { performerFilterHook } from "src/core/performers";
|
||||||
|
|
||||||
|
interface IPerformerDetailsProps {
|
||||||
|
performer: Partial<GQL.PerformerDataFragment>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PerformerGalleriesPanel: React.FC<IPerformerDetailsProps> = ({
|
||||||
|
performer,
|
||||||
|
}) => {
|
||||||
|
return <GalleryList filterHook={performerFilterHook(performer)} />;
|
||||||
|
};
|
|
@ -5,6 +5,7 @@ import {
|
||||||
useListMovieScrapers,
|
useListMovieScrapers,
|
||||||
useListPerformerScrapers,
|
useListPerformerScrapers,
|
||||||
useListSceneScrapers,
|
useListSceneScrapers,
|
||||||
|
useListGalleryScrapers,
|
||||||
} from "src/core/StashService";
|
} from "src/core/StashService";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { TextUtils } from "src/utils";
|
import { TextUtils } from "src/utils";
|
||||||
|
@ -75,6 +76,10 @@ export const SettingsScrapersPanel: React.FC = () => {
|
||||||
data: sceneScrapers,
|
data: sceneScrapers,
|
||||||
loading: loadingScenes,
|
loading: loadingScenes,
|
||||||
} = useListSceneScrapers();
|
} = useListSceneScrapers();
|
||||||
|
const {
|
||||||
|
data: galleryScrapers,
|
||||||
|
loading: loadingGalleries,
|
||||||
|
} = useListGalleryScrapers();
|
||||||
const {
|
const {
|
||||||
data: movieScrapers,
|
data: movieScrapers,
|
||||||
loading: loadingMovies,
|
loading: loadingMovies,
|
||||||
|
@ -124,6 +129,25 @@ export const SettingsScrapersPanel: React.FC = () => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderGalleryScrapeTypes(types: ScrapeType[]) {
|
||||||
|
const typeStrings = types.map((t) => {
|
||||||
|
switch (t) {
|
||||||
|
case ScrapeType.Fragment:
|
||||||
|
return "Gallery Metadata";
|
||||||
|
default:
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ul>
|
||||||
|
{typeStrings.map((t) => (
|
||||||
|
<li key={t}>{t}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function renderMovieScrapeTypes(types: ScrapeType[]) {
|
function renderMovieScrapeTypes(types: ScrapeType[]) {
|
||||||
const typeStrings = types.map((t) => {
|
const typeStrings = types.map((t) => {
|
||||||
switch (t) {
|
switch (t) {
|
||||||
|
@ -161,6 +185,22 @@ export const SettingsScrapersPanel: React.FC = () => {
|
||||||
return renderTable("Scene scrapers", elements);
|
return renderTable("Scene scrapers", elements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderGalleryScrapers() {
|
||||||
|
const elements = (galleryScrapers?.listGalleryScrapers ?? []).map(
|
||||||
|
(scraper) => (
|
||||||
|
<tr key={scraper.id}>
|
||||||
|
<td>{scraper.name}</td>
|
||||||
|
<td>
|
||||||
|
{renderGalleryScrapeTypes(scraper.gallery?.supported_scrapes ?? [])}
|
||||||
|
</td>
|
||||||
|
<td>{renderURLs(scraper.gallery?.urls ?? [])}</td>
|
||||||
|
</tr>
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return renderTable("Gallery Scrapers", elements);
|
||||||
|
}
|
||||||
|
|
||||||
function renderPerformerScrapers() {
|
function renderPerformerScrapers() {
|
||||||
const elements = (performerScrapers?.listPerformerScrapers ?? []).map(
|
const elements = (performerScrapers?.listPerformerScrapers ?? []).map(
|
||||||
(scraper) => (
|
(scraper) => (
|
||||||
|
@ -213,7 +253,7 @@ export const SettingsScrapersPanel: React.FC = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loadingScenes || loadingPerformers || loadingMovies)
|
if (loadingScenes || loadingGalleries || loadingPerformers || loadingMovies)
|
||||||
return <LoadingIndicator />;
|
return <LoadingIndicator />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -230,6 +270,7 @@ export const SettingsScrapersPanel: React.FC = () => {
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
{renderSceneScrapers()}
|
{renderSceneScrapers()}
|
||||||
|
{renderGalleryScrapers()}
|
||||||
{renderPerformerScrapers()}
|
{renderPerformerScrapers()}
|
||||||
{renderMovieScrapers()}
|
{renderMovieScrapers()}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -21,6 +21,7 @@ import {
|
||||||
} from "src/components/Shared";
|
} from "src/components/Shared";
|
||||||
import { useToast } from "src/hooks";
|
import { useToast } from "src/hooks";
|
||||||
import { StudioScenesPanel } from "./StudioScenesPanel";
|
import { StudioScenesPanel } from "./StudioScenesPanel";
|
||||||
|
import { StudioGalleriesPanel } from "./StudioGalleriesPanel";
|
||||||
import { StudioImagesPanel } from "./StudioImagesPanel";
|
import { StudioImagesPanel } from "./StudioImagesPanel";
|
||||||
import { StudioChildrenPanel } from "./StudioChildrenPanel";
|
import { StudioChildrenPanel } from "./StudioChildrenPanel";
|
||||||
|
|
||||||
|
@ -233,7 +234,9 @@ export const Studio: React.FC = () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const activeTabKey =
|
const activeTabKey =
|
||||||
tab === "childstudios" || tab === "images" ? tab : "scenes";
|
tab === "childstudios" || tab === "images" || tab === "galleries"
|
||||||
|
? tab
|
||||||
|
: "scenes";
|
||||||
const setActiveTabKey = (newTab: string | null) => {
|
const setActiveTabKey = (newTab: string | null) => {
|
||||||
if (tab !== newTab) {
|
if (tab !== newTab) {
|
||||||
const tabParam = newTab === "scenes" ? "" : `/${newTab}`;
|
const tabParam = newTab === "scenes" ? "" : `/${newTab}`;
|
||||||
|
@ -329,6 +332,9 @@ export const Studio: React.FC = () => {
|
||||||
<Tab eventKey="scenes" title="Scenes">
|
<Tab eventKey="scenes" title="Scenes">
|
||||||
<StudioScenesPanel studio={studio} />
|
<StudioScenesPanel studio={studio} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
<Tab eventKey="galleries" title="Galleries">
|
||||||
|
<StudioGalleriesPanel studio={studio} />
|
||||||
|
</Tab>
|
||||||
<Tab eventKey="images" title="Images">
|
<Tab eventKey="images" title="Images">
|
||||||
<StudioImagesPanel studio={studio} />
|
<StudioImagesPanel studio={studio} />
|
||||||
</Tab>
|
</Tab>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import React from "react";
|
||||||
|
import * as GQL from "src/core/generated-graphql";
|
||||||
|
import { GalleryList } from "src/components/Galleries/GalleryList";
|
||||||
|
import { studioFilterHook } from "src/core/studios";
|
||||||
|
|
||||||
|
interface IStudioGalleriesPanel {
|
||||||
|
studio: Partial<GQL.StudioDataFragment>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StudioGalleriesPanel: React.FC<IStudioGalleriesPanel> = ({
|
||||||
|
studio,
|
||||||
|
}) => {
|
||||||
|
return <GalleryList filterHook={studioFilterHook(studio)} />;
|
||||||
|
};
|
Loading…
Reference in New Issue