mirror of
https://github.com/portainer/portainer.git
synced 2025-08-08 23:35:31 +02:00
refactor(groups): migrate groups selectors to react [EE-3842] (#8936)
This commit is contained in:
parent
2018529add
commit
e91b4f5c83
38 changed files with 543 additions and 627 deletions
|
@ -1,50 +0,0 @@
|
|||
<div class="col-sm-12 small text-muted">
|
||||
You can select which environment should be part of this group by moving them to the associated environments table. Simply click on any environment entry to move it from one table
|
||||
to the other.
|
||||
</div>
|
||||
<div class="col-sm-12" style="margin-top: 20px">
|
||||
<div class="table-row-container">
|
||||
<!-- available-endpoints -->
|
||||
<div class="datatable table-in-row">
|
||||
<group-association-table
|
||||
loaded="$ctrl.loaded"
|
||||
page-type="$ctrl.pageType"
|
||||
table-type="available"
|
||||
retrieve-page="$ctrl.getAvailableEndpoints"
|
||||
dataset="$ctrl.endpoints.available"
|
||||
entry-click="$ctrl.associateEndpoint"
|
||||
pagination-state="$ctrl.state.available"
|
||||
empty-dataset-message="No environment available"
|
||||
tags="$ctrl.tags"
|
||||
show-tags="true"
|
||||
groups="$ctrl.groups"
|
||||
show-groups="true"
|
||||
has-backend-pagination="true"
|
||||
title="Available environments"
|
||||
data-cy="edgeGroupCreate-availableEndpoints"
|
||||
></group-association-table>
|
||||
</div>
|
||||
<!-- !available-endpoints -->
|
||||
<!-- associated-endpoints -->
|
||||
<div class="datatable table-in-row">
|
||||
<group-association-table
|
||||
loaded="$ctrl.loaded"
|
||||
page-type="$ctrl.pageType"
|
||||
table-type="associated"
|
||||
retrieve-page="$ctrl.getAssociatedEndpoints"
|
||||
dataset="$ctrl.endpoints.associated"
|
||||
entry-click="$ctrl.dissociateEndpoint"
|
||||
pagination-state="$ctrl.state.associated"
|
||||
empty-dataset-message="No associated environment"
|
||||
tags="$ctrl.tags"
|
||||
show-tags="true"
|
||||
groups="$ctrl.groups"
|
||||
show-groups="true"
|
||||
has-backend-pagination="true"
|
||||
title="Associated environments"
|
||||
data-cy="edgeGroupCreate-associatedEndpoints"
|
||||
></group-association-table>
|
||||
</div>
|
||||
<!-- !associated-endpoints -->
|
||||
</div>
|
||||
</div>
|
|
@ -1,16 +0,0 @@
|
|||
import angular from 'angular';
|
||||
import AssociatedEndpointsSelectorController from './associatedEndpointsSelectorController';
|
||||
|
||||
angular.module('portainer.app').component('associatedEndpointsSelector', {
|
||||
templateUrl: './associatedEndpointsSelector.html',
|
||||
controller: AssociatedEndpointsSelectorController,
|
||||
bindings: {
|
||||
endpointIds: '<',
|
||||
tags: '<',
|
||||
groups: '<',
|
||||
hasBackendPagination: '<',
|
||||
|
||||
onAssociate: '<',
|
||||
onDissociate: '<',
|
||||
},
|
||||
});
|
|
@ -1,111 +0,0 @@
|
|||
import angular from 'angular';
|
||||
import _ from 'lodash-es';
|
||||
|
||||
import { EdgeTypes } from '@/react/portainer/environments/types';
|
||||
import { getEnvironments } from '@/react/portainer/environments/environment.service';
|
||||
|
||||
class AssoicatedEndpointsSelectorController {
|
||||
/* @ngInject */
|
||||
constructor($async) {
|
||||
this.$async = $async;
|
||||
|
||||
this.state = {
|
||||
available: {
|
||||
limit: '10',
|
||||
filter: '',
|
||||
pageNumber: 1,
|
||||
totalCount: 0,
|
||||
},
|
||||
associated: {
|
||||
limit: '10',
|
||||
filter: '',
|
||||
pageNumber: 1,
|
||||
totalCount: 0,
|
||||
},
|
||||
};
|
||||
|
||||
this.endpoints = {
|
||||
associated: [],
|
||||
available: null,
|
||||
};
|
||||
|
||||
this.getAvailableEndpoints = this.getAvailableEndpoints.bind(this);
|
||||
this.getAssociatedEndpoints = this.getAssociatedEndpoints.bind(this);
|
||||
this.associateEndpoint = this.associateEndpoint.bind(this);
|
||||
this.dissociateEndpoint = this.dissociateEndpoint.bind(this);
|
||||
this.loadData = this.loadData.bind(this);
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.loadData();
|
||||
}
|
||||
|
||||
$onChanges({ endpointIds }) {
|
||||
if (endpointIds && endpointIds.currentValue) {
|
||||
this.loadData();
|
||||
}
|
||||
}
|
||||
|
||||
loadData() {
|
||||
this.getAvailableEndpoints();
|
||||
this.getAssociatedEndpoints();
|
||||
}
|
||||
|
||||
/* #region internal queries to retrieve endpoints per "side" of the selector */
|
||||
getAvailableEndpoints() {
|
||||
return this.$async(async () => {
|
||||
const { start, filter, limit } = this.getPaginationData('available');
|
||||
const query = { search: filter, types: EdgeTypes };
|
||||
|
||||
const response = await getEnvironments({ start, limit, query });
|
||||
|
||||
const endpoints = _.filter(response.value, (endpoint) => !_.includes(this.endpointIds, endpoint.Id));
|
||||
this.setTableData('available', endpoints, response.totalCount);
|
||||
this.noEndpoints = this.state.available.totalCount === 0;
|
||||
});
|
||||
}
|
||||
|
||||
getAssociatedEndpoints() {
|
||||
return this.$async(async () => {
|
||||
let response = { value: [], totalCount: 0 };
|
||||
if (this.endpointIds.length > 0) {
|
||||
// fetch only if already has associated endpoints
|
||||
const { start, filter, limit } = this.getPaginationData('associated');
|
||||
const query = { search: filter, types: EdgeTypes, endpointIds: this.endpointIds };
|
||||
|
||||
response = await getEnvironments({ start, limit, query });
|
||||
}
|
||||
|
||||
this.setTableData('associated', response.value, response.totalCount);
|
||||
});
|
||||
}
|
||||
|
||||
/* #endregion */
|
||||
|
||||
/* #region On endpoint click (either available or associated) */
|
||||
associateEndpoint(endpoint) {
|
||||
this.onAssociate(endpoint);
|
||||
}
|
||||
|
||||
dissociateEndpoint(endpoint) {
|
||||
this.onDissociate(endpoint);
|
||||
}
|
||||
/* #endregion */
|
||||
|
||||
/* #region Utils funcs */
|
||||
getPaginationData(tableType) {
|
||||
const { pageNumber, limit, filter } = this.state[tableType];
|
||||
const start = (pageNumber - 1) * limit + 1;
|
||||
|
||||
return { start, filter, limit };
|
||||
}
|
||||
|
||||
setTableData(tableType, endpoints, totalCount) {
|
||||
this.endpoints[tableType] = endpoints;
|
||||
this.state[tableType].totalCount = parseInt(totalCount, 10);
|
||||
}
|
||||
/* #endregion */
|
||||
}
|
||||
|
||||
angular.module('portainer.app').controller('AssoicatedEndpointsSelectorController', AssoicatedEndpointsSelectorController);
|
||||
export default AssoicatedEndpointsSelectorController;
|
|
@ -6,14 +6,12 @@ angular.module('portainer.app').component('groupForm', {
|
|||
controller: GroupFormController,
|
||||
bindings: {
|
||||
loaded: '<',
|
||||
pageType: '@',
|
||||
model: '=',
|
||||
availableEndpoints: '=',
|
||||
associatedEndpoints: '=',
|
||||
addLabelAction: '<',
|
||||
removeLabelAction: '<',
|
||||
formAction: '<',
|
||||
formActionLabel: '@',
|
||||
actionInProgress: '<',
|
||||
|
||||
onChangeEnvironments: '<',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<form class="form-horizontal" name="endpointGroupForm">
|
||||
<form class="form-horizontal" name="endpointGroupForm" ng-if="$ctrl.model">
|
||||
<!-- name-input -->
|
||||
<div class="form-group">
|
||||
<label for="group_name" class="col-sm-3 col-lg-2 control-label required text-left">Name</label>
|
||||
|
@ -29,68 +29,19 @@
|
|||
|
||||
<tag-selector ng-if="$ctrl.model.TagIds" value="$ctrl.model.TagIds" on-change="($ctrl.onChangeTags)" allow-create="$ctrl.state.allowCreateTag"> </tag-selector>
|
||||
|
||||
<!-- environments -->
|
||||
<div ng-if="$ctrl.model.Id !== 1">
|
||||
<div class="col-sm-12 form-section-title"> Associated environments </div>
|
||||
<div class="form-group">
|
||||
<div class="col-sm-12 small text-muted">
|
||||
You can select which environment should be part of this group by moving them to the associated environments table. Simply click on any environment entry to move it from one
|
||||
table to the other.
|
||||
</div>
|
||||
<div class="col-sm-12" style="margin-top: 20px">
|
||||
<!-- available-endpoints -->
|
||||
<div class="table-row-container">
|
||||
<div class="datatable table-in-row">
|
||||
<group-association-table
|
||||
loaded="$ctrl.loaded"
|
||||
page-type="$ctrl.pageType"
|
||||
table-type="available"
|
||||
retrieve-page="$ctrl.getPaginatedEndpointsByGroup"
|
||||
dataset="$ctrl.availableEndpoints"
|
||||
entry-click="$ctrl.associateEndpoint"
|
||||
pagination-state="$ctrl.state.available"
|
||||
empty-dataset-message="No environment available"
|
||||
title="Available environments"
|
||||
cy-value="available-endpoints"
|
||||
></group-association-table>
|
||||
</div>
|
||||
<!-- !available-endpoints -->
|
||||
<!-- associated-endpoints -->
|
||||
<div class="table-in-row">
|
||||
<group-association-table
|
||||
loaded="$ctrl.loaded"
|
||||
page-type="$ctrl.pageType"
|
||||
table-type="associated"
|
||||
retrieve-page="$ctrl.getPaginatedEndpointsByGroup"
|
||||
dataset="$ctrl.associatedEndpoints"
|
||||
entry-click="$ctrl.dissociateEndpoint"
|
||||
pagination-state="$ctrl.state.associated"
|
||||
empty-dataset-message="No associated environment"
|
||||
has-backend-pagination="this.pageType !== 'create'"
|
||||
title="Associated environments"
|
||||
cy-value="associated-endpoints"
|
||||
></group-association-table>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !associated-endpoints -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group" ng-if="$ctrl.model.Id !== 1">
|
||||
<associated-endpoints-selector value="$ctrl.associatedEndpoints" on-change="($ctrl.onChangeEnvironments)"></associated-endpoints-selector>
|
||||
</div>
|
||||
<div ng-if="$ctrl.model.Id === 1">
|
||||
<div class="table-in-row">
|
||||
<group-association-table
|
||||
loaded="$ctrl.loaded"
|
||||
page-type="$ctrl.pageType"
|
||||
table-type="associated"
|
||||
retrieve-page="$ctrl.getPaginatedEndpointsByGroup"
|
||||
dataset="$ctrl.associatedEndpoints"
|
||||
pagination-state="$ctrl.state.associated"
|
||||
empty-dataset-message="No environment available"
|
||||
title="Unassociated environments"
|
||||
></group-association-table>
|
||||
</div>
|
||||
|
||||
<div class="-mx-[15px]">
|
||||
<group-association-table
|
||||
ng-if="$ctrl.model.Id === 1"
|
||||
title="'Unassociated environments'"
|
||||
empty-content-message="'No environment available'"
|
||||
query="$ctrl.unassociatedQuery"
|
||||
></group-association-table>
|
||||
</div>
|
||||
<!-- !endpoints -->
|
||||
|
||||
<!-- actions -->
|
||||
<div class="col-sm-12 form-section-title"> Actions </div>
|
||||
<div class="form-group">
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
import _ from 'lodash-es';
|
||||
import angular from 'angular';
|
||||
import { endpointsByGroup } from '@/react/portainer/environments/environment.service';
|
||||
import { notifyError } from '@/portainer/services/notifications';
|
||||
|
||||
class GroupFormController {
|
||||
/* @ngInject */
|
||||
|
@ -12,9 +9,14 @@ class GroupFormController {
|
|||
this.Notifications = Notifications;
|
||||
this.Authentication = Authentication;
|
||||
|
||||
this.associateEndpoint = this.associateEndpoint.bind(this);
|
||||
this.dissociateEndpoint = this.dissociateEndpoint.bind(this);
|
||||
this.getPaginatedEndpointsByGroup = this.getPaginatedEndpointsByGroup.bind(this);
|
||||
this.state = {
|
||||
allowCreateTag: this.Authentication.isAdmin(),
|
||||
};
|
||||
|
||||
this.unassociatedQuery = {
|
||||
groupIds: [1],
|
||||
};
|
||||
|
||||
this.onChangeTags = this.onChangeTags.bind(this);
|
||||
}
|
||||
|
||||
|
@ -23,81 +25,6 @@ class GroupFormController {
|
|||
this.model.TagIds = value;
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.state = {
|
||||
available: {
|
||||
limit: '10',
|
||||
filter: '',
|
||||
pageNumber: 1,
|
||||
totalCount: 0,
|
||||
},
|
||||
associated: {
|
||||
limit: '10',
|
||||
filter: '',
|
||||
pageNumber: 1,
|
||||
totalCount: 0,
|
||||
},
|
||||
allowCreateTag: this.Authentication.isAdmin(),
|
||||
};
|
||||
}
|
||||
associateEndpoint(endpoint) {
|
||||
if (this.pageType === 'create' && !_.includes(this.associatedEndpoints, endpoint)) {
|
||||
this.associatedEndpoints.push(endpoint);
|
||||
} else if (this.pageType === 'edit') {
|
||||
this.GroupService.addEndpoint(this.model.Id, endpoint)
|
||||
.then(() => {
|
||||
this.Notifications.success('Success', 'Environment successfully added to group');
|
||||
this.reloadTablesContent();
|
||||
})
|
||||
.catch((err) => this.Notifications.error('Error', err, 'Unable to add environment to group'));
|
||||
}
|
||||
}
|
||||
|
||||
dissociateEndpoint(endpoint) {
|
||||
if (this.pageType === 'create') {
|
||||
_.remove(this.associatedEndpoints, (item) => item.Id === endpoint.Id);
|
||||
} else if (this.pageType === 'edit') {
|
||||
this.GroupService.removeEndpoint(this.model.Id, endpoint.Id)
|
||||
.then(() => {
|
||||
this.Notifications.success('Success', 'Environment successfully removed from group');
|
||||
this.reloadTablesContent();
|
||||
})
|
||||
.catch((err) => this.Notifications.error('Error', err, 'Unable to remove environment from group'));
|
||||
}
|
||||
}
|
||||
|
||||
reloadTablesContent() {
|
||||
this.getPaginatedEndpointsByGroup(this.pageType, 'available');
|
||||
this.getPaginatedEndpointsByGroup(this.pageType, 'associated');
|
||||
this.GroupService.group(this.model.Id).then((data) => {
|
||||
this.model = data;
|
||||
});
|
||||
}
|
||||
|
||||
getPaginatedEndpointsByGroup(pageType, tableType) {
|
||||
this.$async(async () => {
|
||||
try {
|
||||
if (tableType === 'available') {
|
||||
const context = this.state.available;
|
||||
const start = (context.pageNumber - 1) * context.limit + 1;
|
||||
const data = await endpointsByGroup(1, start, context.limit, { search: context.filter });
|
||||
this.availableEndpoints = data.value;
|
||||
this.state.available.totalCount = data.totalCount;
|
||||
} else if (tableType === 'associated' && pageType === 'edit') {
|
||||
const groupId = this.model.Id ? this.model.Id : 1;
|
||||
const context = this.state.associated;
|
||||
const start = (context.pageNumber - 1) * context.limit + 1;
|
||||
const data = await endpointsByGroup(groupId, start, context.limit, { search: context.filter });
|
||||
this.associatedEndpoints = data.value;
|
||||
this.state.associated.totalCount = data.totalCount;
|
||||
}
|
||||
// ignore (associated + create) group as there is no backend pagination for this table
|
||||
} catch (err) {
|
||||
notifyError('Failure', err, 'Failed getting endpoints for group');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('portainer.app').controller('GroupFormController', GroupFormController);
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
import _ from 'lodash-es';
|
||||
import { idsToTagNames } from 'Portainer/helpers/tagHelper';
|
||||
|
||||
angular.module('portainer.app').component('groupAssociationTable', {
|
||||
templateUrl: './groupAssociationTable.html',
|
||||
controller: function () {
|
||||
this.state = {
|
||||
orderBy: 'Name',
|
||||
reverseOrder: false,
|
||||
paginatedItemLimit: '10',
|
||||
textFilter: '',
|
||||
loading: true,
|
||||
pageNumber: 1,
|
||||
};
|
||||
|
||||
this.changeOrderBy = function (orderField) {
|
||||
this.state.reverseOrder = this.state.orderBy === orderField ? !this.state.reverseOrder : false;
|
||||
this.state.orderBy = orderField;
|
||||
};
|
||||
|
||||
this.onTextFilterChange = function () {
|
||||
this.paginationChangedAction();
|
||||
};
|
||||
|
||||
this.onPageChanged = function (newPageNumber) {
|
||||
this.paginationState.pageNumber = newPageNumber;
|
||||
this.paginationChangedAction();
|
||||
};
|
||||
|
||||
this.onPaginationLimitChanged = function () {
|
||||
this.paginationChangedAction();
|
||||
};
|
||||
|
||||
this.paginationChangedAction = function () {
|
||||
this.retrievePage(this.pageType, this.tableType);
|
||||
};
|
||||
|
||||
this.$onChanges = function (changes) {
|
||||
if (changes.loaded && changes.loaded.currentValue) {
|
||||
this.paginationChangedAction();
|
||||
}
|
||||
};
|
||||
|
||||
this.tagIdsToTagNames = function tagIdsToTagNames(tagIds) {
|
||||
return idsToTagNames(this.tags, tagIds).join(', ') || '-';
|
||||
};
|
||||
|
||||
this.groupIdToGroupName = function groupIdToGroupName(groupId) {
|
||||
const group = _.find(this.groups, { Id: groupId });
|
||||
return group ? group.Name : '';
|
||||
};
|
||||
},
|
||||
bindings: {
|
||||
paginationState: '=',
|
||||
loaded: '<',
|
||||
pageType: '<',
|
||||
tableType: '@',
|
||||
retrievePage: '<',
|
||||
dataset: '<',
|
||||
entryClick: '<',
|
||||
emptyDatasetMessage: '@',
|
||||
tags: '<',
|
||||
showTags: '<',
|
||||
groups: '<',
|
||||
showGroups: '<',
|
||||
hasBackendPagination: '<',
|
||||
cyValue: '@',
|
||||
title: '@',
|
||||
},
|
||||
});
|
|
@ -1,85 +0,0 @@
|
|||
<div class="datatable">
|
||||
<div class="toolBar">
|
||||
<div class="toolBarTitle">{{ $ctrl.title }}</div>
|
||||
<div class="searchBar vertical-center">
|
||||
<pr-icon icon="'search'" class-name="'searchIcon'"></pr-icon>
|
||||
<input
|
||||
type="text"
|
||||
class="searchInput"
|
||||
ng-model="$ctrl.paginationState.filter"
|
||||
ng-change="$ctrl.onTextFilterChange()"
|
||||
ng-model-options="{ debounce: 300 }"
|
||||
placeholder="Search..."
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<table class="table-hover table" data-cy="{{ $ctrl.cyValue }}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Name </th>
|
||||
<th ng-if="$ctrl.showGroups"> Group </th>
|
||||
<th ng-if="$ctrl.showTags"> Tags </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
ng-if="!$ctrl.hasBackendPagination"
|
||||
ng-click="$ctrl.entryClick(item)"
|
||||
class="interactive"
|
||||
dir-paginate="item in $ctrl.dataset | filter:$ctrl.paginationState.filter | itemsPerPage: $ctrl.paginationState.limit"
|
||||
pagination-id="$ctrl.tableType"
|
||||
>
|
||||
<td>
|
||||
{{ item.Name | truncate : 64 }}
|
||||
</td>
|
||||
<td ng-if="$ctrl.showGroups">
|
||||
{{ $ctrl.groupIdToGroupName(item.GroupId) | truncate : 64 }}
|
||||
</td>
|
||||
<td ng-if="$ctrl.showTags">
|
||||
{{ $ctrl.tagIdsToTagNames(item.TagIds) | arraytostr | truncate : 64 }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
ng-if="$ctrl.hasBackendPagination"
|
||||
ng-click="$ctrl.entryClick(item)"
|
||||
class="interactive"
|
||||
dir-paginate="item in $ctrl.dataset | itemsPerPage: $ctrl.paginationState.limit"
|
||||
pagination-id="$ctrl.tableType"
|
||||
total-items="$ctrl.paginationState.totalCount"
|
||||
>
|
||||
<td>
|
||||
{{ item.Name | truncate : 64 }}
|
||||
</td>
|
||||
<td ng-if="$ctrl.showGroups">
|
||||
{{ $ctrl.groupIdToGroupName(item.GroupId) | truncate : 64 }}
|
||||
</td>
|
||||
<td ng-if="$ctrl.showTags">
|
||||
{{ $ctrl.tagIdsToTagNames(item.TagIds) | truncate : 64 }}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr ng-if="!$ctrl.dataset">
|
||||
<td colspan="3" class="text-muted text-center">Loading...</td>
|
||||
</tr>
|
||||
<tr ng-if="$ctrl.dataset.length === 0">
|
||||
<td colspan="3" class="text-muted text-center">{{ $ctrl.emptyDatasetMessage }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="footer" ng-if="$ctrl.dataset">
|
||||
<div class="paginationControls">
|
||||
<form class="form-inline">
|
||||
<span class="limitSelector">
|
||||
<span class="space-right"> Items per page </span>
|
||||
<select ng-model="$ctrl.paginationState.limit" ng-change="$ctrl.onPaginationLimitChanged()">
|
||||
<option value="10">10</option>
|
||||
<option value="25">25</option>
|
||||
<option value="50">50</option>
|
||||
<option value="100">100</option>
|
||||
</select>
|
||||
</span>
|
||||
<dir-pagination-controls pagination-id="$ctrl.tableType" max-size="5" on-page-change="$ctrl.onPageChanged(newPageNumber, oldPageNumber)"></dir-pagination-controls>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -2,6 +2,7 @@ export function EndpointGroupDefaultModel() {
|
|||
this.Name = '';
|
||||
this.Description = '';
|
||||
this.TagIds = [];
|
||||
this.AssociatedEndpoints = [];
|
||||
}
|
||||
|
||||
export function EndpointGroupModel(data) {
|
||||
|
|
|
@ -6,6 +6,8 @@ import { withReactQuery } from '@/react-tools/withReactQuery';
|
|||
import { withUIRouter } from '@/react-tools/withUIRouter';
|
||||
import { AnnotationsBeTeaser } from '@/react/kubernetes/annotations/AnnotationsBeTeaser';
|
||||
import { withFormValidation } from '@/react-tools/withFormValidation';
|
||||
import { GroupAssociationTable } from '@/react/portainer/environments/environment-groups/components/GroupAssociationTable';
|
||||
import { AssociatedEnvironmentsSelector } from '@/react/portainer/environments/environment-groups/components/AssociatedEnvironmentsSelector';
|
||||
|
||||
import {
|
||||
EnvironmentVariablesFieldset,
|
||||
|
@ -204,7 +206,21 @@ export const ngModule = angular
|
|||
'height',
|
||||
])
|
||||
)
|
||||
.component('annotationsBeTeaser', r2a(AnnotationsBeTeaser, []));
|
||||
.component(
|
||||
'groupAssociationTable',
|
||||
r2a(withReactQuery(GroupAssociationTable), [
|
||||
'emptyContentLabel',
|
||||
'onClickRow',
|
||||
'query',
|
||||
'title',
|
||||
'data-cy',
|
||||
])
|
||||
)
|
||||
.component('annotationsBeTeaser', r2a(AnnotationsBeTeaser, []))
|
||||
.component(
|
||||
'associatedEndpointsSelector',
|
||||
r2a(withReactQuery(AssociatedEnvironmentsSelector), ['onChange', 'value'])
|
||||
);
|
||||
|
||||
export const componentsModule = ngModule.name;
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ angular.module('portainer.app').factory('GroupService', [
|
|||
return EndpointGroups.updateAccess({ id: groupId }, { UserAccessPolicies: userAccessPolicies, TeamAccessPolicies: teamAccessPolicies }).$promise;
|
||||
};
|
||||
|
||||
service.addEndpoint = function (groupId, endpoint) {
|
||||
return EndpointGroups.addEndpoint({ id: groupId, action: 'endpoints/' + endpoint.Id }, endpoint).$promise;
|
||||
service.addEndpoint = function (groupId, endpointId) {
|
||||
return EndpointGroups.addEndpoint({ id: groupId, action: 'endpoints/' + endpointId }).$promise;
|
||||
};
|
||||
|
||||
service.removeEndpoint = function (groupId, endpointId) {
|
||||
|
|
|
@ -17,10 +17,12 @@ export const tagKeys = {
|
|||
|
||||
export function useTags<T = Tag[]>({
|
||||
select,
|
||||
}: { select?: (tags: Tag[]) => T } = {}) {
|
||||
enabled = true,
|
||||
}: { select?: (tags: Tag[]) => T; enabled?: boolean } = {}) {
|
||||
return useQuery(tagKeys.all, () => getTags(), {
|
||||
staleTime: 50,
|
||||
select,
|
||||
enabled,
|
||||
...withError('Failed to retrieve tags'),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -5,17 +5,13 @@ angular.module('portainer.app').controller('CreateGroupController', function Cre
|
|||
actionInProgress: false,
|
||||
};
|
||||
|
||||
$scope.onChangeEnvironments = onChangeEnvironments;
|
||||
|
||||
$scope.create = function () {
|
||||
var model = $scope.model;
|
||||
|
||||
var associatedEndpoints = [];
|
||||
for (var i = 0; i < $scope.associatedEndpoints.length; i++) {
|
||||
var endpoint = $scope.associatedEndpoints[i];
|
||||
associatedEndpoints.push(endpoint.Id);
|
||||
}
|
||||
|
||||
$scope.state.actionInProgress = true;
|
||||
GroupService.createGroup(model, associatedEndpoints)
|
||||
GroupService.createGroup(model, $scope.associatedEndpoints)
|
||||
.then(function success() {
|
||||
Notifications.success('Success', 'Group successfully created');
|
||||
$state.go('portainer.groups', {}, { reload: true });
|
||||
|
@ -34,5 +30,11 @@ angular.module('portainer.app').controller('CreateGroupController', function Cre
|
|||
$scope.loaded = true;
|
||||
}
|
||||
|
||||
function onChangeEnvironments(value) {
|
||||
return $scope.$evalAsync(() => {
|
||||
$scope.associatedEndpoints = value;
|
||||
});
|
||||
}
|
||||
|
||||
initView();
|
||||
});
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
<rd-widget-body>
|
||||
<group-form
|
||||
loaded="loaded"
|
||||
page-type="create"
|
||||
model="model"
|
||||
available-endpoints="availableEndpoints"
|
||||
associated-endpoints="associatedEndpoints"
|
||||
add-label-action="addLabel"
|
||||
remove-label-action="removeLabel"
|
||||
form-action="create"
|
||||
form-action-label="Create the group"
|
||||
action-in-progress="state.actionInProgress"
|
||||
on-change-environments="(onChangeEnvironments)"
|
||||
></group-form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
|
|
|
@ -6,15 +6,12 @@
|
|||
<rd-widget-body>
|
||||
<group-form
|
||||
loaded="loaded"
|
||||
page-type="edit"
|
||||
model="group"
|
||||
available-endpoints="availableEndpoints"
|
||||
associated-endpoints="associatedEndpoints"
|
||||
add-label-action="addLabel"
|
||||
remove-label-action="removeLabel"
|
||||
form-action="update"
|
||||
form-action-label="Update the group"
|
||||
action-in-progress="state.actionInProgress"
|
||||
on-change-environments="(onChangeEnvironments)"
|
||||
></group-form>
|
||||
</rd-widget-body>
|
||||
</rd-widget>
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
angular.module('portainer.app').controller('GroupController', function GroupController($q, $scope, $state, $transition$, GroupService, Notifications) {
|
||||
import { getEnvironments } from '@/react/portainer/environments/environment.service';
|
||||
import { notifyError, notifySuccess } from '@/portainer/services/notifications';
|
||||
|
||||
angular.module('portainer.app').controller('GroupController', function GroupController($async, $q, $scope, $state, $transition$, GroupService, Notifications) {
|
||||
$scope.state = {
|
||||
actionInProgress: false,
|
||||
};
|
||||
$scope.onChangeEnvironments = onChangeEnvironments;
|
||||
$scope.associatedEndpoints = [];
|
||||
|
||||
$scope.update = function () {
|
||||
var model = $scope.group;
|
||||
|
@ -20,14 +25,53 @@ angular.module('portainer.app').controller('GroupController', function GroupCont
|
|||
});
|
||||
};
|
||||
|
||||
function onChangeEnvironments(value, meta) {
|
||||
return $async(async () => {
|
||||
let success = false;
|
||||
if (meta.type === 'add') {
|
||||
success = await onAssociate(meta.value);
|
||||
} else if (meta.type === 'remove') {
|
||||
success = await onDisassociate(meta.value);
|
||||
}
|
||||
|
||||
if (success) {
|
||||
$scope.associatedEndpoints = value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function onAssociate(endpointId) {
|
||||
try {
|
||||
await GroupService.addEndpoint($scope.group.Id, endpointId);
|
||||
|
||||
notifySuccess('Success', `Environment successfully added to group`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
notifyError('Failure', err, `Unable to add environment to group`);
|
||||
}
|
||||
}
|
||||
|
||||
async function onDisassociate(endpointId) {
|
||||
try {
|
||||
await GroupService.removeEndpoint($scope.group.Id, endpointId);
|
||||
|
||||
notifySuccess('Success', `Environment successfully removed to group`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
notifyError('Failure', err, `Unable to remove environment to group`);
|
||||
}
|
||||
}
|
||||
|
||||
function initView() {
|
||||
var groupId = $transition$.params().id;
|
||||
|
||||
$q.all({
|
||||
group: GroupService.group(groupId),
|
||||
endpoints: getEnvironments({ query: { groupIds: [groupId] } }),
|
||||
})
|
||||
.then(function success(data) {
|
||||
$scope.group = data.group;
|
||||
$scope.associatedEndpoints = data.endpoints.value.map((endpoint) => endpoint.Id);
|
||||
$scope.loaded = true;
|
||||
})
|
||||
.catch(function error(err) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue