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

refactor(edge/stacks): migrate create view to react [EE-2223] (#11575)
Some checks are pending
ci / build_images (map[arch:amd64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
ci / build_images (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
ci / build_images (map[arch:arm platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:arm64 platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:ppc64le platform:linux version:]) (push) Waiting to run
ci / build_images (map[arch:s390x platform:linux version:]) (push) Waiting to run
ci / build_manifests (push) Blocked by required conditions
/ triage (push) Waiting to run
Lint / Run linters (push) Waiting to run
Test / test-client (push) Waiting to run
Test / test-server (map[arch:amd64 platform:linux]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:1809]) (push) Waiting to run
Test / test-server (map[arch:amd64 platform:windows version:ltsc2022]) (push) Waiting to run
Test / test-server (map[arch:arm64 platform:linux]) (push) Waiting to run

This commit is contained in:
Chaim Lev-Ari 2024-05-06 08:08:03 +03:00 committed by GitHub
parent f22aed34b5
commit 8a81d95253
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
64 changed files with 1878 additions and 1005 deletions

View file

@ -69,7 +69,7 @@ angular
url: '/new?templateId&templateType',
views: {
'content@': {
component: 'createEdgeStackView',
component: 'edgeStacksCreateView',
},
},
data: {

View file

@ -13,7 +13,6 @@ import { withUIRouter } from '@/react-tools/withUIRouter';
import { EdgeGroupAssociationTable } from '@/react/edge/components/EdgeGroupAssociationTable';
import { AssociatedEdgeEnvironmentsSelector } from '@/react/edge/components/AssociatedEdgeEnvironmentsSelector';
import { EnvironmentsDatatable } from '@/react/edge/edge-stacks/ItemView/EnvironmentsDatatable';
import { TemplateFieldset } from '@/react/edge/edge-stacks/CreateView/TemplateFieldset/TemplateFieldset';
import { edgeJobsModule } from './edge-jobs';
@ -102,10 +101,6 @@ const ngModule = angular
'onChange',
'value',
])
)
.component(
'edgeStackCreateTemplateFieldset',
r2a(withReactQuery(TemplateFieldset), ['setValues', 'values', 'errors'])
);
export const componentsModule = ngModule.name;

View file

@ -0,0 +1,13 @@
import angular from 'angular';
import { r2a } from '@/react-tools/react2angular';
import { withCurrentUser } from '@/react-tools/withCurrentUser';
import { withUIRouter } from '@/react-tools/withUIRouter';
import { CreateView } from '@/react/edge/edge-stacks/CreateView/CreateView';
export const stacksModule = angular
.module('portainer.edge.react.views.stacks', [])
.component(
'edgeStacksCreateView',
r2a(withCurrentUser(withUIRouter(CreateView)), [])
).name;

View file

@ -10,9 +10,14 @@ import { ListView as EdgeGroupsListView } from '@/react/edge/edge-groups/ListVie
import { templatesModule } from './templates';
import { jobsModule } from './jobs';
import { stacksModule } from './edge-stacks';
export const viewsModule = angular
.module('portainer.edge.react.views', [templatesModule, jobsModule])
.module('portainer.edge.react.views', [
templatesModule,
jobsModule,
stacksModule,
])
.component(
'waitingRoomView',
r2a(withUIRouter(withReactQuery(withCurrentUser(WaitingRoomView))), [])

View file

@ -1,432 +0,0 @@
import { DeploymentType, EditorType } from '@/react/edge/edge-stacks/types';
import { getValidEditorTypes } from '@/react/edge/edge-stacks/utils';
import { STACK_NAME_VALIDATION_REGEX } from '@/react/constants';
import { confirmWebEditorDiscard } from '@@/modals/confirm';
import { baseEdgeStackWebhookUrl } from '@/portainer/helpers/webhookHelper';
import { EnvironmentType } from '@/react/portainer/environments/types';
import { isBE } from '@/react/portainer/feature-flags/feature-flags.service';
import { getCustomTemplate } from '@/react/portainer/templates/custom-templates/queries/useCustomTemplate';
import { notifyError } from '@/portainer/services/notifications';
import { getCustomTemplateFile } from '@/react/portainer/templates/custom-templates/queries/useCustomTemplateFile';
import { toGitFormModel } from '@/react/portainer/gitops/types';
import { StackType } from '@/react/common/stacks/types';
import { applySetStateAction } from '@/react-tools/apply-set-state-action';
import { getVariablesFieldDefaultValues } from '@/react/portainer/custom-templates/components/CustomTemplatesVariablesField';
import { renderTemplate } from '@/react/portainer/custom-templates/components/utils';
import { getInitialTemplateValues } from '@/react/edge/edge-stacks/CreateView/TemplateFieldset/TemplateFieldset';
import { getAppTemplates } from '@/react/portainer/templates/app-templates/queries/useAppTemplates';
import { fetchFilePreview } from '@/react/portainer/templates/app-templates/queries/useFetchTemplateFile';
import { TemplateViewModel } from '@/react/portainer/templates/app-templates/view-model';
import { getDefaultValues as getAppVariablesDefaultValues } from '@/react/portainer/templates/app-templates/DeployFormWidget/EnvVarsFieldset';
export default class CreateEdgeStackViewController {
/* @ngInject */
constructor($state, $window, EdgeStackService, EdgeGroupService, Notifications, FormHelper, $async, $scope) {
Object.assign(this, { $state, $window, EdgeStackService, EdgeGroupService, Notifications, FormHelper, $async, $scope });
this.formValues = {
Name: '',
StackFileContent: '',
StackFile: null,
RepositoryURL: '',
RepositoryReferenceName: '',
RepositoryAuthentication: false,
RepositoryUsername: '',
RepositoryPassword: '',
ComposeFilePathInRepository: '',
Groups: [],
DeploymentType: 0,
UseManifestNamespaces: false,
TLSSkipVerify: false,
envVars: [],
};
this.EditorType = EditorType;
this.EnvironmentType = EnvironmentType;
this.isBE = isBE;
this.state = {
Method: 'editor',
formValidationError: '',
actionInProgress: false,
StackType: null,
isEditorDirty: false,
hasKubeEndpoint: false,
endpointTypes: [],
baseWebhookUrl: baseEdgeStackWebhookUrl(),
isEdit: false,
templateValues: getInitialTemplateValues(),
};
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.hasType = this.hasType.bind(this);
this.onChangeDeploymentType = this.onChangeDeploymentType.bind(this);
this.onEnvVarChange = this.onEnvVarChange.bind(this);
this.setTemplateValues = this.setTemplateValues.bind(this);
this.onChangeTemplate = this.onChangeTemplate.bind(this);
}
/**
* @param {import('react').SetStateAction<import('@/react/edge/edge-stacks/CreateView/TemplateFieldset/types').Values>} templateAction
*/
setTemplateValues(templateAction) {
return this.$async(async () => {
const newTemplateValues = applySetStateAction(templateAction, this.state.templateValues);
const oldTemplateId = this.state.templateValues.template && this.state.templateValues.template.Id;
const newTemplateId = newTemplateValues.template && newTemplateValues.template.Id;
this.state.templateValues = newTemplateValues;
if (newTemplateId !== oldTemplateId) {
await this.onChangeTemplate(newTemplateValues.type, newTemplateValues.template);
}
if (newTemplateValues.type === 'custom') {
const definitions = this.state.templateValues.template.Variables;
const newFile = renderTemplate(this.state.templateValues.file, this.state.templateValues.variables, definitions);
this.formValues.StackFileContent = newFile;
}
});
}
onChangeTemplate(type, template) {
return this.$async(async () => {
if (!template) {
return;
}
if (type === 'custom') {
this.formValues = {
...this.formValues,
DeploymentType: template.Type === StackType.Kubernetes ? DeploymentType.Kubernetes : DeploymentType.Compose,
...toGitFormModel(template.GitConfig),
...(template.EdgeSettings
? {
PrePullImage: template.EdgeSettings.PrePullImage || false,
RetryDeploy: template.EdgeSettings.RetryDeploy || false,
PrivateRegistryId: template.EdgeSettings.PrivateRegistryId || null,
...template.EdgeSettings.RelativePathSettings,
}
: {}),
};
const fileContent = await getCustomTemplateFile({ id: template.Id, git: !!template.GitConfig });
this.state.templateValues.file = fileContent;
}
if (type === 'app') {
this.formValues.StackFileContent = '';
try {
const fileContent = await fetchFilePreview(template.Id);
this.formValues.StackFileContent = fileContent;
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve Template');
}
}
});
}
onEnvVarChange(envVars) {
return this.$scope.$evalAsync(() => {
this.formValues.envVars = envVars;
});
}
buildAnalyticsProperties() {
const format = 'compose';
const metadata = { type: methodLabel(this.state.Method), format };
if (metadata.type === 'template') {
metadata.templateName = this.state.selectedTemplate && this.state.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();
}
}
/**
*
* @param {'app' | 'custom'} templateType
* @param {number} templateId
* @returns {Promise<void>}
*/
async preSelectTemplate(templateType, templateId) {
return this.$async(async () => {
try {
this.state.Method = 'template';
const template = await getTemplate(templateType, templateId);
if (!template) {
return;
}
this.setTemplateValues({
template,
type: templateType,
envVars: templateType === 'app' ? getAppVariablesDefaultValues(template.Env) : {},
variables: templateType === 'custom' ? getVariablesFieldDefaultValues(template.Variables) : [],
});
} catch (e) {
notifyError('Failed loading template', e);
}
});
}
async $onInit() {
try {
this.edgeGroups = await this.EdgeGroupService.groups();
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve Edge groups');
}
const templateId = parseInt(this.$state.params.templateId, 10);
const templateType = this.$state.params.templateType;
if (templateType && templateId && !Number.isNaN(templateId)) {
this.preSelectTemplate(templateType, templateId);
}
this.$window.onbeforeunload = () => {
if (this.state.Method === 'editor' && this.formValues.StackFileContent && this.state.isEditorDirty) {
return '';
}
};
}
$onDestroy() {
this.state.isEditorDirty = false;
}
createStack() {
return this.$async(async () => {
const name = this.formValues.Name;
if (!this.validateTemplate()) {
return;
}
let envVars = this.formValues.envVars;
if (this.state.Method === 'template' && this.state.templateValues.type === 'app') {
envVars = [...envVars, ...Object.entries(this.state.templateValues.envVars).map(([key, value]) => ({ name: key, value }))];
}
const method = getMethod(this.state.Method, this.state.templateValues.template);
if (!this.validateForm(method)) {
return;
}
this.state.actionInProgress = true;
try {
await this.createStackByMethod(name, method, envVars);
this.Notifications.success('Success', 'Stack successfully deployed');
this.state.isEditorDirty = false;
this.$state.go('edge.stacks');
} catch (err) {
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) {
return this.$scope.$evalAsync(() => {
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]);
}
}
hasType(envType) {
return this.state.endpointTypes.includes(envType);
}
validateForm(method) {
this.state.formValidationError = '';
if (method === 'editor' && this.formValues.StackFileContent === '') {
this.state.formValidationError = 'Stack file content must not be empty';
return;
}
return true;
}
createStackByMethod(name, method, envVars) {
switch (method) {
case 'editor':
return this.createStackFromFileContent(name, envVars);
case 'upload':
return this.createStackFromFileUpload(name, envVars);
case 'repository':
return this.createStackFromGitRepository(name, envVars);
}
}
createStackFromFileContent(name, envVars) {
const { StackFileContent, Groups, DeploymentType, UseManifestNamespaces } = this.formValues;
return this.EdgeStackService.createStackFromFileContent({
name,
StackFileContent,
EdgeGroups: Groups,
DeploymentType,
UseManifestNamespaces,
envVars,
});
}
createStackFromFileUpload(name, envVars) {
const { StackFile, Groups, DeploymentType, UseManifestNamespaces } = this.formValues;
return this.EdgeStackService.createStackFromFileUpload(
{
Name: name,
EdgeGroups: Groups,
DeploymentType,
UseManifestNamespaces,
envVars,
},
StackFile
);
}
async createStackFromGitRepository(name, envVars) {
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,
CreatedFromCustomTemplateID: this.state.templateValues.template && this.state.templateValues.template.Id,
};
return this.EdgeStackService.createStackFromGitRepository(
{
name,
EdgeGroups: Groups,
DeploymentType,
UseManifestNamespaces,
envVars,
},
repositoryOptions
);
}
onChangeDeploymentType(deploymentType) {
return this.$scope.$evalAsync(() => {
this.formValues.DeploymentType = deploymentType;
this.state.Method = 'editor';
this.formValues.StackFileContent = '';
this.state.templateValues = getInitialTemplateValues();
});
}
validateTemplate() {
if (this.state.Method === 'template' && this.state.templateValues.type === 'app') {
return Object.entries(this.state.templateValues.envVars).every(([, value]) => !!value);
}
if (this.state.Method === 'template' && this.state.templateValues.type === 'custom') {
return Object.entries(this.state.templateValues.variables).every(([, v]) => {
return !!v.value;
});
}
return true;
}
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) ||
!this.validateTemplate()
);
}
}
/**
*
* @param {'template'|'repository' | 'editor' | 'upload'} method
* @param {import('@/react/portainer/templates/custom-templates/types').CustomTemplate | undefined} template
* @returns 'repository' | 'editor' | 'upload'
*/
function getMethod(method, template) {
if (method !== 'template') {
return method;
}
if (template && template.GitConfig) {
return 'repository';
}
return 'editor';
}
/**
*
* @param {'app' | 'custom'} templateType
* @param {number} templateId
* @returns {Promise<import('@/react/portainer/templates/app-templates/view-model').TemplateViewModel | import('@/react/portainer/templates/custom-templates/types').CustomTemplate | undefined>}
*/
async function getTemplate(templateType, templateId) {
if (!['app', 'custom'].includes(templateType)) {
notifyError('Invalid template type', `Invalid template type: ${templateType}`);
return;
}
if (templateType === 'app') {
const templatesResponse = await getAppTemplates();
const template = templatesResponse.templates.find((t) => t.id === templateId);
return new TemplateViewModel(template, templatesResponse.version);
}
const template = await getCustomTemplate(templateId);
return template;
}

