1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-02 20:35:25 +02:00

refactor(tags): refactor tag management (#3628)

* refactor(tags): replace tags with tag ids

* refactor(tags): revert tags to be strings and add tagids

* refactor(tags): enable search by tag in home view

* refactor(tags): show endpoint tags

* refactor(endpoints): expect tagIds on create payload

* refactor(endpoints): expect tagIds on update payload

* refactor(endpoints): replace TagIds to TagIDs

* refactor(endpoints): set endpoint group to get TagIDs

* refactor(endpoints): refactor tag-selector to receive tag-ids

* refactor(endpoints): show tags in multi-endpoint-selector

* chore(tags): revert reformat

* refactor(endpoints): remove unneeded bind

* refactor(endpoints): change param tags to tagids in endpoint create

* refactor(endpoints): remove console.log

* refactor(tags): remove deleted tag from endpoint and endpoint group

* fix(endpoints): show loading label while loading tags

* chore(go): remove obsolete import labels

* chore(db): add db version comment

* fix(db): add tag service to migrator

* refactor(db): add error checks in migrator

* style(db): sort props in alphabetical order

* style(tags): fix typo

Co-Authored-By: Anthony Lapenna <anthony.lapenna@portainer.io>

* refactor(endpoints): replace tagsMap with tag string representation

* refactor(tags): rewrite tag delete to be more readable

* refactor(home): rearange code to match former style

* refactor(tags): guard against missing model in tag-selector

* refactor(tags): rename vars in tag_delete

* refactor(tags): allow any authenticated user to fetch tag list

* refactor(endpoints): replace controller function with class

* refactor(endpoints): replace function with helper

* refactor(endpoints): replace controller with class

* refactor(tags): revert tags-selector to use 1 way bindings

* refactor(endpoints): load empty tag array instead of nil

* refactor(endpoints): revert default tag ids

* refactor(endpoints): use function in place

* refactor(tags): use lodash

* style(tags): use parens in arrow functions

* fix(tags): remove tag from tag model

Co-authored-by: Anthony Lapenna <anthony.lapenna@portainer.io>
This commit is contained in:
Chaim Lev-Ari 2020-03-29 12:54:14 +03:00 committed by GitHub
parent fe89a4fc01
commit edd86f2506
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
47 changed files with 404 additions and 171 deletions

View file

@ -1,12 +1,42 @@
angular.module('portainer.app').controller('EndpointItemController', [
function EndpointItemController() {
var ctrl = this;
import angular from 'angular';
import _ from 'lodash-es';
import PortainerEndpointTagHelper from 'Portainer/helpers/tagHelper';
ctrl.editEndpoint = editEndpoint;
function editEndpoint(event) {
event.stopPropagation();
ctrl.onEdit(ctrl.model.Id);
}
class EndpointItemController {
/* @ngInject */
constructor() {
this.editEndpoint = this.editEndpoint.bind(this);
}
]);
editEndpoint(event) {
event.stopPropagation();
this.onEdit(this.model.Id);
}
joinTags() {
if (!this.tags) {
return 'Loading tags...';
}
if (!this.model.TagIds || !this.model.TagIds.length) {
return '';
}
const tagNames = PortainerEndpointTagHelper.idsToTagNames(this.tags, this.model.TagIds);
return _.join(tagNames, ',')
}
$onInit() {
this.endpointTags = this.joinTags();
}
$onChanges({ tags, model }) {
if ((!tags && !model) || (!tags.currentValue && !model.currentValue)) {
return;
}
this.endpointTags = this.joinTags();
}
}
angular.module('portainer.app').controller('EndpointItemController', EndpointItemController);
export default EndpointItemController;

View file

@ -85,14 +85,12 @@
</span>
<span class="space-left space-right">-</span>
</span>
<span ng-if="$ctrl.model.Tags.length === 0">
<span ng-if="$ctrl.endpointTags.length === 0">
<i class="fa fa-tags" aria-hidden="true"></i> No tags
</span>
<span ng-if="$ctrl.model.Tags.length > 0">
<span ng-if="$ctrl.endpointTags.length > 0">
<i class="fa fa-tags" aria-hidden="true"></i>
<span ng-repeat="tag in $ctrl.model.Tags">
{{ tag }}{{ $last? '' : ', ' }}
</span>
{{ $ctrl.endpointTags }}
</span>
</span>
<span class="small text-muted" ng-if="$ctrl.model.Type !== 4">

View file

@ -1,10 +1,15 @@
import angular from 'angular';
import EndpointItemController from './endpoint-item-controller';
angular.module('portainer.app').component('endpointItem', {
templateUrl: './endpointItem.html',
bindings: {
model: '<',
onSelect: '<',
onEdit: '<',
isAdmin:'<'
isAdmin: '<',
tags: '<',
},
controller: 'EndpointItemController'
controller: EndpointItemController,
});

View file

@ -29,12 +29,12 @@ angular.module('portainer.app').controller('EndpointListController', ['Datatable
if (this.hasBackendPagination()) {
this.paginationChangedAction();
} else {
this.state.filteredEndpoints = frontEndpointFilter(this.endpoints, filterValue);
this.state.filteredEndpoints = frontEndpointFilter(this.endpoints, this.tags, filterValue);
this.state.loading = false;
}
}
function frontEndpointFilter(endpoints, filterValue) {
function frontEndpointFilter(endpoints, tags, filterValue) {
if (!endpoints || !endpoints.length || !filterValue) {
return endpoints;
}
@ -47,8 +47,12 @@ angular.module('portainer.app').controller('EndpointListController', ['Datatable
_.includes(endpoint.Name.toLowerCase(), lowerCaseKeyword) ||
_.includes(endpoint.GroupName.toLowerCase(), lowerCaseKeyword) ||
_.includes(endpoint.URL.toLowerCase(), lowerCaseKeyword) ||
_.some(endpoint.Tags, function(tag) {
return _.includes(tag.toLowerCase(), lowerCaseKeyword);
_.some(endpoint.TagIds, tagId => {
const tag = tags.find(t => t.Id === tagId);
if (!tag) {
return false;
}
return _.includes(tag.Name.toLowerCase(), lowerCaseKeyword);
}) ||
_.includes(statusString, keyword)
);

View file

@ -5,6 +5,7 @@ angular.module('portainer.app').component('endpointList', {
titleText: '@',
titleIcon: '@',
endpoints: '<',
tags: '<',
tableKey: '@',
dashboardAction: '<',
snapshotAction: '<',

View file

@ -33,6 +33,7 @@
on-select="$ctrl.dashboardAction"
on-edit="$ctrl.editAction"
is-admin="$ctrl.isAdmin"
tags="$ctrl.tags"
></endpoint-item>
<endpoint-item ng-if="!$ctrl.hasBackendPagination()"
dir-paginate="endpoint in $ctrl.state.filteredEndpoints | itemsPerPage: $ctrl.state.paginatedItemLimit"
@ -40,6 +41,7 @@
on-select="$ctrl.dashboardAction"
on-edit="$ctrl.editAction"
is-admin="$ctrl.isAdmin"
tags="$ctrl.tags"
></endpoint-item>
<div ng-if="$ctrl.state.loading" class="text-center text-muted">
Loading...

View file

@ -28,8 +28,9 @@
<!-- tags -->
<div class="form-group">
<tag-selector
ng-if="$ctrl.availableTags && $ctrl.model.TagIds"
tags="$ctrl.availableTags"
model="$ctrl.model.Tags"
model="$ctrl.model.TagIds"
></tag-selector>
</div>
<!-- !tags -->

View file

@ -69,6 +69,7 @@ angular.module('portainer.app').component('scheduleForm', {
model: '=',
endpoints: '<',
groups: '<',
tags: '<',
addLabelAction: '<',
removeLabelAction: '<',
formAction: '<',

View file

@ -265,9 +265,9 @@
</div>
<!-- node-selection -->
<multi-endpoint-selector
ng-if="$ctrl.endpoints && $ctrl.groups"
ng-if="$ctrl.endpoints && $ctrl.groups && $ctrl.tags"
model="$ctrl.model.Job.Endpoints"
endpoints="$ctrl.endpoints" groups="$ctrl.groups"
endpoints="$ctrl.endpoints" groups="$ctrl.groups" tags="$ctrl.tags"
></multi-endpoint-selector>
<!-- !node-selection -->
<!-- actions -->

View file

@ -2,8 +2,9 @@ angular.module('portainer.app').component('multiEndpointSelector', {
templateUrl: './multiEndpointSelector.html',
controller: 'MultiEndpointSelectorController',
bindings: {
'model': '=',
'endpoints': '<',
'groups': '<'
}
model: '=',
endpoints: '<',
groups: '<',
tags: '<',
},
});

View file

@ -2,13 +2,13 @@
<ui-select-match placeholder="Select one or multiple endpoint(s)">
<span>
{{ $item.Name }}
<span ng-if="$item.Tags.length">({{ $item.Tags | arraytostr }})</span>
</span>
<span ng-if="$item.TagIds.length">({{ $ctrl.tagIdsToTagNames($item.TagIds) | arraytostr }})</span>
</span>
</ui-select-match>
<ui-select-choices group-by="$ctrl.groupEndpoints" group-filter="$ctrl.sortGroups" repeat="endpoint.Id as endpoint in $ctrl.endpoints | filter: { Name: $select.search }">
<span>
{{ endpoint.Name }}
<span ng-if="endpoint.Tags.length">({{ endpoint.Tags | arraytostr }})</span>
</span>
<span ng-if="endpoint.TagIds.length">({{ $ctrl.tagIdsToTagNames(endpoint.TagIds) | arraytostr }})</span>
</span>
</ui-select-choices>
</ui-select>

View file

@ -1,37 +1,40 @@
import _ from 'lodash-es';
import PortainerEndpointTagHelper from 'Portainer/helpers/tagHelper';
angular.module('portainer.app')
.controller('MultiEndpointSelectorController', function () {
var ctrl = this;
import angular from 'angular';
this.sortGroups = function(groups) {
class MultiEndpointSelectorController {
/* @ngInject */
constructor() {
this.sortGroups = this.sortGroups.bind(this);
this.groupEndpoints = this.groupEndpoints.bind(this);
this.tagIdsToTagNames = this.tagIdsToTagNames.bind(this);
}
sortGroups(groups) {
return _.sortBy(groups, ['name']);
};
}
this.groupEndpoints = function(endpoint) {
for (var i = 0; i < ctrl.availableGroups.length; i++) {
var group = ctrl.availableGroups[i];
groupEndpoints(endpoint) {
for (var i = 0; i < this.availableGroups.length; i++) {
var group = this.availableGroups[i];
if (endpoint.GroupId === group.Id) {
return group.Name;
}
}
};
this.$onInit = function() {
this.availableGroups = filterEmptyGroups(this.groups, this.endpoints);
};
function filterEmptyGroups(groups, endpoints) {
return groups.filter(function f(group) {
for (var i = 0; i < endpoints.length; i++) {
var endpoint = endpoints[i];
if (endpoint.GroupId === group.Id) {
return true;
}
}
return false;
});
}
});
tagIdsToTagNames(tagIds) {
return PortainerEndpointTagHelper.idsToTagNames(this.tags, tagIds);
}
$onInit() {
this.availableGroups = _.filter(this.groups, group =>
_.some(this.endpoints, endpoint => endpoint.GroupId == group.Id)
);
}
}
export default MultiEndpointSelectorController;
angular.module('portainer.app').controller('MultiEndpointSelectorController', MultiEndpointSelectorController);

View file

@ -3,6 +3,6 @@ angular.module('portainer.app').component('tagSelector', {
controller: 'TagSelectorController',
bindings: {
tags: '<',
model: '='
}
model: '=',
},
});

View file

@ -3,8 +3,8 @@
Selected tags
</label>
<div class="col-sm-9 col-lg-10" style="padding-top: 4px;">
<span class="tag space-right interactive" ng-repeat="tag in $ctrl.model" ng-click="$ctrl.removeTag(tag)">
{{ tag }}
<span class="tag space-right interactive" ng-repeat="tag in $ctrl.state.selectedTags" ng-click="$ctrl.removeTag(tag)">
{{ tag.Name }}
<a title="Remove tag" ng-click="$ctrl.removeTag(tag)" style="margin-left: 2px;">
<span class="fa fa-trash-alt white-icon" aria-hidden="true"></span>
</a>
@ -20,10 +20,11 @@
type="text" ng-model="$ctrl.state.selectedValue"
id="tags" class="form-control"
placeholder="Select tags..."
uib-typeahead="tag for tag in $ctrl.tags | filter:$viewValue | limitTo:7"
uib-typeahead="tag.Id as tag.Name for tag in $ctrl.tags | filter: $ctrl.filterSelected | filter:$viewValue | limitTo:7"
typeahead-on-select="$ctrl.selectTag($item, $model, $label)"
typeahead-no-results="$ctrl.state.noResult"
typeahead-show-hint="true" typeahead-min-length="0" />
typeahead-show-hint="true" typeahead-min-length="0"
/>
</div>
<div class="col-sm-9 col-lg-10" ng-if="$ctrl.tags.length === 0">
<span class="small text-muted">

View file

@ -1,32 +1,35 @@
import _ from 'lodash-es';
angular.module('portainer.app')
.controller('TagSelectorController', function () {
this.$onChanges = function(changes) {
if(angular.isDefined(changes.tags.currentValue)) {
this.tags = _.difference(changes.tags.currentValue, this.model);
}
angular.module('portainer.app').controller('TagSelectorController', function() {
this.$onInit = function() {
this.state.selectedTags = _.map(this.model, (id) => _.find(this.tags, (t) => t.Id === id));
};
this.state = {
selectedValue: '',
noResult: false
selectedTags: [],
noResult: false,
};
this.selectTag = function($item) {
this.state.selectedValue = '';
this.model.push($item);
this.tags = _.remove(this.tags, function(item) {
return item !== $item;
});
this.model.push($item.Id);
this.state.selectedTags.push($item);
};
this.removeTag = function(tag) {
var idx = this.model.indexOf(tag);
if (idx > -1) {
this.model.splice(idx, 1);
this.tags.push(tag);
}
this.removeTag = function removeTag(tag) {
_.remove(this.state.selectedTags, { Id: tag.Id });
_.remove(this.model, (id) => id === tag.Id);
};
this.filterSelected = filterSelected.bind(this);
function filterSelected($item) {
if (!this.model) {
return true;
}
return !_.includes(this.model, $item.Id);
}
window._remove = _.remove;
});

View file

@ -0,0 +1,9 @@
import _ from 'lodash';
export default class PortainerEndpointTagHelper {
static idsToTagNames(tags, ids) {
const filteredTags = _.filter(tags, tag => _.includes(ids, tag.Id));
const tagNames = _.map(filteredTags, 'Name');
return tagNames;
}
}

View file

@ -1,14 +1,14 @@
export function EndpointGroupDefaultModel() {
this.Name = '';
this.Description = '';
this.Tags = [];
this.TagIds = [];
}
export function EndpointGroupModel(data) {
this.Id = data.Id;
this.Name = data.Name;
this.Description = data.Description;
this.Tags = data.Tags;
this.TagIds = data.TagIds;
this.AuthorizedUsers = data.AuthorizedUsers;
this.AuthorizedTeams = data.AuthorizedTeams;
this.UserAccessPolicies = data.UserAccessPolicies;
@ -18,7 +18,7 @@ export function EndpointGroupModel(data) {
export function EndpointGroupCreateRequest(model, endpoints) {
this.Name = model.Name;
this.Description = model.Description;
this.Tags = model.Tags;
this.TagIds = model.TagIds;
this.AssociatedEndpoints = endpoints;
}
@ -26,7 +26,7 @@ export function EndpointGroupUpdateRequest(model, endpoints) {
this.id = model.Id;
this.Name = model.Name;
this.Description = model.Description;
this.Tags = model.Tags;
this.TagIds = model.TagIds;
this.AssociatedEndpoints = endpoints;
this.UserAccessPolicies = model.UserAccessPolicies;
this.TeamAccessPolicies = model.TeamAccessPolicies;

View file

@ -63,7 +63,7 @@ function EndpointServiceFactory($q, Endpoints, FileUploadService) {
return deferred.promise;
};
service.createRemoteEndpoint = function(name, type, URL, PublicURL, groupID, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
service.createRemoteEndpoint = function(name, type, URL, PublicURL, groupID, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
var deferred = $q.defer();
var endpointURL = URL;
@ -71,7 +71,7 @@ function EndpointServiceFactory($q, Endpoints, FileUploadService) {
endpointURL = 'tcp://' + URL;
}
FileUploadService.createEndpoint(name, type, endpointURL, PublicURL, groupID, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
FileUploadService.createEndpoint(name, type, endpointURL, PublicURL, groupID, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
.then(function success(response) {
deferred.resolve(response.data);
})
@ -82,10 +82,10 @@ function EndpointServiceFactory($q, Endpoints, FileUploadService) {
return deferred.promise;
};
service.createAzureEndpoint = function(name, applicationId, tenantId, authenticationKey, groupId, tags) {
service.createAzureEndpoint = function(name, applicationId, tenantId, authenticationKey, groupId, tagIds) {
var deferred = $q.defer();
FileUploadService.createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tags)
FileUploadService.createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tagIds)
.then(function success(response) {
deferred.resolve(response.data);
})

View file

@ -100,7 +100,7 @@ angular.module('portainer.app')
});
};
service.createEndpoint = function(name, type, URL, PublicURL, groupID, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
service.createEndpoint = function(name, type, URL, PublicURL, groupID, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
return Upload.upload({
url: 'api/endpoints',
data: {
@ -109,7 +109,7 @@ angular.module('portainer.app')
URL: URL,
PublicURL: PublicURL,
GroupID: groupID,
Tags: Upload.json(tags),
TagIds: Upload.json(tagIds),
TLS: TLS,
TLSSkipVerify: TLSSkipVerify,
TLSSkipClientVerify: TLSSkipClientVerify,
@ -121,14 +121,14 @@ angular.module('portainer.app')
});
};
service.createAzureEndpoint = function(name, applicationId, tenantId, authenticationKey, groupId, tags) {
service.createAzureEndpoint = function(name, applicationId, tenantId, authenticationKey, groupId, tagIds) {
return Upload.upload({
url: 'api/endpoints',
data: {
Name: name,
EndpointType: 3,
GroupID: groupId,
Tags: Upload.json(tags),
TagIds: Upload.json(tagIds),
AzureApplicationID: applicationId,
AzureTenantID: tenantId,
AzureAuthenticationKey: authenticationKey

View file

@ -18,7 +18,7 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
AzureApplicationId: '',
AzureTenantId: '',
AzureAuthenticationKey: '',
Tags: []
TagIds: []
};
$scope.copyAgentCommand = function() {
@ -40,7 +40,7 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
var URL = $filter('stripprotocol')($scope.formValues.URL);
var publicURL = $scope.formValues.PublicURL === '' ? URL.split(':')[0] : $scope.formValues.PublicURL;
var groupId = $scope.formValues.GroupId;
var tags = $scope.formValues.Tags;
var tagIds = $scope.formValues.TagIds;
var securityData = $scope.formValues.SecurityFormData;
var TLS = securityData.TLS;
@ -51,7 +51,7 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
var TLSCertFile = TLSSkipClientVerify ? null : securityData.TLSCert;
var TLSKeyFile = TLSSkipClientVerify ? null : securityData.TLSKey;
addEndpoint(name, 1, URL, publicURL, groupId, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile);
addEndpoint(name, 1, URL, publicURL, groupId, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile);
};
$scope.addAgentEndpoint = function() {
@ -59,18 +59,18 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
var URL = $filter('stripprotocol')($scope.formValues.URL);
var publicURL = $scope.formValues.PublicURL === '' ? URL.split(':')[0] : $scope.formValues.PublicURL;
var groupId = $scope.formValues.GroupId;
var tags = $scope.formValues.Tags;
var tagIds = $scope.formValues.TagIds;
addEndpoint(name, 2, URL, publicURL, groupId, tags, true, true, true, null, null, null);
addEndpoint(name, 2, URL, publicURL, groupId, tagIds, true, true, true, null, null, null);
};
$scope.addEdgeAgentEndpoint = function() {
var name = $scope.formValues.Name;
var groupId = $scope.formValues.GroupId;
var tags = $scope.formValues.Tags;
var tagIds = $scope.formValues.TagIds;
var URL = $scope.formValues.URL;
addEndpoint(name, 4, URL, "", groupId, tags, false, false, false, null, null, null);
addEndpoint(name, 4, URL, "", groupId, tagIds, false, false, false, null, null, null);
};
$scope.addAzureEndpoint = function() {
@ -79,14 +79,14 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
var tenantId = $scope.formValues.AzureTenantId;
var authenticationKey = $scope.formValues.AzureAuthenticationKey;
var groupId = $scope.formValues.GroupId;
var tags = $scope.formValues.Tags;
var tagIds = $scope.formValues.TagIds;
createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tags);
createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tagIds);
};
function createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tags) {
function createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tagIds) {
$scope.state.actionInProgress = true;
EndpointService.createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tags)
EndpointService.createAzureEndpoint(name, applicationId, tenantId, authenticationKey, groupId, tagIds)
.then(function success() {
Notifications.success('Endpoint created', name);
$state.go('portainer.endpoints', {}, {reload: true});
@ -99,9 +99,9 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
});
}
function addEndpoint(name, type, URL, PublicURL, groupId, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
function addEndpoint(name, type, URL, PublicURL, groupId, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile) {
$scope.state.actionInProgress = true;
EndpointService.createRemoteEndpoint(name, type, URL, PublicURL, groupId, tags, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
EndpointService.createRemoteEndpoint(name, type, URL, PublicURL, groupId, tagIds, TLS, TLSSkipVerify, TLSSkipClientVerify, TLSCAFile, TLSCertFile, TLSKeyFile)
.then(function success(data) {
Notifications.success('Endpoint created', name);
if (type === 4) {
@ -121,7 +121,7 @@ function ($q, $scope, $state, $filter, clipboard, EndpointService, GroupService,
function initView() {
$q.all({
groups: GroupService.groups(),
tags: TagService.tagNames()
tags: TagService.tags()
})
.then(function success(data) {
$scope.groups = data.groups;

View file

@ -259,8 +259,9 @@
<!-- tags -->
<div class="form-group">
<tag-selector
ng-if="availableTags"
tags="availableTags"
model="formValues.Tags"
model="formValues.TagIds"
></tag-selector>
</div>
<!-- !tags -->

View file

@ -165,8 +165,9 @@
<!-- tags -->
<div class="form-group">
<tag-selector
ng-if="availableTags && endpoint.TagIds"
tags="availableTags"
model="endpoint.Tags"
model="endpoint.TagIds"
></tag-selector>
</div>
<!-- !tags -->

View file

@ -41,12 +41,12 @@ function ($q, $scope, $state, $transition$, $filter, clipboard, EndpointService,
var TLSMode = securityData.TLSMode;
var TLSSkipVerify = TLS && (TLSMode === 'tls_client_noca' || TLSMode === 'tls_only');
var TLSSkipClientVerify = TLS && (TLSMode === 'tls_ca' || TLSMode === 'tls_only');
var payload = {
Name: endpoint.Name,
PublicURL: endpoint.PublicURL,
GroupID: endpoint.GroupId,
Tags: endpoint.Tags,
TagIds: endpoint.TagIds,
TLS: TLS,
TLSSkipVerify: TLSSkipVerify,
TLSSkipClientVerify: TLSSkipClientVerify,
@ -96,7 +96,7 @@ function ($q, $scope, $state, $transition$, $filter, clipboard, EndpointService,
$q.all({
endpoint: EndpointService.endpoint($transition$.params().id),
groups: GroupService.groups(),
tags: TagService.tagNames()
tags: TagService.tags()
})
.then(function success(data) {
var endpoint = data.endpoint;

View file

@ -32,7 +32,7 @@ function ($q, $scope, $state, GroupService, EndpointService, TagService, Notific
};
function initView() {
TagService.tagNames()
TagService.tags()
.then((tags) => {
$scope.availableTags = tags;
$scope.associatedEndpoints = [];

View file

@ -28,7 +28,7 @@ function ($q, $scope, $state, $transition$, GroupService, TagService, Notificati
$q.all({
group: GroupService.group(groupId),
tags: TagService.tagNames()
tags: TagService.tags()
})
.then(function success(data) {
$scope.group = data.group;

View file

@ -34,6 +34,7 @@
<endpoint-list
title-text="Endpoints" title-icon="fa-plug"
endpoints="endpoints" table-key="home_endpoints"
tags="tags"
dashboard-action="goToDashboard"
show-snapshot-action="!applicationState.application.authentication || isAdmin"
snapshot-action="triggerSnapshot"

View file

@ -1,6 +1,6 @@
angular.module('portainer.app')
.controller('HomeController', ['$q', '$scope', '$state', '$interval', 'Authentication', 'EndpointService', 'EndpointHelper', 'GroupService', 'Notifications', 'EndpointProvider', 'StateManager', 'LegacyExtensionManager', 'ModalService', 'MotdService', 'SystemService',
function($q, $scope, $state, $interval, Authentication, EndpointService, EndpointHelper, GroupService, Notifications, EndpointProvider, StateManager, LegacyExtensionManager, ModalService, MotdService, SystemService) {
.controller('HomeController',
function($q, $scope, $state, TagService, Authentication, EndpointService, EndpointHelper, GroupService, Notifications, EndpointProvider, StateManager, LegacyExtensionManager, ModalService, MotdService, SystemService) {
$scope.state = {
connectingToEdgeEndpoint: false,
@ -165,9 +165,9 @@ angular.module('portainer.app')
return deferred.promise;
}
function initView() {
async function initView() {
$scope.isAdmin = Authentication.isAdmin();
MotdService.motd()
.then(function success(data) {
$scope.motd = data;
@ -183,7 +183,13 @@ angular.module('portainer.app')
$scope.endpoints = data.endpoints;
}
});
try {
$scope.tags = await TagService.tags();
} catch(e) {
Notifications.error("Failed loading tags", e)
}
}
initView();
}]);
});

View file

@ -1,8 +1,7 @@
import {ScheduleDefaultModel} from '../../../models/schedule';
angular.module('portainer.app')
.controller('CreateScheduleController', ['$q', '$scope', '$state', 'Notifications', 'EndpointService', 'GroupService', 'ScheduleService',
function ($q, $scope, $state, Notifications, EndpointService, GroupService, ScheduleService) {
.controller('CreateScheduleController', function CreateScheduleController($q, $scope, $state, Notifications, EndpointService, GroupService, ScheduleService, TagService) {
$scope.state = {
actionInProgress: false
@ -39,11 +38,13 @@ function ($q, $scope, $state, Notifications, EndpointService, GroupService, Sche
$q.all({
endpoints: EndpointService.endpoints(),
groups: GroupService.groups()
groups: GroupService.groups(),
tags: TagService.tags()
})
.then(function success(data) {
$scope.endpoints = data.endpoints.value;
$scope.groups = data.groups;
$scope.tags = data.tags;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint list');
@ -51,4 +52,4 @@ function ($q, $scope, $state, Notifications, EndpointService, GroupService, Sche
}
initView();
}]);
});

View file

@ -13,6 +13,7 @@
model="model"
endpoints="endpoints"
groups="groups"
tags="tags"
form-action="create"
form-action-label="Create schedule"
action-in-progress="state.actionInProgress"

View file

@ -25,6 +25,7 @@
model="schedule"
endpoints="endpoints"
groups="groups"
tags="tags"
form-action="update"
form-action-label="Update schedule"
action-in-progress="state.actionInProgress"

View file

@ -1,6 +1,5 @@
angular.module('portainer.app')
.controller('ScheduleController', ['$q', '$scope', '$transition$', '$state', 'Notifications', 'EndpointService', 'GroupService', 'ScheduleService', 'EndpointProvider', 'HostBrowserService', 'FileSaver',
function ($q, $scope, $transition$, $state, Notifications, EndpointService, GroupService, ScheduleService, EndpointProvider, HostBrowserService, FileSaver) {
.controller('ScheduleController', function ScheduleController($q, $scope, $transition$, $state, Notifications, EndpointService, GroupService, ScheduleService, EndpointProvider, HostBrowserService, FileSaver, TagService) {
$scope.state = {
actionInProgress: false
@ -75,7 +74,8 @@ function ($q, $scope, $transition$, $state, Notifications, EndpointService, Grou
file: ScheduleService.getScriptFile(id),
tasks: ScheduleService.scriptExecutionTasks(id),
endpoints: EndpointService.endpoints(),
groups: GroupService.groups()
groups: GroupService.groups(),
tags: TagService.tags()
})
.then(function success(data) {
var schedule = data.schedule;
@ -89,6 +89,7 @@ function ($q, $scope, $transition$, $state, Notifications, EndpointService, Grou
$scope.tasks = data.tasks;
$scope.endpoints = data.endpoints.value;
$scope.groups = data.groups;
$scope.tags = data.tags;
})
.catch(function error(err) {
Notifications.error('Failure', err, 'Unable to retrieve endpoint list');
@ -96,4 +97,4 @@ function ($q, $scope, $transition$, $state, Notifications, EndpointService, Grou
}
initView();
}]);
});