feat(analytics): track existing features (#5448) [EE-1076]

pull/5577/head
Chaim Lev-Ari 2021-09-05 13:03:48 +03:00 committed by GitHub
parent b8e6c5ea91
commit 4ffee27a4b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 361 additions and 55 deletions

View File

@ -163,5 +163,19 @@
"// @failure 500 \"Server error\"",
"// @router /{id} [get]"
]
},
"analytics": {
"prefix": "nlt",
"body": ["analytics-on", "analytics-category=\"$1\"", "analytics-event=\"$2\""],
"description": "analytics"
},
"analytics-if": {
"prefix": "nltf",
"body": ["analytics-if=\"$1\""],
"description": "analytics"
},
"analytics-metadata": {
"prefix": "nltm",
"body": "analytics-properties=\"{ metadata: { $1 } }\""
}
}

View File

@ -1,4 +1,5 @@
import angular from 'angular';
import _ from 'lodash-es';
const basePath = 'http://portainer-ce.app';
@ -131,7 +132,8 @@ function config($analyticsProvider, $windowProvider) {
let metadataString = '';
if (metadata) {
metadataString = JSON.stringify(metadata).toLowerCase();
const kebabCasedMetadata = Object.fromEntries(Object.entries(metadata).map(([key, value]) => [_.kebabCase(key), value]));
metadataString = JSON.stringify(kebabCasedMetadata).toLowerCase();
}
push([

View File

@ -199,6 +199,10 @@
ng-click="$ctrl.createStack()"
button-spinner="$ctrl.state.actionInProgress"
data-cy="edgeStackCreate-createStackButton"
analytics-on
analytics-event="edge-stack-creation"
analytics-category="edge"
analytics-properties="$ctrl.buildAnalyticsProperties()"
>
<span ng-hide="$ctrl.state.actionInProgress">Deploy the stack</span>
<span ng-show="$ctrl.state.actionInProgress">Deployment in progress...</span>

View File

@ -43,6 +43,30 @@ export class CreateEdgeStackViewController {
this.onChangeFormValues = this.onChangeFormValues.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';
}
}
}
async uiCanExit() {
if (this.state.Method === 'editor' && this.formValues.StackFileContent && this.state.isEditorDirty) {
return this.ModalService.confirmWebEditorDiscard();

View File

@ -1,4 +1,13 @@
<button type="button" class="btn btn-xs btn-primary" ng-click="$ctrl.connectConsole()" ng-disabled="$ctrl.state.shell.connected" data-cy="k8sSidebar-shellButton">
<button
type="button"
class="btn btn-xs btn-primary"
ng-click="$ctrl.connectConsole()"
ng-disabled="$ctrl.state.shell.connected"
data-cy="k8sSidebar-shellButton"
analytics-on
analytics-category="kubernetes"
analytics-event="kubernetes-kubectl-shell"
>
<i class="fa fa-terminal space-right"></i> kubectl shell
</button>

View File

@ -299,6 +299,11 @@
ng-click="ctrl.configure()"
ng-disabled="ctrl.state.actionInProgress || !kubernetesClusterSetupForm.$valid || !ctrl.hasValidStorageConfiguration()"
button-spinner="ctrl.state.actionInProgress"
analytics-on
analytics-if="ctrl.restrictDefaultToggledOn()"
analytics-category="kubernetes"
analytics-event="kubernetes-configure"
analytics-properties="{ metadata: { restrictAccessToDefaultNamespace: ctrl.formValues.RestrictDefaultNamespace } }"
>
<span ng-hide="ctrl.state.actionInProgress">Save configuration</span>
<span ng-show="ctrl.state.actionInProgress">Saving configuration...</span>

View File

@ -237,6 +237,10 @@ class KubernetesConfigureController {
}
/* #endregion */
restrictDefaultToggledOn() {
return this.formValues.RestrictDefaultNamespace && !this.oldFormValues.RestrictDefaultNamespace;
}
/* #region ON INIT */
async onInit() {
this.state = {
@ -287,6 +291,8 @@ class KubernetesConfigureController {
ic.NeedsDeletion = false;
return ic;
});
this.oldFormValues = Object.assign({}, this.formValues);
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to retrieve endpoint configuration');
} finally {

View File

@ -151,6 +151,10 @@
ng-click="ctrl.deploy()"
button-spinner="ctrl.state.actionInProgress"
data-cy="k8sAppDeploy-deployButton"
analytics-on
analytics-category="kubernetes"
analytics-event="kubernetes-application-advanced-deployment"
analytics-properties="ctrl.buildAnalyticsProperties()"
>
<span ng-hide="ctrl.state.actionInProgress">Deploy</span>
<span ng-show="ctrl.state.actionInProgress">Deployment in progress...</span>

View File

@ -7,10 +7,11 @@ import { KubernetesDeployManifestTypes, KubernetesDeployBuildMethods, Kubernetes
import { buildOption } from '@/portainer/components/box-selector';
class KubernetesDeployController {
/* @ngInject */
constructor($async, $state, $window, CustomTemplateService, ModalService, Notifications, EndpointProvider, KubernetesResourcePoolService, StackService) {
constructor($async, $state, $window, Authentication, CustomTemplateService, ModalService, Notifications, EndpointProvider, KubernetesResourcePoolService, StackService) {
this.$async = $async;
this.$state = $state;
this.$window = $window;
this.Authentication = Authentication;
this.CustomTemplateService = CustomTemplateService;
this.ModalService = ModalService;
this.Notifications = Notifications;
@ -52,6 +53,47 @@ class KubernetesDeployController {
this.onChangeFormValues = this.onChangeFormValues.bind(this);
this.onRepoUrlChange = this.onRepoUrlChange.bind(this);
this.onRepoRefChange = this.onRepoRefChange.bind(this);
this.buildAnalyticsProperties = this.buildAnalyticsProperties.bind(this);
}
buildAnalyticsProperties() {
const metadata = {
type: buildLabel(this.state.BuildMethod),
format: formatLabel(this.state.DeployType),
role: roleLabel(this.Authentication.isAdmin()),
};
if (this.state.BuildMethod === KubernetesDeployBuildMethods.GIT) {
metadata.auth = this.formValues.RepositoryAuthentication;
}
return { metadata };
function roleLabel(isAdmin) {
if (isAdmin) {
return 'admin';
}
return 'standard';
}
function buildLabel(buildMethod) {
switch (buildMethod) {
case KubernetesDeployBuildMethods.GIT:
return 'git';
case KubernetesDeployBuildMethods.WEB_EDITOR:
return 'web-editor';
}
}
function formatLabel(format) {
switch (format) {
case KubernetesDeployManifestTypes.COMPOSE:
return 'compose';
case KubernetesDeployManifestTypes.KUBERNETES:
return 'manifest';
}
}
}
disableDeploy() {
@ -59,11 +101,13 @@ class KubernetesDeployController {
this.state.BuildMethod === KubernetesDeployBuildMethods.GIT &&
(!this.formValues.RepositoryURL ||
!this.formValues.FilePathInRepository ||
(this.formValues.RepositoryAuthentication && (!this.formValues.RepositoryUsername || !this.formValues.RepositoryPassword))) && _.isEmpty(this.formValues.Namespace);
const isWebEditorInvalid = this.state.BuildMethod === KubernetesDeployBuildMethods.WEB_EDITOR && _.isEmpty(this.formValues.EditorContent) && _.isEmpty(this.formValues.Namespace);
(this.formValues.RepositoryAuthentication && (!this.formValues.RepositoryUsername || !this.formValues.RepositoryPassword))) &&
_.isEmpty(this.formValues.Namespace);
const isWebEditorInvalid =
this.state.BuildMethod === KubernetesDeployBuildMethods.WEB_EDITOR && _.isEmpty(this.formValues.EditorContent) && _.isEmpty(this.formValues.Namespace);
const isURLFormInvalid = this.state.BuildMethod == KubernetesDeployBuildMethods.WEB_EDITOR.URL && _.isEmpty(this.formValues.ManifestURL);
return isGitFormInvalid || isWebEditorInvalid || isURLFormInvalid || this.state.actionInProgress;
return isGitFormInvalid || isWebEditorInvalid || isURLFormInvalid || this.state.actionInProgress;
}
onChangeFormValues(values) {
@ -127,7 +171,7 @@ class KubernetesDeployController {
case KubernetesDeployBuildMethods.CUSTOM_TEMPLATE:
method = KubernetesDeployRequestMethods.STRING;
composeFormat = false;
break;
break;
case this.BuildMethods.URL:
method = KubernetesDeployRequestMethods.URL;
break;

View File

@ -8,8 +8,8 @@ class CustomTemplateSelectorController {
}
async handleChangeTemplate(templateId) {
this.selectedTemplate = this.templates.find((t) => t.id === templateId);
this.onChange(templateId);
this.selectedTemplate = this.templates.find((t) => t.Id === templateId);
this.onChange(templateId, this.selectedTemplate);
}
$onChanges({ value }) {

View File

@ -71,7 +71,16 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="$ctrl.actionInProgress || !registryFormAzure.$valid" button-spinner="$ctrl.actionInProgress">
<button
type="submit"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !registryFormAzure.$valid"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'azure' } }"
>
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>
</button>

View File

@ -93,7 +93,16 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="$ctrl.actionInProgress || !registryFormCustom.$valid" button-spinner="$ctrl.actionInProgress">
<button
type="submit"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !registryFormCustom.$valid"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'custom' }}"
>
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>
</button>

View File

@ -54,7 +54,16 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="$ctrl.actionInProgress || !registryFormDockerhub.$valid" button-spinner="$ctrl.actionInProgress">
<button
type="submit"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !registryFormDockerhub.$valid"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'dockerhub' } }"
>
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>
</button>

View File

@ -133,6 +133,10 @@
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !$ctrl.state.gitlab.selectedItemCount"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'gitlab' } }"
>
<span ng-hide="$ctrl.actionInProgress">Create registries</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>

View File

@ -100,7 +100,16 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="$ctrl.actionInProgress || !registryFormProGet.$valid" button-spinner="$ctrl.actionInProgress">
<button
type="submit"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !registryFormProGet.$valid"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'proget' } }"
>
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>
</button>

View File

@ -67,7 +67,16 @@
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-primary btn-sm" ng-disabled="$ctrl.actionInProgress || !registryFormQuay.$valid" button-spinner="$ctrl.actionInProgress">
<button
type="submit"
class="btn btn-primary btn-sm"
ng-disabled="$ctrl.actionInProgress || !registryFormQuay.$valid"
button-spinner="$ctrl.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-registry-creation"
analytics-properties="{ metadata: { type: 'quay' } }"
>
<span ng-hide="$ctrl.actionInProgress">{{ $ctrl.formActionLabel }}</span>
<span ng-show="$ctrl.actionInProgress">In progress...</span>
</button>

View File

@ -25,7 +25,7 @@ class StackRedeployGitFormController {
RepositoryUsername: '',
RepositoryPassword: '',
Env: [],
// auto upadte
// auto update
AutoUpdate: {
RepositoryAutomaticUpdates: false,
RepositoryMechanism: 'Interval',
@ -38,6 +38,26 @@ class StackRedeployGitFormController {
this.onChangeRef = this.onChangeRef.bind(this);
this.onChangeAutoUpdate = this.onChangeAutoUpdate.bind(this);
this.onChangeEnvVar = this.onChangeEnvVar.bind(this);
this.handleEnvVarChange = this.handleEnvVarChange.bind(this);
}
buildAnalyticsProperties() {
const metadata = {};
if (this.formValues.RepositoryAutomaticUpdates) {
metadata.automaticUpdates = autoSyncLabel(this.formValues.RepositoryMechanism);
}
return { metadata };
function autoSyncLabel(type) {
switch (type) {
case 'Interval':
return 'polling';
case 'Webhook':
return 'webhook';
}
return 'off';
}
}
onChange(values) {
@ -100,10 +120,17 @@ class StackRedeployGitFormController {
return this.$async(async () => {
try {
this.state.inProgress = true;
await this.StackService.updateGitStackSettings(this.stack.Id, this.stack.EndpointId, this.FormHelper.removeInvalidEnvVars(this.formValues.Env), this.formValues);
const stack = await this.StackService.updateGitStackSettings(
this.stack.Id,
this.stack.EndpointId,
this.FormHelper.removeInvalidEnvVars(this.formValues.Env),
this.formValues
);
this.savedFormValues = angular.copy(this.formValues);
this.state.hasUnsavedChanges = false;
this.Notifications.success('Save stack settings successfully');
this.stack = stack;
} catch (err) {
this.Notifications.error('Failure', err, 'Unable to save stack settings');
} finally {
@ -116,6 +143,16 @@ class StackRedeployGitFormController {
return this.state.inProgress || this.state.redeployInProgress;
}
handleEnvVarChange(value) {
this.formValues.Env = value;
}
isAutoUpdateChanged() {
const wasEnabled = !!(this.stack.AutoUpdate && (this.stack.AutoUpdate.Interval || this.stack.AutoUpdate.Webhook));
const isEnabled = this.formValues.AutoUpdate.RepositoryAutomaticUpdates;
return isEnabled !== wasEnabled;
}
$onInit() {
this.formValues.RefName = this.model.ReferenceName;
this.formValues.Env = this.stack.Env;

View File

@ -50,8 +50,9 @@
ng-disabled="$ctrl.isSubmitButtonDisabled() || $ctrl.state.hasUnsavedChanges || !$ctrl.redeployGitForm.$valid"
style="margin-top: 7px; margin-left: 0;"
button-spinner="$ctrl.state.redeployInProgress"
style="margin-top: 7px; margin-left: 0;"
button-spinner="$ctrl.state.inProgress"
analytics-on
analytics-event="docker-stack-pull-redeploy"
analytics-category="docker"
>
<span ng-hide="$ctrl.state.redeployInProgress"> <i class="fa fa-sync space-right" aria-hidden="true"></i> Pull and redeploy </span>
<span ng-show="$ctrl.state.redeployInProgress">In progress...</span>
@ -63,6 +64,10 @@
ng-disabled="$ctrl.isSubmitButtonDisabled() || !$ctrl.state.hasUnsavedChanges || !$ctrl.redeployGitForm.$valid"
style="margin-top: 7px; margin-left: 0;"
button-spinner="$ctrl.state.inProgress"
analytics-on
analytics-event="docker-stack-update-git-settings"
analytics-category="docker"
analytics-properties="$ctrl.buildAnalyticsProperties()"
>
<span ng-hide="$ctrl.state.inProgress"> Save settings </span>
<span ng-show="$ctrl.state.inProgress">In progress...</span>

View File

@ -51,6 +51,10 @@ class SslCertificateController {
});
}
wasHTTPsChanged() {
return this.originalValues.forceHTTPS !== this.formValues.forceHTTPS;
}
async $onInit() {
return this.$async(async () => {
try {

View File

@ -80,6 +80,11 @@
ng-disabled="$ctrl.state.actionInProgress || !$ctrl.isFormChanged()"
ng-click="$ctrl.save()"
button-spinner="$ctrl.state.actionInProgress"
analytics-on
analytics-if="$ctrl.wasHTTPsChanged()"
analytics-category="portainer"
analytics-event="portainer-settings-edit"
analytics-properties="{ metadata: { forceHTTPS: $ctrl.formValues.forceHTTPS } }"
>
<span ng-hide="$ctrl.state.actionInProgress || $ctrl.state.reloadingPage">Apply Changes</span>
<span ng-show="$ctrl.state.actionInProgress">Saving in progress...</span>

View File

@ -5,6 +5,7 @@ angular
.module('portainer.app')
.controller('CreateEndpointController', function CreateEndpointController(
$async,
$analytics,
$q,
$scope,
$state,
@ -167,16 +168,32 @@ angular
});
};
$scope.addAgentEndpoint = function () {
var name = $scope.formValues.Name;
// var URL = $filter('stripprotocol')($scope.formValues.URL);
var URL = $scope.formValues.URL;
var publicURL = $scope.formValues.PublicURL === '' ? URL.split(':')[0] : $scope.formValues.PublicURL;
var groupId = $scope.formValues.GroupId;
var tagIds = $scope.formValues.TagIds;
$scope.addAgentEndpoint = addAgentEndpoint;
async function addAgentEndpoint() {
return $async(async () => {
const name = $scope.formValues.Name;
const URL = $scope.formValues.URL;
const publicURL = $scope.formValues.PublicURL === '' ? URL.split(':')[0] : $scope.formValues.PublicURL;
const groupId = $scope.formValues.GroupId;
const tagIds = $scope.formValues.TagIds;
addEndpoint(name, PortainerEndpointCreationTypes.AgentEnvironment, URL, publicURL, groupId, tagIds, true, true, true, null, null, null);
};
const endpoint = await addEndpoint(name, PortainerEndpointCreationTypes.AgentEnvironment, URL, publicURL, groupId, tagIds, true, true, true, null, null, null);
$analytics.eventTrack('portainer-endpoint-creation', { category: 'portainer', metadata: { type: 'agent', platform: platformLabel(endpoint.Type) } });
});
function platformLabel(type) {
switch (type) {
case PortainerEndpointTypes.DockerEnvironment:
case PortainerEndpointTypes.AgentOnDockerEnvironment:
case PortainerEndpointTypes.EdgeAgentOnDockerEnvironment:
return 'docker';
case PortainerEndpointTypes.KubernetesLocalEnvironment:
case PortainerEndpointTypes.AgentOnKubernetesEnvironment:
case PortainerEndpointTypes.EdgeAgentOnKubernetesEnvironment:
return 'kubernetes';
}
}
}
$scope.addEdgeAgentEndpoint = function () {
var name = $scope.formValues.Name;
@ -213,24 +230,26 @@ angular
});
}
function addEndpoint(name, creationType, URL, PublicURL, groupId, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile, CheckinInterval) {
$scope.state.actionInProgress = true;
EndpointService.createRemoteEndpoint(
name,
creationType,
URL,
PublicURL,
groupId,
tagIds,
TLS,
TLSSkipVerify,
TLSSkipClientVerify,
TLSCAFile,
TLSCertFile,
TLSKeyFile,
CheckinInterval
)
.then(function success(endpoint) {
async function addEndpoint(name, creationType, URL, PublicURL, groupId, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile, CheckinInterval) {
return $async(async () => {
$scope.state.actionInProgress = true;
try {
const endpoint = await EndpointService.createRemoteEndpoint(
name,
creationType,
URL,
PublicURL,
groupId,
tagIds,
TLS,
TLSSkipVerify,
TLSSkipClientVerify,
TLSCAFile,
TLSCertFile,
TLSKeyFile,
CheckinInterval
);
Notifications.success('Endpoint created', name);
switch (endpoint.Type) {
case PortainerEndpointTypes.EdgeAgentOnDockerEnvironment:
@ -244,13 +263,14 @@ angular
$state.go('portainer.endpoints', {}, { reload: true });
break;
}
})
.catch(function error(err) {
return endpoint;
} catch (err) {
Notifications.error('Failure', err, 'Unable to create endpoint');
})
.finally(function final() {
} finally {
$scope.state.actionInProgress = false;
});
}
});
}
function initView() {

View File

@ -482,6 +482,10 @@
ng-click="addDockerEndpoint()"
button-spinner="state.actionInProgress"
data-cy="endpointCreate-createDockerEndpoint"
analytics-on
analytics-category="portainer"
analytics-event="portainer-endpoint-creation"
analytics-properties="{ metadata: { type: 'docker-api' } }"
>
<span ng-hide="state.actionInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
<span ng-show="state.actionInProgress">Creating endpoint...</span>
@ -506,6 +510,10 @@
ng-click="addEdgeAgentEndpoint()"
button-spinner="state.actionInProgress"
data-cy="endpointCreate-createEdgeAgentEndpoint"
analytics-on
analytics-category="portainer"
analytics-event="portainer-endpoint-creation"
analytics-properties="{ metadata: { type: 'edge-agent' } }"
>
<span ng-hide="state.actionInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
<span ng-show="state.actionInProgress">Creating endpoint...</span>
@ -517,6 +525,10 @@
ng-disabled="state.actionInProgress || !endpointCreationForm.$valid"
ng-click="addKubernetesEndpoint()"
button-spinner="state.actionInProgress"
analytics-on
analytics-category="portainer"
analytics-event="portainer-endpoint-creation"
analytics-properties="{ metadata: { type: 'kubernetes-api' } }"
>
<span ng-hide="state.actionInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
<span ng-show="state.actionInProgress">Creating endpoint...</span>
@ -529,6 +541,10 @@
ng-click="addAzureEndpoint()"
button-spinner="state.actionInProgress"
data-cy="endpointCreate-createAzureEndpoint"
analytics-on
analytics-category="portainer"
analytics-event="portainer-endpoint-creation"
analytics-properties="{ metadata: { type: 'azure-api' } }"
>
<span ng-hide="state.actionInProgress"><i class="fa fa-plus" aria-hidden="true"></i> Add endpoint</span>
<span ng-show="state.actionInProgress">Creating endpoint...</span>

View File

@ -23,7 +23,16 @@
Edge identifier: <code>{{ endpoint.EdgeID }}</code>
</p>
<p>
<button type="button" class="btn btn-primary btn-sm" ng-disabled="state.actionInProgress" ng-click="onDeassociateEndpoint()" button-spinner="state.actionInProgress">
<button
type="button"
class="btn btn-primary btn-sm"
ng-disabled="state.actionInProgress"
ng-click="onDeassociateEndpoint()"
button-spinner="state.actionInProgress"
analytics-on
analytics-event="edge-endpoint-deassociate"
analytics-category="edge"
>
<span ng-hide="state.actionInProgress">De-associate</span>
</button>
</p>

View File

@ -26,6 +26,7 @@ angular
clipboard
) {
$scope.onChangeTemplateId = onChangeTemplateId;
$scope.buildAnalyticsProperties = buildAnalyticsProperties;
$scope.formValues = {
Name: '',
@ -54,6 +55,8 @@ angular
editorYamlValidationError: '',
uploadYamlValidationError: '',
isEditorDirty: false,
selectedTemplate: null,
selectedTemplateId: null,
};
$window.onbeforeunload = () => {
@ -76,6 +79,47 @@ angular
$scope.formValues.AdditionalFiles.splice(index, 1);
};
function buildAnalyticsProperties() {
const metadata = { type: methodLabel($scope.state.Method) };
if ($scope.state.Method === 'repository') {
metadata.automaticUpdates = 'off';
if ($scope.formValues.RepositoryAutomaticUpdates) {
metadata.automaticUpdates = autoSyncLabel($scope.formValues.RepositoryMechanism);
}
metadata.auth = $scope.formValues.RepositoryAuthentication;
}
if ($scope.state.Method === 'template') {
metadata.templateName = $scope.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 'custom-template';
}
}
function autoSyncLabel(type) {
switch (type) {
case 'Interval':
return 'polling';
case 'Webhook':
return 'webhook';
}
return 'off';
}
}
function validateForm(accessControlData, isAdmin) {
$scope.state.formValidationError = '';
var error = '';
@ -238,10 +282,11 @@ angular
}
};
function onChangeTemplateId(templateId) {
function onChangeTemplateId(templateId, template) {
return $async(async () => {
try {
$scope.state.templateId = templateId;
$scope.state.selectedTemplateId = templateId;
$scope.state.selectedTemplate = template;
const fileContent = await CustomTemplateService.customTemplateFile(templateId);
$scope.onChangeFileContent(fileContent);

View File

@ -120,11 +120,11 @@
new-template-path="docker.templates.custom.new"
stack-type="state.StackType"
on-change="(onChangeTemplateId)"
value="state.templateId"
value="state.selectedTemplateId"
></custom-template-selector>
<web-editor-form
ng-if="state.Method === 'editor' || (state.Method === 'template' && state.templateId)"
ng-if="state.Method === 'editor' || (state.Method === 'template' && state.selectedTemplateId)"
identifier="stack-creation-editor"
value="formValues.StackFileContent"
on-change="(onChangeFileContent)"
@ -164,6 +164,10 @@
|| !formValues.Name"
ng-click="deployStack()"
button-spinner="state.actionInProgress"
analytics-on
analytics-category="docker"
analytics-event="docker-stack-create"
analytics-properties="buildAnalyticsProperties()"
>
<span ng-hide="state.actionInProgress">Deploy the stack</span>
<span ng-show="state.actionInProgress">Deployment in progress...</span>