View file

@ -1,101 +0,0 @@
<page-header title="'Create Edge stack'" breadcrumbs="[{label:'Edge Stacks', link:'edge.stacks'}, 'Create Edge stack']" reload="true"> </page-header>
<div class="row">
<div class="col-sm-12">
<rd-widget>
<rd-widget-body>
<form class="form-horizontal" name="$ctrl.form">
<!-- name-input -->
<div class="form-group">
<label for="stack_name" class="col-sm-1 control-label required text-left"> Name </label>
<div class="col-sm-11">
<input
type="text"
data-cy="edgeStackCreate-nameInput"
class="form-control"
ng-model="$ctrl.formValues.Name"
id="stack_name"
name="nameField"
ng-pattern="$ctrl.formValues.DeploymentType === $ctrl.EditorType.Compose ? STACK_NAME_VALIDATION_REGEX : ''"
placeholder="e.g. mystack"
auto-focus
required
/>
<div class="help-block" ng-show="$ctrl.form.$invalid">
<div class="small text-warning">
<div ng-messages="$ctrl.form.$error">
<p ng-message="required" class="vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
<span>Name is required.</span>
</p>
<p ng-message="pattern" class="vertical-center">
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon>
<span>This field must consist of lower case alphanumeric characters, '_' or '-' (e.g. 'my-name', or 'abc-123').</span>
</p>
</div>
</div>
</div>
</div>
</div>
<!-- !name-input -->
<edge-groups-selector ng-if="$ctrl.formValues.Groups" value="$ctrl.formValues.Groups" on-change="($ctrl.onChangeGroups)"></edge-groups-selector>
<p class="col-sm-12 vertical-center help-block small text-warning" ng-if="$ctrl.formValues.DeploymentType === undefined">
<pr-icon icon="'alert-triangle'" mode="'warning'"></pr-icon> There are no available deployment types when there is more than one type of environment in your edge group
selection (e.g. Kubernetes and Docker environments). Please select edge groups that have environments of the same type.
</p>
<edge-stack-deployment-type-selector
value="$ctrl.formValues.DeploymentType"
has-docker-endpoint="$ctrl.hasType($ctrl.EnvironmentType.EdgeAgentOnDocker)"
has-kube-endpoint="$ctrl.hasType($ctrl.EnvironmentType.EdgeAgentOnKubernetes)"
on-change="($ctrl.onChangeDeploymentType)"
></edge-stack-deployment-type-selector>
<edge-stacks-docker-compose-form
ng-if="$ctrl.formValues.DeploymentType == $ctrl.EditorType.Compose"
form-values="$ctrl.formValues"
state="$ctrl.state"
template-values="$ctrl.state.templateValues"
set-template-values="$ctrl.setTemplateValues"
></edge-stacks-docker-compose-form>
<edge-stacks-kube-manifest-form
ng-if="$ctrl.formValues.DeploymentType == $ctrl.EditorType.Kubernetes"
form-values="$ctrl.formValues"
state="$ctrl.state"
></edge-stacks-kube-manifest-form>
<div ng-if="$ctrl.isBE">
<environment-variables-panel values="$ctrl.formValues.envVars" on-change="($ctrl.onEnvVarChange)"></environment-variables-panel>
</div>
<!-- actions -->
<div class="col-sm-12 form-section-title"> Actions </div>
<div class="form-group">
<div class="col-sm-12">
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.state.actionInProgress || $ctrl.formIsInvalid()"
ng-click="$ctrl.createStack()"
button-spinner="$ctrl.state.actionInProgress"
analytics-on
analytics-event="edge-stack-creation"
analytics-category="edge"
analytics-properties="$ctrl.buildAnalyticsProperties()"
data-cy="edgeStackCreate-createStackButton"
>
<span ng-hide="$ctrl.state.actionInProgress">Deploy the stack</span>
<span ng-show="$ctrl.state.actionInProgress">Deployment in progress...</span>
</button>
<span class="text-danger" ng-if="$ctrl.state.formValidationError" style="margin-left: 5px"> {{ $ctrl.state.formValidationError }} </span>
</div>
</div>
<!-- !actions -->
</form>
</rd-widget-body>
</rd-widget>
</div>
</div>

