portainer/app/react/edge/templates/custom-templates/CreateView/InnerForm.tsx

200 lines
5.8 KiB
TypeScript

import { Form, FormikErrors, useFormikContext } from 'formik';
import { CommonFields } from '@/react/portainer/custom-templates/components/CommonFields';
import { CustomTemplatesVariablesDefinitionField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField';
import { PlatformField } from '@/react/portainer/custom-templates/components/PlatformSelector';
import { GitForm } from '@/react/portainer/gitops/GitForm';
import {
getTemplateVariables,
intersectVariables,
isTemplateVariablesEnabled,
} from '@/react/portainer/custom-templates/components/utils';
import { TemplateTypeSelector } from '@/react/portainer/custom-templates/components/TemplateTypeSelector';
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
import { applySetStateAction } from '@/react-tools/apply-set-state-action';
import { BoxSelector } from '@@/BoxSelector';
import { WebEditorForm, usePreventExit } from '@@/WebEditorForm';
import { FileUploadForm } from '@@/form-components/FileUpload';
import { FormActions } from '@@/form-components/FormActions';
import { FormSection } from '@@/form-components/FormSection';
import {
editor,
upload,
git,
} from '@@/BoxSelector/common-options/build-methods';
import { FormValues, Method, buildMethods } from './types';
import { EdgeSettingsFieldset } from './EdgeSettingsFieldset';
export function InnerForm({ isLoading }: { isLoading: boolean }) {
const {
values,
initialValues,
setFieldValue,
errors,
isValid,
setFieldError,
setValues,
isSubmitting,
} = useFormikContext<FormValues>();
usePreventExit(
initialValues.FileContent,
values.FileContent,
values.Method === editor.value && !isSubmitting
);
const isGit = values.Method === git.value;
return (
<Form className="form-horizontal">
<CommonFields
values={values}
onChange={(newValues) =>
setValues((values) => ({ ...values, ...newValues }))
}
errors={errors}
/>
<PlatformField
value={values.Platform}
onChange={(value) => setFieldValue('Platform', value)}
/>
<TemplateTypeSelector
value={values.Type}
onChange={(value) => setFieldValue('Type', value)}
/>
<FormSection title="Build method">
<BoxSelector
slim
options={buildMethods}
value={values.Method}
onChange={handleChangeMethod}
radioName="buildMethod"
/>
</FormSection>
{values.Method === editor.value && (
<WebEditorForm
id="custom-template-creation-editor"
value={values.FileContent}
onChange={handleChangeFileContent}
yaml
placeholder="Define or paste the content of your docker compose file here"
error={errors.FileContent}
>
<p>
You can get more information about Compose file format in the{' '}
<a
href="https://docs.docker.com/compose/compose-file/"
target="_blank"
rel="noreferrer"
>
official documentation
</a>
.
</p>
</WebEditorForm>
)}
{values.Method === upload.value && (
<FileUploadForm
description="You can upload a Compose file from your computer."
value={values.File}
onChange={(value) => setFieldValue('File', value)}
required
/>
)}
{isTemplateVariablesEnabled && (
<CustomTemplatesVariablesDefinitionField
value={values.Variables}
onChange={(values) => setFieldValue('Variables', values)}
isVariablesNamesFromParent={values.Method === editor.value}
errors={errors.Variables}
/>
)}
{values.Method === git.value && (
<GitForm
value={values.Git}
onChange={(newValues) =>
setValues((values) => ({
...values,
Git: { ...values.Git, ...newValues },
}))
}
errors={errors.Git}
/>
)}
{values.EdgeSettings && (
<EdgeSettingsFieldset
setValues={(edgeSetValues) =>
setValues((values) => ({
...values,
EdgeSettings: applySetStateAction(
edgeSetValues,
values.EdgeSettings
),
}))
}
gitConfig={isGit ? values.Git : undefined}
fileValues={{
fileContent: values.FileContent,
file: values.File,
}}
values={values.EdgeSettings}
errors={errors.EdgeSettings as FormikErrors<EdgeTemplateSettings>}
setFieldError={setFieldError}
/>
)}
<FormActions
isLoading={isLoading}
isValid={isValid}
loadingText="Creating custom template..."
submitLabel="Create custom template"
/>
</Form>
);
function handleChangeFileContent(value: string) {
setFieldValue(
'FileContent',
value,
isTemplateVariablesEnabled ? !value : true
);
parseTemplate(value);
}
function parseTemplate(value: string) {
if (!isTemplateVariablesEnabled || value === '') {
setFieldValue('Variables', []);
return;
}
const [variables, validationError] = getTemplateVariables(value);
const isValid = !!variables;
setFieldError(
'FileContent',
validationError ? `Template invalid: ${validationError}` : undefined
);
if (isValid) {
setFieldValue(
'Variables',
intersectVariables(values.Variables, variables)
);
}
}
function handleChangeMethod(method: Method) {
setFieldValue('FileContent', '');
setFieldValue('Variables', []);
setFieldValue('Method', method);
}
}