import { EditorType } from '@/react/edge/edge-stacks/types';
import { PortainerEndpointTypes } from '@/portainer/models/endpoint/models';
import { getValidEditorTypes } from '@/react/edge/edge-stacks/utils';
import { STACK_NAME_VALIDATION_REGEX } from '@/react/constants';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
export default class CreateEdgeStackViewController {
/* @ngInject */
constructor($state, $window, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async, $scope) {
Object.assign(this, { $state, $window, EdgeStackService, EdgeGroupService, EdgeTemplateService, Notifications, FormHelper, $async, $scope });
this.formValues = {
Name: '',
StackFileContent: '',
StackFile: null,
RepositoryURL: '',
RepositoryReferenceName: '',
RepositoryAuthentication: false,
RepositoryUsername: '',
RepositoryPassword: '',
Env: [],
ComposeFilePathInRepository: '',
Groups: [],
DeploymentType: 0,
UseManifestNamespaces: false,
TLSSkipVerify: false,
};
this.EditorType = EditorType;
this.state = {
Method: 'editor',
formValidationError: '',
actionInProgress: false,
StackType: null,
isEditorDirty: false,
hasKubeEndpoint: false,
endpointTypes: [],
this.edgeGroups = null;
$scope.STACK_NAME_VALIDATION_REGEX = STACK_NAME_VALIDATION_REGEX;
this.createStack = this.createStack.bind(this);
this.validateForm = this.validateForm.bind(this);
this.createStackByMethod = this.createStackByMethod.bind(this);
this.createStackFromFileContent = this.createStackFromFileContent.bind(this);
this.createStackFromFileUpload = this.createStackFromFileUpload.bind(this);
this.createStackFromGitRepository = this.createStackFromGitRepository.bind(this);
this.onChangeGroups = this.onChangeGroups.bind(this);
this.hasDockerEndpoint = this.hasDockerEndpoint.bind(this);
this.hasKubeEndpoint = this.hasKubeEndpoint.bind(this);
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
}
buildAnalyticsProperties() {
const format = 'compose';
const metadata = { type: methodLabel(this.state.Method), format };
if (metadata.type === 'template') {
metadata.templateName = this.selectedTemplate.title;
return { metadata };
function methodLabel(method) {
switch (method) {
case 'editor':
return 'web-editor';
case 'repository':
return 'git';
case 'upload':
return 'file-upload';
case 'template':
return 'template';
uiCanExit() {
if (this.state.Method === 'editor' && this.formValues.StackFileContent && this.state.isEditorDirty) {
return confirmWebEditorDiscard();
async $onInit() {
try {
this.edgeGroups = await this.EdgeGroupService.groups();
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve Edge groups');
this.$window.onbeforeunload = () => {
return '';
$onDestroy() {
this.state.isEditorDirty = false;
createStack() {
return this.$async(async () => {
const name = this.formValues.Name;
let method = this.state.Method;
if (method === 'template') {
method = 'editor';
if (!this.validateForm(method)) {
return;
this.state.actionInProgress = true;
await this.createStackByMethod(name, method);
this.Notifications.success('Success', 'Stack successfully deployed');
this.$state.go('edge.stacks');
this.Notifications.error('Deployment error', err, 'Unable to deploy stack');
} finally {
this.state.actionInProgress = false;
});
onChangeGroups(groups) {
return this.$scope.$evalAsync(() => {
this.formValues.Groups = groups;
this.checkIfEndpointTypes(groups);
checkIfEndpointTypes(groups) {
const edgeGroups = groups.map((id) => this.edgeGroups.find((e) => e.Id === id));
this.state.endpointTypes = edgeGroups.flatMap((group) => group.EndpointTypes);
this.selectValidDeploymentType();
selectValidDeploymentType() {
const validTypes = getValidEditorTypes(this.state.endpointTypes);
if (!validTypes.includes(this.formValues.DeploymentType)) {
this.onChangeDeploymentType(validTypes[0]);
hasKubeEndpoint() {
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment);
hasDockerEndpoint() {
return this.state.endpointTypes.includes(PortainerEndpointTypes.EdgeAgentOnDockerEnvironment);
validateForm(method) {
this.state.formValidationError = '';
if (method === 'editor' && this.formValues.StackFileContent === '') {
this.state.formValidationError = 'Stack file content must not be empty';
return true;
createStackByMethod(name, method) {
return this.createStackFromFileContent(name);
return this.createStackFromFileUpload(name);
return this.createStackFromGitRepository(name);
createStackFromFileContent(name) {
const { StackFileContent, Groups, DeploymentType, UseManifestNamespaces } = this.formValues;
return this.EdgeStackService.createStackFromFileContent({
name,
StackFileContent,
EdgeGroups: Groups,
DeploymentType,
UseManifestNamespaces,
createStackFromFileUpload(name) {
const { StackFile, Groups, DeploymentType, UseManifestNamespaces } = this.formValues;
return this.EdgeStackService.createStackFromFileUpload(
{
Name: name,
},
StackFile
);
createStackFromGitRepository(name) {
const { Groups, DeploymentType, UseManifestNamespaces } = this.formValues;
const repositoryOptions = {
RepositoryURL: this.formValues.RepositoryURL,
RepositoryReferenceName: this.formValues.RepositoryReferenceName,
FilePathInRepository: this.formValues.ComposeFilePathInRepository,
RepositoryAuthentication: this.formValues.RepositoryAuthentication,
RepositoryUsername: this.formValues.RepositoryUsername,
RepositoryPassword: this.formValues.RepositoryPassword,
TLSSkipVerify: this.formValues.TLSSkipVerify,
return this.EdgeStackService.createStackFromGitRepository(
repositoryOptions
onChangeDeploymentType(deploymentType) {
this.formValues.DeploymentType = deploymentType;
this.state.Method = 'editor';
this.formValues.StackFileContent = '';
formIsInvalid() {
return (
this.form.$invalid ||
!this.formValues.Groups.length ||
(['template', 'editor'].includes(this.state.Method) && !this.formValues.StackFileContent) ||
('upload' === this.state.Method && !this.formValues.StackFile)