ui(admin): allow editing allocations for servers
This commit is contained in:
parent
656ac62ad2
commit
a6ab61adba
13 changed files with 219 additions and 84 deletions
|
@ -3,6 +3,7 @@ import { Field as FormikField, FieldProps } from 'formik';
|
|||
import Input from '@/components/elements/Input';
|
||||
import Label from '@/components/elements/Label';
|
||||
import InputError from '@/components/elements/InputError';
|
||||
import tw from 'twin.macro';
|
||||
|
||||
interface OwnProps {
|
||||
name: string;
|
||||
|
@ -20,7 +21,10 @@ const Field = forwardRef<HTMLInputElement, Props>(({ id, name, light = false, la
|
|||
({ field, form: { errors, touched } }: FieldProps) => (
|
||||
<div>
|
||||
{label &&
|
||||
<Label htmlFor={id} isLight={light}>{label}</Label>
|
||||
<div css={tw`flex flex-row`} title={description}>
|
||||
<Label htmlFor={id} isLight={light}>{label}</Label>
|
||||
{/*{description && <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" css={tw`h-4 w-4 ml-1 cursor-pointer`}><path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/></svg>}*/}
|
||||
</div>
|
||||
}
|
||||
<Input
|
||||
id={id}
|
||||
|
|
|
@ -5,7 +5,7 @@ interface Props {
|
|||
}
|
||||
|
||||
const Select = styled.select<Props>`
|
||||
${tw`shadow-none block p-3 pr-8 rounded border w-full text-sm transition-colors duration-150 ease-linear`};
|
||||
${tw`shadow-none block p-3 pr-8 rounded border-2 w-full text-sm transition-colors duration-150 ease-linear`};
|
||||
|
||||
&, &:hover:not(:disabled), &:focus {
|
||||
${tw`outline-none`};
|
||||
|
|
|
@ -2,6 +2,7 @@ import { CSSObject } from '@emotion/serialize';
|
|||
import { Field as FormikField, FieldProps } from 'formik';
|
||||
import React, { forwardRef } from 'react';
|
||||
import Select, { ContainerProps, ControlProps, GroupProps, IndicatorContainerProps, IndicatorProps, InputProps, MenuListComponentProps, MenuProps, MultiValueProps, OptionProps, PlaceholderProps, SingleValueProps, StylesConfig, ValueContainerProps } from 'react-select';
|
||||
import Async from 'react-select/async';
|
||||
import Creatable from 'react-select/creatable';
|
||||
import tw, { theme } from 'twin.macro';
|
||||
import Label from '@/components/elements/Label';
|
||||
|
@ -219,7 +220,7 @@ export interface Option {
|
|||
label: string;
|
||||
}
|
||||
|
||||
interface Props {
|
||||
interface SelectFieldProps {
|
||||
id?: string;
|
||||
name: string;
|
||||
label?: string;
|
||||
|
@ -242,26 +243,24 @@ interface Props {
|
|||
className?: string;
|
||||
}
|
||||
|
||||
const SelectField = forwardRef<HTMLElement, Props>(({ id, name, label, description, validate, className, isMulti, isCreatable, ...props }, ref) => {
|
||||
const { options } = props;
|
||||
const SelectField = forwardRef<HTMLElement, SelectFieldProps>(
|
||||
function Select2 ({ id, name, label, description, validate, className, isMulti, isCreatable, ...props }, ref) {
|
||||
const { options } = props;
|
||||
|
||||
const onChange = (options: Option | Option[], name: string, setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void) => {
|
||||
if (isMulti) {
|
||||
setFieldValue(name, (options as Option[]).map(o => o.value));
|
||||
return;
|
||||
}
|
||||
const onChange = (options: Option | Option[], name: string, setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void) => {
|
||||
if (isMulti) {
|
||||
setFieldValue(name, (options as Option[]).map(o => o.value));
|
||||
return;
|
||||
}
|
||||
|
||||
setFieldValue(name, (options as Option).value);
|
||||
};
|
||||
setFieldValue(name, (options as Option).value);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormikField innerRef={ref} name={name} validate={validate}>
|
||||
{
|
||||
({ field, form: { errors, touched, setFieldValue } }: FieldProps) => (
|
||||
return (
|
||||
<FormikField innerRef={ref} name={name} validate={validate}>
|
||||
{({ field, form: { errors, touched, setFieldValue } }: FieldProps) => (
|
||||
<div className={className}>
|
||||
{label &&
|
||||
<Label htmlFor={id}>{label}</Label>
|
||||
}
|
||||
{label && <Label htmlFor={id}>{label}</Label>}
|
||||
{isCreatable ?
|
||||
<Creatable
|
||||
{...field}
|
||||
|
@ -291,11 +290,64 @@ const SelectField = forwardRef<HTMLElement, Props>(({ id, name, label, descripti
|
|||
description ? <p css={tw`text-neutral-400 text-xs mt-1`}>{description}</p> : null
|
||||
}
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</FormikField>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
interface AsyncSelectFieldProps {
|
||||
id?: string;
|
||||
name: string;
|
||||
label?: string;
|
||||
description?: string;
|
||||
placeholder?: string;
|
||||
validate?: (value: any) => undefined | string | Promise<any>;
|
||||
|
||||
isMulti?: boolean;
|
||||
|
||||
className?: string;
|
||||
|
||||
loadOptions(inputValue: string, callback: (options: Array<Option>) => void): void;
|
||||
}
|
||||
|
||||
const AsyncSelectField = forwardRef<HTMLElement, AsyncSelectFieldProps>(
|
||||
function AsyncSelect2 ({ id, name, label, description, validate, className, isMulti, ...props }, ref) {
|
||||
const onChange = (options: Option | Option[], name: string, setFieldValue: (field: string, value: any, shouldValidate?: boolean) => void) => {
|
||||
if (isMulti) {
|
||||
setFieldValue(name, (options as Option[]).map(o => Number(o.value)));
|
||||
return;
|
||||
}
|
||||
</FormikField>
|
||||
);
|
||||
});
|
||||
SelectField.displayName = 'SelectField';
|
||||
|
||||
setFieldValue(name, Number((options as Option).value));
|
||||
};
|
||||
|
||||
return (
|
||||
<FormikField innerRef={ref} name={name} validate={validate}>
|
||||
{({ field, form: { errors, touched, setFieldValue } }: FieldProps) => (
|
||||
<div className={className}>
|
||||
{label && <Label htmlFor={id}>{label}</Label>}
|
||||
<Async
|
||||
{...props}
|
||||
id={id}
|
||||
name={name}
|
||||
styles={SelectStyle}
|
||||
onChange={o => onChange(o, name, setFieldValue)}
|
||||
isMulti={isMulti}
|
||||
/>
|
||||
{touched[field.name] && errors[field.name] ?
|
||||
<p css={tw`text-red-200 text-xs mt-1`}>
|
||||
{(errors[field.name] as string).charAt(0).toUpperCase() + (errors[field.name] as string).slice(1)}
|
||||
</p>
|
||||
:
|
||||
description ? <p css={tw`text-neutral-400 text-xs mt-1`}>{description}</p> : null
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</FormikField>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default SelectField;
|
||||
export { AsyncSelectField };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue