mirror of
https://github.com/stashapp/stash.git
synced 2025-12-06 08:26:00 +01:00
Fix batch performer tagging with multiple endpoints (#3548)
* Set stash ids correctly during performer batch add * Refactor performer tagger dialogs
This commit is contained in:
parent
7cff71c35f
commit
5a41001246
4 changed files with 332 additions and 236 deletions
|
|
@ -336,6 +336,10 @@ func (s *Manager) StashBoxBatchPerformerTag(ctx context.Context, input StashBoxB
|
|||
for _, performerID := range input.PerformerIds {
|
||||
if id, err := strconv.Atoi(performerID); err == nil {
|
||||
performer, err := performerQuery.Find(ctx, id)
|
||||
if err == nil {
|
||||
err = performer.LoadStashIDs(ctx, performerQuery)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
tasks = append(tasks, StashBoxPerformerTagTask{
|
||||
performer: performer,
|
||||
|
|
@ -382,6 +386,10 @@ func (s *Manager) StashBoxBatchPerformerTag(ctx context.Context, input StashBoxB
|
|||
}
|
||||
|
||||
for _, performer := range performers {
|
||||
if err := performer.LoadStashIDs(ctx, performerQuery); err != nil {
|
||||
return fmt.Errorf("error loading stash ids for performer %s: %v", performer.Name, err)
|
||||
}
|
||||
|
||||
tasks = append(tasks, StashBoxPerformerTagTask{
|
||||
performer: performer,
|
||||
refresh: input.Refresh,
|
||||
|
|
|
|||
|
|
@ -50,17 +50,10 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
|
||||
if t.refresh {
|
||||
var performerID string
|
||||
txnErr := txn.WithReadTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
||||
stashids, _ := instance.Repository.Performer.GetStashIDs(ctx, t.performer.ID)
|
||||
for _, id := range stashids {
|
||||
if id.Endpoint == t.box.Endpoint {
|
||||
performerID = id.StashID
|
||||
}
|
||||
for _, id := range t.performer.StashIDs.List() {
|
||||
if id.Endpoint == t.box.Endpoint {
|
||||
performerID = id.StashID
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if txnErr != nil {
|
||||
logger.Warnf("error while executing read transaction: %v", err)
|
||||
}
|
||||
if performerID != "" {
|
||||
performer, err = client.FindStashBoxPerformerByID(ctx, performerID)
|
||||
|
|
@ -87,80 +80,7 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
|
||||
if performer != nil {
|
||||
if t.performer != nil {
|
||||
partial := models.NewPerformerPartial()
|
||||
|
||||
if performer.Aliases != nil && !excluded["aliases"] {
|
||||
partial.Aliases = &models.UpdateStrings{
|
||||
Values: stringslice.FromString(*performer.Aliases, ","),
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
}
|
||||
if performer.Birthdate != nil && *performer.Birthdate != "" && !excluded["birthdate"] {
|
||||
value := getDate(performer.Birthdate)
|
||||
partial.Birthdate = models.NewOptionalDate(*value)
|
||||
}
|
||||
if performer.CareerLength != nil && !excluded["career_length"] {
|
||||
partial.CareerLength = models.NewOptionalString(*performer.CareerLength)
|
||||
}
|
||||
if performer.Country != nil && !excluded["country"] {
|
||||
partial.Country = models.NewOptionalString(*performer.Country)
|
||||
}
|
||||
if performer.Ethnicity != nil && !excluded["ethnicity"] {
|
||||
partial.Ethnicity = models.NewOptionalString(*performer.Ethnicity)
|
||||
}
|
||||
if performer.EyeColor != nil && !excluded["eye_color"] {
|
||||
partial.EyeColor = models.NewOptionalString(*performer.EyeColor)
|
||||
}
|
||||
if performer.FakeTits != nil && !excluded["fake_tits"] {
|
||||
partial.FakeTits = models.NewOptionalString(*performer.FakeTits)
|
||||
}
|
||||
if performer.Gender != nil && !excluded["gender"] {
|
||||
partial.Gender = models.NewOptionalString(*performer.Gender)
|
||||
}
|
||||
if performer.Height != nil && !excluded["height"] {
|
||||
h, err := strconv.Atoi(*performer.Height)
|
||||
if err == nil {
|
||||
partial.Height = models.NewOptionalInt(h)
|
||||
}
|
||||
}
|
||||
if performer.Weight != nil && !excluded["weight"] {
|
||||
w, err := strconv.Atoi(*performer.Weight)
|
||||
if err == nil {
|
||||
partial.Weight = models.NewOptionalInt(w)
|
||||
}
|
||||
}
|
||||
if performer.Instagram != nil && !excluded["instagram"] {
|
||||
partial.Instagram = models.NewOptionalString(*performer.Instagram)
|
||||
}
|
||||
if performer.Measurements != nil && !excluded["measurements"] {
|
||||
partial.Measurements = models.NewOptionalString(*performer.Measurements)
|
||||
}
|
||||
if excluded["name"] && performer.Name != nil {
|
||||
partial.Name = models.NewOptionalString(*performer.Name)
|
||||
}
|
||||
if performer.Piercings != nil && !excluded["piercings"] {
|
||||
partial.Piercings = models.NewOptionalString(*performer.Piercings)
|
||||
}
|
||||
if performer.Tattoos != nil && !excluded["tattoos"] {
|
||||
partial.Tattoos = models.NewOptionalString(*performer.Tattoos)
|
||||
}
|
||||
if performer.Twitter != nil && !excluded["twitter"] {
|
||||
partial.Twitter = models.NewOptionalString(*performer.Twitter)
|
||||
}
|
||||
if performer.URL != nil && !excluded["url"] {
|
||||
partial.URL = models.NewOptionalString(*performer.URL)
|
||||
}
|
||||
if !t.refresh {
|
||||
partial.StashIDs = &models.UpdateStashIDs{
|
||||
StashIDs: []models.StashID{
|
||||
{
|
||||
Endpoint: t.box.Endpoint,
|
||||
StashID: *performer.RemoteSiteID,
|
||||
},
|
||||
},
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
}
|
||||
partial := t.getPartial(performer, excluded)
|
||||
|
||||
txnErr := txn.WithTxn(ctx, instance.Repository, func(ctx context.Context) error {
|
||||
r := instance.Repository
|
||||
|
|
@ -168,12 +88,13 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
|
||||
if len(performer.Images) > 0 && !excluded["image"] {
|
||||
image, err := utils.ReadImageFromURL(ctx, performer.Images[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = r.Performer.UpdateImage(ctx, t.performer.ID, image)
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
err = r.Performer.UpdateImage(ctx, t.performer.ID, image)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
logger.Warnf("Failed to read performer image: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,7 +108,7 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
return err
|
||||
})
|
||||
if txnErr != nil {
|
||||
logger.Warnf("failure to execute partial update of performer: %v", err)
|
||||
logger.Warnf("failure to execute partial update of performer: %v", txnErr)
|
||||
}
|
||||
} else if t.name != nil && performer.Name != nil {
|
||||
currentTime := time.Now()
|
||||
|
|
@ -258,6 +179,87 @@ func (t *StashBoxPerformerTagTask) stashBoxPerformerTag(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
func (t *StashBoxPerformerTagTask) getPartial(performer *models.ScrapedPerformer, excluded map[string]bool) models.PerformerPartial {
|
||||
partial := models.NewPerformerPartial()
|
||||
|
||||
if performer.Aliases != nil && !excluded["aliases"] {
|
||||
partial.Aliases = &models.UpdateStrings{
|
||||
Values: stringslice.FromString(*performer.Aliases, ","),
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
}
|
||||
if performer.Birthdate != nil && *performer.Birthdate != "" && !excluded["birthdate"] {
|
||||
value := getDate(performer.Birthdate)
|
||||
partial.Birthdate = models.NewOptionalDate(*value)
|
||||
}
|
||||
if performer.CareerLength != nil && !excluded["career_length"] {
|
||||
partial.CareerLength = models.NewOptionalString(*performer.CareerLength)
|
||||
}
|
||||
if performer.Country != nil && !excluded["country"] {
|
||||
partial.Country = models.NewOptionalString(*performer.Country)
|
||||
}
|
||||
if performer.Ethnicity != nil && !excluded["ethnicity"] {
|
||||
partial.Ethnicity = models.NewOptionalString(*performer.Ethnicity)
|
||||
}
|
||||
if performer.EyeColor != nil && !excluded["eye_color"] {
|
||||
partial.EyeColor = models.NewOptionalString(*performer.EyeColor)
|
||||
}
|
||||
if performer.FakeTits != nil && !excluded["fake_tits"] {
|
||||
partial.FakeTits = models.NewOptionalString(*performer.FakeTits)
|
||||
}
|
||||
if performer.Gender != nil && !excluded["gender"] {
|
||||
partial.Gender = models.NewOptionalString(*performer.Gender)
|
||||
}
|
||||
if performer.Height != nil && !excluded["height"] {
|
||||
h, err := strconv.Atoi(*performer.Height)
|
||||
if err == nil {
|
||||
partial.Height = models.NewOptionalInt(h)
|
||||
}
|
||||
}
|
||||
if performer.Weight != nil && !excluded["weight"] {
|
||||
w, err := strconv.Atoi(*performer.Weight)
|
||||
if err == nil {
|
||||
partial.Weight = models.NewOptionalInt(w)
|
||||
}
|
||||
}
|
||||
if performer.Instagram != nil && !excluded["instagram"] {
|
||||
partial.Instagram = models.NewOptionalString(*performer.Instagram)
|
||||
}
|
||||
if performer.Measurements != nil && !excluded["measurements"] {
|
||||
partial.Measurements = models.NewOptionalString(*performer.Measurements)
|
||||
}
|
||||
if excluded["name"] && performer.Name != nil {
|
||||
partial.Name = models.NewOptionalString(*performer.Name)
|
||||
}
|
||||
if performer.Piercings != nil && !excluded["piercings"] {
|
||||
partial.Piercings = models.NewOptionalString(*performer.Piercings)
|
||||
}
|
||||
if performer.Tattoos != nil && !excluded["tattoos"] {
|
||||
partial.Tattoos = models.NewOptionalString(*performer.Tattoos)
|
||||
}
|
||||
if performer.Twitter != nil && !excluded["twitter"] {
|
||||
partial.Twitter = models.NewOptionalString(*performer.Twitter)
|
||||
}
|
||||
if performer.URL != nil && !excluded["url"] {
|
||||
partial.URL = models.NewOptionalString(*performer.URL)
|
||||
}
|
||||
if !t.refresh {
|
||||
// #3547 - need to overwrite the stash id for the endpoint, but preserve
|
||||
// existing stash ids for other endpoints
|
||||
partial.StashIDs = &models.UpdateStashIDs{
|
||||
StashIDs: t.performer.StashIDs.List(),
|
||||
Mode: models.RelationshipUpdateModeSet,
|
||||
}
|
||||
|
||||
partial.StashIDs.Set(models.StashID{
|
||||
Endpoint: t.box.Endpoint,
|
||||
StashID: *performer.RemoteSiteID,
|
||||
})
|
||||
}
|
||||
|
||||
return partial
|
||||
}
|
||||
|
||||
func getDate(val *string) *models.Date {
|
||||
if val == nil {
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -21,6 +21,18 @@ func (u *UpdateStashIDs) AddUnique(v StashID) {
|
|||
u.StashIDs = append(u.StashIDs, v)
|
||||
}
|
||||
|
||||
// Set sets or replaces the stash id for the endpoint in the provided value.
|
||||
func (u *UpdateStashIDs) Set(v StashID) {
|
||||
for i, vv := range u.StashIDs {
|
||||
if vv.Endpoint == v.Endpoint {
|
||||
u.StashIDs[i] = v
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
u.StashIDs = append(u.StashIDs, v)
|
||||
}
|
||||
|
||||
type StashIDCriterionInput struct {
|
||||
// If present, this value is treated as a predicate.
|
||||
// That is, it will filter based on stash_ids with the matching endpoint
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import React, { useEffect, useMemo, useRef, useState } from "react";
|
||||
import { Button, Card, Form, InputGroup, ProgressBar } from "react-bootstrap";
|
||||
import { FormattedMessage, useIntl } from "react-intl";
|
||||
import { Link } from "react-router-dom";
|
||||
|
|
@ -30,6 +30,204 @@ type JobFragment = Pick<
|
|||
|
||||
const CLASSNAME = "PerformerTagger";
|
||||
|
||||
interface IPerformerBatchUpdateModal {
|
||||
performers: GQL.PerformerDataFragment[];
|
||||
isIdle: boolean;
|
||||
selectedEndpoint: { endpoint: string; index: number };
|
||||
onBatchUpdate: (queryAll: boolean, refresh: boolean) => void;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const PerformerBatchUpdateModal: React.FC<IPerformerBatchUpdateModal> = ({
|
||||
performers,
|
||||
isIdle,
|
||||
selectedEndpoint,
|
||||
onBatchUpdate,
|
||||
close,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const [queryAll, setQueryAll] = useState(false);
|
||||
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const { data: allPerformers } = GQL.useFindPerformersQuery({
|
||||
variables: {
|
||||
performer_filter: {
|
||||
stash_id_endpoint: {
|
||||
endpoint: selectedEndpoint.endpoint,
|
||||
modifier: refresh
|
||||
? GQL.CriterionModifier.NotNull
|
||||
: GQL.CriterionModifier.IsNull,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
per_page: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const performerCount = useMemo(() => {
|
||||
// get all stash ids for the selected endpoint
|
||||
const filteredStashIDs = performers.map((p) =>
|
||||
p.stash_ids.filter((s) => s.endpoint === selectedEndpoint.endpoint)
|
||||
);
|
||||
|
||||
return queryAll
|
||||
? allPerformers?.findPerformers.count
|
||||
: filteredStashIDs.filter((s) =>
|
||||
// if refresh, then we filter out the performers without a stash id
|
||||
// otherwise, we want untagged performers, filtering out those with a stash id
|
||||
refresh ? s.length > 0 : s.length === 0
|
||||
).length;
|
||||
}, [queryAll, refresh, performers, allPerformers, selectedEndpoint.endpoint]);
|
||||
|
||||
return (
|
||||
<ModalComponent
|
||||
show
|
||||
icon={faTags}
|
||||
header={intl.formatMessage({
|
||||
id: "performer_tagger.update_performers",
|
||||
})}
|
||||
accept={{
|
||||
text: intl.formatMessage({
|
||||
id: "performer_tagger.update_performers",
|
||||
}),
|
||||
onClick: () => onBatchUpdate(queryAll, refresh),
|
||||
}}
|
||||
cancel={{
|
||||
text: intl.formatMessage({ id: "actions.cancel" }),
|
||||
variant: "danger",
|
||||
onClick: () => close(),
|
||||
}}
|
||||
disabled={!isIdle}
|
||||
>
|
||||
<Form.Group>
|
||||
<Form.Label>
|
||||
<h6>
|
||||
<FormattedMessage id="performer_tagger.performer_selection" />
|
||||
</h6>
|
||||
</Form.Label>
|
||||
<Form.Check
|
||||
id="query-page"
|
||||
type="radio"
|
||||
name="performer-query"
|
||||
label={<FormattedMessage id="performer_tagger.current_page" />}
|
||||
defaultChecked
|
||||
onChange={() => setQueryAll(false)}
|
||||
/>
|
||||
<Form.Check
|
||||
id="query-all"
|
||||
type="radio"
|
||||
name="performer-query"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.query_all_performers_in_the_database",
|
||||
})}
|
||||
defaultChecked={false}
|
||||
onChange={() => setQueryAll(true)}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Label>
|
||||
<h6>
|
||||
<FormattedMessage id="performer_tagger.tag_status" />
|
||||
</h6>
|
||||
</Form.Label>
|
||||
<Form.Check
|
||||
id="untagged-performers"
|
||||
type="radio"
|
||||
name="performer-refresh"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.untagged_performers",
|
||||
})}
|
||||
defaultChecked
|
||||
onChange={() => setRefresh(false)}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.updating_untagged_performers_description" />
|
||||
</Form.Text>
|
||||
<Form.Check
|
||||
id="tagged-performers"
|
||||
type="radio"
|
||||
name="performer-refresh"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.refresh_tagged_performers",
|
||||
})}
|
||||
defaultChecked={false}
|
||||
onChange={() => setRefresh(true)}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.refreshing_will_update_the_data" />
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="performer_tagger.number_of_performers_will_be_processed"
|
||||
values={{
|
||||
performer_count: performerCount,
|
||||
}}
|
||||
/>
|
||||
</b>
|
||||
</ModalComponent>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPerformerBatchAddModal {
|
||||
isIdle: boolean;
|
||||
onBatchAdd: (input: string) => void;
|
||||
close: () => void;
|
||||
}
|
||||
|
||||
const PerformerBatchAddModal: React.FC<IPerformerBatchAddModal> = ({
|
||||
isIdle,
|
||||
onBatchAdd,
|
||||
close,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const performerInput = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
return (
|
||||
<ModalComponent
|
||||
show
|
||||
icon={faStar}
|
||||
header={intl.formatMessage({
|
||||
id: "performer_tagger.add_new_performers",
|
||||
})}
|
||||
accept={{
|
||||
text: intl.formatMessage({
|
||||
id: "performer_tagger.add_new_performers",
|
||||
}),
|
||||
onClick: () => {
|
||||
if (performerInput.current) {
|
||||
onBatchAdd(performerInput.current.value);
|
||||
} else {
|
||||
close();
|
||||
}
|
||||
},
|
||||
}}
|
||||
cancel={{
|
||||
text: intl.formatMessage({ id: "actions.cancel" }),
|
||||
variant: "danger",
|
||||
onClick: () => close(),
|
||||
}}
|
||||
disabled={!isIdle}
|
||||
>
|
||||
<Form.Control
|
||||
className="text-input"
|
||||
as="textarea"
|
||||
ref={performerInput}
|
||||
placeholder={intl.formatMessage({
|
||||
id: "performer_tagger.performer_names_separated_by_comma",
|
||||
})}
|
||||
rows={6}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.any_names_entered_will_be_queried" />
|
||||
</Form.Text>
|
||||
</ModalComponent>
|
||||
);
|
||||
};
|
||||
|
||||
interface IPerformerTaggerListProps {
|
||||
performers: GQL.PerformerDataFragment[];
|
||||
selectedEndpoint: { endpoint: string; index: number };
|
||||
|
|
@ -61,27 +259,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
|
|||
Record<string, Partial<GQL.SlimPerformerDataFragment>>
|
||||
>({});
|
||||
const [queries, setQueries] = useState<Record<string, string>>({});
|
||||
const [queryAll, setQueryAll] = useState(false);
|
||||
|
||||
const [refresh, setRefresh] = useState(false);
|
||||
const { data: allPerformers } = GQL.useFindPerformersQuery({
|
||||
variables: {
|
||||
performer_filter: {
|
||||
stash_id: {
|
||||
value: "",
|
||||
modifier: refresh
|
||||
? GQL.CriterionModifier.NotNull
|
||||
: GQL.CriterionModifier.IsNull,
|
||||
},
|
||||
},
|
||||
filter: {
|
||||
per_page: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
const [showBatchAdd, setShowBatchAdd] = useState(false);
|
||||
const [showBatchUpdate, setShowBatchUpdate] = useState(false);
|
||||
const performerInput = useRef<HTMLTextAreaElement | null>(null);
|
||||
|
||||
const [error, setError] = useState<
|
||||
Record<string, { message?: string; details?: string } | undefined>
|
||||
|
|
@ -144,14 +324,12 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
|
|||
.finally(() => setLoadingUpdate(undefined));
|
||||
};
|
||||
|
||||
async function handleBatchAdd() {
|
||||
if (performerInput.current) {
|
||||
onBatchAdd(performerInput.current.value);
|
||||
}
|
||||
async function handleBatchAdd(input: string) {
|
||||
onBatchAdd(input);
|
||||
setShowBatchAdd(false);
|
||||
}
|
||||
|
||||
const handleBatchUpdate = () => {
|
||||
const handleBatchUpdate = (queryAll: boolean, refresh: boolean) => {
|
||||
onBatchUpdate(!queryAll ? performers.map((p) => p.id) : undefined, refresh);
|
||||
setShowBatchUpdate(false);
|
||||
};
|
||||
|
|
@ -388,128 +566,24 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
|
|||
|
||||
return (
|
||||
<Card>
|
||||
<ModalComponent
|
||||
show={showBatchUpdate}
|
||||
icon={faTags}
|
||||
header={intl.formatMessage({
|
||||
id: "performer_tagger.update_performers",
|
||||
})}
|
||||
accept={{
|
||||
text: intl.formatMessage({
|
||||
id: "performer_tagger.update_performers",
|
||||
}),
|
||||
onClick: handleBatchUpdate,
|
||||
}}
|
||||
cancel={{
|
||||
text: intl.formatMessage({ id: "actions.cancel" }),
|
||||
variant: "danger",
|
||||
onClick: () => setShowBatchUpdate(false),
|
||||
}}
|
||||
disabled={!isIdle}
|
||||
>
|
||||
<Form.Group>
|
||||
<Form.Label>
|
||||
<h6>
|
||||
<FormattedMessage id="performer_tagger.performer_selection" />
|
||||
</h6>
|
||||
</Form.Label>
|
||||
<Form.Check
|
||||
id="query-page"
|
||||
type="radio"
|
||||
name="performer-query"
|
||||
label={<FormattedMessage id="performer_tagger.current_page" />}
|
||||
defaultChecked
|
||||
onChange={() => setQueryAll(false)}
|
||||
/>
|
||||
<Form.Check
|
||||
id="query-all"
|
||||
type="radio"
|
||||
name="performer-query"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.query_all_performers_in_the_database",
|
||||
})}
|
||||
defaultChecked={false}
|
||||
onChange={() => setQueryAll(true)}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Form.Group>
|
||||
<Form.Label>
|
||||
<h6>
|
||||
<FormattedMessage id="performer_tagger.tag_status" />
|
||||
</h6>
|
||||
</Form.Label>
|
||||
<Form.Check
|
||||
id="untagged-performers"
|
||||
type="radio"
|
||||
name="performer-refresh"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.untagged_performers",
|
||||
})}
|
||||
defaultChecked
|
||||
onChange={() => setRefresh(false)}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.updating_untagged_performers_description" />
|
||||
</Form.Text>
|
||||
<Form.Check
|
||||
id="tagged-performers"
|
||||
type="radio"
|
||||
name="performer-refresh"
|
||||
label={intl.formatMessage({
|
||||
id: "performer_tagger.refresh_tagged_performers",
|
||||
})}
|
||||
defaultChecked={false}
|
||||
onChange={() => setRefresh(true)}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.refreshing_will_update_the_data" />
|
||||
</Form.Text>
|
||||
</Form.Group>
|
||||
<b>
|
||||
<FormattedMessage
|
||||
id="performer_tagger.number_of_performers_will_be_processed"
|
||||
values={{
|
||||
performer_count: queryAll
|
||||
? allPerformers?.findPerformers.count
|
||||
: performers.filter((p) =>
|
||||
refresh ? p.stash_ids.length > 0 : p.stash_ids.length === 0
|
||||
).length,
|
||||
}}
|
||||
/>
|
||||
</b>
|
||||
</ModalComponent>
|
||||
<ModalComponent
|
||||
show={showBatchAdd}
|
||||
icon={faStar}
|
||||
header={intl.formatMessage({
|
||||
id: "performer_tagger.add_new_performers",
|
||||
})}
|
||||
accept={{
|
||||
text: intl.formatMessage({
|
||||
id: "performer_tagger.add_new_performers",
|
||||
}),
|
||||
onClick: handleBatchAdd,
|
||||
}}
|
||||
cancel={{
|
||||
text: intl.formatMessage({ id: "actions.cancel" }),
|
||||
variant: "danger",
|
||||
onClick: () => setShowBatchAdd(false),
|
||||
}}
|
||||
disabled={!isIdle}
|
||||
>
|
||||
<Form.Control
|
||||
className="text-input"
|
||||
as="textarea"
|
||||
ref={performerInput}
|
||||
placeholder={intl.formatMessage({
|
||||
id: "performer_tagger.performer_names_separated_by_comma",
|
||||
})}
|
||||
rows={6}
|
||||
{showBatchUpdate && (
|
||||
<PerformerBatchUpdateModal
|
||||
close={() => setShowBatchUpdate(false)}
|
||||
isIdle={isIdle}
|
||||
selectedEndpoint={selectedEndpoint}
|
||||
performers={performers}
|
||||
onBatchUpdate={handleBatchUpdate}
|
||||
/>
|
||||
<Form.Text>
|
||||
<FormattedMessage id="performer_tagger.any_names_entered_will_be_queried" />
|
||||
</Form.Text>
|
||||
</ModalComponent>
|
||||
)}
|
||||
|
||||
{showBatchAdd && (
|
||||
<PerformerBatchAddModal
|
||||
close={() => setShowBatchAdd(false)}
|
||||
isIdle={isIdle}
|
||||
onBatchAdd={handleBatchAdd}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="ml-auto mb-3">
|
||||
<Button onClick={() => setShowBatchAdd(true)}>
|
||||
<FormattedMessage id="performer_tagger.batch_add_performers" />
|
||||
|
|
|
|||
Loading…
Reference in a new issue