mirror of https://github.com/portainer/portainer
feat(webhook): teasers of pull images and webhook for EE EE-1332 (#6278)
* feat(webhook): teasers of pull images and webhook for EEpull/6557/head
parent
fa208c7f2a
commit
37ca62eb06
|
@ -3,6 +3,7 @@ import _ from 'lodash-es';
|
||||||
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
|
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
|
||||||
|
|
||||||
import * as envVarsUtils from '@/portainer/helpers/env-vars';
|
import * as envVarsUtils from '@/portainer/helpers/env-vars';
|
||||||
|
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||||
import { ContainerCapabilities, ContainerCapability } from '../../../models/containerCapabilities';
|
import { ContainerCapabilities, ContainerCapability } from '../../../models/containerCapabilities';
|
||||||
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel';
|
import { AccessControlFormData } from '../../../../portainer/components/accessControlForm/porAccessControlFormModel';
|
||||||
import { ContainerDetailsViewModel } from '../../../models/container';
|
import { ContainerDetailsViewModel } from '../../../models/container';
|
||||||
|
@ -65,7 +66,7 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
||||||
$scope.create = create;
|
$scope.create = create;
|
||||||
$scope.update = update;
|
$scope.update = update;
|
||||||
$scope.endpoint = endpoint;
|
$scope.endpoint = endpoint;
|
||||||
|
$scope.containerWebhookFeature = FeatureId.CONTAINER_WEBHOOK;
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
alwaysPull: true,
|
alwaysPull: true,
|
||||||
Console: 'none',
|
Console: 'none',
|
||||||
|
|
|
@ -65,6 +65,28 @@
|
||||||
</por-image-registry>
|
</por-image-registry>
|
||||||
<!-- !image-and-registry -->
|
<!-- !image-and-registry -->
|
||||||
</div>
|
</div>
|
||||||
|
<!-- create-webhook -->
|
||||||
|
<div ng-if="isAdmin && applicationState.endpoint.type !== 4">
|
||||||
|
<div class="col-sm-12 form-section-title"> Webhooks </div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label class="control-label text-left">
|
||||||
|
Create a container webhook
|
||||||
|
<portainer-tooltip
|
||||||
|
position="top"
|
||||||
|
message="Create a webhook (or callback URI) to automate the recreate this container. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and recreate this container."
|
||||||
|
></portainer-tooltip>
|
||||||
|
</label>
|
||||||
|
<label class="switch box-selector-item limited business" style="margin-left: 20px">
|
||||||
|
<input type="checkbox" ng-model="formValues.EnableWebhook" disabled="disabled" ng-checked="true" />
|
||||||
|
<i class="orange-icon" aria-hidden="true" style="margin-right: 2px"></i>
|
||||||
|
</label>
|
||||||
|
<be-feature-indicator feature="containerWebhookFeature"></be-feature-indicator>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- !create-webhook -->
|
||||||
|
|
||||||
<div class="col-sm-12 form-section-title"> Network ports configuration </div>
|
<div class="col-sm-12 form-section-title"> Network ports configuration </div>
|
||||||
<!-- publish-exposed-ports -->
|
<!-- publish-exposed-ports -->
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|
|
@ -110,6 +110,19 @@
|
||||||
<td>Finished</td>
|
<td>Finished</td>
|
||||||
<td>{{ container.State.FinishedAt | getisodate }}</td>
|
<td>{{ container.State.FinishedAt | getisodate }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr ng-if="isAdmin && displayRecreateButton && applicationState.endpoint.type !== 4">
|
||||||
|
<td colspan="1">
|
||||||
|
Container webhook
|
||||||
|
<portainer-tooltip
|
||||||
|
position="top"
|
||||||
|
message="Webhook (or callback URI) used to automate the recreate this container. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and recreate this container."
|
||||||
|
></portainer-tooltip>
|
||||||
|
<label class="switch box-selector-item limited business" style="margin-left: 20px">
|
||||||
|
<input disable-authorization="DockerContainerUpdate" type="checkbox" ng-model="WebhookExists" disabled="disabled" ng-checked="true" /><i></i>
|
||||||
|
</label>
|
||||||
|
<be-feature-indicator feature="containerWebhookFeature"></be-feature-indicator>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
|
<tr authorization="DockerContainerLogs, DockerContainerInspect, DockerContainerStats, DockerExecStart">
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
<div class="btn-group" role="group" aria-label="...">
|
<div class="btn-group" role="group" aria-label="...">
|
||||||
|
|
|
@ -2,6 +2,7 @@ import moment from 'moment';
|
||||||
import _ from 'lodash-es';
|
import _ from 'lodash-es';
|
||||||
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
|
import { PorImageRegistryModel } from 'Docker/models/porImageRegistry';
|
||||||
import { confirmContainerDeletion } from '@/portainer/services/modal.service/prompt';
|
import { confirmContainerDeletion } from '@/portainer/services/modal.service/prompt';
|
||||||
|
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||||
|
|
||||||
angular.module('portainer.docker').controller('ContainerController', [
|
angular.module('portainer.docker').controller('ContainerController', [
|
||||||
'$q',
|
'$q',
|
||||||
|
@ -49,6 +50,7 @@ angular.module('portainer.docker').controller('ContainerController', [
|
||||||
$scope.activityTime = 0;
|
$scope.activityTime = 0;
|
||||||
$scope.portBindings = [];
|
$scope.portBindings = [];
|
||||||
$scope.displayRecreateButton = false;
|
$scope.displayRecreateButton = false;
|
||||||
|
$scope.containerWebhookFeature = FeatureId.CONTAINER_WEBHOOK;
|
||||||
|
|
||||||
$scope.config = {
|
$scope.config = {
|
||||||
RegistryModel: new PorImageRegistryModel(),
|
RegistryModel: new PorImageRegistryModel(),
|
||||||
|
|
|
@ -10,6 +10,7 @@ class GitFormAutoUpdateFieldsetController {
|
||||||
this.onChangeInterval = this.onChangeField('RepositoryFetchInterval');
|
this.onChangeInterval = this.onChangeField('RepositoryFetchInterval');
|
||||||
|
|
||||||
this.limitedFeature = FeatureId.FORCE_REDEPLOYMENT;
|
this.limitedFeature = FeatureId.FORCE_REDEPLOYMENT;
|
||||||
|
this.stackPullImageFeature = FeatureId.STACK_PULL_IMAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
copyWebhook() {
|
copyWebhook() {
|
||||||
|
|
|
@ -51,6 +51,11 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-group" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<por-switch-field name="forcePullImage" feature-id="$ctrl.stackPullImageFeature" checked="$ctrl.model.ForcePullImage" label="'Pull latest image'"> </por-switch-field>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
|
<div class="form-group" ng-if="$ctrl.model.RepositoryAutomaticUpdates">
|
||||||
<div class="col-sm-12">
|
<div class="col-sm-12">
|
||||||
<por-switch-field
|
<por-switch-field
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import uuidv4 from 'uuid/v4';
|
import uuidv4 from 'uuid/v4';
|
||||||
import { RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
import { RepositoryMechanismTypes } from 'Kubernetes/models/deploy';
|
||||||
|
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||||
class StackRedeployGitFormController {
|
class StackRedeployGitFormController {
|
||||||
/* @ngInject */
|
/* @ngInject */
|
||||||
constructor($async, $state, StackService, ModalService, Notifications, WebhookHelper, FormHelper) {
|
constructor($async, $state, $compile, $scope, StackService, ModalService, Notifications, WebhookHelper, FormHelper) {
|
||||||
this.$async = $async;
|
this.$async = $async;
|
||||||
this.$state = $state;
|
this.$state = $state;
|
||||||
|
this.$compile = $compile;
|
||||||
|
this.$scope = $scope;
|
||||||
this.StackService = StackService;
|
this.StackService = StackService;
|
||||||
this.ModalService = ModalService;
|
this.ModalService = ModalService;
|
||||||
this.Notifications = Notifications;
|
this.Notifications = Notifications;
|
||||||
this.WebhookHelper = WebhookHelper;
|
this.WebhookHelper = WebhookHelper;
|
||||||
this.FormHelper = FormHelper;
|
this.FormHelper = FormHelper;
|
||||||
|
$scope.stackPullImageFeature = FeatureId.STACK_PULL_IMAGE;
|
||||||
this.state = {
|
this.state = {
|
||||||
inProgress: false,
|
inProgress: false,
|
||||||
redeployInProgress: false,
|
redeployInProgress: false,
|
||||||
|
@ -86,27 +89,21 @@ class StackRedeployGitFormController {
|
||||||
}
|
}
|
||||||
|
|
||||||
async submit() {
|
async submit() {
|
||||||
return this.$async(async () => {
|
const tplCrop =
|
||||||
|
'<div>Any changes to this stack or application made locally in Portainer will be overridden, which may cause service interruption.</div>' +
|
||||||
|
'<div"><div style="position: absolute; right: 110px; top: 68px; z-index: 999">' +
|
||||||
|
'<be-feature-indicator feature="stackPullImageFeature"></be-feature-indicator></div></div>';
|
||||||
|
const template = angular.element(tplCrop);
|
||||||
|
const html = this.$compile(template)(this.$scope);
|
||||||
|
this.ModalService.confirmStackUpdate(html, true, true, 'btn-warning', function (result) {
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const confirmed = await this.ModalService.confirmAsync({
|
|
||||||
title: 'Are you sure?',
|
|
||||||
message: 'Any changes to this stack or application made locally in Portainer will be overridden, which may cause service interruption.',
|
|
||||||
buttons: {
|
|
||||||
confirm: {
|
|
||||||
label: 'Update',
|
|
||||||
className: 'btn-warning',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!confirmed) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.state.redeployInProgress = true;
|
this.state.redeployInProgress = true;
|
||||||
|
this.StackService.updateGit(this.stack.Id, this.stack.EndpointId, this.FormHelper.removeInvalidEnvVars(this.formValues.Env), false, this.formValues);
|
||||||
await this.StackService.updateGit(this.stack.Id, this.stack.EndpointId, this.FormHelper.removeInvalidEnvVars(this.formValues.Env), false, this.formValues);
|
|
||||||
this.Notifications.success('Pulled and redeployed stack successfully');
|
this.Notifications.success('Pulled and redeployed stack successfully');
|
||||||
await this.$state.reload();
|
this.$state.reload();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.Notifications.error('Failure', err, 'Failed redeploying stack');
|
this.Notifications.error('Failure', err, 'Failed redeploying stack');
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -23,4 +23,7 @@ export enum FeatureId {
|
||||||
ACTIVITY_AUDIT = 'activity-audit',
|
ACTIVITY_AUDIT = 'activity-audit',
|
||||||
FORCE_REDEPLOYMENT = 'force-redeployment',
|
FORCE_REDEPLOYMENT = 'force-redeployment',
|
||||||
HIDE_AUTO_UPDATE_WINDOW = 'hide-auto-update-window',
|
HIDE_AUTO_UPDATE_WINDOW = 'hide-auto-update-window',
|
||||||
|
STACK_PULL_IMAGE = 'stack-pull-image',
|
||||||
|
STACK_WEBHOOK = 'stack-webhook',
|
||||||
|
CONTAINER_WEBHOOK = 'container-webhook',
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ export async function init(edition: Edition) {
|
||||||
[FeatureId.TEAM_MEMBERSHIP]: Edition.BE,
|
[FeatureId.TEAM_MEMBERSHIP]: Edition.BE,
|
||||||
[FeatureId.FORCE_REDEPLOYMENT]: Edition.BE,
|
[FeatureId.FORCE_REDEPLOYMENT]: Edition.BE,
|
||||||
[FeatureId.HIDE_AUTO_UPDATE_WINDOW]: Edition.BE,
|
[FeatureId.HIDE_AUTO_UPDATE_WINDOW]: Edition.BE,
|
||||||
|
[FeatureId.STACK_PULL_IMAGE]: Edition.BE,
|
||||||
|
[FeatureId.STACK_WEBHOOK]: Edition.BE,
|
||||||
|
[FeatureId.CONTAINER_WEBHOOK]: Edition.BE,
|
||||||
};
|
};
|
||||||
|
|
||||||
state.currentEdition = currentEdition;
|
state.currentEdition = currentEdition;
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
export const K8S_RESOURCE_POOL_LB_QUOTA = 'k8s-resourcepool-Ibquota';
|
||||||
|
export const K8S_RESOURCE_POOL_STORAGE_QUOTA = 'k8s-resourcepool-storagequota';
|
||||||
|
export const RBAC_ROLES = 'rbac-roles';
|
||||||
|
export const REGISTRY_MANAGEMENT = 'registry-management';
|
||||||
|
export const K8S_SETUP_DEFAULT = 'k8s-setup-default';
|
||||||
|
export const S3_BACKUP_SETTING = 's3-backup-setting';
|
||||||
|
export const HIDE_INTERNAL_AUTHENTICATION_PROMPT = 'hide-internal-authentication-prompt';
|
||||||
|
export const TEAM_MEMBERSHIP = 'team-membership';
|
||||||
|
export const HIDE_INTERNAL_AUTH = 'hide-internal-auth';
|
||||||
|
export const EXTERNAL_AUTH_LDAP = 'external-auth-ldap';
|
||||||
|
export const ACTIVITY_AUDIT = 'activity-audit';
|
||||||
|
export const HIDE_AUTO_UPDATE_WINDOW = 'hide-auto-update-window';
|
||||||
|
export const FORCE_REDEPLOYMENT = 'force-redeployment';
|
||||||
|
export const STACK_PULL_IMAGE = 'stack-pull-image';
|
||||||
|
export const STACK_WEBHOOK = 'stack-webhook';
|
||||||
|
export const CONTAINER_WEBHOOK = 'container-webhook';
|
|
@ -22,6 +22,7 @@ import {
|
||||||
confirmContainerDeletion,
|
confirmContainerDeletion,
|
||||||
confirmContainerRecreation,
|
confirmContainerRecreation,
|
||||||
confirmServiceForceUpdate,
|
confirmServiceForceUpdate,
|
||||||
|
confirmStackUpdate,
|
||||||
confirmKubeconfigSelection,
|
confirmKubeconfigSelection,
|
||||||
selectRegistry,
|
selectRegistry,
|
||||||
} from './prompt';
|
} from './prompt';
|
||||||
|
@ -57,6 +58,7 @@ export function ModalServiceAngular() {
|
||||||
confirmChangePassword,
|
confirmChangePassword,
|
||||||
confirmImageExport,
|
confirmImageExport,
|
||||||
confirmServiceForceUpdate,
|
confirmServiceForceUpdate,
|
||||||
|
confirmStackUpdate,
|
||||||
selectRegistry,
|
selectRegistry,
|
||||||
confirmContainerDeletion,
|
confirmContainerDeletion,
|
||||||
confirmKubeconfigSelection,
|
confirmKubeconfigSelection,
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import sanitize from 'sanitize-html';
|
import sanitize from 'sanitize-html';
|
||||||
import bootbox from 'bootbox';
|
import bootbox from 'bootbox';
|
||||||
|
import '@/portainer/components/BoxSelector/BoxSelectorItem.css';
|
||||||
|
|
||||||
import { applyBoxCSS, ButtonsOptions, confirmButtons } from './utils';
|
import { applyBoxCSS, ButtonsOptions, confirmButtons } from './utils';
|
||||||
|
|
||||||
|
@ -136,6 +137,46 @@ export function confirmServiceForceUpdate(
|
||||||
customizeCheckboxPrompt(box, sanitizedMessage);
|
customizeCheckboxPrompt(box, sanitizedMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function confirmStackUpdate(
|
||||||
|
message: string,
|
||||||
|
defaultDisabled: boolean,
|
||||||
|
defaultToggle: boolean,
|
||||||
|
confirmButtonClassName: string | undefined,
|
||||||
|
callback: PromptCallback
|
||||||
|
) {
|
||||||
|
const box = prompt({
|
||||||
|
title: 'Are you sure?',
|
||||||
|
inputType: 'checkbox',
|
||||||
|
inputOptions: [
|
||||||
|
{
|
||||||
|
text: 'Pull latest image version<i></i>',
|
||||||
|
value: '1',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
buttons: {
|
||||||
|
confirm: {
|
||||||
|
label: 'Update',
|
||||||
|
className: confirmButtonClassName || 'btn-primary',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
callback,
|
||||||
|
});
|
||||||
|
box.find('.bootbox-body').prepend(message);
|
||||||
|
const checkbox = box.find('.bootbox-input-checkbox');
|
||||||
|
checkbox.prop('checked', defaultToggle);
|
||||||
|
checkbox.prop('disabled', defaultDisabled);
|
||||||
|
const checkboxDiv = box.find('.checkbox');
|
||||||
|
checkboxDiv.removeClass('checkbox');
|
||||||
|
checkboxDiv.prop(
|
||||||
|
'style',
|
||||||
|
'position: relative; display: block; margin-top: 10px; margin-bottom: 10px;'
|
||||||
|
);
|
||||||
|
const checkboxLabel = box.find('.form-check-label');
|
||||||
|
checkboxLabel.addClass('switch box-selector-item limited business');
|
||||||
|
const switchEle = checkboxLabel.find('i');
|
||||||
|
switchEle.prop('style', 'margin-left:20px');
|
||||||
|
}
|
||||||
|
|
||||||
export function confirmKubeconfigSelection(
|
export function confirmKubeconfigSelection(
|
||||||
options: InputOption[],
|
options: InputOption[],
|
||||||
expiryMessage: string,
|
expiryMessage: string,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import uuidv4 from 'uuid/v4';
|
||||||
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
||||||
import { STACK_NAME_VALIDATION_REGEX } from '@/constants';
|
import { STACK_NAME_VALIDATION_REGEX } from '@/constants';
|
||||||
import { RepositoryMechanismTypes } from '@/kubernetes/models/deploy';
|
import { RepositoryMechanismTypes } from '@/kubernetes/models/deploy';
|
||||||
|
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('portainer.app')
|
.module('portainer.app')
|
||||||
|
@ -31,8 +32,9 @@ angular
|
||||||
) {
|
) {
|
||||||
$scope.onChangeTemplateId = onChangeTemplateId;
|
$scope.onChangeTemplateId = onChangeTemplateId;
|
||||||
$scope.buildAnalyticsProperties = buildAnalyticsProperties;
|
$scope.buildAnalyticsProperties = buildAnalyticsProperties;
|
||||||
|
$scope.stackWebhookFeature = FeatureId.STACK_WEBHOOK;
|
||||||
$scope.STACK_NAME_VALIDATION_REGEX = STACK_NAME_VALIDATION_REGEX;
|
$scope.STACK_NAME_VALIDATION_REGEX = STACK_NAME_VALIDATION_REGEX;
|
||||||
|
$scope.isAdmin = Authentication.isAdmin();
|
||||||
|
|
||||||
$scope.formValues = {
|
$scope.formValues = {
|
||||||
Name: '',
|
Name: '',
|
||||||
|
|
|
@ -157,6 +157,25 @@
|
||||||
</editor-description>
|
</editor-description>
|
||||||
</web-editor-form>
|
</web-editor-form>
|
||||||
|
|
||||||
|
<div ng-if="state.Method !== 'repository' && isAdmin && applicationState.endpoint.type !== 4">
|
||||||
|
<div class="col-sm-12 form-section-title"> Webhooks </div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label class="control-label text-left">
|
||||||
|
Create a Stack webhook
|
||||||
|
<portainer-tooltip
|
||||||
|
position="top"
|
||||||
|
message="Create a webhook (or callback URI) to automate the update of this stack. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and re-deploy this stack."
|
||||||
|
></portainer-tooltip>
|
||||||
|
</label>
|
||||||
|
<label class="switch box-selector-item limited business" style="margin-left: 20px">
|
||||||
|
<input type="checkbox" ng-model="formValues.EnableWebhook" disabled="disabled" ng-checked="true" /><i></i>
|
||||||
|
</label>
|
||||||
|
<be-feature-indicator feature="stackWebhookFeature"></be-feature-indicator>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- environment-variables -->
|
<!-- environment-variables -->
|
||||||
<environment-variables-panel ng-model="formValues.Env" explanation="These values will be used as substitutions in the stack file" on-change="(handleEnvVarChange)">
|
<environment-variables-panel ng-model="formValues.Env" explanation="These values will be used as substitutions in the stack file" on-change="(handleEnvVarChange)">
|
||||||
</environment-variables-panel>
|
</environment-variables-panel>
|
||||||
|
|
|
@ -160,6 +160,26 @@
|
||||||
></code-editor>
|
></code-editor>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="isAdmin && applicationState.endpoint.type !== 4">
|
||||||
|
<div class="col-sm-12 form-section-title"> Webhooks </div>
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<label class="control-label text-left">
|
||||||
|
Create a Stack webhook
|
||||||
|
<portainer-tooltip
|
||||||
|
position="top"
|
||||||
|
message="Create a webhook (or callback URI) to automate the update of this stack. Sending a POST request to this callback URI (without requiring any authentication) will pull the most up-to-date version of the associated image and re-deploy this stack."
|
||||||
|
></portainer-tooltip>
|
||||||
|
</label>
|
||||||
|
<label class="switch box-selector-item limited business" style="margin-left: 20px">
|
||||||
|
<input type="checkbox" ng-model="formValues.EnableWebhook" disabled="disabled" ng-checked="true" /><i></i>
|
||||||
|
</label>
|
||||||
|
<be-feature-indicator feature="stackWebhookFeature"></be-feature-indicator>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- environment-variables -->
|
<!-- environment-variables -->
|
||||||
<div ng-if="stack">
|
<div ng-if="stack">
|
||||||
<environment-variables-panel
|
<environment-variables-panel
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel';
|
import { AccessControlFormData } from 'Portainer/components/accessControlForm/porAccessControlFormModel';
|
||||||
|
import { FeatureId } from 'Portainer/feature-flags/enums';
|
||||||
|
|
||||||
angular.module('portainer.app').controller('StackController', [
|
angular.module('portainer.app').controller('StackController', [
|
||||||
'$async',
|
'$async',
|
||||||
|
'$compile',
|
||||||
'$q',
|
'$q',
|
||||||
'$scope',
|
'$scope',
|
||||||
'$state',
|
'$state',
|
||||||
|
@ -27,6 +29,7 @@ angular.module('portainer.app').controller('StackController', [
|
||||||
'endpoint',
|
'endpoint',
|
||||||
function (
|
function (
|
||||||
$async,
|
$async,
|
||||||
|
$compile,
|
||||||
$q,
|
$q,
|
||||||
$scope,
|
$scope,
|
||||||
$state,
|
$state,
|
||||||
|
@ -52,6 +55,9 @@ angular.module('portainer.app').controller('StackController', [
|
||||||
endpoint
|
endpoint
|
||||||
) {
|
) {
|
||||||
$scope.endpoint = endpoint;
|
$scope.endpoint = endpoint;
|
||||||
|
$scope.isAdmin = Authentication.isAdmin();
|
||||||
|
$scope.stackWebhookFeature = FeatureId.STACK_WEBHOOK;
|
||||||
|
$scope.stackPullImageFeature = FeatureId.STACK_PULL_IMAGE;
|
||||||
$scope.state = {
|
$scope.state = {
|
||||||
actionInProgress: false,
|
actionInProgress: false,
|
||||||
migrationInProgress: false,
|
migrationInProgress: false,
|
||||||
|
@ -216,32 +222,43 @@ angular.module('portainer.app').controller('StackController', [
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.deployStack = function () {
|
$scope.deployStack = function () {
|
||||||
var stackFile = $scope.stackFileContent;
|
const stack = $scope.stack;
|
||||||
var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env);
|
const tplCrop =
|
||||||
var prune = $scope.formValues.Prune;
|
'<div>Do you want to force an update of the stack?</div>' +
|
||||||
var stack = $scope.stack;
|
'<div style="position: absolute; right: 110px; top: 48px; z-index: 999"><be-feature-indicator feature="stackPullImageFeature"></be-feature-indicator></div>';
|
||||||
|
const template = angular.element(tplCrop);
|
||||||
|
const html = $compile(template)($scope);
|
||||||
|
// 'Do you want to force an update of the stack?'
|
||||||
|
ModalService.confirmStackUpdate(html, true, true, null, function (result) {
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var stackFile = $scope.stackFileContent;
|
||||||
|
var env = FormHelper.removeInvalidEnvVars($scope.formValues.Env);
|
||||||
|
var prune = $scope.formValues.Prune;
|
||||||
|
|
||||||
// TODO: this is a work-around for stacks created with Portainer version >= 1.17.1
|
// TODO: this is a work-around for stacks created with Portainer version >= 1.17.1
|
||||||
// The EndpointID property is not available for these stacks, we can pass
|
// The EndpointID property is not available for these stacks, we can pass
|
||||||
// the current endpoint identifier as a part of the update request. It will be used if
|
// the current endpoint identifier as a part of the update request. It will be used if
|
||||||
// the EndpointID property is not defined on the stack.
|
// the EndpointID property is not defined on the stack.
|
||||||
if (stack.EndpointId === 0) {
|
if (stack.EndpointId === 0) {
|
||||||
stack.EndpointId = endpoint.Id;
|
stack.EndpointId = endpoint.Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
$scope.state.actionInProgress = true;
|
$scope.state.actionInProgress = true;
|
||||||
StackService.updateStack(stack, stackFile, env, prune)
|
StackService.updateStack(stack, stackFile, env, prune)
|
||||||
.then(function success() {
|
.then(function success() {
|
||||||
Notifications.success('Stack successfully deployed');
|
Notifications.success('Stack successfully deployed');
|
||||||
$scope.state.isEditorDirty = false;
|
$scope.state.isEditorDirty = false;
|
||||||
$state.reload();
|
$state.reload();
|
||||||
})
|
})
|
||||||
.catch(function error(err) {
|
.catch(function error(err) {
|
||||||
Notifications.error('Failure', err, 'Unable to create stack');
|
Notifications.error('Failure', err, 'Unable to create stack');
|
||||||
})
|
})
|
||||||
.finally(function final() {
|
.finally(function final() {
|
||||||
$scope.state.actionInProgress = false;
|
$scope.state.actionInProgress = false;
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.editorUpdate = function (cm) {
|
$scope.editorUpdate = function (cm) {
|
||||||
|
|
|
@ -4547,7 +4547,6 @@ angular-moment-picker@^0.10.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
angular-mocks "1.6.1"
|
angular-mocks "1.6.1"
|
||||||
angular-sanitize "1.6.1"
|
angular-sanitize "1.6.1"
|
||||||
lodash-es "^4.17.15"
|
|
||||||
|
|
||||||
angular-resource@1.8.2:
|
angular-resource@1.8.2:
|
||||||
version "1.8.2"
|
version "1.8.2"
|
||||||
|
@ -12598,9 +12597,9 @@ locate-path@^6.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-locate "^5.0.0"
|
p-locate "^5.0.0"
|
||||||
|
|
||||||
lodash-es@^4.17.21:
|
lodash-es@^4.17.15, lodash-es@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
|
||||||
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
|
||||||
|
|
||||||
lodash-webpack-plugin@^0.11.6:
|
lodash-webpack-plugin@^0.11.6:
|
||||||
|
|
Loading…
Reference in New Issue