mirror of
https://github.com/portainer/portainer.git
synced 2025-08-07 23:05:26 +02:00
refactor(ui): replace ng selectors with react-select [EE-3608] (#7203)
Co-authored-by: LP B <xAt0mZ@users.noreply.github.com>
This commit is contained in:
parent
1e21961e6a
commit
ceaee4e175
66 changed files with 1188 additions and 625 deletions
|
@ -72,8 +72,8 @@
|
|||
class="form-group mt-4"
|
||||
ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && ($ctrl.isAdmin || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1))"
|
||||
>
|
||||
<div class="col-sm-12 vertical-center">
|
||||
<label for="group-access" class="control-label text-left col-sm-3 col-lg-2 !p-0">
|
||||
<div class="w-full vertical-center">
|
||||
<label for="group-access" class="control-label text-left col-sm-3 col-lg-2 !pt-0">
|
||||
Authorized teams
|
||||
<portainer-tooltip
|
||||
ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length > 0"
|
||||
|
@ -84,54 +84,45 @@
|
|||
message="'As you are a member of multiple teams, you can select which teams(s) will be able to manage this resource.'"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<span ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length === 0" class="small text-muted" style="margin-left: 20px">
|
||||
You have not yet created any teams. Head over to the <a ui-sref="portainer.teams">Teams view</a> to manage teams.
|
||||
</span>
|
||||
<div
|
||||
isteven-multi-select
|
||||
ng-if="($ctrl.isAdmin && $ctrl.availableTeams.length > 0) || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1)"
|
||||
class="col-sm-9 col-lg-10"
|
||||
input-model="$ctrl.availableTeams"
|
||||
output-model="$ctrl.formData.AuthorizedTeams"
|
||||
button-label="Name"
|
||||
item-label="Name"
|
||||
tick-property="selected"
|
||||
helper-elements="filter"
|
||||
search-property="Name"
|
||||
translation="{nothingSelected: 'Select one or more teams', search: 'Search...'}"
|
||||
data-cy="portainer-selectTeamAccess"
|
||||
>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<span ng-if="$ctrl.isAdmin && $ctrl.availableTeams.length === 0" class="small text-muted">
|
||||
You have not yet created any teams. Head over to the <a ui-sref="portainer.teams">Teams view</a> to manage teams.
|
||||
</span>
|
||||
|
||||
<por-access-control-form-team-selector
|
||||
ng-if="($ctrl.isAdmin && $ctrl.availableTeams.length > 0) || (!$ctrl.isAdmin && $ctrl.availableTeams.length > 1)"
|
||||
options="$ctrl.availableTeams"
|
||||
value="$ctrl.formData.AuthorizedTeams"
|
||||
input-id="'teams-selector'"
|
||||
on-change="($ctrl.onAuthorizedTeamsChange)"
|
||||
></por-access-control-form-team-selector>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- !authorized-teams -->
|
||||
<!-- authorized-users -->
|
||||
<div class="form-group" ng-if="$ctrl.formData.AccessControlEnabled && $ctrl.formData.Ownership === $ctrl.RCO.RESTRICTED && $ctrl.isAdmin">
|
||||
<div class="col-sm-12 vertical-center">
|
||||
<label for="group-access" class="control-label text-left col-sm-3 col-lg-2 !p-0">
|
||||
<div class="w-full vertical-center">
|
||||
<label for="group-access" class="control-label text-left col-sm-3 col-lg-2 !pt-0">
|
||||
Authorized users
|
||||
<portainer-tooltip
|
||||
ng-if="$ctrl.isAdmin && $ctrl.availableUsers.length > 0"
|
||||
message="'You can select which user(s) will be able to manage this resource.'"
|
||||
></portainer-tooltip>
|
||||
</label>
|
||||
<span ng-if="$ctrl.availableUsers.length === 0" class="small text-muted" style="margin-left: 20px">
|
||||
You have not yet created any users. Head over to the <a ui-sref="portainer.users">Users view</a> to manage users.
|
||||
</span>
|
||||
<div
|
||||
isteven-multi-select
|
||||
ng-if="$ctrl.availableUsers.length > 0"
|
||||
class="col-sm-9 col-lg-10"
|
||||
input-model="$ctrl.availableUsers"
|
||||
output-model="$ctrl.formData.AuthorizedUsers"
|
||||
button-label="Username"
|
||||
item-label="Username"
|
||||
tick-property="selected"
|
||||
helper-elements="filter"
|
||||
search-property="Username"
|
||||
translation="{nothingSelected: 'Select one or more users', search: 'Search...'}"
|
||||
data-cy="portainer-selectUserAccess"
|
||||
>
|
||||
<div class="col-sm-9 col-lg-10">
|
||||
<span ng-if="$ctrl.availableUsers.length === 0" class="small text-muted">
|
||||
You have not yet created any users. Head over to the <a ui-sref="portainer.users">Users view</a> to manage users.
|
||||
</span>
|
||||
|
||||
<por-access-control-form-user-selector
|
||||
ng-if="$ctrl.availableUsers.length > 0"
|
||||
options="$ctrl.availableUsers"
|
||||
value="$ctrl.formData.AuthorizedUsers"
|
||||
input-id="'users-selector'"
|
||||
on-change="($ctrl.onAuthorizedUsersChange)"
|
||||
></por-access-control-form-user-selector>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,9 @@ angular.module('portainer.app').controller('porAccessControlFormController', [
|
|||
|
||||
ctrl.RCO = RCO;
|
||||
|
||||
this.onAuthorizedTeamsChange = onAuthorizedTeamsChange.bind(this);
|
||||
this.onAuthorizedUsersChange = onAuthorizedUsersChange.bind(this);
|
||||
|
||||
ctrl.availableTeams = [];
|
||||
ctrl.availableUsers = [];
|
||||
|
||||
|
@ -31,18 +34,24 @@ angular.module('portainer.app').controller('porAccessControlFormController', [
|
|||
}
|
||||
|
||||
function setAuthorizedUsersAndTeams(authorizedUsers, authorizedTeams) {
|
||||
angular.forEach(ctrl.availableUsers, function (user) {
|
||||
var found = _.find(authorizedUsers, { Id: user.Id });
|
||||
if (found) {
|
||||
user.selected = true;
|
||||
}
|
||||
});
|
||||
ctrl.formData.AuthorizedTeams = authorizedTeams;
|
||||
ctrl.formData.AuthorizedUsers = authorizedUsers;
|
||||
}
|
||||
|
||||
angular.forEach(ctrl.availableTeams, function (team) {
|
||||
var found = _.find(authorizedTeams, { Id: team.Id });
|
||||
if (found) {
|
||||
team.selected = true;
|
||||
}
|
||||
function onAuthorizedTeamsChange(AuthorizedTeams) {
|
||||
onChange({ AuthorizedTeams });
|
||||
}
|
||||
|
||||
function onAuthorizedUsersChange(AuthorizedUsers) {
|
||||
onChange({ AuthorizedUsers });
|
||||
}
|
||||
|
||||
function onChange(formData) {
|
||||
$scope.$evalAsync(() => {
|
||||
ctrl.formData = {
|
||||
...ctrl.formData,
|
||||
...formData,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
import angular from 'angular';
|
||||
|
||||
import { porAccessManagement } from './por-access-management';
|
||||
import { porAccessManagementUsersSelector } from './por-access-management-users-selector';
|
||||
|
||||
export default angular
|
||||
.module('portainer.app.component.access-management', [])
|
||||
.component('porAccessManagement', porAccessManagement)
|
||||
.component('porAccessManagementUsersSelector', porAccessManagementUsersSelector).name;
|
||||
export default angular.module('portainer.app.component.access-management', []).component('porAccessManagement', porAccessManagement).name;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
export const porAccessManagementUsersSelector = {
|
||||
templateUrl: './por-access-management-users-selector.html',
|
||||
bindings: {
|
||||
options: '<',
|
||||
value: '=',
|
||||
},
|
||||
};
|
|
@ -1,20 +0,0 @@
|
|||
<div class="form-group">
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left vertical-center"> Select user(s) and/or team(s) </label>
|
||||
<div class="col-sm-9 col-lg-4 vertical-center">
|
||||
<span class="small text-muted" ng-if="$ctrl.options.length === 0"> No users or teams available. </span>
|
||||
<span
|
||||
isteven-multi-select
|
||||
ng-if="$ctrl.options.length > 0"
|
||||
input-model="$ctrl.options"
|
||||
output-model="$ctrl.value"
|
||||
button-label="icon Name"
|
||||
item-label="icon Name"
|
||||
tick-property="ticked"
|
||||
helper-elements="filter"
|
||||
search-property="Name"
|
||||
translation="{nothingSelected: 'Select one or more users and/or teams', search: 'Search...'}"
|
||||
data-cy="component-selectUser"
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
|
@ -13,7 +13,11 @@
|
|||
</span>
|
||||
</div>
|
||||
|
||||
<por-access-management-users-selector options="ctrl.availableUsersAndTeams" value="ctrl.formValues.multiselectOutput"></por-access-management-users-selector>
|
||||
<por-access-management-users-selector
|
||||
options="ctrl.availableUsersAndTeams"
|
||||
value="ctrl.formValues.multiselectOutput"
|
||||
on-change="(ctrl.onChangeUsersAndTeams)"
|
||||
></por-access-management-users-selector>
|
||||
|
||||
<div class="form-group" ng-if="ctrl.entityType !== 'registry'">
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left"> Role </label>
|
||||
|
@ -38,7 +42,7 @@
|
|||
<button
|
||||
type="submit"
|
||||
class="btn btn-primary btn-sm vertical-center"
|
||||
ng-disabled="(ctrl.availableUsersAndTeams | filter:{ticked:true}).length === 0 || ctrl.actionInProgress"
|
||||
ng-disabled="ctrl.formValues.multiselectOutput.length === 0 || ctrl.actionInProgress"
|
||||
ng-click="ctrl.authorizeAccess()"
|
||||
button-spinner="ctrl.actionInProgress"
|
||||
data-cy="access-createAccess"
|
||||
|
|
|
@ -6,13 +6,20 @@ import { isLimitedToBE } from '@/portainer/feature-flags/feature-flags.service';
|
|||
|
||||
class PorAccessManagementController {
|
||||
/* @ngInject */
|
||||
constructor(Notifications, AccessService, RoleService) {
|
||||
Object.assign(this, { Notifications, AccessService, RoleService });
|
||||
constructor($scope, Notifications, AccessService, RoleService) {
|
||||
Object.assign(this, { $scope, Notifications, AccessService, RoleService });
|
||||
|
||||
this.limitedToBE = false;
|
||||
|
||||
this.unauthorizeAccess = this.unauthorizeAccess.bind(this);
|
||||
this.updateAction = this.updateAction.bind(this);
|
||||
this.onChangeUsersAndTeams = this.onChangeUsersAndTeams.bind(this);
|
||||
}
|
||||
|
||||
onChangeUsersAndTeams(value) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.formValues.multiselectOutput = value;
|
||||
});
|
||||
}
|
||||
|
||||
updateAction() {
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
angular.module('portainer.app').component('endpointSelector', {
|
||||
templateUrl: './endpointSelector.html',
|
||||
controller: 'EndpointSelectorController',
|
||||
bindings: {
|
||||
model: '=',
|
||||
endpoints: '<',
|
||||
groups: '<',
|
||||
},
|
||||
});
|
|
@ -1,8 +0,0 @@
|
|||
<ui-select ng-model="$ctrl.model">
|
||||
<ui-select-match placeholder="Select an environment">
|
||||
<span>{{ $select.selected.Name }}</span>
|
||||
</ui-select-match>
|
||||
<ui-select-choices group-by="$ctrl.groupEndpoints" group-filter="$ctrl.sortGroups" repeat="endpoint in ($ctrl.endpoints | filter: $select.search) track by endpoint.Id">
|
||||
<span>{{ endpoint.Name }}</span>
|
||||
</ui-select-choices>
|
||||
</ui-select>
|
|
@ -1,35 +0,0 @@
|
|||
import _ from 'lodash-es';
|
||||
|
||||
angular.module('portainer.app').controller('EndpointSelectorController', function () {
|
||||
var ctrl = this;
|
||||
|
||||
this.sortGroups = function (groups) {
|
||||
return _.sortBy(groups, ['name']);
|
||||
};
|
||||
|
||||
this.groupEndpoints = function (endpoint) {
|
||||
for (var i = 0; i < ctrl.availableGroups.length; i++) {
|
||||
var group = ctrl.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;
|
||||
});
|
||||
}
|
||||
});
|
|
@ -2,16 +2,19 @@ import { STACK_NAME_VALIDATION_REGEX } from '@/constants';
|
|||
|
||||
angular.module('portainer.app').controller('StackDuplicationFormController', [
|
||||
'Notifications',
|
||||
function StackDuplicationFormController(Notifications) {
|
||||
'$scope',
|
||||
function StackDuplicationFormController(Notifications, $scope) {
|
||||
var ctrl = this;
|
||||
|
||||
ctrl.environmentSelectorOptions = null;
|
||||
|
||||
ctrl.state = {
|
||||
duplicationInProgress: false,
|
||||
migrationInProgress: false,
|
||||
};
|
||||
|
||||
ctrl.formValues = {
|
||||
endpoint: null,
|
||||
endpointId: null,
|
||||
newName: '',
|
||||
};
|
||||
|
||||
|
@ -23,15 +26,24 @@ angular.module('portainer.app').controller('StackDuplicationFormController', [
|
|||
ctrl.migrateStack = migrateStack;
|
||||
ctrl.isMigrationButtonDisabled = isMigrationButtonDisabled;
|
||||
ctrl.isEndpointSelected = isEndpointSelected;
|
||||
ctrl.onChangeEnvironment = onChangeEnvironment;
|
||||
ctrl.$onChanges = $onChanges;
|
||||
|
||||
function isFormValidForMigration() {
|
||||
return ctrl.formValues.endpoint && ctrl.formValues.endpoint.Id;
|
||||
return ctrl.formValues.endpointId;
|
||||
}
|
||||
|
||||
function isFormValidForDuplication() {
|
||||
return isFormValidForMigration() && ctrl.formValues.newName && !ctrl.yamlError;
|
||||
}
|
||||
|
||||
function onChangeEnvironment(endpointId) {
|
||||
console.log({ endpointId });
|
||||
return $scope.$evalAsync(() => {
|
||||
ctrl.formValues.endpointId = endpointId;
|
||||
});
|
||||
}
|
||||
|
||||
function duplicateStack() {
|
||||
if (!ctrl.formValues.newName) {
|
||||
Notifications.error('Failure', null, 'Stack name is required for duplication');
|
||||
|
@ -40,7 +52,7 @@ angular.module('portainer.app').controller('StackDuplicationFormController', [
|
|||
ctrl.state.duplicationInProgress = true;
|
||||
ctrl
|
||||
.onDuplicate({
|
||||
endpointId: ctrl.formValues.endpoint.Id,
|
||||
endpointId: ctrl.formValues.endpointId,
|
||||
name: ctrl.formValues.newName ? ctrl.formValues.newName : undefined,
|
||||
})
|
||||
.finally(function () {
|
||||
|
@ -52,7 +64,7 @@ angular.module('portainer.app').controller('StackDuplicationFormController', [
|
|||
ctrl.state.migrationInProgress = true;
|
||||
ctrl
|
||||
.onMigrate({
|
||||
endpointId: ctrl.formValues.endpoint.Id,
|
||||
endpointId: ctrl.formValues.endpointId,
|
||||
name: ctrl.formValues.newName ? ctrl.formValues.newName : undefined,
|
||||
})
|
||||
.finally(function () {
|
||||
|
@ -65,11 +77,42 @@ angular.module('portainer.app').controller('StackDuplicationFormController', [
|
|||
}
|
||||
|
||||
function isTargetEndpointAndCurrentEquals() {
|
||||
return ctrl.formValues.endpoint && ctrl.formValues.endpoint.Id === ctrl.currentEndpointId;
|
||||
return ctrl.formValues.endpointId === ctrl.currentEndpointId;
|
||||
}
|
||||
|
||||
function isEndpointSelected() {
|
||||
return ctrl.formValues.endpoint && ctrl.formValues.endpoint.Id;
|
||||
return ctrl.formValues.endpointId;
|
||||
}
|
||||
|
||||
function $onChanges() {
|
||||
ctrl.environmentSelectorOptions = getOptions(ctrl.groups, ctrl.endpoints);
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
function getOptions(groups, environments) {
|
||||
if (!groups || !environments) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const groupSet = environments.reduce((groupSet, environment) => {
|
||||
const groupEnvironments = groupSet[environment.GroupId] || [];
|
||||
|
||||
return {
|
||||
...groupSet,
|
||||
[environment.GroupId]: [...groupEnvironments, { label: environment.Name, value: environment.Id }],
|
||||
};
|
||||
}, {});
|
||||
|
||||
return Object.entries(groupSet).map(([groupId, environments]) => {
|
||||
const group = groups.find((group) => group.Id === parseInt(groupId, 10));
|
||||
if (!group) {
|
||||
throw new Error('missing group');
|
||||
}
|
||||
|
||||
return {
|
||||
label: group.Name,
|
||||
options: environments,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<endpoint-selector ng-if="$ctrl.endpoints && $ctrl.groups" model="$ctrl.formValues.endpoint" endpoints="$ctrl.endpoints" groups="$ctrl.groups"></endpoint-selector>
|
||||
<div class="form-group" ng-if="$ctrl.endpoints && $ctrl.groups">
|
||||
<por-select value="$ctrl.formValues.endpointId" on-change="($ctrl.onChangeEnvironment)" options="$ctrl.environmentSelectorOptions"></por-select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
|
|
@ -17,6 +17,7 @@ type TeamAccessPolicies = Record<TeamId, AccessPolicy>;
|
|||
export type RegistryId = number;
|
||||
export interface Registry {
|
||||
Id: RegistryId;
|
||||
Name: string;
|
||||
}
|
||||
|
||||
interface RegistryAccess {
|
||||
|
|
|
@ -6,7 +6,8 @@ import AccessViewerPolicyModel from '../../models/access';
|
|||
|
||||
export default class AccessViewerController {
|
||||
/* @ngInject */
|
||||
constructor(Notifications, RoleService, UserService, GroupService, TeamService, TeamMembershipService, Authentication) {
|
||||
constructor($scope, Notifications, RoleService, UserService, GroupService, TeamService, TeamMembershipService, Authentication) {
|
||||
this.$scope = $scope;
|
||||
this.Notifications = Notifications;
|
||||
this.RoleService = RoleService;
|
||||
this.UserService = UserService;
|
||||
|
@ -17,40 +18,51 @@ export default class AccessViewerController {
|
|||
|
||||
this.limitedFeature = 'rbac-roles';
|
||||
this.users = [];
|
||||
this.selectedUserId = null;
|
||||
|
||||
this.onUserSelect = this.onUserSelect.bind(this);
|
||||
}
|
||||
|
||||
onUserSelect() {
|
||||
this.userRoles = [];
|
||||
const userRoles = {};
|
||||
const user = this.selectedUser;
|
||||
const userMemberships = _.filter(this.teamMemberships, { UserId: user.Id });
|
||||
onUserSelect(selectedUserId) {
|
||||
this.$scope.$evalAsync(() => {
|
||||
this.userRoles = [];
|
||||
this.selectedUserId = selectedUserId;
|
||||
|
||||
for (const [, endpoint] of _.entries(this.endpoints)) {
|
||||
let role = this.getRoleFromUserEndpointPolicy(user, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
const userRoles = {};
|
||||
const user = this.allUsers.find((user) => user.Id === selectedUserId);
|
||||
if (!user) {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
|
||||
role = this.getRoleFromUserEndpointGroupPolicy(user, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
const userMemberships = _.filter(this.teamMemberships, { UserId: user.value });
|
||||
|
||||
for (const [, endpoint] of _.entries(this.endpoints)) {
|
||||
let role = this.getRoleFromUserEndpointPolicy(user, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
}
|
||||
|
||||
role = this.getRoleFromUserEndpointGroupPolicy(user, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
}
|
||||
|
||||
role = this.getRoleFromTeamEndpointPolicies(userMemberships, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
}
|
||||
|
||||
role = this.getRoleFromTeamEndpointGroupPolicies(userMemberships, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
}
|
||||
}
|
||||
|
||||
role = this.getRoleFromTeamEndpointPolicies(userMemberships, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
continue;
|
||||
}
|
||||
|
||||
role = this.getRoleFromTeamEndpointGroupPolicies(userMemberships, endpoint);
|
||||
if (role) {
|
||||
userRoles[endpoint.Id] = role;
|
||||
}
|
||||
}
|
||||
|
||||
this.userRoles = _.values(userRoles);
|
||||
this.userRoles = _.values(userRoles);
|
||||
});
|
||||
}
|
||||
|
||||
findLowestRole(policies) {
|
||||
|
@ -150,7 +162,8 @@ export default class AccessViewerController {
|
|||
this.roles = _.keyBy(await this.RoleService.roles(), 'Id');
|
||||
this.teams = _.keyBy(await this.TeamService.teams(), 'Id');
|
||||
this.teamMemberships = await this.TeamMembershipService.memberships();
|
||||
this.users = await this.teamMemberUsers(this.allUsers, this.teamMemberships);
|
||||
const teamUsers = await this.teamMemberUsers(this.allUsers, this.teamMemberships);
|
||||
this.users = teamUsers.map((user) => ({ label: user.Username, value: user.Id }));
|
||||
} catch (err) {
|
||||
this.Notifications.error('Failure', err, 'Unable to retrieve accesses');
|
||||
}
|
||||
|
|
|
@ -12,14 +12,9 @@
|
|||
<div class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<span class="small text-muted" ng-if="$ctrl.users.length === 0"> No user available </span>
|
||||
<ui-select ng-if="$ctrl.users.length > 0" ng-model="$ctrl.selectedUser" ng-change="$ctrl.onUserSelect()">
|
||||
<ui-select-match placeholder="Select a user">
|
||||
<span>{{ $select.selected.Username }}</span>
|
||||
</ui-select-match>
|
||||
<ui-select-choices repeat="item in ($ctrl.users | filter: $select.search)">
|
||||
<span>{{ item.Username }}</span>
|
||||
</ui-select-choices>
|
||||
</ui-select>
|
||||
|
||||
<por-select ng-if="$ctrl.users.length > 0" value="$ctrl.selectedUserId" options="$ctrl.users" on-change="($ctrl.onUserSelect)" placeholder="'Select a user'">
|
||||
</por-select>
|
||||
</div>
|
||||
</div>
|
||||
<access-viewer-datatable table-key="access_viewer" dataset="$ctrl.userRoles" order-by="EndpointName" is-admin="$ctrl.isAdmin"> </access-viewer-datatable>
|
||||
|
|
|
@ -17,6 +17,9 @@ import { withI18nSuspense } from '@/react-tools/withI18nSuspense';
|
|||
import { SettingsFDO } from '@/react/portainer/settings/EdgeComputeView/SettingsFDO';
|
||||
import { SettingsOpenAMT } from '@/react/portainer/settings/EdgeComputeView/SettingsOpenAMT';
|
||||
import { InternalAuth } from '@/react/portainer/settings/AuthenticationView/InternalAuth';
|
||||
import { PorAccessControlFormTeamSelector } from '@/react/portainer/access-control/PorAccessControlForm/TeamsSelector';
|
||||
import { PorAccessControlFormUserSelector } from '@/react/portainer/access-control/PorAccessControlForm/UsersSelector';
|
||||
import { PorAccessManagementUsersSelector } from '@/react/portainer/access-control/AccessManagement/PorAccessManagementUsersSelector';
|
||||
|
||||
import { PageHeader } from '@@/PageHeader';
|
||||
import { TagSelector } from '@@/TagSelector';
|
||||
|
@ -29,6 +32,8 @@ import { DashboardItem } from '@@/DashboardItem';
|
|||
import { SearchBar } from '@@/datatables/SearchBar';
|
||||
import { FallbackImage } from '@@/FallbackImage';
|
||||
import { BadgeIcon } from '@@/BoxSelector/BadgeIcon';
|
||||
import { TeamsSelector } from '@@/TeamsSelector';
|
||||
import { PortainerSelect } from '@@/form-components/PortainerSelect';
|
||||
|
||||
import { fileUploadField } from './file-upload-field';
|
||||
import { switchField } from './switch-field';
|
||||
|
@ -140,4 +145,54 @@ export const componentsModule = angular
|
|||
.component(
|
||||
'internalAuth',
|
||||
r2a(InternalAuth, ['onSaveSettings', 'isLoading', 'value', 'onChange'])
|
||||
)
|
||||
.component(
|
||||
'teamsSelector',
|
||||
r2a(TeamsSelector, [
|
||||
'onChange',
|
||||
'value',
|
||||
'dataCy',
|
||||
'inputId',
|
||||
'name',
|
||||
'placeholder',
|
||||
'teams',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'porAccessControlFormTeamSelector',
|
||||
r2a(PorAccessControlFormTeamSelector, [
|
||||
'inputId',
|
||||
'onChange',
|
||||
'options',
|
||||
'value',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'porAccessControlFormUserSelector',
|
||||
r2a(PorAccessControlFormUserSelector, [
|
||||
'inputId',
|
||||
'onChange',
|
||||
'options',
|
||||
'value',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'porSelect',
|
||||
r2a(PortainerSelect, [
|
||||
'name',
|
||||
'inputId',
|
||||
'placeholder',
|
||||
'disabled',
|
||||
'data-cy',
|
||||
'bindToBody',
|
||||
'value',
|
||||
'onChange',
|
||||
'options',
|
||||
'isMulti',
|
||||
'isClearable',
|
||||
])
|
||||
)
|
||||
.component(
|
||||
'porAccessManagementUsersSelector',
|
||||
r2a(PorAccessManagementUsersSelector, ['onChange', 'options', 'value'])
|
||||
).name;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export default class LdapCustomAdminGroupController {
|
||||
/* @ngInject */
|
||||
constructor($async, Notifications, LDAPService) {
|
||||
Object.assign(this, { $async, Notifications, LDAPService });
|
||||
constructor($async, $scope, Notifications, LDAPService) {
|
||||
Object.assign(this, { $async, $scope, Notifications, LDAPService });
|
||||
|
||||
this.groups = null;
|
||||
this.groupstest = null;
|
||||
|
@ -10,6 +10,7 @@ export default class LdapCustomAdminGroupController {
|
|||
this.onRemoveClick = this.onRemoveClick.bind(this);
|
||||
this.onAddClick = this.onAddClick.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
this.onAdminGroupChange = this.onAdminGroupChange.bind(this);
|
||||
}
|
||||
|
||||
onAddClick() {
|
||||
|
@ -24,7 +25,8 @@ export default class LdapCustomAdminGroupController {
|
|||
return this.$async(async () => {
|
||||
try {
|
||||
this.groups = null;
|
||||
this.groups = await this.onSearchClick();
|
||||
const groups = await this.onSearchClick();
|
||||
this.groups = groups.map((group) => ({ label: group.name, value: group.name }));
|
||||
this.enableAssignAdminGroup = this.groups && this.groups.length > 0;
|
||||
} catch (error) {
|
||||
this.Notifications.error('Failure', error, 'Failed to search groups');
|
||||
|
@ -32,14 +34,15 @@ export default class LdapCustomAdminGroupController {
|
|||
});
|
||||
}
|
||||
|
||||
onAdminGroupChange(value) {
|
||||
return this.$scope.$evalAsync(() => {
|
||||
this.selectedAdminGroups = value;
|
||||
});
|
||||
}
|
||||
|
||||
async $onInit() {
|
||||
if (this.settings.AdminAutoPopulate && this.settings.AdminGroups && this.settings.AdminGroups.length > 0) {
|
||||
const settings = {
|
||||
...this.settings,
|
||||
AdminGroupSearchSettings: this.settings.AdminGroupSearchSettings.map((search) => ({ ...search, GroupFilter: search.GroupFilter || this.defaultAdminGroupSearchFilter })),
|
||||
};
|
||||
|
||||
this.groups = await this.LDAPService.adminGroups(settings);
|
||||
await this.search();
|
||||
}
|
||||
|
||||
if (this.groups && this.groups.length > 0) {
|
||||
|
|
|
@ -114,22 +114,18 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-if="$ctrl.settings.AdminAutoPopulate">
|
||||
<div class="col-sm-12">
|
||||
<label for="group-access" class="control-label text-left"> Select Group(s) </label>
|
||||
<span
|
||||
class="ml-7"
|
||||
isteven-multi-select
|
||||
ng-if="$ctrl.enableAssignAdminGroup"
|
||||
input-model="$ctrl.groups"
|
||||
output-model="$ctrl.selectedAdminGroups"
|
||||
button-label="name"
|
||||
item-label="name"
|
||||
tick-property="selected"
|
||||
helper-elements="filter"
|
||||
search-property="name"
|
||||
translation="{nothingSelected: 'Select one or more groups', search: 'Search...'}"
|
||||
<div class="form-group" ng-if="$ctrl.settings.AdminAutoPopulate && $ctrl.groups">
|
||||
<label for="group-access" class="control-label text-left col-sm-2"> Select Group(s) </label>
|
||||
<div class="col-sm-8">
|
||||
<por-select
|
||||
data-cy="'group-access-selector'"
|
||||
input-id="'group-access'"
|
||||
value="$ctrl.selectedAdminGroups"
|
||||
on-change="($ctrl.onAdminGroupChange)"
|
||||
options="$ctrl.groups"
|
||||
placeholder="'Select one or more groups'"
|
||||
is-multi="true"
|
||||
>
|
||||
</span>
|
||||
</por-select>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -105,25 +105,20 @@
|
|||
<!-- !admin-checkbox -->
|
||||
<!-- teams -->
|
||||
<div class="form-group" ng-if="!formValues.Administrator">
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left">Add to team(s)</label>
|
||||
<label class="col-sm-3 col-lg-2 control-label text-left" for="teams-selector">Add to team(s)</label>
|
||||
<div class="col-sm-8">
|
||||
<span class="small text-muted" ng-if="teams.length === 0">
|
||||
You don't seem to have any teams to add users into. Head over to the <a ui-sref="portainer.teams">Teams view</a> to create some.
|
||||
</span>
|
||||
<span
|
||||
isteven-multi-select
|
||||
<teams-selector
|
||||
ng-if="teams.length > 0"
|
||||
input-model="teams"
|
||||
output-model="formValues.Teams"
|
||||
button-label="Name"
|
||||
item-label="Name"
|
||||
tick-property="ticked"
|
||||
helper-elements="filter"
|
||||
search-property="Name"
|
||||
translation="{nothingSelected: 'Select one or more teams', search: 'Search...'}"
|
||||
data-cy="user-teamSelect"
|
||||
>
|
||||
</span>
|
||||
value="formValues.TeamIds"
|
||||
teams="teams"
|
||||
placeholder="'Select one or more teams'"
|
||||
data-cy="'user-teamSelect'"
|
||||
on-change="(onChangeTeamIds)"
|
||||
input-id="'teams-selector'"
|
||||
></teams-selector>
|
||||
</div>
|
||||
</div>
|
||||
<!-- !teams -->
|
||||
|
|
|
@ -23,7 +23,7 @@ angular.module('portainer.app').controller('UsersController', [
|
|||
Password: '',
|
||||
ConfirmPassword: '',
|
||||
Administrator: false,
|
||||
Teams: [],
|
||||
TeamIds: [],
|
||||
};
|
||||
|
||||
$scope.handleAdministratorChange = function (checked) {
|
||||
|
@ -32,6 +32,12 @@ angular.module('portainer.app').controller('UsersController', [
|
|||
});
|
||||
};
|
||||
|
||||
$scope.onChangeTeamIds = function (teamIds) {
|
||||
return $scope.$evalAsync(() => {
|
||||
$scope.formValues.TeamIds = teamIds;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.checkUsernameValidity = function () {
|
||||
var valid = true;
|
||||
for (var i = 0; i < $scope.users.length; i++) {
|
||||
|
@ -50,11 +56,7 @@ angular.module('portainer.app').controller('UsersController', [
|
|||
var username = $scope.formValues.Username;
|
||||
var password = $scope.formValues.Password;
|
||||
var role = $scope.formValues.Administrator ? 1 : 2;
|
||||
var teamIds = [];
|
||||
angular.forEach($scope.formValues.Teams, function (team) {
|
||||
teamIds.push(team.Id);
|
||||
});
|
||||
UserService.createUser(username, password, role, teamIds)
|
||||
UserService.createUser(username, password, role, $scope.formValues.TeamIds)
|
||||
.then(function success() {
|
||||
Notifications.success('User successfully created', username);
|
||||
$state.reload();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue