mirror of
https://github.com/invoke-ai/InvokeAI
synced 2024-08-30 20:32:17 +00:00
fix(ui): Clean up manual add forms
This commit is contained in:
parent
5906888477
commit
2aefa06ef1
@ -333,6 +333,7 @@
|
|||||||
"addNewModel": "Add New Model",
|
"addNewModel": "Add New Model",
|
||||||
"addCheckpointModel": "Add Checkpoint / Safetensor Model",
|
"addCheckpointModel": "Add Checkpoint / Safetensor Model",
|
||||||
"addDiffuserModel": "Add Diffusers",
|
"addDiffuserModel": "Add Diffusers",
|
||||||
|
"scanForModels": "Scan For Models",
|
||||||
"addManually": "Add Manually",
|
"addManually": "Add Manually",
|
||||||
"manual": "Manual",
|
"manual": "Manual",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
import { Flex } from '@chakra-ui/react';
|
||||||
|
import { ReactElement } from 'react';
|
||||||
|
|
||||||
|
export function IAIFormItemWrapper({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactElement | ReactElement[];
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Flex
|
||||||
|
sx={{
|
||||||
|
flexDirection: 'column',
|
||||||
|
padding: 4,
|
||||||
|
rowGap: 4,
|
||||||
|
borderRadius: 'base',
|
||||||
|
width: 'full',
|
||||||
|
bg: 'base.900',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
Flex,
|
||||||
FormControl,
|
FormControl,
|
||||||
FormErrorMessage,
|
FormErrorMessage,
|
||||||
FormHelperText,
|
FormHelperText,
|
||||||
@ -28,6 +29,7 @@ import type { RootState } from 'app/store';
|
|||||||
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
import { setAddNewModelUIOption } from 'features/ui/store/uiSlice';
|
||||||
import type { FieldInputProps, FormikProps } from 'formik';
|
import type { FieldInputProps, FormikProps } from 'formik';
|
||||||
import IAIForm from 'common/components/IAIForm';
|
import IAIForm from 'common/components/IAIForm';
|
||||||
|
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
||||||
|
|
||||||
const MIN_MODEL_SIZE = 64;
|
const MIN_MODEL_SIZE = 64;
|
||||||
const MAX_MODEL_SIZE = 2048;
|
const MAX_MODEL_SIZE = 2048;
|
||||||
@ -71,14 +73,20 @@ export default function AddCheckpointModel() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<VStack gap={2} alignItems="flex-start">
|
<VStack gap={2} alignItems="flex-start">
|
||||||
<SearchModels />
|
<Flex columnGap={4}>
|
||||||
<IAICheckbox
|
<IAICheckbox
|
||||||
label={t('modelManager.addManually')}
|
isChecked={!addManually}
|
||||||
isChecked={addManually}
|
label={t('modelManager.scanForModels')}
|
||||||
onChange={() => setAddmanually(!addManually)}
|
onChange={() => setAddmanually(!addManually)}
|
||||||
/>
|
/>
|
||||||
|
<IAICheckbox
|
||||||
|
label={t('modelManager.addManually')}
|
||||||
|
isChecked={addManually}
|
||||||
|
onChange={() => setAddmanually(!addManually)}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
|
||||||
{addManually && (
|
{addManually ? (
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={addModelFormValues}
|
initialValues={addModelFormValues}
|
||||||
onSubmit={addModelFormSubmitHandler}
|
onSubmit={addModelFormSubmitHandler}
|
||||||
@ -90,209 +98,225 @@ export default function AddCheckpointModel() {
|
|||||||
{t('modelManager.manual')}
|
{t('modelManager.manual')}
|
||||||
</Text>
|
</Text>
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<FormControl
|
<IAIFormItemWrapper>
|
||||||
isInvalid={!!errors.name && touched.name}
|
<FormControl
|
||||||
isRequired
|
isInvalid={!!errors.name && touched.name}
|
||||||
>
|
isRequired
|
||||||
<FormLabel htmlFor="name" fontSize="sm">
|
>
|
||||||
{t('modelManager.name')}
|
<FormLabel htmlFor="name" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.name')}
|
||||||
<VStack alignItems="start">
|
</FormLabel>
|
||||||
<Field
|
<VStack alignItems="start">
|
||||||
as={IAIInput}
|
<Field
|
||||||
id="name"
|
as={IAIInput}
|
||||||
name="name"
|
id="name"
|
||||||
type="text"
|
name="name"
|
||||||
validate={baseValidation}
|
type="text"
|
||||||
width="full"
|
validate={baseValidation}
|
||||||
/>
|
width="full"
|
||||||
{!!errors.name && touched.name ? (
|
/>
|
||||||
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
{!!errors.name && touched.name ? (
|
||||||
) : (
|
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
||||||
<FormHelperText margin={0}>
|
) : (
|
||||||
{t('modelManager.nameValidationMsg')}
|
<FormHelperText margin={0}>
|
||||||
</FormHelperText>
|
{t('modelManager.nameValidationMsg')}
|
||||||
)}
|
</FormHelperText>
|
||||||
</VStack>
|
)}
|
||||||
</FormControl>
|
</VStack>
|
||||||
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<FormControl
|
<IAIFormItemWrapper>
|
||||||
isInvalid={!!errors.description && touched.description}
|
<FormControl
|
||||||
isRequired
|
isInvalid={!!errors.description && touched.description}
|
||||||
>
|
isRequired
|
||||||
<FormLabel htmlFor="description" fontSize="sm">
|
>
|
||||||
{t('modelManager.description')}
|
<FormLabel htmlFor="description" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.description')}
|
||||||
<VStack alignItems="start">
|
</FormLabel>
|
||||||
<Field
|
<VStack alignItems="start">
|
||||||
as={IAIInput}
|
<Field
|
||||||
id="description"
|
as={IAIInput}
|
||||||
name="description"
|
id="description"
|
||||||
type="text"
|
name="description"
|
||||||
width="full"
|
type="text"
|
||||||
/>
|
width="full"
|
||||||
{!!errors.description && touched.description ? (
|
/>
|
||||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
{!!errors.description && touched.description ? (
|
||||||
) : (
|
<FormErrorMessage>
|
||||||
<FormHelperText margin={0}>
|
{errors.description}
|
||||||
{t('modelManager.descriptionValidationMsg')}
|
</FormErrorMessage>
|
||||||
</FormHelperText>
|
) : (
|
||||||
)}
|
<FormHelperText margin={0}>
|
||||||
</VStack>
|
{t('modelManager.descriptionValidationMsg')}
|
||||||
</FormControl>
|
</FormHelperText>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
{/* Config */}
|
{/* Config */}
|
||||||
<FormControl
|
<IAIFormItemWrapper>
|
||||||
isInvalid={!!errors.config && touched.config}
|
<FormControl
|
||||||
isRequired
|
isInvalid={!!errors.config && touched.config}
|
||||||
>
|
isRequired
|
||||||
<FormLabel htmlFor="config" fontSize="sm">
|
>
|
||||||
{t('modelManager.config')}
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.config')}
|
||||||
<VStack alignItems="start">
|
</FormLabel>
|
||||||
<Field
|
<VStack alignItems="start">
|
||||||
as={IAIInput}
|
<Field
|
||||||
id="config"
|
as={IAIInput}
|
||||||
name="config"
|
id="config"
|
||||||
type="text"
|
name="config"
|
||||||
width="full"
|
type="text"
|
||||||
/>
|
width="full"
|
||||||
{!!errors.config && touched.config ? (
|
/>
|
||||||
<FormErrorMessage>{errors.config}</FormErrorMessage>
|
{!!errors.config && touched.config ? (
|
||||||
) : (
|
<FormErrorMessage>{errors.config}</FormErrorMessage>
|
||||||
<FormHelperText margin={0}>
|
) : (
|
||||||
{t('modelManager.configValidationMsg')}
|
<FormHelperText margin={0}>
|
||||||
</FormHelperText>
|
{t('modelManager.configValidationMsg')}
|
||||||
)}
|
</FormHelperText>
|
||||||
</VStack>
|
)}
|
||||||
</FormControl>
|
</VStack>
|
||||||
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
{/* Weights */}
|
{/* Weights */}
|
||||||
<FormControl
|
<IAIFormItemWrapper>
|
||||||
isInvalid={!!errors.weights && touched.weights}
|
<FormControl
|
||||||
isRequired
|
isInvalid={!!errors.weights && touched.weights}
|
||||||
>
|
isRequired
|
||||||
<FormLabel htmlFor="config" fontSize="sm">
|
>
|
||||||
{t('modelManager.modelLocation')}
|
<FormLabel htmlFor="config" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.modelLocation')}
|
||||||
<VStack alignItems="start">
|
</FormLabel>
|
||||||
<Field
|
<VStack alignItems="start">
|
||||||
as={IAIInput}
|
<Field
|
||||||
id="weights"
|
as={IAIInput}
|
||||||
name="weights"
|
id="weights"
|
||||||
type="text"
|
name="weights"
|
||||||
width="full"
|
type="text"
|
||||||
/>
|
width="full"
|
||||||
{!!errors.weights && touched.weights ? (
|
/>
|
||||||
<FormErrorMessage>{errors.weights}</FormErrorMessage>
|
{!!errors.weights && touched.weights ? (
|
||||||
) : (
|
<FormErrorMessage>{errors.weights}</FormErrorMessage>
|
||||||
<FormHelperText margin={0}>
|
) : (
|
||||||
{t('modelManager.modelLocationValidationMsg')}
|
<FormHelperText margin={0}>
|
||||||
</FormHelperText>
|
{t('modelManager.modelLocationValidationMsg')}
|
||||||
)}
|
</FormHelperText>
|
||||||
</VStack>
|
)}
|
||||||
</FormControl>
|
</VStack>
|
||||||
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
{/* VAE */}
|
{/* VAE */}
|
||||||
<FormControl isInvalid={!!errors.vae && touched.vae}>
|
<IAIFormItemWrapper>
|
||||||
<FormLabel htmlFor="vae" fontSize="sm">
|
<FormControl isInvalid={!!errors.vae && touched.vae}>
|
||||||
{t('modelManager.vaeLocation')}
|
<FormLabel htmlFor="vae" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.vaeLocation')}
|
||||||
<VStack alignItems="start">
|
|
||||||
<Field
|
|
||||||
as={IAIInput}
|
|
||||||
id="vae"
|
|
||||||
name="vae"
|
|
||||||
type="text"
|
|
||||||
width="full"
|
|
||||||
/>
|
|
||||||
{!!errors.vae && touched.vae ? (
|
|
||||||
<FormErrorMessage>{errors.vae}</FormErrorMessage>
|
|
||||||
) : (
|
|
||||||
<FormHelperText margin={0}>
|
|
||||||
{t('modelManager.vaeLocationValidationMsg')}
|
|
||||||
</FormHelperText>
|
|
||||||
)}
|
|
||||||
</VStack>
|
|
||||||
</FormControl>
|
|
||||||
|
|
||||||
<HStack width="100%" gap={8}>
|
|
||||||
{/* Width */}
|
|
||||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
|
||||||
<FormLabel htmlFor="width" fontSize="sm">
|
|
||||||
{t('modelManager.width')}
|
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
<VStack alignItems="start">
|
<VStack alignItems="start">
|
||||||
<Field id="width" name="width">
|
<Field
|
||||||
{({
|
as={IAIInput}
|
||||||
field,
|
id="vae"
|
||||||
form,
|
name="vae"
|
||||||
}: {
|
type="text"
|
||||||
field: FieldInputProps<number>;
|
width="full"
|
||||||
form: FormikProps<InvokeModelConfigProps>;
|
/>
|
||||||
}) => (
|
{!!errors.vae && touched.vae ? (
|
||||||
<IAINumberInput
|
<FormErrorMessage>{errors.vae}</FormErrorMessage>
|
||||||
id="width"
|
|
||||||
name="width"
|
|
||||||
min={MIN_MODEL_SIZE}
|
|
||||||
max={MAX_MODEL_SIZE}
|
|
||||||
step={64}
|
|
||||||
value={form.values.width}
|
|
||||||
onChange={(value) =>
|
|
||||||
form.setFieldValue(field.name, Number(value))
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
{!!errors.width && touched.width ? (
|
|
||||||
<FormErrorMessage>{errors.width}</FormErrorMessage>
|
|
||||||
) : (
|
) : (
|
||||||
<FormHelperText margin={0}>
|
<FormHelperText margin={0}>
|
||||||
{t('modelManager.widthValidationMsg')}
|
{t('modelManager.vaeLocationValidationMsg')}
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
|
<HStack width="100%">
|
||||||
|
{/* Width */}
|
||||||
|
<IAIFormItemWrapper>
|
||||||
|
<FormControl isInvalid={!!errors.width && touched.width}>
|
||||||
|
<FormLabel htmlFor="width" fontSize="sm">
|
||||||
|
{t('modelManager.width')}
|
||||||
|
</FormLabel>
|
||||||
|
<VStack alignItems="start">
|
||||||
|
<Field id="width" name="width">
|
||||||
|
{({
|
||||||
|
field,
|
||||||
|
form,
|
||||||
|
}: {
|
||||||
|
field: FieldInputProps<number>;
|
||||||
|
form: FormikProps<InvokeModelConfigProps>;
|
||||||
|
}) => (
|
||||||
|
<IAINumberInput
|
||||||
|
id="width"
|
||||||
|
name="width"
|
||||||
|
min={MIN_MODEL_SIZE}
|
||||||
|
max={MAX_MODEL_SIZE}
|
||||||
|
step={64}
|
||||||
|
value={form.values.width}
|
||||||
|
onChange={(value) =>
|
||||||
|
form.setFieldValue(field.name, Number(value))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
{!!errors.width && touched.width ? (
|
||||||
|
<FormErrorMessage>{errors.width}</FormErrorMessage>
|
||||||
|
) : (
|
||||||
|
<FormHelperText margin={0}>
|
||||||
|
{t('modelManager.widthValidationMsg')}
|
||||||
|
</FormHelperText>
|
||||||
|
)}
|
||||||
|
</VStack>
|
||||||
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
{/* Height */}
|
{/* Height */}
|
||||||
<FormControl isInvalid={!!errors.height && touched.height}>
|
<IAIFormItemWrapper>
|
||||||
<FormLabel htmlFor="height" fontSize="sm">
|
<FormControl isInvalid={!!errors.height && touched.height}>
|
||||||
{t('modelManager.height')}
|
<FormLabel htmlFor="height" fontSize="sm">
|
||||||
</FormLabel>
|
{t('modelManager.height')}
|
||||||
<VStack alignItems="start">
|
</FormLabel>
|
||||||
<Field id="height" name="height">
|
<VStack alignItems="start">
|
||||||
{({
|
<Field id="height" name="height">
|
||||||
field,
|
{({
|
||||||
form,
|
field,
|
||||||
}: {
|
form,
|
||||||
field: FieldInputProps<number>;
|
}: {
|
||||||
form: FormikProps<InvokeModelConfigProps>;
|
field: FieldInputProps<number>;
|
||||||
}) => (
|
form: FormikProps<InvokeModelConfigProps>;
|
||||||
<IAINumberInput
|
}) => (
|
||||||
id="height"
|
<IAINumberInput
|
||||||
name="height"
|
id="height"
|
||||||
min={MIN_MODEL_SIZE}
|
name="height"
|
||||||
max={MAX_MODEL_SIZE}
|
min={MIN_MODEL_SIZE}
|
||||||
step={64}
|
max={MAX_MODEL_SIZE}
|
||||||
value={form.values.height}
|
step={64}
|
||||||
onChange={(value) =>
|
value={form.values.height}
|
||||||
form.setFieldValue(field.name, Number(value))
|
onChange={(value) =>
|
||||||
}
|
form.setFieldValue(field.name, Number(value))
|
||||||
/>
|
}
|
||||||
)}
|
/>
|
||||||
</Field>
|
)}
|
||||||
|
</Field>
|
||||||
|
|
||||||
{!!errors.height && touched.height ? (
|
{!!errors.height && touched.height ? (
|
||||||
<FormErrorMessage>{errors.height}</FormErrorMessage>
|
<FormErrorMessage>{errors.height}</FormErrorMessage>
|
||||||
) : (
|
) : (
|
||||||
<FormHelperText margin={0}>
|
<FormHelperText margin={0}>
|
||||||
{t('modelManager.heightValidationMsg')}
|
{t('modelManager.heightValidationMsg')}
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
</IAIFormItemWrapper>
|
||||||
</HStack>
|
</HStack>
|
||||||
|
|
||||||
<IAIButton
|
<IAIButton
|
||||||
@ -306,6 +330,8 @@ export default function AddCheckpointModel() {
|
|||||||
</IAIForm>
|
</IAIForm>
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
|
) : (
|
||||||
|
<SearchModels />
|
||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
);
|
);
|
||||||
|
@ -17,29 +17,8 @@ import { Field, Formik } from 'formik';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
import type { RootState } from 'app/store';
|
import type { RootState } from 'app/store';
|
||||||
import type { ReactElement } from 'react';
|
|
||||||
import IAIForm from 'common/components/IAIForm';
|
import IAIForm from 'common/components/IAIForm';
|
||||||
|
import { IAIFormItemWrapper } from 'common/components/IAIForms/IAIFormItemWrapper';
|
||||||
function FormItemWrapper({
|
|
||||||
children,
|
|
||||||
}: {
|
|
||||||
children: ReactElement | ReactElement[];
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<Flex
|
|
||||||
sx={{
|
|
||||||
flexDirection: 'column',
|
|
||||||
padding: 4,
|
|
||||||
rowGap: 4,
|
|
||||||
borderRadius: 'base',
|
|
||||||
width: 'full',
|
|
||||||
bg: 'base.900',
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Flex>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function AddDiffusersModel() {
|
export default function AddDiffusersModel() {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
@ -95,7 +74,7 @@ export default function AddDiffusersModel() {
|
|||||||
{({ handleSubmit, errors, touched }) => (
|
{({ handleSubmit, errors, touched }) => (
|
||||||
<IAIForm onSubmit={handleSubmit}>
|
<IAIForm onSubmit={handleSubmit}>
|
||||||
<VStack rowGap={2}>
|
<VStack rowGap={2}>
|
||||||
<FormItemWrapper>
|
<IAIFormItemWrapper>
|
||||||
{/* Name */}
|
{/* Name */}
|
||||||
<FormControl
|
<FormControl
|
||||||
isInvalid={!!errors.name && touched.name}
|
isInvalid={!!errors.name && touched.name}
|
||||||
@ -123,9 +102,9 @@ export default function AddDiffusersModel() {
|
|||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItemWrapper>
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
<FormItemWrapper>
|
<IAIFormItemWrapper>
|
||||||
{/* Description */}
|
{/* Description */}
|
||||||
<FormControl
|
<FormControl
|
||||||
isInvalid={!!errors.description && touched.description}
|
isInvalid={!!errors.description && touched.description}
|
||||||
@ -152,9 +131,9 @@ export default function AddDiffusersModel() {
|
|||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItemWrapper>
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
<FormItemWrapper>
|
<IAIFormItemWrapper>
|
||||||
<Text fontWeight="bold" fontSize="sm">
|
<Text fontWeight="bold" fontSize="sm">
|
||||||
{t('modelManager.formMessageDiffusersModelLocation')}
|
{t('modelManager.formMessageDiffusersModelLocation')}
|
||||||
</Text>
|
</Text>
|
||||||
@ -213,9 +192,9 @@ export default function AddDiffusersModel() {
|
|||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItemWrapper>
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
<FormItemWrapper>
|
<IAIFormItemWrapper>
|
||||||
{/* VAE Path */}
|
{/* VAE Path */}
|
||||||
<Text fontWeight="bold">
|
<Text fontWeight="bold">
|
||||||
{t('modelManager.formMessageDiffusersVAELocation')}
|
{t('modelManager.formMessageDiffusersVAELocation')}
|
||||||
@ -277,7 +256,7 @@ export default function AddDiffusersModel() {
|
|||||||
)}
|
)}
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</FormItemWrapper>
|
</IAIFormItemWrapper>
|
||||||
|
|
||||||
<IAIButton type="submit" isLoading={isProcessing}>
|
<IAIButton type="submit" isLoading={isProcessing}>
|
||||||
{t('modelManager.addModel')}
|
{t('modelManager.addModel')}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user