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:
parent
a0f583a17d
commit
68950fbb24
81 changed files with 2047 additions and 334 deletions
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue