Add "toolbar" buttons for some list actions (#1673)

* Support adding buttons to list "toolbar"
* Show add and remove images to gallery in toolbar
* Show button to play selected scenes to list toolbar
This commit is contained in:
gitgiggety
2021-08-26 02:46:07 +02:00
committed by GitHub
parent e98302fcd0
commit 2e83405841
6 changed files with 62 additions and 30 deletions

View File

@@ -11,6 +11,7 @@
* Added not equals/greater than/less than modifiers for resolution criteria. ([#1568](https://github.com/stashapp/stash/pull/1568)) * Added not equals/greater than/less than modifiers for resolution criteria. ([#1568](https://github.com/stashapp/stash/pull/1568))
### 🎨 Improvements ### 🎨 Improvements
* Move Play Selected Scenes, and Add/Remove Gallery Image buttons to button toolbar. ([#1673](https://github.com/stashapp/stash/pull/1673))
* Add image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672)) * Add image and gallery counts to tag list view. ([#1672](https://github.com/stashapp/stash/pull/1672))
* Prompt when leaving gallery edit page with unsaved changes. ([#1654](https://github.com/stashapp/stash/pull/1654)) * Prompt when leaving gallery edit page with unsaved changes. ([#1654](https://github.com/stashapp/stash/pull/1654))
* Show largest duplicates first in scene duplicate checker. ([#1639](https://github.com/stashapp/stash/pull/1639)) * Show largest duplicates first in scene duplicate checker. ([#1639](https://github.com/stashapp/stash/pull/1639))

View File

@@ -8,6 +8,7 @@ import { mutateAddGalleryImages } from "src/core/StashService";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { TextUtils } from "src/utils"; import { TextUtils } from "src/utils";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
interface IGalleryAddProps { interface IGalleryAddProps {
gallery: Partial<GQL.GalleryDataFragment>; gallery: Partial<GQL.GalleryDataFragment>;
@@ -87,6 +88,7 @@ export const GalleryAddPanel: React.FC<IGalleryAddProps> = ({ gallery }) => {
onClick: addImages, onClick: addImages,
isDisplayed: showWhenSelected, isDisplayed: showWhenSelected,
postRefetch: true, postRefetch: true,
icon: "plus" as IconProp,
}, },
]; ];

View File

@@ -8,6 +8,7 @@ import { showWhenSelected, PersistanceLevel } from "src/hooks/ListHook";
import { useToast } from "src/hooks"; import { useToast } from "src/hooks";
import { TextUtils } from "src/utils"; import { TextUtils } from "src/utils";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
interface IGalleryDetailsProps { interface IGalleryDetailsProps {
gallery: GQL.GalleryDataFragment; gallery: GQL.GalleryDataFragment;
@@ -81,6 +82,8 @@ export const GalleryImagesPanel: React.FC<IGalleryDetailsProps> = ({
onClick: removeImages, onClick: removeImages,
isDisplayed: showWhenSelected, isDisplayed: showWhenSelected,
postRefetch: true, postRefetch: true,
icon: "minus" as IconProp,
buttonVariant: "danger",
}, },
]; ];

View File

@@ -8,12 +8,15 @@ import {
} from "react-bootstrap"; } from "react-bootstrap";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { Icon } from "../Shared"; import { Icon } from "../Shared";
interface IListFilterOperation { interface IListFilterOperation {
text: string; text: string;
onClick: () => void; onClick: () => void;
isDisplayed?: () => boolean; isDisplayed?: () => boolean;
icon?: IconProp;
buttonVariant?: string;
} }
interface IListOperationButtonsProps { interface IListOperationButtonsProps {
@@ -60,37 +63,53 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
}; };
}); });
function maybeRenderSelectedButtons() { function maybeRenderButtons() {
if (itemsSelected && (onEdit || onDelete)) { const buttons = (otherOperations ?? []).filter((o) => {
if (!o.icon) {
return false;
}
if (!o.isDisplayed) {
return true;
}
return o.isDisplayed();
});
if (itemsSelected) {
if (onEdit) {
buttons.push({
icon: "pencil-alt",
text: intl.formatMessage({ id: "actions.edit" }),
onClick: onEdit,
});
}
if (onDelete) {
buttons.push({
icon: "trash",
text: intl.formatMessage({ id: "actions.delete" }),
onClick: onDelete,
buttonVariant: "danger",
});
}
}
if (buttons.length > 0) {
return ( return (
<ButtonGroup className="ml-2 mb-1"> <ButtonGroup className="ml-2 mb-1">
{onEdit && ( {buttons.map((button) => {
return (
<OverlayTrigger <OverlayTrigger
overlay={ overlay={<Tooltip id="edit">{button.text}</Tooltip>}
<Tooltip id="edit">
{intl.formatMessage({ id: "actions.edit" })}
</Tooltip>
}
> >
<Button variant="secondary" onClick={onEdit}> <Button
<Icon icon="pencil-alt" /> variant={button.buttonVariant ?? "secondary"}
onClick={button.onClick}
>
<Icon icon={button.icon as IconProp} />
</Button> </Button>
</OverlayTrigger> </OverlayTrigger>
)} );
})}
{onDelete && (
<OverlayTrigger
overlay={
<Tooltip id="delete">
{intl.formatMessage({ id: "actions.delete" })}
</Tooltip>
}
>
<Button variant="danger" onClick={onDelete}>
<Icon icon="trash" />
</Button>
</OverlayTrigger>
)}
</ButtonGroup> </ButtonGroup>
); );
} }
@@ -165,7 +184,7 @@ export const ListOperationButtons: React.FC<IListOperationButtonsProps> = ({
return ( return (
<> <>
{maybeRenderSelectedButtons()} {maybeRenderButtons()}
<div className="mx-2">{renderMore()}</div> <div className="mx-2">{renderMore()}</div>
</> </>

View File

@@ -3,6 +3,7 @@ import _ from "lodash";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { import {
FindScenesQueryResult, FindScenesQueryResult,
SlimSceneDataFragment, SlimSceneDataFragment,
@@ -44,6 +45,7 @@ export const SceneList: React.FC<ISceneList> = ({
text: intl.formatMessage({ id: "actions.play_selected" }), text: intl.formatMessage({ id: "actions.play_selected" }),
onClick: playSelected, onClick: playSelected,
isDisplayed: showWhenSelected, isDisplayed: showWhenSelected,
icon: "play" as IconProp,
}, },
{ {
text: intl.formatMessage({ id: "actions.play_random" }), text: intl.formatMessage({ id: "actions.play_random" }),

View File

@@ -10,6 +10,7 @@ import React, {
import { ApolloError } from "@apollo/client"; import { ApolloError } from "@apollo/client";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import Mousetrap from "mousetrap"; import Mousetrap from "mousetrap";
import { IconProp } from "@fortawesome/fontawesome-svg-core";
import { import {
SlimSceneDataFragment, SlimSceneDataFragment,
SceneMarkerDataFragment, SceneMarkerDataFragment,
@@ -96,6 +97,8 @@ export interface IListHookOperation<T> {
selectedIds: Set<string> selectedIds: Set<string>
) => boolean; ) => boolean;
postRefetch?: boolean; postRefetch?: boolean;
icon?: IconProp;
buttonVariant?: string;
} }
export enum PersistanceLevel { export enum PersistanceLevel {
@@ -357,6 +360,8 @@ const RenderList = <
return true; return true;
}, },
icon: o.icon,
buttonVariant: o.buttonVariant,
})); }));
function onEdit() { function onEdit() {