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:
DingDongSoLong4 2023-04-24 22:56:21 +02:00 committed by GitHub
parent 203afb3d1b
commit 152f9114b2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 53 deletions

View file

@ -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>

View file

@ -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>
</>
);
};

View file

@ -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;
}

View file

@ -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>

View file

@ -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>