Show counts on entity list tabs (#2169)

This commit is contained in:
kermieisinthehouse
2022-01-03 19:04:50 -08:00
committed by GitHub
parent 849c590b2a
commit 90a4931bdc
6 changed files with 150 additions and 18 deletions

View File

@@ -1,3 +1,6 @@
### 🎨 Improvements
Show counts on list tabs in Performer, Studio and Tag pages. ([#2169](https://github.com/stashapp/stash/pull/2169))
### 🐛 Bug fixes ### 🐛 Bug fixes
* Generate sprites for short video files. ([#2167](https://github.com/stashapp/stash/pull/2167)) * Generate sprites for short video files. ([#2167](https://github.com/stashapp/stash/pull/2167))
* Fix stash-box scraping including underscores in ethnicity. ([#2191](https://github.com/stashapp/stash/pull/2191)) * Fix stash-box scraping including underscores in ethnicity. ([#2191](https://github.com/stashapp/stash/pull/2191))

View File

@@ -1,5 +1,5 @@
import React, { useEffect, useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import { Button, Tabs, Tab } from "react-bootstrap"; import { Button, Tabs, Tab, Badge } from "react-bootstrap";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { useParams, useHistory } from "react-router-dom"; import { useParams, useHistory } from "react-router-dom";
import { Helmet } from "react-helmet"; import { Helmet } from "react-helmet";
@@ -147,16 +147,56 @@ const PerformerPage: React.FC<IProps> = ({ performer }) => {
<Tab eventKey="details" title={intl.formatMessage({ id: "details" })}> <Tab eventKey="details" title={intl.formatMessage({ id: "details" })}>
<PerformerDetailsPanel performer={performer} /> <PerformerDetailsPanel performer={performer} />
</Tab> </Tab>
<Tab eventKey="scenes" title={intl.formatMessage({ id: "scenes" })}> <Tab
eventKey="scenes"
title={
<React.Fragment>
{intl.formatMessage({ id: "scenes" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(performer.scene_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<PerformerScenesPanel performer={performer} /> <PerformerScenesPanel performer={performer} />
</Tab> </Tab>
<Tab eventKey="galleries" title={intl.formatMessage({ id: "galleries" })}> <Tab
eventKey="galleries"
title={
<React.Fragment>
{intl.formatMessage({ id: "galleries" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(performer.gallery_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<PerformerGalleriesPanel performer={performer} /> <PerformerGalleriesPanel performer={performer} />
</Tab> </Tab>
<Tab eventKey="images" title={intl.formatMessage({ id: "images" })}> <Tab
eventKey="images"
title={
<React.Fragment>
{intl.formatMessage({ id: "images" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(performer.image_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<PerformerImagesPanel performer={performer} /> <PerformerImagesPanel performer={performer} />
</Tab> </Tab>
<Tab eventKey="movies" title={intl.formatMessage({ id: "movies" })}> <Tab
eventKey="movies"
title={
<React.Fragment>
{intl.formatMessage({ id: "movies" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(performer.movie_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<PerformerMoviesPanel performer={performer} /> <PerformerMoviesPanel performer={performer} />
</Tab> </Tab>
<Tab eventKey="edit" title={intl.formatMessage({ id: "actions.edit" })}> <Tab eventKey="edit" title={intl.formatMessage({ id: "actions.edit" })}>

View File

@@ -117,7 +117,7 @@ export const SettingsServicesPanel: React.FC = () => {
function renderDeadline(until?: string) { function renderDeadline(until?: string) {
if (until) { if (until) {
const deadline = new Date(until); const deadline = new Date(until);
return `until ${deadline.toLocaleString()}`; return `until ${intl.formatDate(deadline)}`;
} }
return ""; return "";

View File

@@ -1,4 +1,4 @@
import { Tabs, Tab } from "react-bootstrap"; import { Tabs, Tab, Badge } from "react-bootstrap";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useParams, useHistory } from "react-router-dom"; import { useParams, useHistory } from "react-router-dom";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@@ -216,16 +216,43 @@ const StudioPage: React.FC<IProps> = ({ studio }) => {
activeKey={activeTabKey} activeKey={activeTabKey}
onSelect={setActiveTabKey} onSelect={setActiveTabKey}
> >
<Tab eventKey="scenes" title={intl.formatMessage({ id: "scenes" })}> <Tab
eventKey="scenes"
title={
<React.Fragment>
{intl.formatMessage({ id: "scenes" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(studio.scene_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<StudioScenesPanel studio={studio} /> <StudioScenesPanel studio={studio} />
</Tab> </Tab>
<Tab <Tab
eventKey="galleries" eventKey="galleries"
title={intl.formatMessage({ id: "galleries" })} title={
<React.Fragment>
{intl.formatMessage({ id: "galleries" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(studio.gallery_count ?? 0)}
</Badge>
</React.Fragment>
}
> >
<StudioGalleriesPanel studio={studio} /> <StudioGalleriesPanel studio={studio} />
</Tab> </Tab>
<Tab eventKey="images" title={intl.formatMessage({ id: "images" })}> <Tab
eventKey="images"
title={
<React.Fragment>
{intl.formatMessage({ id: "images" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(studio.image_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<StudioImagesPanel studio={studio} /> <StudioImagesPanel studio={studio} />
</Tab> </Tab>
<Tab <Tab
@@ -234,12 +261,29 @@ const StudioPage: React.FC<IProps> = ({ studio }) => {
> >
<StudioPerformersPanel studio={studio} /> <StudioPerformersPanel studio={studio} />
</Tab> </Tab>
<Tab eventKey="movies" title={intl.formatMessage({ id: "movies" })}> <Tab
eventKey="movies"
title={
<React.Fragment>
{intl.formatMessage({ id: "movies" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(studio.movie_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<StudioMoviesPanel studio={studio} /> <StudioMoviesPanel studio={studio} />
</Tab> </Tab>
<Tab <Tab
eventKey="childstudios" eventKey="childstudios"
title={intl.formatMessage({ id: "subsidiary_studios" })} title={
<React.Fragment>
{intl.formatMessage({ id: "subsidiary_studios" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(studio.child_studios?.length)}
</Badge>
</React.Fragment>
}
> >
<StudioChildrenPanel studio={studio} /> <StudioChildrenPanel studio={studio} />
</Tab> </Tab>

View File

@@ -1,4 +1,4 @@
import { Tabs, Tab, Dropdown } from "react-bootstrap"; import { Tabs, Tab, Dropdown, Badge } from "react-bootstrap";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useParams, useHistory } from "react-router-dom"; import { useParams, useHistory } from "react-router-dom";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
@@ -297,27 +297,68 @@ const TagPage: React.FC<IProps> = ({ tag }) => {
activeKey={activeTabKey} activeKey={activeTabKey}
onSelect={setActiveTabKey} onSelect={setActiveTabKey}
> >
<Tab eventKey="scenes" title={intl.formatMessage({ id: "scenes" })}> <Tab
eventKey="scenes"
title={
<React.Fragment>
{intl.formatMessage({ id: "scenes" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(tag.scene_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<TagScenesPanel tag={tag} /> <TagScenesPanel tag={tag} />
</Tab> </Tab>
<Tab eventKey="images" title={intl.formatMessage({ id: "images" })}> <Tab
eventKey="images"
title={
<React.Fragment>
{intl.formatMessage({ id: "images" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(tag.image_count ?? 0)}
</Badge>
</React.Fragment>
}
>
<TagImagesPanel tag={tag} /> <TagImagesPanel tag={tag} />
</Tab> </Tab>
<Tab <Tab
eventKey="galleries" eventKey="galleries"
title={intl.formatMessage({ id: "galleries" })} title={
<React.Fragment>
{intl.formatMessage({ id: "galleries" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(tag.gallery_count ?? 0)}
</Badge>
</React.Fragment>
}
> >
<TagGalleriesPanel tag={tag} /> <TagGalleriesPanel tag={tag} />
</Tab> </Tab>
<Tab <Tab
eventKey="markers" eventKey="markers"
title={intl.formatMessage({ id: "markers" })} title={
<React.Fragment>
{intl.formatMessage({ id: "markers" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(tag.scene_marker_count ?? 0)}
</Badge>
</React.Fragment>
}
> >
<TagMarkersPanel tag={tag} /> <TagMarkersPanel tag={tag} />
</Tab> </Tab>
<Tab <Tab
eventKey="performers" eventKey="performers"
title={intl.formatMessage({ id: "performers" })} title={
<React.Fragment>
{intl.formatMessage({ id: "performers" })}
<Badge className="left-spacing" pill variant="secondary">
{intl.formatNumber(tag.performer_count ?? 0)}
</Badge>
</React.Fragment>
}
> >
<TagPerformersPanel tag={tag} /> <TagPerformersPanel tag={tag} />
</Tab> </Tab>

View File

@@ -752,3 +752,7 @@ select {
background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4.95 10' fill='%23fff'><polygon points='1.41 4.67 2.48 3.18 3.54 4.67 1.41 4.67'/><polygon points='3.54 5.33 2.48 6.82 1.41 5.33 3.54 5.33'/></svg>") background: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4.95 10' fill='%23fff'><polygon points='1.41 4.67 2.48 3.18 3.54 4.67 1.41 4.67'/><polygon points='3.54 5.33 2.48 6.82 1.41 5.33 3.54 5.33'/></svg>")
no-repeat right 2px center; no-repeat right 2px center;
} }
.left-spacing {
margin-left: 0.5em;
}