feat(stack): front end backport changes to CE EE-1199 (#5455)

* feat(stack): front end backport changes to CE EE-1199

* fix k8s deploy logic

* fixed web editor confirmation message typo. EE-1501

* fix(stack): fixed issue auth detail not remembered EE-1502 (#5459)

* show status in buttons

* removed onChangeRef function.

* moved buttons in git form to its own component

* removed unused variable.

Co-authored-by: ArrisLee <arris_li@hotmail.com>
pull/5505/head
fhanportainer 2021-08-25 14:04:12 +12:00 committed by GitHub
parent 9fae031390
commit 6d87c77ab0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 1783 additions and 1415 deletions

View File

@ -217,7 +217,7 @@ func (handler *Handler) deployKubernetesStack(request *http.Request, endpoint *p
return "", errors.Wrap(err, "failed to add application labels") return "", errors.Wrap(err, "failed to add application labels")
} }
return handler.KubernetesDeployer.Deploy(request, endpoint, stackConfig, namespace) return handler.KubernetesDeployer.Deploy(request, endpoint, string(manifest), namespace)
} }

View File

@ -14,6 +14,8 @@ import {
KubernetesPortainerApplicationNote, KubernetesPortainerApplicationNote,
KubernetesPortainerApplicationOwnerLabel, KubernetesPortainerApplicationOwnerLabel,
KubernetesPortainerApplicationStackNameLabel, KubernetesPortainerApplicationStackNameLabel,
KubernetesPortainerApplicationStackIdLabel,
KubernetesPortainerApplicationKindLabel,
} from 'Kubernetes/models/application/models'; } from 'Kubernetes/models/application/models';
import { KubernetesServiceTypes } from 'Kubernetes/models/service/models'; import { KubernetesServiceTypes } from 'Kubernetes/models/service/models';
import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper'; import KubernetesResourceReservationHelper from 'Kubernetes/helpers/resourceReservationHelper';
@ -55,6 +57,8 @@ class KubernetesApplicationConverter {
res.Id = data.metadata.uid; res.Id = data.metadata.uid;
res.Name = data.metadata.name; res.Name = data.metadata.name;
res.StackName = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationStackNameLabel] || '-' : '-'; res.StackName = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationStackNameLabel] || '-' : '-';
res.StackId = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationStackIdLabel] || '' : '';
res.ApplicationKind = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationKindLabel] || '' : '';
res.ApplicationOwner = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationOwnerLabel] || '' : ''; res.ApplicationOwner = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationOwnerLabel] || '' : '';
res.Note = data.metadata.annotations ? data.metadata.annotations[KubernetesPortainerApplicationNote] || '' : ''; res.Note = data.metadata.annotations ? data.metadata.annotations[KubernetesPortainerApplicationNote] || '' : '';
res.ApplicationName = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationNameLabel] || res.Name : res.Name; res.ApplicationName = data.metadata.labels ? data.metadata.labels[KubernetesPortainerApplicationNameLabel] || res.Name : res.Name;

View File