View file

@ -1,6 +0,0 @@
import controller from './create-edge-stack-view.controller';
export const createEdgeStackView = {
templateUrl: './create-edge-stack-view.html',
controller,
};

View file

@ -1,51 +0,0 @@
import { getInitialTemplateValues } from '@/react/edge/edge-stacks/CreateView/TemplateFieldset/TemplateFieldset';
import { editor, git, edgeStackTemplate, upload } from '@@/BoxSelector/common-options/build-methods';
class DockerComposeFormController {
/* @ngInject */
constructor($async, Notifications) {
Object.assign(this, { $async, Notifications });
this.methodOptions = [editor, upload, git, edgeStackTemplate];
this.onChangeFileContent = this.onChangeFileContent.bind(this);
this.onChangeFile = this.onChangeFile.bind(this);
this.onChangeMethod = this.onChangeMethod.bind(this);
this.onChangeFormValues = this.onChangeFormValues.bind(this);
this.isGitTemplate = this.isGitTemplate.bind(this);
}
isGitTemplate() {
return this.state.Method === 'template' && !!this.templateValues.template && !!this.templateValues.template.GitConfig;
}
onChangeFormValues(newValues) {
return this.$async(async () => {
this.formValues = {
...this.formValues,
...newValues,
};
});
}
onChangeMethod(method) {
this.state.Method = method;
this.formValues.StackFileContent = '';
this.setTemplateValues(getInitialTemplateValues());
}
onChangeFileContent(value) {
return this.$async(async () => {
this.formValues.StackFileContent = value;
this.state.isEditorDirty = true;
});
}
onChangeFile(value) {
return this.$async(async () => {
this.formValues.StackFile = value;
});
}
}
export default DockerComposeFormController;

