- handleChangeItem(key, value)}
+ error={error}
+ />
+ ) : (
+ renderItem(
+ item,
+ (value: T) => handleChangeItem(key, value),
+ error
+ )
+ )}
+
{movable && (
<>
-
+
+
+
+
+
+
@@ -111,7 +127,8 @@
|| ($ctrl.state.Method === 'editor' && !$ctrl.formValues.FileContent)
|| ($ctrl.state.Method === 'upload' && !$ctrl.formValues.File)
|| ($ctrl.state.Method === 'repository' && ((!$ctrl.formValues.RepositoryURL || !$ctrl.formValues.ComposeFilePathInRepository) || ($ctrl.formValues.RepositoryAuthentication && (!$ctrl.formValues.RepositoryUsername || !$ctrl.formValues.RepositoryPassword))))
- || !$ctrl.formValues.Title"
+ || !$ctrl.formValues.Title
+ || !$ctrl.state.isTemplateValid"
ng-click="$ctrl.createCustomTemplate()"
button-spinner="$ctrl.state.actionInProgress"
>
diff --git a/app/portainer/views/custom-templates/create-custom-template-view/createCustomTemplateViewController.js b/app/portainer/views/custom-templates/create-custom-template-view/createCustomTemplateViewController.js
index 614486c0a..ce05716fb 100644
--- a/app/portainer/views/custom-templates/create-custom-template-view/createCustomTemplateViewController.js
+++ b/app/portainer/views/custom-templates/create-custom-template-view/createCustomTemplateViewController.js
@@ -1,6 +1,7 @@
import _ from 'lodash';
import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel';
import { TEMPLATE_NAME_VALIDATION_REGEX } from '@/constants';
+import { getTemplateVariables, intersectVariables } from '@/react/portainer/custom-templates/components/utils';
class CreateCustomTemplateViewController {
/* @ngInject */
@@ -35,6 +36,7 @@ class CreateCustomTemplateViewController {
Platform: 1,
Type: 1,
AccessControlData: new AccessControlFormData(),
+ Variables: [],
};
this.state = {
@@ -45,6 +47,7 @@ class CreateCustomTemplateViewController {
loading: true,
isEditorDirty: false,
templateNameRegex: TEMPLATE_NAME_VALIDATION_REGEX,
+ isTemplateValid: true,
};
this.templates = [];
@@ -58,7 +61,21 @@ class CreateCustomTemplateViewController {
this.createCustomTemplateFromGitRepository = this.createCustomTemplateFromGitRepository.bind(this);
this.editorUpdate = this.editorUpdate.bind(this);
this.onChangeMethod = this.onChangeMethod.bind(this);
- this.onChangeFormValues = this.onChangeFormValues.bind(this);
+ this.onVariablesChange = this.onVariablesChange.bind(this);
+ this.handleChange = this.handleChange.bind(this);
+ }
+
+ onVariablesChange(value) {
+ this.handleChange({ Variables: value });
+ }
+
+ handleChange(values) {
+ return this.$async(async () => {
+ this.formValues = {
+ ...this.formValues,
+ ...values,
+ };
+ });
}
createCustomTemplate() {
@@ -67,6 +84,7 @@ class CreateCustomTemplateViewController {
onChangeMethod() {
this.formValues.FileContent = '';
+ this.formValues.Variables = [];
this.selectedTemplate = null;
}
@@ -151,12 +169,22 @@ class CreateCustomTemplateViewController {
}
editorUpdate(cm) {
- this.formValues.FileContent = cm.getValue();
+ const value = cm.getValue();
+ this.formValues.FileContent = value;
this.state.isEditorDirty = true;
+ this.parseTemplate(value);
}
- onChangeFormValues(newValues) {
- this.formValues = newValues;
+ parseTemplate(templateStr) {
+ const variables = getTemplateVariables(templateStr);
+
+ const isValid = !!variables;
+
+ this.state.isTemplateValid = isValid;
+
+ if (isValid) {
+ this.onVariablesChange(intersectVariables(this.formValues.Variables, variables));
+ }
}
async $onInit() {
diff --git a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html b/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html
index 50301d032..7fdd124ec 100644
--- a/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html
+++ b/app/portainer/views/custom-templates/custom-templates-view/customTemplatesView.html
@@ -17,6 +17,12 @@
unselect-template="$ctrl.unselectTemplate"
>
+
+