1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-07 23:05:26 +02:00

feat(edge/templates): introduce custom templates [EE-6208] (#10561)

This commit is contained in:
Chaim Lev-Ari 2023-11-15 10:45:07 +02:00 committed by GitHub
parent a0f583a17d
commit 68950fbb24
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
81 changed files with 2047 additions and 334 deletions

View file

@ -26,6 +26,7 @@ export const ngModule = angular
'value',
'onChange',
'definitions',
'errors',
])
)
.component('customTemplatesVariablesField', VariablesFieldAngular)
@ -46,7 +47,6 @@ export const ngModule = angular
'selectedId',
'disabledTypes',
'fixedCategories',
'hideDuplicate',
])
)
.component(
@ -56,6 +56,7 @@ export const ngModule = angular
'onSelect',
'templates',
'selectedId',
'templateLinkParams',
])
)
.component(

View file

@ -101,3 +101,30 @@ export function isAxiosError<
>(error: unknown): error is AxiosError<ResponseType> {
return axiosOrigin.isAxiosError(error);
}
export function arrayToJson<T>(arr?: Array<T>) {
if (!arr) {
return '';
}
return JSON.stringify(arr);
}
export function json2formData(json: Record<string, unknown>) {
const formData = new FormData();
Object.entries(json).forEach(([key, value]) => {
if (typeof value === 'undefined' || value === null) {
return;
}
if (Array.isArray(value)) {
formData.append(key, arrayToJson(value));
return;
}
formData.append(key, value as string);
});
return formData;
}

View file

@ -1,11 +1,10 @@
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';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { getTemplateVariables, intersectVariables, isTemplateVariablesEnabled } from '@/react/portainer/custom-templates/components/utils';
import { editor, upload, git } from '@@/BoxSelector/common-options/build-methods';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
import { fetchFilePreview } from '@/react/portainer/templates/app-templates/queries/useFetchTemplateInfoMutation';
import { fetchFilePreview } from '@/react/portainer/templates/app-templates/queries/useFetchTemplateFile';
class CreateCustomTemplateViewController {
/* @ngInject */
@ -26,7 +25,7 @@ class CreateCustomTemplateViewController {
this.buildMethods = [editor, upload, git];
this.isTemplateVariablesEnabled = isBE;
this.isTemplateVariablesEnabled = isTemplateVariablesEnabled;
this.formValues = {
Title: '',
@ -207,7 +206,7 @@ class CreateCustomTemplateViewController {
return;
}
const variables = getTemplateVariables(templateStr);
const [variables] = getTemplateVariables(templateStr);
const isValid = !!variables;

View file

@ -1,9 +1,9 @@
import _ from 'lodash-es';
import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel';
import { TEMPLATE_NAME_VALIDATION_REGEX } from '@/constants';
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { isTemplateVariablesEnabled, renderTemplate } from '@/react/portainer/custom-templates/components/utils';
import { confirmDelete } from '@@/modals/confirm';
import { getVariablesFieldDefaultValues } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField';
class CustomTemplatesViewController {
/* @ngInject */
@ -34,7 +34,7 @@ class CustomTemplatesViewController {
this.StateManager = StateManager;
this.StackService = StackService;
this.isTemplateVariablesEnabled = isBE;
this.isTemplateVariablesEnabled = isTemplateVariablesEnabled;
this.DOCKER_STANDALONE = 'DOCKER_STANDALONE';
this.DOCKER_SWARM_MODE = 'DOCKER_SWARM_MODE';
@ -93,7 +93,8 @@ class CustomTemplatesViewController {
}
async getTemplatesAsync() {
try {
this.templates = await this.CustomTemplateService.customTemplates([1, 2]);
const templates = await this.CustomTemplateService.customTemplates([1, 2]);
this.templates = templates.filter((t) => !t.EdgeTemplate);
} catch (err) {
this.Notifications.error('Failed loading templates', err, 'Unable to load custom templates');
}
@ -221,7 +222,7 @@ class CustomTemplatesViewController {
this.state.deployable = this.isDeployable(applicationState.endpoint, template.Type);
if (template.Variables && template.Variables.length > 0) {
const variables = Object.fromEntries(template.Variables.map((variable) => [variable.name, '']));
const variables = getVariablesFieldDefaultValues(template.Variables);
this.onChangeTemplateVariables(variables);
}
}

View file

@ -4,8 +4,7 @@ import { ResourceControlViewModel } from '@/react/portainer/access-control/model
import { TEMPLATE_NAME_VALIDATION_REGEX } from '@/constants';
import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel';
import { getTemplateVariables, intersectVariables } from '@/react/portainer/custom-templates/components/utils';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { getTemplateVariables, intersectVariables, isTemplateVariablesEnabled } from '@/react/portainer/custom-templates/components/utils';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
class EditCustomTemplateViewController {
@ -13,7 +12,7 @@ class EditCustomTemplateViewController {
constructor($async, $state, $window, Authentication, CustomTemplateService, FormValidator, Notifications, ResourceControlService) {
Object.assign(this, { $async, $state, $window, Authentication, CustomTemplateService, FormValidator, Notifications, ResourceControlService });
this.isTemplateVariablesEnabled = isBE;
this.isTemplateVariablesEnabled = isTemplateVariablesEnabled;
this.formValues = {
Variables: [],
@ -178,7 +177,7 @@ class EditCustomTemplateViewController {
return;
}
const variables = getTemplateVariables(templateStr);
const [variables] = getTemplateVariables(templateStr);
const isValid = !!variables;

View file

@ -4,12 +4,12 @@ import { AccessControlFormData } from '@/portainer/components/accessControlForm/
import { STACK_NAME_VALIDATION_REGEX } from '@/react/constants';
import { RepositoryMechanismTypes } from '@/kubernetes/models/deploy';
import { FeatureId } from '@/react/portainer/feature-flags/enums';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
import { isTemplateVariablesEnabled, renderTemplate } from '@/react/portainer/custom-templates/components/utils';
import { editor, upload, git, customTemplate } from '@@/BoxSelector/common-options/build-methods';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
import { parseAutoUpdateResponse, transformAutoUpdateViewModel } from '@/react/portainer/gitops/AutoUpdateFieldset/utils';
import { baseStackWebhookUrl, createWebhookId } from '@/portainer/helpers/webhookHelper';
import { getVariablesFieldDefaultValues } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField';
angular
.module('portainer.app')
@ -28,13 +28,12 @@ angular
FormHelper,
StackHelper,
ContainerHelper,
CustomTemplateService,
ContainerService,
endpoint
) {
$scope.onChangeTemplateId = onChangeTemplateId;
$scope.onChangeTemplateVariables = onChangeTemplateVariables;
$scope.isTemplateVariablesEnabled = isBE;
$scope.isTemplateVariablesEnabled = isTemplateVariablesEnabled;
$scope.buildAnalyticsProperties = buildAnalyticsProperties;
$scope.stackWebhookFeature = FeatureId.STACK_WEBHOOK;
$scope.buildMethods = [editor, upload, git, customTemplate];
@ -54,7 +53,7 @@ angular
ComposeFilePathInRepository: 'docker-compose.yml',
AccessControlData: new AccessControlFormData(),
EnableWebhook: false,
Variables: {},
Variables: [],
AutoUpdate: parseAutoUpdateResponse(),
TLSSkipVerify: false,
};
@ -313,7 +312,7 @@ angular
}
if (template.Variables && template.Variables.length > 0) {
const variables = Object.fromEntries(template.Variables.map((variable) => [variable.name, '']));
const variables = getVariablesFieldDefaultValues(template.Variables);
onChangeTemplateVariables(variables);
}
} catch (err) {