mirror of
https://github.com/portainer/portainer.git
synced 2025-08-05 13:55:21 +02:00
feat(edge/templates): introduce edge specific settings [EE-6276] (#10609)
This commit is contained in:
parent
68950fbb24
commit
e43d076269
42 changed files with 885 additions and 319 deletions
|
@ -6,6 +6,7 @@ import { notifySuccess } from '@/portainer/services/notifications';
|
|||
import { useCreateTemplateMutation } from '@/react/portainer/templates/custom-templates/queries/useCreateTemplateMutation';
|
||||
import { Platform } from '@/react/portainer/templates/types';
|
||||
import { useFetchTemplateFile } from '@/react/portainer/templates/app-templates/queries/useFetchTemplateFile';
|
||||
import { getDefaultEdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
|
||||
import { editor } from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
|
@ -47,6 +48,7 @@ export function CreateTemplateForm() {
|
|||
RepositoryURLValid: true,
|
||||
TLSSkipVerify: false,
|
||||
},
|
||||
EdgeSettings: getDefaultEdgeTemplateSettings(),
|
||||
};
|
||||
|
||||
return (
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
import { FormikErrors } from 'formik';
|
||||
import { SetStateAction } from 'react';
|
||||
|
||||
import { RelativePathFieldset } from '@/react/portainer/gitops/RelativePathFieldset/RelativePathFieldset';
|
||||
import { PrivateRegistryFieldsetWrapper } from '@/react/edge/edge-stacks/ItemView/EditEdgeStackForm/PrivateRegistryFieldsetWrapper';
|
||||
import { PrePullToggle } from '@/react/edge/edge-stacks/components/PrePullToggle';
|
||||
import { RetryDeployToggle } from '@/react/edge/edge-stacks/components/RetryDeployToggle';
|
||||
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
import { GitFormModel } from '@/react/portainer/gitops/types';
|
||||
|
||||
import { FormSection } from '@@/form-components/FormSection';
|
||||
|
||||
export function EdgeSettingsFieldset({
|
||||
values,
|
||||
setValues,
|
||||
errors,
|
||||
gitConfig,
|
||||
fileValues,
|
||||
setFieldError,
|
||||
}: {
|
||||
values: EdgeTemplateSettings;
|
||||
setValues: (values: SetStateAction<EdgeTemplateSettings>) => void;
|
||||
errors?: FormikErrors<EdgeTemplateSettings>;
|
||||
gitConfig?: GitFormModel;
|
||||
setFieldError: (field: string, message: string) => void;
|
||||
fileValues: {
|
||||
fileContent?: string;
|
||||
file?: File;
|
||||
};
|
||||
}) {
|
||||
const isGit = !!gitConfig;
|
||||
return (
|
||||
<>
|
||||
{isGit && (
|
||||
<FormSection title="Advanced settings">
|
||||
<RelativePathFieldset
|
||||
value={values.RelativePathSettings}
|
||||
gitModel={gitConfig}
|
||||
onChange={(newValues) =>
|
||||
setValues((values) => ({
|
||||
...values,
|
||||
RelativePathSettings: {
|
||||
...values.RelativePathSettings,
|
||||
...newValues,
|
||||
},
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</FormSection>
|
||||
)}
|
||||
|
||||
<PrivateRegistryFieldsetWrapper
|
||||
value={values.PrivateRegistryId}
|
||||
onChange={(registryId) =>
|
||||
setValues((values) => ({
|
||||
...values,
|
||||
PrivateRegistryId: registryId,
|
||||
}))
|
||||
}
|
||||
values={fileValues}
|
||||
onFieldError={(error) => setFieldError('Edge?.Registries', error)}
|
||||
error={errors?.PrivateRegistryId}
|
||||
isGit={isGit}
|
||||
/>
|
||||
|
||||
<PrePullToggle
|
||||
onChange={(value) =>
|
||||
setValues((values) => ({ ...values, PrePullImage: value }))
|
||||
}
|
||||
value={values.PrePullImage}
|
||||
/>
|
||||
|
||||
<RetryDeployToggle
|
||||
onChange={(value) =>
|
||||
setValues((values) => ({ ...values, RetryDeploy: value }))
|
||||
}
|
||||
value={values.RetryDeploy}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
import { SchemaOf, boolean, mixed, number, object } from 'yup';
|
||||
|
||||
import { relativePathValidation } from '@/react/portainer/gitops/RelativePathFieldset/validation';
|
||||
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
||||
|
||||
export function edgeFieldsetValidation(): SchemaOf<EdgeTemplateSettings> {
|
||||
if (!isBE) {
|
||||
return mixed().default(undefined) as SchemaOf<EdgeTemplateSettings>;
|
||||
}
|
||||
|
||||
return object({
|
||||
RelativePathSettings: relativePathValidation(),
|
||||
PrePullImage: boolean().default(false),
|
||||
RetryDeploy: boolean().default(false),
|
||||
PrivateRegistryId: number().default(undefined),
|
||||
StaggerConfig: mixed(),
|
||||
});
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
import { Form, useFormikContext } from 'formik';
|
||||
import { Form, FormikErrors, useFormikContext } from 'formik';
|
||||
|
||||
import { CommonFields } from '@/react/portainer/custom-templates/components/CommonFields';
|
||||
import { CustomTemplatesVariablesDefinitionField } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField';
|
||||
|
@ -10,6 +10,8 @@ import {
|
|||
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';
|
||||
|
@ -23,6 +25,7 @@ import {
|
|||
} from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
import { FormValues, Method, buildMethods } from './types';
|
||||
import { EdgeSettingsFieldset } from './EdgeSettingsFieldset';
|
||||
|
||||
export function InnerForm({ isLoading }: { isLoading: boolean }) {
|
||||
const {
|
||||
|
@ -41,6 +44,8 @@ export function InnerForm({ isLoading }: { isLoading: boolean }) {
|
|||
values.FileContent,
|
||||
values.Method === editor.value && !isSubmitting
|
||||
);
|
||||
|
||||
const isGit = values.Method === git.value;
|
||||
return (
|
||||
<Form className="form-horizontal">
|
||||
<CommonFields
|
||||
|
@ -103,6 +108,15 @@ export function InnerForm({ isLoading }: { isLoading: boolean }) {
|
|||
/>
|
||||
)}
|
||||
|
||||
{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}
|
||||
|
@ -116,12 +130,25 @@ export function InnerForm({ isLoading }: { isLoading: boolean }) {
|
|||
/>
|
||||
)}
|
||||
|
||||
{isTemplateVariablesEnabled && (
|
||||
<CustomTemplatesVariablesDefinitionField
|
||||
value={values.Variables}
|
||||
onChange={(values) => setFieldValue('Variables', values)}
|
||||
isVariablesNamesFromParent={values.Method === editor.value}
|
||||
errors={errors.Variables}
|
||||
{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}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { type Values as CommonFieldsValues } from '@/react/portainer/custom-temp
|
|||
import { DefinitionFieldValues } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesDefinitionField';
|
||||
import { Platform } from '@/react/portainer/templates/types';
|
||||
import { GitFormModel } from '@/react/portainer/gitops/types';
|
||||
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
|
||||
import {
|
||||
editor,
|
||||
|
@ -22,4 +23,5 @@ export interface FormValues extends CommonFieldsValues {
|
|||
File: File | undefined;
|
||||
Git: GitFormModel;
|
||||
Variables: DefinitionFieldValues;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
} from '@@/BoxSelector/common-options/build-methods';
|
||||
|
||||
import { buildMethods } from './types';
|
||||
import { edgeFieldsetValidation } from './EdgeSettingsFieldset.validation';
|
||||
|
||||
export function useValidation() {
|
||||
const { user } = useCurrentUser();
|
||||
|
@ -51,6 +52,7 @@ export function useValidation() {
|
|||
then: () => buildGitValidationSchema(gitCredentialsQuery.data || []),
|
||||
}),
|
||||
Variables: variablesValidation(),
|
||||
EdgeSettings: edgeFieldsetValidation(),
|
||||
}).concat(
|
||||
commonFieldsValidation({ templates: customTemplatesQuery.data })
|
||||
),
|
||||
|
|
|
@ -38,6 +38,7 @@ export function EditTemplateForm({ template }: { template: CustomTemplate }) {
|
|||
|
||||
FileContent: fileQuery.data || '',
|
||||
Git: template.GitConfig ? toGitFormModel(template.GitConfig) : undefined,
|
||||
EdgeSettings: template.EdgeSettings,
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -72,6 +73,7 @@ export function EditTemplateForm({ template }: { template: CustomTemplate }) {
|
|||
Note: values.Note,
|
||||
Platform: values.Platform,
|
||||
Variables: values.Variables,
|
||||
EdgeSettings: values.EdgeSettings,
|
||||
...values.Git,
|
||||
},
|
||||
{
|
||||
|
|
|
@ -12,9 +12,9 @@ import { EditTemplateForm } from './EditTemplateForm';
|
|||
export function EditView() {
|
||||
const router = useRouter();
|
||||
const {
|
||||
params: { id },
|
||||
params: { id: templateId },
|
||||
} = useCurrentStateAndParams();
|
||||
const customTemplateQuery = useCustomTemplate(id);
|
||||
const customTemplateQuery = useCustomTemplate(templateId);
|
||||
|
||||
useEffect(() => {
|
||||
if (customTemplateQuery.data && !customTemplateQuery.data.EdgeTemplate) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { Form, useFormikContext } from 'formik';
|
||||
import { Form, FormikErrors, useFormikContext } from 'formik';
|
||||
import { RefreshCw } from 'lucide-react';
|
||||
|
||||
import { CommonFields } from '@/react/portainer/custom-templates/components/CommonFields';
|
||||
|
@ -11,12 +11,16 @@ import {
|
|||
isTemplateVariablesEnabled,
|
||||
} from '@/react/portainer/custom-templates/components/utils';
|
||||
import { TemplateTypeSelector } from '@/react/portainer/custom-templates/components/TemplateTypeSelector';
|
||||
import { applySetStateAction } from '@/react-tools/apply-set-state-action';
|
||||
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
|
||||
import { WebEditorForm, usePreventExit } from '@@/WebEditorForm';
|
||||
import { FormActions } from '@@/form-components/FormActions';
|
||||
import { Button } from '@@/buttons';
|
||||
import { FormError } from '@@/form-components/FormError';
|
||||
|
||||
import { EdgeSettingsFieldset } from '../CreateView/EdgeSettingsFieldset';
|
||||
|
||||
import { FormValues } from './types';
|
||||
|
||||
export function InnerForm({
|
||||
|
@ -74,7 +78,11 @@ export function InnerForm({
|
|||
value={gitFileContent || values.FileContent}
|
||||
onChange={handleChangeFileContent}
|
||||
yaml
|
||||
placeholder="Define or paste the content of your docker compose file here"
|
||||
placeholder={
|
||||
gitFileContent
|
||||
? 'Preview of the file from git repository'
|
||||
: 'Define or paste the content of your docker compose file here'
|
||||
}
|
||||
error={errors.FileContent}
|
||||
readonly={isEditorReadonly}
|
||||
>
|
||||
|
@ -91,6 +99,15 @@ export function InnerForm({
|
|||
</p>
|
||||
</WebEditorForm>
|
||||
|
||||
{isTemplateVariablesEnabled && (
|
||||
<CustomTemplatesVariablesDefinitionField
|
||||
value={values.Variables}
|
||||
onChange={(values) => setFieldValue('Variables', values)}
|
||||
isVariablesNamesFromParent={!isEditorReadonly}
|
||||
errors={errors.Variables}
|
||||
/>
|
||||
)}
|
||||
|
||||
{values.Git && (
|
||||
<>
|
||||
<GitForm
|
||||
|
@ -121,12 +138,21 @@ export function InnerForm({
|
|||
</>
|
||||
)}
|
||||
|
||||
{isTemplateVariablesEnabled && (
|
||||
<CustomTemplatesVariablesDefinitionField
|
||||
value={values.Variables}
|
||||
onChange={(values) => setFieldValue('Variables', values)}
|
||||
isVariablesNamesFromParent={!isEditorReadonly}
|
||||
errors={errors.Variables}
|
||||
{values.EdgeSettings && (
|
||||
<EdgeSettingsFieldset
|
||||
setValues={(edgeValues) =>
|
||||
setFieldValue(
|
||||
'EdgeSettings',
|
||||
applySetStateAction(edgeValues, values.EdgeSettings)
|
||||
)
|
||||
}
|
||||
gitConfig={values.Git}
|
||||
fileValues={{
|
||||
fileContent: values.FileContent,
|
||||
}}
|
||||
values={values.EdgeSettings}
|
||||
errors={errors.EdgeSettings as FormikErrors<EdgeTemplateSettings>}
|
||||
setFieldError={setFieldError}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import { DefinitionFieldValues } from '@/react/portainer/custom-templates/compon
|
|||
import { Platform } from '@/react/portainer/templates/types';
|
||||
import { type Values as CommonFieldsValues } from '@/react/portainer/custom-templates/components/CommonFields';
|
||||
import { GitFormModel } from '@/react/portainer/gitops/types';
|
||||
import { EdgeTemplateSettings } from '@/react/portainer/templates/custom-templates/types';
|
||||
|
||||
export interface FormValues extends CommonFieldsValues {
|
||||
Platform: Platform;
|
||||
|
@ -10,4 +11,5 @@ export interface FormValues extends CommonFieldsValues {
|
|||
FileContent: string;
|
||||
Git?: GitFormModel;
|
||||
Variables: DefinitionFieldValues;
|
||||
EdgeSettings?: EdgeTemplateSettings;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import { useCurrentUser } from '@/react/hooks/useUser';
|
|||
import { useCustomTemplates } from '@/react/portainer/templates/custom-templates/queries/useCustomTemplates';
|
||||
import { Platform } from '@/react/portainer/templates/types';
|
||||
|
||||
import { edgeFieldsetValidation } from '../CreateView/EdgeSettingsFieldset.validation';
|
||||
|
||||
export function useValidation(
|
||||
currentTemplateId: CustomTemplate['Id'],
|
||||
isGit: boolean
|
||||
|
@ -40,6 +42,7 @@ export function useValidation(
|
|||
? buildGitValidationSchema(gitCredentialsQuery.data || [])
|
||||
: mixed(),
|
||||
Variables: variablesValidation(),
|
||||
EdgeSettings: edgeFieldsetValidation(),
|
||||
}).concat(
|
||||
commonFieldsValidation({
|
||||
templates: customTemplatesQuery.data,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue