1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

refactor(app): migrate env var form section [EE-6232] (#10499)

* refactor(app): migrate env var form section [EE-6232]

* allow undoing delete in inputlist
This commit is contained in:
Ali 2024-01-03 08:17:54 +13:00 committed by GitHub
parent 6228314e3c
commit 488393007f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 274 additions and 209 deletions

View file

@ -0,0 +1,59 @@
import { FormError } from '../FormError';
import { InputLabeled } from '../Input/InputLabeled';
import { ItemProps } from '../InputList';
import { EnvVar } from './types';
export function EnvironmentVariableItem({
item,
onChange,
disabled,
error,
readOnly,
index,
}: ItemProps<EnvVar>) {
return (
<div className="relative flex w-full flex-col">
<div className="flex w-full items-start gap-2">
<div className="w-1/2">
<InputLabeled
className="w-full"
label="name"
required
value={item.name}
onChange={(e) => handleChange({ name: e.target.value })}
disabled={disabled}
needsDeletion={item.needsDeletion}
readOnly={readOnly}
placeholder="e.g. FOO"
size="small"
id={`env-name${index}`}
/>
{error && (
<div>
<FormError className="mt-1 !mb-0">
{Object.values(error)[0]}
</FormError>
</div>
)}
</div>
<InputLabeled
className="w-1/2"
label="value"
value={item.value}
onChange={(e) => handleChange({ value: e.target.value })}
disabled={disabled}
needsDeletion={item.needsDeletion}
readOnly={readOnly}
placeholder="e.g. bar"
size="small"
id={`env-value${index}`}
/>
</div>
</div>
);
function handleChange(partial: Partial<EnvVar>) {
onChange({ ...item, ...partial });
}
}

View file

@ -1,7 +1,8 @@
import { useState } from 'react';
import { array, object, SchemaOf, string } from 'yup';
import { array, boolean, object, SchemaOf, string } from 'yup';
import { ArrayError } from '../InputList/InputList';
import { buildUniquenessTest } from '../validate-unique';
import { AdvancedMode } from './AdvancedMode';
import { SimpleMode } from './SimpleMode';
@ -11,21 +12,24 @@ export function EnvironmentVariablesFieldset({
onChange,
values,
errors,
canUndoDelete,
}: {
values: Value;
onChange(value: Value): void;
errors?: ArrayError<Value>;
canUndoDelete?: boolean;
}) {
const [simpleMode, setSimpleMode] = useState(true);
return (
<div className="col-sm-12">
<>
{simpleMode ? (
<SimpleMode
onAdvancedModeClick={() => setSimpleMode(false)}
onChange={onChange}
value={values}
errors={errors}
canUndoDelete={canUndoDelete}
/>
) : (
<AdvancedMode
@ -34,7 +38,7 @@ export function EnvironmentVariablesFieldset({
value={values}
/>
)}
</div>
</>
);
}
@ -43,6 +47,14 @@ export function envVarValidation(): SchemaOf<Value> {
object({
name: string().required('Name is required'),
value: string().default(''),
needsDeletion: boolean().default(false),
})
).test(
'unique',
'This environment variable is already defined.',
buildUniquenessTest(
() => 'This environment variable is already defined.',
'name'
)
);
}

View file

@ -34,11 +34,13 @@ export function EnvironmentVariablesPanel({
</div>
)}
<EnvironmentVariablesFieldset
values={values}
onChange={onChange}
errors={errors}
/>
<div className="col-sm-12">
<EnvironmentVariablesFieldset
values={values}
onChange={onChange}
errors={errors}
/>
</div>
{showHelpMessage && (
<div className="col-sm-12">

View file

@ -7,24 +7,24 @@ import { Button } from '@@/buttons';
import { TextTip } from '@@/Tip/TextTip';
import { FileUploadField } from '@@/form-components/FileUpload';
import { InputList } from '@@/form-components/InputList';
import { ArrayError, ItemProps } from '@@/form-components/InputList/InputList';
import { InputLabeled } from '@@/form-components/Input/InputLabeled';
import { ArrayError } from '@@/form-components/InputList/InputList';
import { FormError } from '../FormError';
import { type EnvVar, type Value } from './types';
import type { Value } from './types';
import { parseDotEnvFile } from './utils';
import { EnvironmentVariableItem } from './EnvironmentVariableItem';
export function SimpleMode({
value,
onChange,
onAdvancedModeClick,
errors,
canUndoDelete,
}: {
value: Value;
onChange: (value: Value) => void;
onAdvancedModeClick: () => void;
errors?: ArrayError<Value>;
canUndoDelete?: boolean;
}) {
return (
<>
@ -47,13 +47,17 @@ export function SimpleMode({
onChange={onChange}
value={value}
isAddButtonHidden
item={Item}
item={EnvironmentVariableItem}
errors={errors}
canUndoDelete={canUndoDelete}
/>
<div className="flex gap-2">
<Button
onClick={() => onChange([...value, { name: '', value: '' }])}
onClick={() =>
onChange([...value, { name: '', value: '', needsDeletion: false }])
}
className="!ml-0"
color="default"
icon={Plus}
>
@ -66,54 +70,6 @@ export function SimpleMode({
);
}
function Item({
item,
onChange,
disabled,
error,
readOnly,
index,
}: ItemProps<EnvVar>) {
return (
<div className="relative flex w-full flex-col">
<div className="flex w-full items-center gap-2">
<InputLabeled
className="w-1/2"
label="name"
value={item.name}
onChange={(e) => handleChange({ name: e.target.value })}
disabled={disabled}
readOnly={readOnly}
placeholder="e.g. FOO"
size="small"
id={`env-name${index}`}
/>
<InputLabeled
className="w-1/2"
label="value"
value={item.value}
onChange={(e) => handleChange({ value: e.target.value })}
disabled={disabled}
readOnly={readOnly}
placeholder="e.g. bar"
size="small"
id={`env-value${index}`}
/>
</div>
{!!error && (
<div className="absolute -bottom-5">
<FormError className="m-0">{Object.values(error)[0]}</FormError>
</div>
)}
</div>
);
function handleChange(partial: Partial<EnvVar>) {
onChange({ ...item, ...partial });
}
}
function FileEnv({ onChooseFile }: { onChooseFile: (file: Value) => void }) {
const [file, setFile] = useState<File | null>(null);

View file

@ -1,6 +1,7 @@
export interface EnvVar {
name: string;
value?: string;
needsDeletion?: boolean;
}
export type Value = Array<EnvVar>;