View file

@ -1,41 +0,0 @@
<div class="col-sm-12 form-section-title"> Build method </div>
<box-selector slim="true" radio-name="'method'" value="$ctrl.state.Method" options="$ctrl.methodOptions" on-change="($ctrl.onChangeMethod)"></box-selector>
<!-- template -->
<div ng-if="$ctrl.state.Method === 'template'">
<edge-stack-create-template-fieldset values="$ctrl.templateValues" set-values="$ctrl.setTemplateValues"></edge-stack-create-template-fieldset>
</div>
<!-- !template -->
<web-editor-form
ng-if="$ctrl.state.Method === 'editor' || ($ctrl.state.Method === 'template' && $ctrl.templateValues.template)"
identifier="stack-creation-editor"
value="$ctrl.formValues.StackFileContent"
on-change="($ctrl.onChangeFileContent)"
ng-required="true"
yml="true"
placeholder="Define or paste the content of your docker compose file here"
versions="$ctrl.formValues.versions"
read-only="$ctrl.isGitTemplate()"
>
<editor-description>
You can get more information about Compose file format in the
<a href="https://docs.docker.com/compose/compose-file/" target="_blank"> official documentation </a>
.
</editor-description>
</web-editor-form>
<file-upload-form ng-if="$ctrl.state.Method === 'upload'" file="$ctrl.formValues.StackFile" on-change="($ctrl.onChangeFile)" ng-required="true">
<file-upload-description> You can upload a Compose file from your computer. </file-upload-description>
</file-upload-form>
<div ng-if="$ctrl.state.Method == 'repository' || $ctrl.isGitTemplate()">
<git-form
value="$ctrl.formValues"
on-change="($ctrl.onChangeFormValues)"
base-webhook-url="{{ $ctrl.state.baseWebhookUrl }}"
webhook-id="{{ $ctrl.state.webhookId }}"
created-from-custom-template-id="($ctrl.state.templateValues.type === 'custom' ? $ctrl.state.templateValues.template.Id : 0)"
docs-links
></git-form>
</div>

