2021-09-02 05:28:51 +00:00
|
|
|
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
2022-05-31 10:00:47 +00:00
|
|
|
import { getTemplateVariables, intersectVariables } from '@/react/portainer/custom-templates/components/utils';
|
2022-11-13 08:10:18 +00:00
|
|
|
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
|
2022-08-22 08:55:48 +00:00
|
|
|
import { editor, upload } from '@@/BoxSelector/common-options/build-methods';
|
2021-09-02 05:28:51 +00:00
|
|
|
|
|
|
|
class KubeCreateCustomTemplateViewController {
|
|
|
|
/* @ngInject */
|
|
|
|
constructor($async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService) {
|
|
|
|
Object.assign(this, { $async, $state, Authentication, CustomTemplateService, FormValidator, ModalService, Notifications, ResourceControlService });
|
|
|
|
|
2022-08-22 08:55:48 +00:00
|
|
|
this.methodOptions = [editor, upload];
|
2021-09-02 05:28:51 +00:00
|
|
|
|
|
|
|
this.templates = null;
|
2022-06-16 05:32:41 +00:00
|
|
|
this.isTemplateVariablesEnabled = isBE;
|
2021-09-02 05:28:51 +00:00
|
|
|
|
|
|
|
this.state = {
|
|
|
|
method: 'editor',
|
|
|
|
actionInProgress: false,
|
|
|
|
formValidationError: '',
|
|
|
|
isEditorDirty: false,
|
2022-05-31 10:00:47 +00:00
|
|
|
isTemplateValid: true,
|
2021-09-02 05:28:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
this.formValues = {
|
|
|
|
FileContent: '',
|
|
|
|
File: null,
|
|
|
|
Title: '',
|
|
|
|
Description: '',
|
|
|
|
Note: '',
|
|
|
|
Logo: '',
|
|
|
|
AccessControlData: new AccessControlFormData(),
|
2022-05-31 10:00:47 +00:00
|
|
|
Variables: [],
|
2021-09-02 05:28:51 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
this.onChangeFile = this.onChangeFile.bind(this);
|
|
|
|
this.onChangeFileContent = this.onChangeFileContent.bind(this);
|
|
|
|
this.onChangeMethod = this.onChangeMethod.bind(this);
|
|
|
|
this.onBeforeOnload = this.onBeforeOnload.bind(this);
|
2022-05-31 10:00:47 +00:00
|
|
|
this.handleChange = this.handleChange.bind(this);
|
|
|
|
this.onVariablesChange = this.onVariablesChange.bind(this);
|
2021-09-02 05:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onChangeMethod(method) {
|
|
|
|
this.state.method = method;
|
2022-05-31 10:00:47 +00:00
|
|
|
this.formValues.Variables = [];
|
2021-09-02 05:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
onChangeFileContent(content) {
|
2022-05-31 10:00:47 +00:00
|
|
|
this.handleChange({ FileContent: content });
|
|
|
|
this.parseTemplate(content);
|
2021-09-02 05:28:51 +00:00
|
|
|
this.state.isEditorDirty = true;
|
|
|
|
}
|
|
|
|
|
2022-05-31 10:00:47 +00:00
|
|
|
parseTemplate(templateStr) {
|
2022-06-16 05:32:41 +00:00
|
|
|
if (!this.isTemplateVariablesEnabled) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-05-31 10:00:47 +00:00
|
|
|
const variables = getTemplateVariables(templateStr);
|
|
|
|
|
|
|
|
const isValid = !!variables;
|
|
|
|
|
|
|
|
this.state.isTemplateValid = isValid;
|
|
|
|
|
|
|
|
if (isValid) {
|
|
|
|
this.onVariablesChange(intersectVariables(this.formValues.Variables, variables));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
onVariablesChange(value) {
|
|
|
|
this.handleChange({ Variables: value });
|
|
|
|
}
|
|
|
|
|
2021-09-02 05:28:51 +00:00
|
|
|
onChangeFile(file) {
|
2022-05-31 10:00:47 +00:00
|
|
|
this.handleChange({ File: file });
|
|
|
|
}
|
|
|
|
|
|
|
|
handleChange(values) {
|
2022-01-05 13:39:34 +00:00
|
|
|
return this.$async(async () => {
|
2022-05-31 10:00:47 +00:00
|
|
|
this.formValues = {
|
|
|
|
...this.formValues,
|
|
|
|
...values,
|
|
|
|
};
|
2022-01-05 13:39:34 +00:00
|
|
|
});
|
2021-09-02 05:28:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
async createCustomTemplate() {
|
|
|
|
return this.$async(async () => {
|
|
|
|
const { method } = this.state;
|
|
|
|
|
|
|
|
if (!this.validateForm(method)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.state.actionInProgress = true;
|
|
|
|
try {
|
2022-10-02 20:49:28 +00:00
|
|
|
const customTemplate = await this.createCustomTemplateByMethod(method, this.formValues);
|
2021-09-02 05:28:51 +00:00
|
|
|
|
|
|
|
const accessControlData = this.formValues.AccessControlData;
|
|
|
|
const userDetails = this.Authentication.getUserDetails();
|
|
|
|
const userId = userDetails.ID;
|
|
|
|
await this.ResourceControlService.applyResourceControl(userId, accessControlData, customTemplate.ResourceControl);
|
|
|
|
|
2022-08-10 05:07:35 +00:00
|
|
|
this.Notifications.success('Success', 'Custom template successfully created');
|
2021-09-02 05:28:51 +00:00
|
|
|
this.state.isEditorDirty = false;
|
|
|
|
this.$state.go('kubernetes.templates.custom');
|
|
|
|
} catch (err) {
|
|
|
|
this.Notifications.error('Failure', err, 'Failed creating custom template');
|
|
|
|
} finally {
|
|
|
|
this.state.actionInProgress = false;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
createCustomTemplateByMethod(method, template) {
|
|
|
|
template.Type = 3;
|
|
|
|
|
|
|
|
switch (method) {
|
|
|
|
case 'editor':
|
|
|
|
return this.createCustomTemplateFromFileContent(template);
|
|
|
|
case 'upload':
|
|
|
|
return this.createCustomTemplateFromFileUpload(template);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
createCustomTemplateFromFileContent(template) {
|
|
|
|
return this.CustomTemplateService.createCustomTemplateFromFileContent(template);
|
|
|
|
}
|
|
|
|
|
|
|
|
createCustomTemplateFromFileUpload(template) {
|
|
|
|
return this.CustomTemplateService.createCustomTemplateFromFileUpload(template);
|
|
|
|
}
|
|
|
|
|
|
|
|
validateForm(method) {
|
|
|
|
this.state.formValidationError = '';
|
|
|
|
|
|
|
|
if (method === 'editor' && this.formValues.FileContent === '') {
|
|
|
|
this.state.formValidationError = 'Template file content must not be empty';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const title = this.formValues.Title;
|
|
|
|
const isNotUnique = this.templates.some((template) => template.Title === title);
|
|
|
|
if (isNotUnique) {
|
|
|
|
this.state.formValidationError = 'A template with the same name already exists';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-31 10:00:47 +00:00
|
|
|
if (!this.state.isTemplateValid) {
|
|
|
|
this.state.formValidationError = 'Template is not valid';
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-09-02 05:28:51 +00:00
|
|
|
const isAdmin = this.Authentication.isAdmin();
|
|
|
|
const accessControlData = this.formValues.AccessControlData;
|
|
|
|
const error = this.FormValidator.validateAccessControl(accessControlData, isAdmin);
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
this.state.formValidationError = error;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
async $onInit() {
|
|
|
|
return this.$async(async () => {
|
|
|
|
const { fileContent, type } = this.$state.params;
|
|
|
|
|
|
|
|
this.formValues.FileContent = fileContent;
|
2022-05-31 10:00:47 +00:00
|
|
|
this.parseTemplate(fileContent);
|
2021-09-02 05:28:51 +00:00
|
|
|
if (type) {
|
|
|
|
this.formValues.Type = +type;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
this.templates = await this.CustomTemplateService.customTemplates(3);
|
|
|
|
} catch (err) {
|
|
|
|
this.Notifications.error('Failure loading', err, 'Failed loading custom templates');
|
|
|
|
}
|
|
|
|
|
|
|
|
this.state.loading = false;
|
|
|
|
|
|
|
|
window.addEventListener('beforeunload', this.onBeforeOnload);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
$onDestroy() {
|
|
|
|
window.removeEventListener('beforeunload', this.onBeforeOnload);
|
|
|
|
}
|
|
|
|
|
|
|
|
isEditorDirty() {
|
|
|
|
return this.state.method === 'editor' && this.formValues.FileContent && this.state.isEditorDirty;
|
|
|
|
}
|
|
|
|
|
|
|
|
onBeforeOnload(event) {
|
|
|
|
if (this.isEditorDirty()) {
|
|
|
|
event.preventDefault();
|
|
|
|
event.returnValue = '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uiCanExit() {
|
|
|
|
if (this.isEditorDirty()) {
|
|
|
|
return this.ModalService.confirmWebEditorDiscard();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default KubeCreateCustomTemplateViewController;
|