mirror of
https://github.com/stashapp/stash.git
synced 2026-04-17 04:24:07 +02:00
Add hint for alias duplicates (#3653)
* Add hint for duplicate aliases * Fix spacing * Fix country select border * Improve date picker header alignment
This commit is contained in:
parent
203afb3d1b
commit
152f9114b2
5 changed files with 82 additions and 53 deletions
|
|
@ -104,14 +104,19 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
.test({
|
||||
name: "unique",
|
||||
test: (value, context) => {
|
||||
if (!value) return true;
|
||||
const aliases = new Set(value);
|
||||
aliases.add(context.parent.name);
|
||||
return value.length + 1 === aliases.size;
|
||||
const aliases = [context.parent.name, ...value];
|
||||
const dupes = aliases
|
||||
.map((e, i, a) => {
|
||||
if (a.indexOf(e) !== i) {
|
||||
return String(i - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter((e) => e !== null) as string[];
|
||||
if (dupes.length === 0) return true;
|
||||
return new yup.ValidationError(dupes.join(" "), value, "alias_list");
|
||||
},
|
||||
message: intl.formatMessage({
|
||||
id: "validation.aliases_must_be_unique",
|
||||
}),
|
||||
}),
|
||||
gender: yup.string<GQL.GenderEnum | "">().ensure(),
|
||||
birthdate: yup
|
||||
|
|
@ -845,6 +850,14 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
);
|
||||
}
|
||||
|
||||
const aliasErrors = Array.isArray(formik.errors.alias_list)
|
||||
? formik.errors.alias_list[0]
|
||||
: formik.errors.alias_list;
|
||||
const aliasErrorMsg = aliasErrors
|
||||
? intl.formatMessage({ id: "validation.aliases_must_be_unique" })
|
||||
: undefined;
|
||||
const aliasErrorIdx = aliasErrors?.split(" ").map((e) => parseInt(e));
|
||||
|
||||
return (
|
||||
<>
|
||||
{renderScrapeModal()}
|
||||
|
|
@ -899,11 +912,8 @@ export const PerformerEditPanel: React.FC<IPerformerDetails> = ({
|
|||
<StringListInput
|
||||
value={formik.values.alias_list ?? []}
|
||||
setValue={(value) => formik.setFieldValue("alias_list", value)}
|
||||
errors={
|
||||
Array.isArray(formik.errors.alias_list)
|
||||
? formik.errors.alias_list[0]
|
||||
: formik.errors.alias_list
|
||||
}
|
||||
errors={aliasErrorMsg}
|
||||
errorIdx={aliasErrorIdx}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ interface IStringListInputProps {
|
|||
placeholder?: string;
|
||||
className?: string;
|
||||
errors?: string;
|
||||
errorIdx?: number[];
|
||||
}
|
||||
|
||||
export const StringListInput: React.FC<IStringListInputProps> = (props) => {
|
||||
|
|
@ -35,10 +36,11 @@ export const StringListInput: React.FC<IStringListInputProps> = (props) => {
|
|||
<div className={`string-list-input ${props.errors ? "is-invalid" : ""}`}>
|
||||
<Form.Group>
|
||||
{values.map((v, i) => (
|
||||
// eslint-disable-next-line react/no-array-index-key
|
||||
<InputGroup className={props.className} key={i}>
|
||||
<Form.Control
|
||||
className="text-input"
|
||||
className={`text-input ${
|
||||
props.errorIdx?.includes(i) ? "is-invalid" : ""
|
||||
}`}
|
||||
value={v}
|
||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
|
||||
valueChanged(i, e.currentTarget.value)
|
||||
|
|
@ -58,7 +60,7 @@ export const StringListInput: React.FC<IStringListInputProps> = (props) => {
|
|||
))}
|
||||
</Form.Group>
|
||||
</div>
|
||||
<div className="invalid-feedback">{props.errors}</div>
|
||||
<div className="invalid-feedback mt-n2">{props.errors}</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@
|
|||
}
|
||||
|
||||
.details-edit {
|
||||
/*
|
||||
The penultimate button should be wrapped in an unstyled div.
|
||||
/*
|
||||
The penultimate button should be wrapped in an unstyled div.
|
||||
This allows the div to expand, to right-justify the last (save / delete) button.
|
||||
*/
|
||||
|
||||
|
|
@ -285,8 +285,8 @@ button.collapse-button.btn-primary:not(:disabled):not(.disabled):active {
|
|||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.string-list-input .text-input {
|
||||
margin-bottom: 0.25rem;
|
||||
.string-list-input .input-group {
|
||||
margin-bottom: 0.35rem;
|
||||
}
|
||||
|
||||
.bulk-update-text-input {
|
||||
|
|
@ -316,14 +316,6 @@ button.collapse-button.btn-primary:not(:disabled):not(.disabled):active {
|
|||
}
|
||||
}
|
||||
|
||||
.CountrySelect {
|
||||
/* stylelint-disable */
|
||||
.react-select__control:hover {
|
||||
border: none;
|
||||
}
|
||||
/* stylelint-enable */
|
||||
}
|
||||
|
||||
.date-input.form-control:focus {
|
||||
// z-index gets set to 3 in input groups
|
||||
z-index: inherit;
|
||||
|
|
@ -339,6 +331,11 @@ div.react-datepicker {
|
|||
.react-datepicker-time__header {
|
||||
background-color: $secondary;
|
||||
color: $text-color;
|
||||
padding-top: 0.4rem;
|
||||
}
|
||||
|
||||
.react-datepicker__navigation {
|
||||
top: 0.4rem;
|
||||
}
|
||||
|
||||
.react-datepicker__day {
|
||||
|
|
@ -376,11 +373,11 @@ div.react-datepicker {
|
|||
|
||||
.react-datepicker__month-dropdown-container {
|
||||
margin-left: 0;
|
||||
margin-right: 0.25rem;
|
||||
margin-right: 0.1rem;
|
||||
}
|
||||
|
||||
.react-datepicker__year-dropdown-container {
|
||||
margin-left: 0.25rem;
|
||||
margin-left: 0.1rem;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,14 +53,19 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
.test({
|
||||
name: "unique",
|
||||
test: (value, context) => {
|
||||
if (!value) return true;
|
||||
const aliases = new Set(value);
|
||||
aliases.add(context.parent.name);
|
||||
return value.length + 1 === aliases.size;
|
||||
const aliases = [context.parent.name, ...value];
|
||||
const dupes = aliases
|
||||
.map((e, i, a) => {
|
||||
if (a.indexOf(e) !== i) {
|
||||
return String(i - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter((e) => e !== null) as string[];
|
||||
if (dupes.length === 0) return true;
|
||||
return new yup.ValidationError(dupes.join(" "), value, "aliases");
|
||||
},
|
||||
message: intl.formatMessage({
|
||||
id: "validation.aliases_must_be_unique",
|
||||
}),
|
||||
}),
|
||||
ignore_auto_tag: yup.boolean().defined(),
|
||||
stash_ids: yup.mixed<GQL.StashIdInput[]>().defined(),
|
||||
|
|
@ -187,6 +192,14 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
);
|
||||
}
|
||||
|
||||
const aliasErrors = Array.isArray(formik.errors.aliases)
|
||||
? formik.errors.aliases[0]
|
||||
: formik.errors.aliases;
|
||||
const aliasErrorMsg = aliasErrors
|
||||
? intl.formatMessage({ id: "validation.aliases_must_be_unique" })
|
||||
: undefined;
|
||||
const aliasErrorIdx = aliasErrors?.split(" ").map((e) => parseInt(e));
|
||||
|
||||
return (
|
||||
<>
|
||||
<Prompt
|
||||
|
|
@ -291,11 +304,8 @@ export const StudioEditPanel: React.FC<IStudioEditPanel> = ({
|
|||
<StringListInput
|
||||
value={formik.values.aliases ?? []}
|
||||
setValue={(value) => formik.setFieldValue("aliases", value)}
|
||||
errors={
|
||||
Array.isArray(formik.errors.aliases)
|
||||
? formik.errors.aliases[0]
|
||||
: formik.errors.aliases
|
||||
}
|
||||
errors={aliasErrorMsg}
|
||||
errorIdx={aliasErrorIdx}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
|
|
|
|||
|
|
@ -48,14 +48,19 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
.test({
|
||||
name: "unique",
|
||||
test: (value, context) => {
|
||||
if (!value) return true;
|
||||
const aliases = new Set(value);
|
||||
aliases.add(context.parent.name);
|
||||
return value.length + 1 === aliases.size;
|
||||
const aliases = [context.parent.name, ...value];
|
||||
const dupes = aliases
|
||||
.map((e, i, a) => {
|
||||
if (a.indexOf(e) !== i) {
|
||||
return String(i - 1);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
.filter((e) => e !== null) as string[];
|
||||
if (dupes.length === 0) return true;
|
||||
return new yup.ValidationError(dupes.join(" "), value, "aliases");
|
||||
},
|
||||
message: intl.formatMessage({
|
||||
id: "validation.aliases_must_be_unique",
|
||||
}),
|
||||
}),
|
||||
description: yup.string().ensure(),
|
||||
parent_ids: yup.array(yup.string().required()).defined(),
|
||||
|
|
@ -114,6 +119,14 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
ImageUtils.onImageChange(event, onImageLoad);
|
||||
}
|
||||
|
||||
const aliasErrors = Array.isArray(formik.errors.aliases)
|
||||
? formik.errors.aliases[0]
|
||||
: formik.errors.aliases;
|
||||
const aliasErrorMsg = aliasErrors
|
||||
? intl.formatMessage({ id: "validation.aliases_must_be_unique" })
|
||||
: undefined;
|
||||
const aliasErrorIdx = aliasErrors?.split(" ").map((e) => parseInt(e));
|
||||
|
||||
const isEditing = true;
|
||||
|
||||
// TODO: CSS class
|
||||
|
|
@ -165,11 +178,8 @@ export const TagEditPanel: React.FC<ITagEditPanel> = ({
|
|||
<StringListInput
|
||||
value={formik.values.aliases}
|
||||
setValue={(value) => formik.setFieldValue("aliases", value)}
|
||||
errors={
|
||||
Array.isArray(formik.errors.aliases)
|
||||
? formik.errors.aliases[0]
|
||||
: formik.errors.aliases
|
||||
}
|
||||
errors={aliasErrorMsg}
|
||||
errorIdx={aliasErrorIdx}
|
||||
/>
|
||||
</Col>
|
||||
</Form.Group>
|
||||
|
|
|
|||
Loading…
Reference in a new issue