View file

@ -1,13 +0,0 @@
import controller from './docker-compose-form.controller.js';
export const edgeStacksDockerComposeForm = {
templateUrl: './docker-compose-form.html',
controller,
bindings: {
formValues: '=',
state: '=',
templateValues: '<',
setTemplateValues: '<',
},
};

View file

@ -1,13 +0,0 @@
import angular from 'angular';
import { createEdgeStackView } from './create-edge-stack-view';
import { edgeStacksDockerComposeForm } from './docker-compose-form';
import { kubeManifestForm } from './kube-manifest-form';
import { kubeDeployDescription } from './kube-deploy-description';
export default angular
.module('portainer.edge.stacks.create', [])
.component('createEdgeStackView', createEdgeStackView)
.component('edgeStacksDockerComposeForm', edgeStacksDockerComposeForm)
.component('edgeStacksKubeManifestForm', kubeManifestForm)
.component('kubeDeployDescription', kubeDeployDescription).name;

View file

@ -1,3 +0,0 @@
export const kubeDeployDescription = {
templateUrl: './kube-deploy-description.html',
};

View file

@ -1,5 +0,0 @@
<div>Templates allow deploying any kind of Kubernetes resource (Deployment, Secret, ConfigMap...)</div>
<div>
You can get more information about Kubernetes file format in the
<a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/kubernetes-objects/" target="_blank">official documentation</a>.
</div>