@ -41,6 +41,10 @@ export const KubernetesApplicationQuotaDefaults = {
export const KubernetesPortainerApplicationStackNameLabel = 'io.portainer.kubernetes.application.stack'; export const KubernetesPortainerApplicationStackNameLabel = 'io.portainer.kubernetes.application.stack';
export const KubernetesPortainerApplicationStackIdLabel = 'io.portainer.kubernetes.application.stackid';
export const KubernetesPortainerApplicationKindLabel = 'io.portainer.kubernetes.application.kind';
export const KubernetesPortainerApplicationNameLabel = 'io.portainer.kubernetes.application.name'; export const KubernetesPortainerApplicationNameLabel = 'io.portainer.kubernetes.application.name';
export const KubernetesPortainerApplicationOwnerLabel = 'io.portainer.kubernetes.application.owner'; export const KubernetesPortainerApplicationOwnerLabel = 'io.portainer.kubernetes.application.owner';

View File

@ -7,6 +7,8 @@ const _KubernetesApplication = Object.freeze({
Id: '', Id: '',
Name: '', Name: '',
StackName: '', StackName: '',
StackId: '',
ApplicationKind: '',
ApplicationOwner: '', ApplicationOwner: '',
ApplicationName: '', ApplicationName: '',
ResourcePool: '', ResourcePool: '',
@ -91,3 +93,9 @@ export class KubernetesApplicationPort {
Object.assign(this, JSON.parse(JSON.stringify(_KubernetesApplicationPort))); Object.assign(this, JSON.parse(JSON.stringify(_KubernetesApplicationPort)));
} }
} }
export const KubernetesDeploymentTypes = Object.freeze({
GIT: 'git',
CONTENT: 'content',
APPLICATION_FORM: 'application form',
});

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@ import {
KubernetesApplicationQuotaDefaults, KubernetesApplicationQuotaDefaults,
KubernetesApplicationTypes, KubernetesApplicationTypes,
KubernetesApplicationPlacementTypes, KubernetesApplicationPlacementTypes,
KubernetesDeploymentTypes,
} from 'Kubernetes/models/application/models'; } from 'Kubernetes/models/application/models';
import { import {
KubernetesApplicationConfigurationFormValue, KubernetesApplicationConfigurationFormValue,
@ -49,7 +50,8 @@ class KubernetesCreateApplicationController {
KubernetesPersistentVolumeClaimService, KubernetesPersistentVolumeClaimService,
KubernetesNamespaceHelper, KubernetesNamespaceHelper,
KubernetesVolumeService, KubernetesVolumeService,
RegistryService RegistryService,
StackService
) { ) {
this.$async = $async; this.$async = $async;
this.$state = $state; this.$state = $state;
@ -66,6 +68,7 @@ class KubernetesCreateApplicationController {
this.KubernetesPersistentVolumeClaimService = KubernetesPersistentVolumeClaimService; this.KubernetesPersistentVolumeClaimService = KubernetesPersistentVolumeClaimService;
this.KubernetesNamespaceHelper = KubernetesNamespaceHelper; this.KubernetesNamespaceHelper = KubernetesNamespaceHelper;
this.RegistryService = RegistryService; this.RegistryService = RegistryService;
this.StackService = StackService;
this.ApplicationDeploymentTypes = KubernetesApplicationDeploymentTypes; this.ApplicationDeploymentTypes = KubernetesApplicationDeploymentTypes;
this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies; this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies;
@ -74,8 +77,11 @@ class KubernetesCreateApplicationController {
this.ApplicationTypes = KubernetesApplicationTypes; this.ApplicationTypes = KubernetesApplicationTypes;
this.ApplicationConfigurationFormValueOverridenKeyTypes = KubernetesApplicationConfigurationFormValueOverridenKeyTypes; this.ApplicationConfigurationFormValueOverridenKeyTypes = KubernetesApplicationConfigurationFormValueOverridenKeyTypes;
this.ServiceTypes = KubernetesServiceTypes; this.ServiceTypes = KubernetesServiceTypes;
this.KubernetesDeploymentTypes = KubernetesDeploymentTypes;
this.state = { this.state = {
appType: this.KubernetesDeploymentTypes.APPLICATION_FORM,
updateWebEditorInProgress: false,
actionInProgress: false, actionInProgress: false,
useLoadBalancer: false, useLoadBalancer: false,
useServerMetrics: false, useServerMetrics: false,
@ -124,13 +130,54 @@ class KubernetesCreateApplicationController {
this.state.useServerMetrics = false; this.state.useServerMetrics = false;
this.formValues = new KubernetesApplicationFormValues(); this.formValues = new KubernetesApplicationFormValues();
this.gitFormValues = {
RefName: '',
RepositoryAuthentication: false,
RepositoryUsername: '',
RepositoryPassword: '',
};
this.updateApplicationAsync = this.updateApplicationAsync.bind(this); this.updateApplicationAsync = this.updateApplicationAsync.bind(this);
this.deployApplicationAsync = this.deployApplicationAsync.bind(this); this.deployApplicationAsync = this.deployApplicationAsync.bind(this);
this.setPullImageValidity = this.setPullImageValidity.bind(this); this.setPullImageValidity = this.setPullImageValidity.bind(this);
this.onChangeFileContent = this.onChangeFileContent.bind(this);
} }
/* #endregion */ /* #endregion */
onChangeFileContent(value) {
if (this.stackFileContent.replace(/(\r\n|\n|\r)/gm, '') !== value.replace(/(\r\n|\n|\r)/gm, '')) {
this.state.isEditorDirty = true;
this.stackFileContent = value;
}
}
async updateApplicationViaWebEditor() {
return this.$async(async () => {
try {
const confirmed = await this.ModalService.confirmAsync({
title: 'Are you sure?',
message: 'Any changes to this application will be overriden and may cause a service interruption. Do you wish to continue',
buttons: {
confirm: {
label: 'Update',
className: 'btn-warning',
},
},
});
if (!confirmed) {
return;
}
this.state.updateWebEditorInProgress = true;
await this.StackService.updateKubeStack({ EndpointId: this.endpoint.Id, Id: this.application.StackId }, this.stackFileContent, null);
await this.$state.reload();
} catch (err) {
this.Notifications.error('Failure', err, 'Failed redeploying application');
} finally {
this.state.updateWebEditorInProgress = false;
}
});
}
setPullImageValidity(validity) { setPullImageValidity(validity) {
this.state.pullImageValidity = validity; this.state.pullImageValidity = validity;
} }
@ -980,6 +1027,23 @@ class KubernetesCreateApplicationController {
this.nodesLabels, this.nodesLabels,
this.filteredIngresses this.filteredIngresses
); );
if (this.application.ApplicationKind) {
this.state.appType = this.KubernetesDeploymentTypes[this.application.ApplicationKind.toUpperCase()];
if (this.application.StackId) {
if (this.application.ApplicationKind === this.KubernetesDeploymentTypes.GIT) {
this.stack = await this.StackService.stack(this.application.StackId);
this.gitFormValues.RefName = this.stack.GitConfig.ReferenceName;
if (this.stack.GitConfig && this.stack.GitConfig.Authentication) {
this.gitFormValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username;
this.gitFormValues.RepositoryAuthentication = true;
}
} else if (this.application.ApplicationKind === this.KubernetesDeploymentTypes.CONTENT) {
this.stackFileContent = await this.StackService.getStackFile(this.application.StackId);
}
}
}
this.formValues.OriginalIngresses = this.filteredIngresses; this.formValues.OriginalIngresses = this.filteredIngresses;
this.formValues.ImageModel = await this.parseImageConfiguration(this.formValues.ImageModel); this.formValues.ImageModel = await this.parseImageConfiguration(this.formValues.ImageModel);
this.savedFormValues = angular.copy(this.formValues); this.savedFormValues = angular.copy(this.formValues);

View File

@ -66,7 +66,8 @@
<td>Creation</td> <td>Creation</td>
<td> <td>
<span ng-if="ctrl.application.ApplicationOwner" style="margin-right: 5px;"> <i class="fas fa-user"></i> {{ ctrl.application.ApplicationOwner }} </span> <span ng-if="ctrl.application.ApplicationOwner" style="margin-right: 5px;"> <i class="fas fa-user"></i> {{ ctrl.application.ApplicationOwner }} </span>
<span> <i class="fas fa-clock"></i> {{ ctrl.application.CreationDate | getisodate }} </span> <span> <i class="fas fa-clock"></i> {{ ctrl.application.CreationDate | getisodate }}</span>
<span> <i class="fa fa-file-code space-left space-right" aria-hidden="true"></i> Deployed from {{ ctrl.state.appType }}</span>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@ -1,7 +1,12 @@
import angular from 'angular'; import angular from 'angular';
import _ from 'lodash-es'; import _ from 'lodash-es';
import * as JsonPatch from 'fast-json-patch'; import * as JsonPatch from 'fast-json-patch';
import { KubernetesApplicationDataAccessPolicies, KubernetesApplicationDeploymentTypes, KubernetesApplicationTypes } from 'Kubernetes/models/application/models'; import {
KubernetesApplicationDataAccessPolicies,
KubernetesApplicationDeploymentTypes,
KubernetesApplicationTypes,
KubernetesDeploymentTypes,
} from 'Kubernetes/models/application/models';
import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper'; import KubernetesEventHelper from 'Kubernetes/helpers/eventHelper';
import KubernetesApplicationHelper from 'Kubernetes/helpers/application'; import KubernetesApplicationHelper from 'Kubernetes/helpers/application';
import { KubernetesServiceTypes } from 'Kubernetes/models/service/models'; import { KubernetesServiceTypes } from 'Kubernetes/models/service/models';
@ -127,6 +132,7 @@ class KubernetesApplicationController {
this.KubernetesApplicationDeploymentTypes = KubernetesApplicationDeploymentTypes; this.KubernetesApplicationDeploymentTypes = KubernetesApplicationDeploymentTypes;
this.KubernetesApplicationTypes = KubernetesApplicationTypes; this.KubernetesApplicationTypes = KubernetesApplicationTypes;
this.EndpointProvider = EndpointProvider; this.EndpointProvider = EndpointProvider;
this.KubernetesDeploymentTypes = KubernetesDeploymentTypes;
this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies; this.ApplicationDataAccessPolicies = KubernetesApplicationDataAccessPolicies;
this.KubernetesServiceTypes = KubernetesServiceTypes; this.KubernetesServiceTypes = KubernetesServiceTypes;
@ -137,6 +143,7 @@ class KubernetesApplicationController {
this.getApplicationAsync = this.getApplicationAsync.bind(this); this.getApplicationAsync = this.getApplicationAsync.bind(this);
this.getEvents = this.getEvents.bind(this); this.getEvents = this.getEvents.bind(this);
this.getEventsAsync = this.getEventsAsync.bind(this); this.getEventsAsync = this.getEventsAsync.bind(this);
this.updateApplicationKindText = this.updateApplicationKindText.bind(this);
this.updateApplicationAsync = this.updateApplicationAsync.bind(this); this.updateApplicationAsync = this.updateApplicationAsync.bind(this);
this.redeployApplicationAsync = this.redeployApplicationAsync.bind(this); this.redeployApplicationAsync = this.redeployApplicationAsync.bind(this);
this.rollbackApplicationAsync = this.rollbackApplicationAsync.bind(this); this.rollbackApplicationAsync = this.rollbackApplicationAsync.bind(this);
@ -258,6 +265,14 @@ class KubernetesApplicationController {
return this.$async(this.updateApplicationAsync); return this.$async(this.updateApplicationAsync);
} }
updateApplicationKindText() {
if (this.application.ApplicationKind === this.KubernetesDeploymentTypes.GIT) {
this.state.appType = `git repository`;
} else if (this.application.ApplicationKind === this.KubernetesDeploymentTypes.CONTENT) {
this.state.appType = `web editor`;
}
}
/** /**
* EVENTS * EVENTS
*/ */
@ -334,6 +349,7 @@ class KubernetesApplicationController {
namespace: this.$transition$.params().namespace, namespace: this.$transition$.params().namespace,
name: this.$transition$.params().name, name: this.$transition$.params().name,
}, },
appType: this.KubernetesDeploymentTypes.APPLICATION_FORM,
eventWarningCount: 0, eventWarningCount: 0,
placementWarning: false, placementWarning: false,
expandedNote: false, expandedNote: false,
@ -350,6 +366,7 @@ class KubernetesApplicationController {
await this.getApplication(); await this.getApplication();
await this.getEvents(); await this.getEvents();
this.updateApplicationKindText();
this.state.viewReady = true; this.state.viewReady = true;
} }

View File

@ -9,7 +9,6 @@ export const webEditorForm = {
placeholder: '@', placeholder: '@',
yml: '<', yml: '<',
value: '<', value: '<',
onChange: '<', onChange: '<',
}, },

View File

@ -6,6 +6,7 @@ export const gitFormAuthFieldset = {
bindings: { bindings: {
model: '<', model: '<',
onChange: '<', onChange: '<',
showAuthExplanation: '<',
isEdit: '<', isEdit: '<',
}, },
}; };

View File

@ -0,0 +1,15 @@
<div class="form-group" ng-class="$ctrl.className">
<div class="col-sm-12">
<p>
This stack was deployed from the git repository <code>{{ $ctrl.url }}</code>
.
</p>
<p>
Update
<code
>{{ $ctrl.configFilePath }}<span ng-if="$ctrl.additionalFiles.length > 0">,{{ $ctrl.additionalFiles.join(',') }}</span></code
>
in git and pull from here to update the stack.
</p>
</div>
</div>

View File

@ -0,0 +1,9 @@
export const gitFormInfoPanel = {
templateUrl: './git-form-info-panel.html',
bindings: {
url: '<',
configFilePath: '<',
additionalFiles: '<',
className: '@',
},
};

View File

@ -8,6 +8,7 @@ import { gitFormAutoUpdateFieldset } from './git-form-auto-update-fieldset';
import { gitFormComposePathField } from './git-form-compose-path-field'; import { gitFormComposePathField } from './git-form-compose-path-field';
import { gitFormRefField } from './git-form-ref-field'; import { gitFormRefField } from './git-form-ref-field';
import { gitFormUrlField } from './git-form-url-field'; import { gitFormUrlField } from './git-form-url-field';
import { gitFormInfoPanel } from './git-form-info-panel';
export default angular export default angular
.module('portainer.app.components.forms.git', []) .module('portainer.app.components.forms.git', [])
@ -15,6 +16,7 @@ export default angular
.component('gitFormRefField', gitFormRefField) .component('gitFormRefField', gitFormRefField)
.component('gitForm', gitForm) .component('gitForm', gitForm)
.component('gitFormUrlField', gitFormUrlField) .component('gitFormUrlField', gitFormUrlField)
.component('gitFormInfoPanel', gitFormInfoPanel)
.component('gitFormAdditionalFilesPanel', gitFormAdditionalFilesPanel) .component('gitFormAdditionalFilesPanel', gitFormAdditionalFilesPanel)
.component('gitFormAdditionalFileItem', gitFormAdditionalFileItem) .component('gitFormAdditionalFileItem', gitFormAdditionalFileItem)
.component('gitFormAutoUpdateFieldset', gitFormAutoUpdateFieldset) .component('gitFormAutoUpdateFieldset', gitFormAutoUpdateFieldset)

View File

@ -0,0 +1,87 @@
class KubernetesAppGitFormController {
/* @ngInject */
constructor($async, $state, StackService, ModalService, Notifications) {
this.$async = $async;
this.$state = $state;
this.StackService = StackService;
this.ModalService = ModalService;
this.Notifications = Notifications;
this.state = {
saveGitSettingsInProgress: false,
redeployInProgress: false,
showConfig: true,
isEdit: false,
};
this.onChange = this.onChange.bind(this);
this.onChangeRef = this.onChangeRef.bind(this);
}
onChangeRef(value) {
this.onChange({ RefName: value });
}
onChange(values) {
this.gitFormValues = {
...this.gitFormValues,
...values,
};
}
async pullAndRedeployApplication() {
return this.$async(async () => {
try {
const confirmed = await this.ModalService.confirmAsync({
title: 'Are you sure?',
message: 'Any changes to this application will be overriden by the definition in git and may cause a service interruption. Do you wish to continue',
buttons: {
confirm: {
label: 'Update',
className: 'btn-warning',
},
},
});
if (!confirmed) {
return;
}
this.state.redeployInProgress = true;
this.Notifications.success('Pulled and redeployed stack successfully');
await this.StackService.updateKubeGit(this.stack.Id, this.stack.EndpointId, this.namespace, this.gitFormValues);
await this.$state.reload();
} catch (err) {
this.Notifications.error('Failure', err, 'Failed redeploying application');
} finally {
this.state.redeployInProgress = false;
}
});
}
async saveGitSettings() {
return this.$async(async () => {
try {
this.state.saveGitSettingsInProgress = true;
await this.StackService.updateKubeStack({ EndpointId: this.stack.EndpointId, Id: this.stack.Id }, null, this.gitFormValues);
this.Notifications.success('Save stack settings successfully');
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to save application settings');
} finally {
this.state.saveGitSettingsInProgress = false;
}
});
}
isSubmitButtonDisabled() {
return this.state.saveGitSettingsInProgress || this.state.redeployInProgress;
}
$onInit() {
if (this.stack.GitConfig && this.stack.GitConfig.Authentication) {
this.formValues.RepositoryUsername = this.stack.GitConfig.Authentication.Username;
this.formValues.RepositoryAuthentication = true;
this.state.isEdit = true;
}
}
}
export default KubernetesAppGitFormController;

View File

@ -0,0 +1,58 @@
<form name="$ctrl.redeployGitForm">
<div class="col-sm-12 form-section-title">
Redeploy from git repository
</div>
<div class="form-group text-muted">
<div class="col-sm-12">
<p>
Pull the latest manifest from git and redeploy the application.
</p>
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<p>
<a class="small interactive" ng-click="$ctrl.state.showConfig = !$ctrl.state.showConfig">
<i ng-class="['fa space-right', { 'fa-minus': $ctrl.state.showConfig, 'fa-plus': !$ctrl.state.showConfig }]" aria-hidden="true"></i>
{{ $ctrl.state.showConfig ? 'Hide' : 'Advanced' }} configuration
</a>
</p>
</div>
</div>
<git-form-ref-field ng-if="$ctrl.state.showConfig" value="$ctrl.gitFormValues.RefName" on-change="($ctrl.onChangeRef)"></git-form-ref-field>
<git-form-auth-fieldset
ng-if="$ctrl.state.showConfig"
model="$ctrl.gitFormValues"
is-edit="$ctrl.isEdit"
on-change="($ctrl.onChange)"
show-auth-explanation="true"
></git-form-auth-fieldset>
<div class="col-sm-12 form-section-title">
Actions
</div>
<!-- #Git buttons -->
<button
class="btn btn-sm btn-primary"
ng-click="$ctrl.pullAndRedeployApplication()"
ng-disabled="$ctrl.isSubmitButtonDisabled() || !$ctrl.redeployGitForm.$valid"
style="margin-top: 7px; margin-left: 0;"
button-spinner="ctrl.state.redeployInProgress"
analytics-category="kubernetes"
analytics-event="kubernetes-application-edit-git-pull"
>
<span ng-show="!$ctrl.state.redeployInProgress"> <i class="fa fa-sync space-right" aria-hidden="true"></i> Pull and update application </span>
<span ng-show="$ctrl.state.redeployInProgress">In progress...</span>
</button>
<button
class="btn btn-sm btn-primary"
ng-click="$ctrl.saveGitSettings()"
ng-disabled="$ctrl.isSubmitButtonDisabled() || !$ctrl.redeployGitForm.$valid"
style="margin-top: 7px; margin-left: 0;"
button-spinner="$ctrl.state.saveGitSettingsInProgress"
>
<span ng-show="!$ctrl.state.saveGitSettingsInProgress"> Save settings </span>
<span ng-show="$ctrl.state.saveGitSettingsInProgress">In progress...</span>
</button>
</form>

View File

@ -0,0 +1,15 @@
import angular from 'angular';
import controller from './kubernetes-app-git-form.controller';
const kubernetesAppGitForm = {
templateUrl: './kubernetes-app-git-form.html',
controller,
bindings: {
gitFormValues: '<',
namespace: '<',
stack: '<',
isEdit: '<',
},
};
angular.module('portainer.app').component('kubernetesAppGitForm', kubernetesAppGitForm);

View File

@ -2,21 +2,12 @@
<div class="col-sm-12 form-section-title"> <div class="col-sm-12 form-section-title">
Redeploy from git repository Redeploy from git repository
</div> </div>
<div class="text-muted small form-group"> <git-form-info-panel
<div class="col-sm-12"> class-name="text-muted small"
<p> url="$ctrl.model.URL"
This stack was deployed from the git repository <code>{{ $ctrl.model.URL }}</code> config-file-path="$ctrl.model.ConfigFilePath"
. additional-files="$ctrl.stack.AdditionalFiles"
</p> ></git-form-info-panel>
<p>
Update
<code
>{{ $ctrl.model.ConfigFilePath }}<span ng-if="$ctrl.stack.AdditionalFiles.length > 0">,{{ $ctrl.stack.AdditionalFiles.join(',') }}</span></code
>
in git and pull from here to update the stack.
</p>
</div>
</div>
<git-form-auto-update-fieldset model="$ctrl.formValues.AutoUpdate" on-change="($ctrl.onChange)"></git-form-auto-update-fieldset> <git-form-auto-update-fieldset model="$ctrl.formValues.AutoUpdate" on-change="($ctrl.onChange)"></git-form-auto-update-fieldset>
<div class="form-group"> <div class="form-group">

View File

@ -15,6 +15,7 @@ angular.module('portainer.app').factory('StackService', [
'use strict'; 'use strict';
var service = { var service = {
updateGit, updateGit,
updateKubeGit,
}; };
service.stack = function (id) { service.stack = function (id) {
@ -268,6 +269,25 @@ angular.module('portainer.app').factory('StackService', [
return Stack.update({ endpointId: stack.EndpointId }, { id: stack.Id, StackFileContent: stackFile, Env: env, Prune: prune }).$promise; return Stack.update({ endpointId: stack.EndpointId }, { id: stack.Id, StackFileContent: stackFile, Env: env, Prune: prune }).$promise;
}; };
service.updateKubeStack = function (stack, stackFile, gitConfig) {
let payload = {};
if (stackFile) {
payload = {
StackFileContent: stackFile,
};
} else {
payload = {
RepositoryReferenceName: gitConfig.RefName,
RepositoryAuthentication: gitConfig.RepositoryAuthentication,
RepositoryUsername: gitConfig.RepositoryUsername,
RepositoryPassword: gitConfig.RepositoryPassword,
};
}
return Stack.update({ id: stack.Id, endpointId: stack.EndpointId }, payload).$promise;
};
service.createComposeStackFromFileUpload = function (name, stackFile, env, endpointId) { service.createComposeStackFromFileUpload = function (name, stackFile, env, endpointId) {
return FileUploadService.createComposeStack(name, stackFile, env, endpointId); return FileUploadService.createComposeStack(name, stackFile, env, endpointId);
}; };
@ -417,6 +437,19 @@ angular.module('portainer.app').factory('StackService', [
).$promise; ).$promise;
} }
function updateKubeGit(id, endpointId, namespace, gitConfig) {
return Stack.updateGit(
{ endpointId, id },
{
Namespace: namespace,
RepositoryReferenceName: gitConfig.RefName,
RepositoryAuthentication: gitConfig.RepositoryAuthentication,
RepositoryUsername: gitConfig.RepositoryUsername,
RepositoryPassword: gitConfig.RepositoryPassword,
}
).$promise;
}
service.updateGitStackSettings = function (id, endpointId, env, gitConfig) { service.updateGitStackSettings = function (id, endpointId, env, gitConfig) {
// prepare auto update // prepare auto update
const autoUpdate = {}; const autoUpdate = {};

View File

@ -33,7 +33,7 @@ angular
StackFile: null, StackFile: null,
RepositoryURL: '', RepositoryURL: '',
RepositoryReferenceName: '', RepositoryReferenceName: '',
RepositoryAuthentication: false, RepositoryAuthentication: true,
RepositoryUsername: '', RepositoryUsername: '',
RepositoryPassword: '', RepositoryPassword: '',
Env: [], Env: [],