View file

@ -1,11 +0,0 @@
import controller from './kube-manifest-form.controller.js';
export const kubeManifestForm = {
templateUrl: './kube-manifest-form.html',
controller,
bindings: {
formValues: '=',
state: '=',
},
};

View file

@ -1,48 +0,0 @@
import { editor, git, upload } from '@@/BoxSelector/common-options/build-methods';
class KubeManifestFormController {
/* @ngInject */
constructor($async) {
Object.assign(this, { $async });
this.methodOptions = [editor, upload, git];
this.onChangeFileContent = this.onChangeFileContent.bind(this);
this.onChangeFormValues = this.onChangeFormValues.bind(this);
this.onChangeFile = this.onChangeFile.bind(this);
this.onChangeMethod = this.onChangeMethod.bind(this);
this.onChangeUseManifestNamespaces = this.onChangeUseManifestNamespaces.bind(this);
}
onChangeFormValues(newValues) {
return this.$async(async () => {
this.formValues = {
...this.formValues,
...newValues,
};
});
}
onChangeUseManifestNamespaces(value) {
this.onChangeFormValues({ UseManifestNamespaces: value });
}
onChangeFileContent(value) {
this.state.isEditorDirty = true;
this.formValues.StackFileContent = value;
}
onChangeFile(value) {
return this.$async(async () => {
this.formValues.StackFile = value;
});
}
onChangeMethod(method) {
return this.$async(async () => {
this.state.Method = method;
});
}
}
export default KubeManifestFormController;

View file

@ -1,42 +0,0 @@
<div class="form-group">
<div class="col-sm-12">
<por-switch-field
label="'Use namespace(s) specified from manifest'"
tooltip="'If you have defined namespaces in your deployment file turning this on will enforce the use of those only in the deployment'"
checked="$ctrl.formValues.UseManifestNamespaces"
on-change="($ctrl.onChangeUseManifestNamespaces)"
></por-switch-field>
</div>
</div>
<div class="col-sm-12 form-section-title"> Build method </div>
<box-selector slim="true" radio-name="'method'" value="$ctrl.state.Method" options="$ctrl.methodOptions" on-change="($ctrl.onChangeMethod)"></box-selector>
<web-editor-form
ng-if="$ctrl.state.Method === 'editor'"
identifier="stack-creation-editor"
value="$ctrl.formValues.StackFileContent"
on-change="($ctrl.onChangeFileContent)"
yml="true"
placeholder="Define or paste the content of your manifest here"
ng-required="true"
>
<editor-description>
<kube-deploy-description></kube-deploy-description>
</editor-description>
</web-editor-form>
<file-upload-form ng-if="$ctrl.state.Method === 'upload'" file="$ctrl.formValues.StackFile" on-change="($ctrl.onChangeFile)" ng-required="true">
<file-upload-description>
<kube-deploy-description></kube-deploy-description>
</file-upload-description>
</file-upload-form>
<git-form
ng-if="$ctrl.state.Method === 'repository'"
deploy-method="kubernetes"
value="$ctrl.formValues"
on-change="($ctrl.onChangeFormValues)"
base-webhook-url="{{ $ctrl.state.baseWebhookUrl }}"
webhook-id="{{ $ctrl.state.webhookId }}"
></git-form>

View file

@ -1,5 +1,3 @@
import angular from 'angular';
import createModule from './createEdgeStackView';
export default angular.module('portainer.edge.stacks', [createModule]).name;
export default angular.module('portainer.edge.stacks', []).name;