2020-06-18 12:57:12 +02:00
<!-- Modal subscription -->
< div class = "modal fade" id = "subscriptionRequiredModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.subscriptionDialog.title' | tr }}< / h4 >
2020-06-18 12:57:12 +02:00
< / div >
< div class = "modal-body" >
2021-01-13 16:54:25 +01:00
< p > To add more users, please setup a paid plain.< / p >
2020-06-18 12:57:12 +02:00
< / div >
< div class = "modal-footer" >
2021-01-13 15:03:26 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "openSubscriptionSetup()" > {{ 'users.subscriptionDialog.setupAction' | tr }}< / button >
< / div >
< / div >
< / div >
< / div >
<!-- Modal subscription group -->
< div class = "modal fade" id = "subscriptionRequiredGroupModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h4 class = "modal-title" > {{ 'users.subscriptionDialog.title' | tr }}< / h4 >
< / div >
< div class = "modal-body" >
2021-01-13 16:54:25 +01:00
< p > User groups are part of the business plan.< / p >
2021-01-13 15:03:26 +01:00
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "openSubscriptionSetup()" > {{ 'users.subscriptionDialog.setupAction' | tr }}< / button >
2020-06-18 12:57:12 +02:00
< / div >
< / div >
< / div >
< / div >
2018-01-22 13:01:38 -08:00
<!-- Modal add user -->
< div class = "modal fade" id = "userAddModal" tabindex = "-1" role = "dialog" >
2020-11-13 16:44:39 +01:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h4 class = "modal-title" > {{ 'users.addUserDialog.title' | tr }}< / h4 >
< / div >
< div class = "modal-body" >
< form name = "useradd_form" role = "form" ng-submit = "useradd.submit()" autocomplete = "off" >
< div class = "form-group" ng-class = "{ 'has-error': (useradd_form.displayName.$dirty && useradd_form.displayName.$invalid) || (!useradd_form.displayName.$dirty && useradd.error.displayName) }" >
< label class = "control-label" > {{ 'users.user.fullName' | tr }}< / label >
2021-09-16 09:05:40 +02:00
< input type = "text" class = "form-control" ng-model = "useradd.displayName" name = "displayName" id = "inputUserAddDisplayName" ng-required autofocus autocomplete = "off" >
2020-11-13 16:44:39 +01:00
< div class = "control-label" ng-show = "(!useradd_form.displayName.$dirty && useradd.error.displayName) || (useradd_form.displayName.$dirty && useradd_form.displayName.$invalid) || (!useradd_form.displayName.$dirty && useradd.error.displayName)" >
< small ng-show = "useradd_form.displayName.$error.displayName" > {{ 'users.user.errorNotValidFullName' | tr }}< / small >
< small ng-show = "!useradd_form.displayName.$dirty && useradd.error.displayName" > {{ useradd.error.displayName }}< / small >
< / div >
< / div >
< input type = "password" style = "display: none;" >
< div class = "form-group" ng-class = "{ 'has-error': (useradd_form.email.$dirty && useradd_form.email.$invalid) || (!useradd_form.email.$dirty && useradd.error.email) }" >
< label class = "control-label" > {{ 'users.user.email' | tr }}< / label >
2021-09-16 09:05:40 +02:00
< input type = "email" class = "form-control" ng-model = "useradd.email" name = "email" id = "inputUserAddEmail" required >
2020-11-13 16:44:39 +01:00
< div class = "control-label" ng-show = "(!useradd_form.email.$dirty && useradd.error.email) || (useradd_form.email.$dirty && useradd_form.email.$invalid) || (!useradd_form.email.$dirty && useradd.error.email)" >
< small ng-show = "useradd_form.email.$error.required" > {{ 'users.user.errorEmailRequired' | tr }}< / small >
< small ng-show = "useradd_form.email.$error.email" > {{ 'users.user.errorInvalidEmail' | tr }}< / small >
< small ng-show = "!useradd_form.email.$dirty && useradd.error.email" > {{ useradd.error.email }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
< div class = "form-group" ng-class = "{ 'has-error': (useradd_form.username.$dirty && useradd_form.username.$invalid) || (!useradd_form.username.$dirty && useradd.error.username) }" >
< label class = "control-label" > {{ 'users.user.username' | tr }}< / label >
2021-09-16 09:05:40 +02:00
< input type = "text" class = "form-control" ng-model = "useradd.username" name = "username" id = "inputUserAddUsername" placeholder = "{{ 'users.user.usernamePlaceholder' | tr }}" >
2020-11-13 16:44:39 +01:00
< div class = "control-label" ng-show = "(!useradd_form.username.$dirty && useradd.error.username) || (useradd_form.username.$dirty && useradd_form.username.$invalid) || (!useradd_form.username.$dirty && useradd.error.username)" >
< small ng-show = "useradd_form.username.$error.username" > {{ 'users.user.errorInvalidUsername' | tr }}< / small >
< small ng-show = "!useradd_form.username.$dirty && useradd.error.username" > {{ useradd.error.username }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
< div class = "form-group" ng-show = "userInfo.isAtLeastAdmin" >
< label class = "control-label" > {{ 'users.user.role' | tr }} < sup > < a ng-href = "https://docs.cloudron.io/user-management/#roles" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup > < / label >
< div class = "control-label" >
2021-01-13 16:19:14 +01:00
< select class = "form-control" uib-tooltip = "{{ config.features.userRoles ? '' : 'Only available in the business plan' }}" ng-disabled = "!config.features.userRoles" ng-model = "useradd.role" ng-options = "role.id as role.name disable when role.disabled for role in roles" > < / select >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
< div class = "form-group" >
< label class = "control-label" > {{ 'users.user.groups' | tr }}< / label >
< div class = "control-label" >
< div ng-show = "groups.length === 0" > {{ 'users.user.noGroups' | tr }}< / div >
< multiselect ng-show = "groups.length !== 0" ng-model = "useradd.selectedGroups" options = "group.name for group in groups" data-compare-by = "name" data-multiple = "true" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
< / div >
< / div >
< input class = "ng-hide" type = "submit" ng-disabled = "useradd_form.$invalid || useradd.busy" / >
< / form >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "useradd.submit()" ng-disabled = "useradd_form.$invalid || useradd.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "useradd.busy" > < / i > {{ 'users.addUserDialog.addUserAction' | tr }}< / button >
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2021-01-14 17:14:32 +01:00
<!-- Modal transfer ownership -->
< div class = "modal fade" id = "transferOwnershipModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2021-01-19 22:26:43 +01:00
< h4 class = "modal-title" > {{ 'users.transferOwnershipDialog.title' | tr }}< / h4 >
2021-01-14 17:14:32 +01:00
< / div >
< div class = "modal-body" >
< p class = "text-bold text-danger" ng-show = "transferOwnership.error" > {{ transferOwnership.error }}< / p >
2021-01-19 22:27:55 +01:00
< p > {{ 'users.transferOwnershipDialog.description' | tr }}< / p >
2021-01-19 22:26:43 +01:00
< div class = "form-group" >
2021-01-19 22:27:55 +01:00
< label class = "control-label" > {{ 'users.transferOwnershipDialog.newOwner' | tr }}< / label >
2021-01-19 22:26:43 +01:00
< div class = "control-label" >
< multiselect ng-model = "transferOwnership.selectedUser" options = "user.username for user in users" data-compare-by = "id" data-multiple = "false" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
< / div >
< / div >
2021-01-14 17:14:32 +01:00
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
2021-01-19 22:26:43 +01:00
< button type = "button" class = "btn btn-danger" ng-click = "transferOwnership.submit()" ng-hide = "transferOwnership.error" ng-disabled = "!transferOwnership.selectedUser || transferOwnership.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "transferOwnership.busy" > < / i > {{ 'users.transferOwnershipDialog.transferAction' | tr }}< / button >
2021-01-14 17:14:32 +01:00
< / div >
< / div >
< / div >
< / div >
2018-01-22 13:01:38 -08:00
<!-- Modal remove user -->
< div class = "modal fade" id = "userRemoveModal" tabindex = "-1" role = "dialog" >
2019-05-13 23:55:54 +02:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.deleteUserDialog.title' | tr:{ username: (userremove.userInfo.username || userremove.userInfo.email) } }}< / h4 >
2019-05-13 23:55:54 +02:00
< / div >
< div class = "modal-body" >
2020-03-06 12:23:50 -08:00
< p class = "text-bold text-danger" ng-show = "userremove.error" > {{ userremove.error }}< / p >
2020-11-13 16:44:39 +01:00
< p ng-hide = "userremove.error" > {{ 'users.deleteUserDialog.description' | tr }}< / p >
2019-05-13 23:55:54 +02:00
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-danger" ng-click = "userremove.submit()" ng-hide = "userremove.error" ng-disabled = "userremove.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "userremove.busy" > < / i > {{ 'users.deleteUserDialog.deleteAction' | tr }}< / button >
2019-05-13 23:55:54 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-05-13 23:55:54 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
<!-- Modal edit user -->
< div class = "modal fade" id = "userEditModal" tabindex = "-1" role = "dialog" >
2019-08-30 13:32:20 +02:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.editUserDialog.title' | tr:{ username: (useredit.userInfo.username || useredit.userInfo.email) } }}< / h4 >
2019-08-30 13:32:20 +02:00
< / div >
< div class = "modal-body" >
< div ng-show = "useredit.source" >
2020-11-13 16:44:39 +01:00
< p class = "text-warning" > {{ 'users.editUserDialog.externalLdapWarning' | tr }}< / p >
< p > < label > {{ 'users.user.displayName' | tr }}< / label > < br / > < input type = "text" class = "form-control" ng-disabled = "true" ng-model = "useredit.displayName" >
< p > < label > {{ 'users.user.email' | tr }}< / label > < br / > < input type = "text" class = "form-control" ng-disabled = "true" ng-model = "useredit.email" > < / p >
2019-08-30 13:32:20 +02:00
< / div >
< form name = "useredit_form" role = "form" ng-submit = "useredit.submit()" autocomplete = "off" >
2020-10-23 11:47:37 -07:00
< p class = "has-error text-center" ng-show = "useredit.error.generic" > {{ useredit.error.generic }}< / p >
2019-08-30 13:32:20 +02:00
< div class = "form-group" ng-hide = "useredit.source" ng-class = "{ 'has-error': (useredit_form.displayName.$dirty && useredit_form.displayName.$invalid) || (!useredit_form.displayName.$dirty && useredit.error.displayName) }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.user.displayName' | tr }}< / label >
2019-08-30 13:32:20 +02:00
< div class = "control-label" ng-show = "(!useredit_form.displayName.$dirty && useredit.error.displayName) || (useredit_form.displayName.$dirty && useredit_form.displayName.$invalid) || (!useredit_form.displayName.$dirty && useredit.error.displayName)" >
2020-11-13 16:44:39 +01:00
< small ng-show = "useredit_form.displayName.$error.required" > {{ 'users.user.errorDisplayNameRequired' | tr }}< / small >
2019-08-30 13:32:20 +02:00
< small ng-show = "!useredit_form.displayName.$dirty && useredit.error.displayName" > {{ useredit.error.displayName }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2019-08-30 13:32:20 +02:00
< input type = "text" class = "form-control" ng-model = "useredit.displayName" name = "displayName" required autofocus autocomplete = "off" >
< / div >
< div class = "form-group" ng-hide = "useredit.source" ng-class = "{ 'has-error': (useredit_form.email.$dirty && useredit_form.email.$invalid) || (!useredit_form.email.$dirty && useredit.error.email) }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.user.primaryEmail' | tr }}< / label >
2019-08-30 13:32:20 +02:00
< div class = "control-label" ng-show = "(!useredit_form.email.$dirty && useredit.error.email) || (useredit_form.email.$dirty && useredit_form.email.$invalid) || (!useredit_form.email.$dirty && useredit.error.email)" >
2020-11-13 16:44:39 +01:00
< small ng-show = "useredit_form.email.$error.required" > {{ 'users.user.errorEmailRequired' | tr }}< / small >
< small ng-show = "useredit_form.email.$error.email" > {{ 'users.user.errorInvalidEmail' | tr }}< / small >
2019-08-30 13:32:20 +02:00
< small ng-show = "!useredit_form.email.$dirty && useredit.error.email" > {{ useredit.error.email }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2019-08-30 13:32:20 +02:00
< input type = "email" class = "form-control" ng-model = "useredit.email" name = "email" required >
< / div >
< div class = "form-group" ng-hide = "useredit.source" ng-class = "{ 'has-error': (useredit_form.fallbackEmail.$dirty && useredit_form.fallbackEmail.$invalid) || (!useredit_form.fallbackEmail.$dirty && useredit.error.fallbackEmail) }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.user.recoveryEmail' | tr }}< / label >
2019-08-30 13:32:20 +02:00
< div class = "control-label" ng-show = "(!useredit_form.fallbackEmail.$dirty && useredit.error.fallbackEmail) || (useredit_form.fallbackEmail.$dirty && useredit_form.fallbackEmail.$invalid) || (!useredit_form.fallbackEmail.$dirty && useredit.error.fallbackEmail)" >
2020-11-13 16:44:39 +01:00
< small ng-show = "useredit_form.fallbackEmail.$error.required" > {{ 'users.user.errorEmailRequired' | tr }}< / small >
< small ng-show = "useredit_form.fallbackEmail.$error.fallbackEmail" > {{ 'users.user.errorInvalidEmail' | tr }}< / small >
2019-08-30 13:32:20 +02:00
< small ng-show = "!useredit_form.fallbackEmail.$dirty && useredit.error.fallbackEmail" > {{ useredit.error.fallbackEmail }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2019-08-30 13:32:20 +02:00
< input type = "fallbackEmail" class = "form-control" ng-model = "useredit.fallbackEmail" name = "fallbackEmail" required >
< / div >
2020-03-06 12:33:36 -08:00
< div class = "form-group" ng-show = "!isMe(useredit.userInfo) && userInfo.isAtLeastAdmin" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.user.role' | tr }} < sup > < a ng-href = "https://docs.cloudron.io/user-management/#roles" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup > < / label >
2020-02-21 21:12:25 +01:00
< div class = "control-label" >
2021-01-13 16:19:14 +01:00
< select class = "form-control" uib-tooltip = "{{ config.features.userRoles ? '' : 'Only available in the business plan' }}" ng-disabled = "!config.features.userRoles" ng-model = "useredit.role" ng-options = "role.id as role.name disable when role.disabled for role in roles" > < / select >
2020-02-17 14:05:26 +01:00
< / div >
2019-08-30 13:32:20 +02:00
< / div >
2020-02-22 17:51:30 +01:00
< div class = "form-group" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.user.groups' | tr }}< / label >
2020-02-22 17:51:30 +01:00
< div class = "control-label" >
2020-11-13 16:44:39 +01:00
< div ng-show = "groups.length === 0" > {{ 'users.user.noGroups' | tr }}< / div >
2020-02-22 17:51:30 +01:00
< multiselect ng-show = "groups.length !== 0" ng-model = "useredit.selectedGroups" options = "group.name for group in groups" data-compare-by = "id" data-multiple = "true" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
< / div >
< / div >
2019-08-30 13:32:20 +02:00
< div class = "form-group" ng-hide = "isMe(useredit.userInfo)" >
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "useredit.active" > {{ 'users.user.activeCheckbox' | tr }} < sup > < a ng-href = "https://docs.cloudron.io/user-management/#disable-user" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup >
2019-08-30 13:32:20 +02:00
< / label >
< / div >
< / div >
< input class = "hide" type = "submit" ng-disabled = "useredit_form.$invalid || useredit.busy" / >
< / form >
< / div >
< div class = "modal-footer" >
2021-09-16 13:21:55 +02:00
< button type = "button" class = "btn btn-danger pull-left" ng-click = "useredit.reset2FA()" uib-tooltip = "{{ (useredit.userInfo.twoFactorAuthenticationEnabled ? 'users.passwordResetDialog.2FAIsSetup' : 'users.passwordResetDialog.no2FASetup') | tr }}" ng-disabled = "!useredit.userInfo.twoFactorAuthenticationEnabled || useredit.reset2FABusy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "useredit.reset2FABusy" > < / i > {{ 'users.passwordResetDialog.reset2FAAction' | tr }}< / button >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "useredit.submit()" ng-disabled = "useredit_form.$invalid || useredit.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "useredit.busy" > < / i > {{ 'main.dialog.save' | tr }}< / button >
2019-08-30 13:32:20 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-08-30 13:32:20 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
<!-- Modal add group -->
< div class = "modal fade" id = "groupAddModal" tabindex = "-1" role = "dialog" >
2019-11-05 22:08:48 +01:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.addGroupDialog.title' | tr }}< / h4 >
2019-11-05 22:08:48 +01:00
< / div >
< div class = "modal-body" >
< form name = "groupAddForm" role = "form" novalidate ng-submit = "groupAdd.submit()" autocomplete = "off" >
< div class = "form-group" ng-class = "{ 'has-error': (groupAddForm.name.$dirty && groupAddForm.name.$invalid) || (!groupAddForm.name.$dirty && groupAdd.error.name) }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "groupAddName" > {{ 'users.group.name' | tr }}< / label >
2019-11-05 22:08:48 +01:00
< div class = "control-label" ng-show = "(!groupAddForm.name.$dirty && groupAdd.error.name) || (groupAddForm.name.$dirty && groupAddForm.name.$invalid) || (!groupAddForm.name.$dirty && groupAdd.error.name)" >
2020-11-13 16:44:39 +01:00
< small ng-show = "groupAddForm.name.$error.required" > {{ 'users.group.errorNameRequired' | tr }}< / small >
< small ng-show = "groupAddForm.name.$error.minlength" > {{ 'users.group.errorNameTooShort' | tr }}< / small >
< small ng-show = "groupAddForm.name.$error.maxlength" > {{ 'users.group.errorNameTooLong' | tr }}< / small >
2019-11-05 22:08:48 +01:00
< small ng-show = "!groupAddForm.name.$dirty && groupAdd.error.name" > {{ groupAdd.error.name }}< / small >
2018-01-22 13:01:38 -08:00
< / div >
2019-11-05 22:08:48 +01:00
< input type = "text" class = "form-control" ng-model = "groupAdd.name" id = "groupAddName" name = "name" ng-maxlength = "200" ng-minlength = "1" required autofocus >
< / div >
< div class = "form-group" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.group.users' | tr }}< / label >
2019-11-05 22:08:48 +01:00
< div class = "control-label" >
< multiselect ng-model = "groupAdd.selectedUsers" options = "(user.username || user.email) for user in allUsers" data-compare-by = "email" data-multiple = "true" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
2018-01-22 13:01:38 -08:00
< / div >
2019-11-05 22:08:48 +01:00
< / div >
< input class = "hide" type = "submit" ng-disabled = "groupAddForm.$invalid || groupAdd.busy" / >
< / form >
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "groupAdd.submit()" ng-disabled = "groupAddForm.$invalid || groupAdd.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "groupAdd.busy" > < / i > {{ 'users.group.addGroupAction' | tr }}< / button >
2019-11-05 22:08:48 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-11-05 22:08:48 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2018-06-18 17:45:09 -07:00
<!-- Modal edit group -->
< div class = "modal fade" id = "groupEditModal" tabindex = "-1" role = "dialog" >
2019-11-05 22:08:48 +01:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.editGroupDialog.title' | tr:{ name: groupEdit.groupInfo.name } }}< / h4 >
2019-11-05 22:08:48 +01:00
< / div >
< div class = "modal-body" >
2020-11-13 16:44:39 +01:00
< p class = "text-warning" ng-show = "groupEdit.source" > {{ 'users.editGroupDialog.externalLdapWarning' | tr }}< / p >
2020-06-05 08:18:40 +02:00
2019-11-05 22:08:48 +01:00
< form name = "groupEdit_form" role = "form" ng-submit = "groupEdit.submit()" autocomplete = "off" >
< div class = "form-group" ng-class = "{ 'has-error': groupEditForm.groupName.$invalid }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.group.name' | tr }}< / label >
2020-06-05 08:18:40 +02:00
< input type = "text" class = "form-control" ng-model = "groupEdit.name" name = "groupName" ng-disabled = "groupEdit.busy || groupEdit.source" autofocus >
2019-11-05 22:08:48 +01:00
< / div >
< div class = "form-group" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" > {{ 'users.group.users' | tr }}< / label >
2019-11-05 22:08:48 +01:00
< div class = "control-label" >
< multiselect ng-model = "groupEdit.selectedUsers" options = "(user.username || user.email) for user in allUsers" data-compare-by = "email" data-multiple = "true" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
2018-06-18 17:45:09 -07:00
< / div >
2019-11-05 22:08:48 +01:00
< / div >
2021-02-18 17:01:49 +01:00
< div class = "form-group" >
< label class = "control-label" > Access to Apps< / label >
< div class = "control-label" >
< multiselect ng-model = "groupEdit.selectedApps" options = "(app.label || app.fqdn) for app in groupEdit.apps" data-compare-by = "fqdn" data-multiple = "true" filter-after-rows = "5" scroll-after-rows = "10" > < / multiselect >
< / div >
< / div >
2019-11-05 22:08:48 +01:00
< input class = "hide" type = "submit" ng-disabled = "groupEdit_form.$invalid || useredit.busy" / >
< / form >
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-success" ng-click = "groupEdit.submit()" ng-disabled = "groupEdit_form.$invalid || groupEdit.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "groupEdit.busy" > < / i > {{ 'main.dialog.save' | tr }}< / button >
2019-11-05 22:08:48 +01:00
< / div >
2018-06-18 17:45:09 -07:00
< / div >
2019-11-05 22:08:48 +01:00
< / div >
2018-06-18 17:45:09 -07:00
< / div >
2018-01-22 13:01:38 -08:00
<!-- Modal remove group -->
< div class = "modal fade" id = "groupRemoveModal" tabindex = "-1" role = "dialog" >
2019-05-13 23:55:54 +02:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.deleteGroupDialog.title' | tr:{ name: groupRemove.group.name } }}< / h4 >
2019-05-13 23:55:54 +02:00
< / div >
< div class = "modal-body" >
< div ng-show = "groupRemove.memberCount" class = "text-danger" >
2020-11-13 16:44:39 +01:00
< b > {{ 'users.deleteGroupDialog.description' | tr:{ memberCount: groupRemove.memberCount } }}< / b >
2019-05-13 23:55:54 +02:00
< br / >
< br / >
2018-01-22 13:01:38 -08:00
< / div >
2019-05-13 23:55:54 +02:00
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-danger" ng-click = "groupRemove.submit()" ng-disabled = "groupRemove.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "groupRemove.busy" > < / i > {{ 'users.deleteGroupDialog.deleteAction' | tr }}< / button >
2019-05-13 23:55:54 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-05-13 23:55:54 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2021-09-16 14:35:17 +02:00
<!-- Modal password reset -->
< div class = "modal fade" id = "passwordResetModal" tabindex = "-1" role = "dialog" >
2020-11-13 16:44:39 +01:00
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2021-09-16 14:35:17 +02:00
< h4 class = "modal-title" > {{ 'users.passwordResetDialog.title' | tr:{ username: (passwordReset.user.username || passwordReset.user.email) } }}< / h4 >
2020-11-13 16:44:39 +01:00
< / div >
< div class = "modal-body" >
2021-09-16 14:35:17 +02:00
< div ng-hide = "passwordReset.resetLink" >
2021-04-15 17:38:32 +02:00
< p > {{ 'users.passwordResetDialog.resetLinkExplanation' | tr }}< / p >
2021-09-16 14:35:17 +02:00
< button type = "button" class = "btn btn-primary" ng-click = "passwordReset.submit()" ng-disabled = "passwordReset.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "passwordReset.busy" > < / i > {{ 'users.passwordResetDialog.newLinkAction' | tr }}< / button >
2021-04-15 17:16:15 +02:00
< / div >
2021-09-16 14:35:17 +02:00
< div ng-show = "passwordReset.resetLink" >
2021-09-16 16:03:07 +02:00
< p > {{ 'users.passwordResetDialog.description' | tr:{ email: passwordReset.user.fallbackEmail } }}< / p >
2021-04-15 17:16:15 +02:00
< div class = "input-group" style = "margin-bottom: 10px" >
2021-09-16 14:35:17 +02:00
< input type = "text" id = "passwordResetLinkInput" class = "form-control" ng-value = "passwordReset.resetLink" readonly / >
2021-04-15 17:16:15 +02:00
< span class = "input-group-btn" >
2021-09-16 14:35:17 +02:00
< button class = "btn btn-default" id = "setupLinkButton" type = "button" data-clipboard-target = "#passwordResetLinkInput" > < i class = "fa fa-clipboard" > < / i > < / button >
2021-04-15 17:16:15 +02:00
< / span >
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
< div class = "modal-footer" >
2021-04-15 17:16:15 +02:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.close' | tr }}< / button >
2020-11-13 16:44:39 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2021-09-16 15:46:26 +02:00
<!-- Modal invitation -->
< div class = "modal fade" id = "invitationModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
< h4 class = "modal-title" > {{ 'users.invitationDialog.title' | tr:{ username: (invitation.user.username || invitation.user.email) } }}< / h4 >
< / div >
< div class = "modal-body" >
< div ng-hide = "invitation.inviteLink" >
< p > {{ 'users.invitationDialog.inviteLinkExplanation' | tr }}< / p >
< button type = "button" class = "btn btn-primary" ng-click = "invitation.submit()" ng-disabled = "invitation.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "invitation.busy" > < / i > {{ 'users.invitationDialog.newLinkAction' | tr }}< / button >
< / div >
< div ng-show = "invitation.inviteLink" >
2021-09-16 16:03:07 +02:00
< p > {{ 'users.invitationDialog.description' | tr:{ email: invitation.user.fallbackEmail } }}< / p >
2021-09-16 15:46:26 +02:00
< div class = "input-group" style = "margin-bottom: 10px" >
< input type = "text" id = "invitationLinkInput" class = "form-control" ng-value = "invitation.inviteLink" readonly / >
< span class = "input-group-btn" >
< button class = "btn btn-default" id = "setupLinkButton" type = "button" data-clipboard-target = "#invitationLinkInput" > < i class = "fa fa-clipboard" > < / i > < / button >
< / span >
< / div >
< / div >
< / div >
< div class = "modal-footer" >
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.close' | tr }}< / button >
< / div >
< / div >
< / div >
< / div >
2019-08-30 12:40:23 +02:00
<!-- Modal external ldap -->
< div class = "modal fade" id = "externalLdapModal" tabindex = "-1" role = "dialog" >
< div class = "modal-dialog" >
< div class = "modal-content" >
< div class = "modal-header" >
2020-11-13 16:44:39 +01:00
< h4 class = "modal-title" > {{ 'users.externalLdapDialog.title' | tr }}< / h4 >
2019-08-30 12:40:23 +02:00
< / div >
< div class = "modal-body" >
2019-10-25 16:13:52 -07:00
< p class = "has-error text-center" ng-show = "externalLdap.error.generic" > {{ externalLdap.error.generic }}< / p >
2019-10-25 15:38:04 -07:00
< div class = "form-group" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "ldapProvider" > {{ 'users.externalLdap.provider' | tr }} < sup > < a ng-href = "https://docs.cloudron.io/user-management/#external-ldap" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup > < / label >
2019-10-25 15:38:04 -07:00
< select class = "form-control" id = "ldapProvider" ng-model = "externalLdap.provider" ng-options = "a.value as a.name for a in ldapProvider" > < / select >
2019-08-30 12:40:23 +02:00
< / div >
2019-10-25 15:38:04 -07:00
< div uib-collapse = "externalLdap.provider === 'noop'" >
2019-08-30 12:40:23 +02:00
< form name = "externalLdapConfigForm" role = "form" novalidate ng-submit = "externalLdap.submit()" autocomplete = "off" >
< fieldset >
<!-- avoid browsers to attempt an autofill for bindDN/bindPassword -->
< input type = "password" style = "display: none;" >
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.url }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigUrl" > {{ 'users.externalLdap.server' | tr }}< / label >
2019-10-25 15:38:04 -07:00
< input type = "text" class = "form-control" ng-model = "externalLdap.url" id = "inputExternalLdapConfigUrl" name = "url" ng-disabled = "externalLdap.busy" placeholder = "ldaps://example.com:636" required >
2019-08-30 12:40:23 +02:00
< / div >
2020-06-25 17:53:57 +02:00
< div class = "form-group" >
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "externalLdap.acceptSelfSignedCerts" > {{ 'users.externalLdap.acceptSelfSignedCert' | tr }}
2020-06-25 17:53:57 +02:00
< / label >
< / div >
2021-05-14 10:01:23 -07:00
< p class = "has-error" ng-show = "externalLdap.error.acceptSelfSignedCerts" > {{ 'users.externalLdap.errorSelfSignedCert' | tr }}< / p >
2020-06-25 17:53:57 +02:00
< / div >
2019-08-30 12:40:23 +02:00
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.baseDn }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigBaseDn" > {{ 'users.externalLdap.baseDn' | tr }}< / label >
2019-10-25 15:38:04 -07:00
< input type = "text" class = "form-control" ng-model = "externalLdap.baseDn" id = "inputExternalLdapConfigBaseDn" name = "baseDn" ng-disabled = "externalLdap.busy" placeholder = "ou=users,dc=example,dc=com" required >
2019-08-30 12:40:23 +02:00
< / div >
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.filter }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigFilter" > {{ 'users.externalLdap.filter' | tr }}< / label >
2019-10-25 15:38:04 -07:00
< input type = "text" class = "form-control" ng-model = "externalLdap.filter" id = "inputExternalLdapConfigFilter" name = "filter" ng-disabled = "externalLdap.busy" placeholder = "(objectClass=inetOrgPerson)" required >
2019-08-30 12:40:23 +02:00
< / div >
2019-10-25 16:38:59 -07:00
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.usernameField }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigUsernameField" > {{ 'users.externalLdap.usernameField' | tr }}< / label >
2019-10-31 11:39:42 -07:00
< input type = "text" class = "form-control" ng-model = "externalLdap.usernameField" id = "inputExternalLdapConfigUsernameField" name = "usernameField" ng-disabled = "externalLdap.busy" placeholder = "uid or sAMAcountName" >
2019-10-25 16:38:59 -07:00
< / div >
2020-06-04 12:30:31 +02:00
< div class = "form-group" >
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "externalLdap.syncGroups" > {{ 'users.externalLdap.syncGroups' | tr }}< / sup >
2020-06-04 12:30:31 +02:00
< / label >
< / div >
< / div >
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.groupBaseDn }" ng-show = "externalLdap.syncGroups" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigGroupBaseDn" > {{ 'users.externalLdap.groupBaseDn' | tr }}< / label >
2020-06-04 12:30:31 +02:00
< input type = "text" class = "form-control" ng-model = "externalLdap.groupBaseDn" id = "inputExternalLdapConfigGroupBaseDn" name = "groupBaseDn" ng-disabled = "externalLdap.busy" placeholder = "ou=groups,dc=example,dc=com" ng-required = "externalLdap.syncGroups" >
2020-06-03 21:24:04 +02:00
< / div >
2020-06-04 12:30:31 +02:00
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.groupFilter }" ng-show = "externalLdap.syncGroups" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigGroupFilter" > {{ 'users.externalLdap.groupFilter' | tr }}< / label >
2020-06-04 12:30:31 +02:00
< input type = "text" class = "form-control" ng-model = "externalLdap.groupFilter" id = "inputExternalLdapConfigGroupFilter" name = "groupFilter" ng-disabled = "externalLdap.busy" placeholder = "(objectClass=groupOfNames)" ng-required = "externalLdap.syncGroups" >
2020-06-03 21:24:04 +02:00
< / div >
2020-06-04 12:30:31 +02:00
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.groupnameField }" ng-show = "externalLdap.syncGroups" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigGroupnameField" > {{ 'users.externalLdap.groupnameField' | tr }}< / label >
2020-06-04 12:30:31 +02:00
< input type = "text" class = "form-control" ng-model = "externalLdap.groupnameField" id = "inputExternalLdapConfigGroupnameField" name = "groupnameField" ng-disabled = "externalLdap.busy" placeholder = "cn" ng-required = "externalLdap.syncGroups" >
2020-06-03 21:24:04 +02:00
< / div >
2019-08-30 12:40:23 +02:00
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.credentials }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigBindDn" > {{ 'users.externalLdap.bindUsername' | tr }}< / label >
2019-10-25 15:38:04 -07:00
< input type = "text" class = "form-control" ng-model = "externalLdap.bindDn" id = "inputExternalLdapConfigBindDn" name = "bindDn" ng-disabled = "externalLdap.busy" placeholder = "uid=admin,ou=Users,dc=example,dc=com" >
2019-08-30 12:40:23 +02:00
< / div >
< div class = "form-group" ng-class = "{ 'has-error': externalLdap.error.credentials }" >
2020-11-13 16:44:39 +01:00
< label class = "control-label" for = "inputExternalLdapConfigBindPassword" > {{ 'users.externalLdap.bindPassword' | tr }}< / label >
2019-10-25 15:38:04 -07:00
< input type = "password" class = "form-control" ng-model = "externalLdap.bindPassword" id = "inputExternalLdapConfigBindPassword" name = "bindPassword" ng-disabled = "externalLdap.busy" placeholder = "" >
2019-08-30 12:40:23 +02:00
< / div >
2019-11-20 22:42:32 +01:00
< div class = "form-group" >
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "externalLdap.autoCreate" > {{ 'users.externalLdap.autocreateUsersOnLogin' | tr }}
2019-11-20 22:42:32 +01:00
< / label >
< / div >
< / div >
2019-08-30 12:40:23 +02:00
< input class = "ng-hide" type = "submit" ng-disabled = "externalLdapConfigForm.$invalid" / >
< / fieldset >
< / form >
< / div >
< / div >
< div class = "modal-footer" >
2020-11-13 16:44:39 +01:00
< button type = "button" class = "btn btn-default" data-dismiss = "modal" > {{ 'main.dialog.cancel' | tr }}< / button >
< button type = "button" class = "btn btn-primary" ng-click = "externalLdap.submit()" ng-disabled = "externalLdapConfigForm.$invalid || externalLdap.busy" > < i class = "fa fa-circle-notch fa-spin" ng-show = "externalLdap.busy" > < / i > {{ 'main.dialog.save' | tr }}< / button >
2019-08-30 12:40:23 +02:00
< / div >
< / div >
< / div >
< / div >
2018-01-22 13:01:38 -08:00
< div class = "content content-large" >
< div class = "text-left" >
2020-07-09 21:51:51 -07:00
< h2 >
2020-10-28 16:17:14 +01:00
{{ 'users.title' | tr }}
2020-06-18 12:57:12 +02:00
< button class = "btn btn-primary btn-outline pull-right" ng-click = "useradd.show()" >
2020-11-13 16:44:39 +01:00
< i class = "fa fa-user-plus" > < / i > {{ 'users.newUserAction' | tr }}
2020-03-05 16:31:41 -08:00
< / button >
2020-07-09 21:51:51 -07:00
< / h2 >
2018-01-22 13:01:38 -08:00
< / div >
2019-01-15 13:30:37 +01:00
< div class = "row" >
< div class = "col-lg-12" >
2020-03-26 18:32:49 -07:00
< div class = "users-filter" >
2021-03-31 17:01:00 +02:00
< input type = "text" class = "form-control" style = "min-width: 350px;" ng-model = "userSearchString" ng-model-options = "{ debounce: 1000 }" ng-change = "updateFilter()" placeholder = "{{ 'main.searchPlaceholder' | tr }}" / >
2019-01-15 13:30:37 +01:00
< select class = "form-control" ng-model = "pageItems" ng-options = "a.name for a in pageItemCount" ng-change = "updateFilter(true)" > < / select >
< / div >
< div class = "pagination pull-right" >
2020-11-12 11:42:11 +01:00
< button class = "btn btn-default btn-outline" ng-click = "showPrevPage()" ng-disabled = "userRefreshBusy || currentPage <= 1" > < i class = "fa fa-angle-double-left" > < / i > {{ 'main.pagination.prev' | tr }}< / button >
< button class = "btn btn-default btn-outline" ng-click = "showNextPage()" ng-disabled = "userRefreshBusy || users.length < pageItems.value" > {{ 'main.pagination.next' | tr }} < i class = "fa fa-angle-double-right" > < / i > < / button >
2019-01-15 13:30:37 +01:00
< / div >
< / div >
< / div >
< div >
< div class = "card card-large" >
2018-01-22 13:01:38 -08:00
< div class = "grid-item-top" >
2019-01-16 14:02:08 +01:00
< div class = "row ng-hide" ng-show = "userRefreshBusy" >
2019-01-15 13:30:37 +01:00
< div class = "col-lg-12 text-center" >
< h2 > < i class = "fa fa-circle-notch fa-spin" > < / i > < / h2 >
2018-01-22 13:01:38 -08:00
< / div >
2019-01-15 13:30:37 +01:00
< / div >
2019-01-16 14:02:08 +01:00
< div class = "row ng-hide" ng-hide = "userRefreshBusy" >
2019-01-15 13:30:37 +01:00
< div class = "col-lg-12" >
2019-01-16 14:02:08 +01:00
< table class = "table table-hover" style = "margin: 0;" >
2019-01-15 13:30:37 +01:00
< thead >
< tr >
< th style = "width: 0.5%;" > < / th >
2020-11-13 16:44:39 +01:00
< th style = "width:45%" > {{ 'users.users.user' | tr }}< / th >
< th style = "width:49.5%" class = "hidden-xs hidden-sm" > {{ 'users.users.groups' | tr }}< / th >
2020-11-11 22:50:57 +01:00
< th style = "width: 5%" class = "text-right" > {{ 'main.actions' | tr }}< / th >
2019-01-15 13:30:37 +01:00
< / tr >
< / thead >
< tbody >
2019-08-13 15:30:40 +02:00
< tr ng-show = "users.length === 0" >
2020-11-13 16:44:39 +01:00
< td colspan = "5" class = "text-center text-muted" > {{ 'users.users.empty' | tr }}< / td >
2019-08-13 15:30:40 +02:00
< / tr >
2019-08-08 07:39:43 -07:00
< tr ng-repeat = "user in users" ng-class = "{'text-muted': !user.active}" >
2019-01-15 13:30:37 +01:00
< td >
2021-03-30 13:31:24 +02:00
< i class = "fas fa-crown arrow" ng-show = "user.active && user.role === 'owner'" uib-tooltip = "{{ 'users.users.superadminTooltip' | tr }}" > < / i >
< i class = "fa fa-user-tie arrow" ng-show = "user.active && user.role === 'admin'" uib-tooltip = "{{ 'users.users.adminTooltip' | tr }}" > < / i >
< i class = "fas fa-users-cog arrow" ng-show = "user.active && user.role === 'usermanager'" uib-tooltip = "{{ 'users.users.usermanagerTooltip' | tr }}" > < / i >
2020-11-13 16:44:39 +01:00
< i class = "fa fa-ban" ng-show = "!user.active" uib-tooltip = "{{ 'users.users.inactiveTooltip' | tr }}" > < / i >
2019-01-15 13:30:37 +01:00
< / td >
2020-03-07 14:05:58 -08:00
< td class = "hand elide-table-cell" ng-click = "canEdit(user) && useredit.show(user)" ng-show = "user.username" >
2020-11-13 16:44:39 +01:00
{{ user.displayName }} < span class = "text-muted" > {{ user.username }}< / span > < i ng-show = "user.source" class = "far fa-address-book" uib-tooltip = "{{ 'users.users.externalLdapTooltip' | tr }}" > < / i >
2019-01-15 13:30:37 +01:00
< / td >
2020-03-07 14:05:58 -08:00
< td class = "hand elide-table-cell" ng-click = "canEdit(user) && useredit.show(user)" ng-hide = "user.username" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" uib-tooltip = "{{ 'users.users.notActivatedYetTooltip' | tr }}" > {{ user.fallbackEmail }}< / span >
2019-01-15 13:30:37 +01:00
< / td >
2020-03-07 14:05:58 -08:00
< td class = "text-left hand elide-table-cell hidden-xs hidden-sm" ng-click = "canEdit(user) && useredit.show(user)" >
2019-01-15 13:30:37 +01:00
< span class = "group-badge" ng-repeat = "groupId in user.groupIds" >
{{ groupsById[groupId].name }}
< / span >
< / td >
2018-01-22 13:01:38 -08:00
2019-01-15 13:30:37 +01:00
< td class = "text-right no-wrap" style = "vertical-align: bottom" >
2021-01-19 22:26:43 +01:00
< button ng-show = "isMe(user) && userInfo.role === 'owner' && user.role === 'owner' && !config.features.userRoles" class = "btn btn-xs btn-default" ng-click = "transferOwnership.show()" uib-tooltip = "{{ 'users.users.transferOwnershipTooltip' | tr }}" > < i class = "fas fa-random" > < / i > < / button >
2021-09-16 15:46:26 +02:00
< button ng-disabled = "!canEdit(user) || isMe(user) || user.source" class = "btn btn-xs btn-default" ng-click = "invitation.show(user)" uib-tooltip = "{{ 'users.users.invitationTooltip' | tr }}" > < i class = "fas fa-paper-plane" > < / i > < / button >
2021-09-16 14:35:17 +02:00
< button ng-disabled = "!canEdit(user) || isMe(user) || user.source" class = "btn btn-xs btn-default" ng-click = "passwordReset.show(user)" uib-tooltip = "{{ 'users.users.resetPasswordTooltip' | tr }}" > < i class = "fas fa-key" > < / i > < / button >
2020-11-13 16:44:39 +01:00
< button ng-disabled = "!canEdit(user)" class = "btn btn-xs btn-default" ng-click = "useredit.show(user)" uib-tooltip = "{{ 'users.users.editUserTooltip' | tr }}" > < i class = "fa fa-pencil-alt" > < / i > < / button >
< button ng-disabled = "!canEdit(user) || isMe(user)" class = "btn btn-xs btn-danger" ng-click = "userremove.show(user)" uib-tooltip = "{{ 'users.users.removeUserTooltip' | tr }}" > < i class = "far fa-trash-alt" > < / i > < / button >
2019-01-15 13:30:37 +01:00
< / td >
< / tr >
< / tbody >
< / table >
2018-01-22 13:01:38 -08:00
< / div >
2019-01-15 13:30:37 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-01-15 13:30:37 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
< br / >
< div class = "text-left" >
2021-01-13 14:49:23 +01:00
< h2 >
{{ 'users.groups.title' | tr }}
< button class = "btn btn-primary btn-outline pull-right" ng-click = "groupAdd.show()" >
< i class = "fa fa-plus" > < / i > {{ 'users.groups.newGroupAction' | tr }}
< / button >
< / h2 >
2018-01-22 13:01:38 -08:00
< / div >
< div class = "card card-large" >
2020-11-13 16:44:39 +01:00
< div class = "grid-item-top" >
< div class = "row ng-hide" ng-show = "!ready" >
< div class = "col-lg-12 text-center" >
< h2 > < i class = "fa fa-circle-notch fa-spin" > < / i > < / h2 >
< / div >
< / div >
< div class = "row animateMeOpacity ng-hide" ng-show = "ready" >
< div class = "col-lg-12" >
< table class = "table table-hover" style = "margin: 0;" >
< thead >
< tr >
< th style = "width: 45%" > {{ 'users.groups.name' | tr }}< / th >
< th style = "width: 49.5%" class = "hidden-xs hidden-sm" > {{ 'users.groups.users' | tr }}< / th >
< th style = "width: 5%" class = "text-right" > {{ 'main.actions' | tr }}< / th >
< / tr >
< / thead >
< tbody >
< tr ng-repeat = "group in groups" >
< td class = "hand elide-table-cell" style = "text-overflow: ellipsis; white-space: nowrap;" ng-click = "groupEdit.show(group)" >
{{ group.name }} < i ng-show = "group.source" class = "far fa-address-book" uib-tooltip = "{{ 'users.groups.externalLdapTooltip' | tr }}" > < / i >
< / td >
< td class = "hand elide-table-cell" style = "text-overflow: ellipsis; white-space: nowrap;" ng-click = "groupEdit.show(group)" >
{{ groupMembers(group) }}
< / td >
< td class = "text-right no-wrap" style = "vertical-align: bottom" >
< button class = "btn btn-xs btn-default" ng-click = "groupEdit.show(group)" uib-tooltip = "Edit Group" > < i class = "fa fa-pencil-alt" > < / i > < / button >
< button class = "btn btn-xs btn-danger" ng-click = "groupRemove.show(group)" uib-tooltip = "Remove Group" > < i class = "far fa-trash-alt" > < / i > < / button >
< / td >
< / tr >
< / tbody >
< / table >
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2020-11-13 16:44:39 +01:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >
2019-08-29 09:59:57 +02:00
2020-02-24 18:01:42 +01:00
< div class = "text-left" style = "margin-top: 50px;" ng-show = "user.isAtLeastAdmin" >
2020-11-13 16:44:39 +01:00
< h2 > {{ 'users.settings.title' | tr }}< / h2 >
2020-07-09 21:51:51 -07:00
< / div >
< div class = "card card-large" ng-show = "user.isAtLeastAdmin" >
< form name = "directoryConfigForm" role = "form" novalidate ng-submit = "directoryConfig.submit()" autocomplete = "off" >
2020-07-17 10:11:45 -07:00
< fieldset ng-disabled = "directoryConfig.busy || !config.features.directoryConfig" >
2020-07-09 21:51:51 -07:00
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "directoryConfig.editableUserProfiles" > {{ 'users.settings.allowProfileEditCheckbox' | tr }} < sup > < a ng-href = "https://docs.cloudron.io/user-management/#lock-profile" class = "help" target = "_blank" > < i class = "fa fa-question-circle" > < / i > < / a > < / sup >
2020-07-09 21:51:51 -07:00
< / label >
< / div >
2020-07-10 10:43:08 -07:00
< div class = "checkbox" >
< label >
2020-11-13 16:44:39 +01:00
< input type = "checkbox" ng-model = "directoryConfig.mandatory2FA" > {{ 'users.settings.require2FACheckbox' | tr }}
2020-07-10 10:43:08 -07:00
< / label >
< / div >
2020-07-09 21:51:51 -07:00
< / fieldset >
< / form >
< br / >
2020-07-17 10:11:45 -07:00
< div class = "row" ng-hide = "config.features.directoryConfig" >
< div class = "col-md-12" >
2020-11-13 16:44:39 +01:00
< span > {{ 'users.settings.subscriptionRequired' | tr }} < a href = "" class = "pull-right" ng-click = "openSubscriptionSetup()" > {{ 'users.settings.subscriptionRequiredAction' | tr }}< / a > < / span >
2020-07-09 21:51:51 -07:00
< / div >
2020-07-17 10:11:45 -07:00
< / div >
< div class = "row" ng-show = "config.features.directoryConfig" >
< div class = "col-md-12" >
2020-07-22 18:09:30 -07:00
< span class = "has-error" ng-show = "directoryConfig.errorMessage" > {{ directoryConfig.errorMessage }}< / span >
2020-07-17 10:11:45 -07:00
< button class = "btn btn-outline btn-primary pull-right" ng-click = "directoryConfig.submit()" ng-disabled = "!directoryConfigForm.$dirty || directoryConfig.busy" >
2020-11-13 16:44:39 +01:00
< i class = "fa fa-circle-notch fa-spin" ng-show = "directoryConfig.busy" > < / i > {{ 'users.settings.saveAction' | tr }}
2020-07-09 21:51:51 -07:00
< / button >
< / div >
< / div >
< / div >
< div class = "text-left" style = "margin-top: 50px;" ng-show = "user.isAtLeastAdmin" >
2020-11-13 16:44:39 +01:00
< h2 > {{ 'users.externalLdap.title' | tr }}< / h2 >
2019-08-29 09:59:57 +02:00
< / div >
2020-02-24 18:01:42 +01:00
< div class = "card card-large" ng-show = "user.isAtLeastAdmin" >
2019-08-29 09:59:57 +02:00
< div class = "row" >
2020-11-13 16:44:39 +01:00
< div class = "col-md-12" > {{ 'users.externalLdap.description' | tr }}< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-02-28 19:27:19 +01:00
2019-11-07 11:35:04 -08:00
< br / >
2019-08-29 09:59:57 +02:00
2020-02-28 19:27:19 +01:00
< div class = "row" ng-hide = "config.features.externalLdap" >
< div class = "col-md-12" >
2020-11-13 16:44:39 +01:00
{{ 'users.externalLdap.subscriptionRequired' | tr }} < a href = "" class = "pull-right" ng-click = "openSubscriptionSetup()" > {{ 'users.externalLdap.subscriptionRequiredAction' | tr }}< / a >
2020-02-28 19:27:19 +01:00
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2019-08-30 13:09:19 +02:00
2020-02-13 16:34:37 +01:00
< div ng-show = "config.features.externalLdap" >
2020-03-18 21:43:47 -07:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider === 'noop'" >
< div class = "col-xs-12" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.noopInfo' | tr }}< / span >
2020-03-18 21:43:47 -07:00
< / div >
< / div >
2020-03-09 13:04:44 -07:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
2020-02-13 15:30:31 +01:00
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.provider' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.provider }}< / span >
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.server' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.url }}< / span >
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-06-25 17:53:57 +02:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.acceptSelfSignedCert' | tr }}< / span >
2020-06-25 17:53:57 +02:00
< / div >
< div class = "col-xs-6 text-right" >
2020-07-01 14:59:50 +02:00
< span > {{ externalLdap.currentConfig.acceptSelfSignedCerts ? 'Yes' : 'No' }}< / span >
2020-06-25 17:53:57 +02:00
< / div >
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.baseDn' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.baseDn }}< / span >
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.filter' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.filter }}< / span >
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-06-03 21:24:04 +02:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
2020-06-04 12:30:31 +02:00
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.usernameField' | tr }}< / span >
2020-06-04 12:30:31 +02:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.usernameField || 'uid' }}< / span >
< / div >
< / div >
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.syncGroups' | tr }}< / span >
2020-06-04 12:30:31 +02:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.syncGroups ? 'Yes' : 'No' }}< / span >
< / div >
< / div >
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop' && externalLdap.currentConfig.syncGroups" >
2020-06-03 21:24:04 +02:00
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.groupBaseDn' | tr }}< / span >
2020-06-03 21:24:04 +02:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.groupBaseDn }}< / span >
< / div >
< / div >
2020-06-04 12:30:31 +02:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop' && externalLdap.currentConfig.syncGroups" >
2020-06-03 21:24:04 +02:00
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.groupFilter' | tr }}< / span >
2020-06-03 21:24:04 +02:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.groupFilter }}< / span >
< / div >
< / div >
2020-06-04 12:30:31 +02:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop' && externalLdap.currentConfig.syncGroups" >
2020-02-13 15:30:31 +01:00
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.groupnameField' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
2020-06-04 12:30:31 +02:00
< span > {{ externalLdap.currentConfig.groupnameField }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
2019-08-29 09:59:57 +02:00
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.auth' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.bindDn ? 'Yes' : 'No' }}< / span >
< / div >
2019-11-20 22:42:32 +01:00
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" ng-show = "externalLdap.currentConfig.provider !== 'noop'" >
< div class = "col-xs-6" >
2020-11-13 16:44:39 +01:00
< span class = "text-muted" > {{ 'users.externalLdap.autocreateUsersOnLogin' | tr }}< / span >
2020-02-13 15:30:31 +01:00
< / div >
< div class = "col-xs-6 text-right" >
< span > {{ externalLdap.currentConfig.autoCreate ? 'Yes' : 'No' }}< / span >
2019-11-07 11:35:04 -08:00
< / div >
2019-08-29 09:59:57 +02:00
< / div >
2019-11-07 11:35:04 -08:00
2020-02-13 15:30:31 +01:00
< div class = "row" >
< br / >
< div class = "col-md-12" style = "margin-bottom: 10px;" >
< div ng-show = "externalLdap.syncBusy" class = "progress progress-striped active animateMe" >
< div class = "progress-bar progress-bar-success" role = "progressbar" style = "width: {{ externalLdap.percent }}%" > < / div >
< / div >
< / div >
2019-11-07 11:35:04 -08:00
< / div >
2020-02-13 15:30:31 +01:00
< div class = "row" >
< div class = "col-md-6" >
< p ng-show = "externalLdap.syncBusy" > {{ externalLdap.message }}< / p >
< p ng-hide = "externalLdap.syncBusy" >
< div class = "has-error" ng-show = "!externalLdap.active" > {{ externalLdap.errorMessage }}< / div >
< / p >
< / div >
< div class = "col-md-6 text-right" >
2020-11-13 16:44:39 +01:00
< button class = "btn btn-primary pull-right" ng-click = "externalLdap.show()" > {{ 'users.externalLdap.configureAction' | tr }}< / button >
< button class = "btn btn-success pull-right" ng-disabled = "externalLdap.currentConfig.provider === 'noop'" ng-click = "externalLdap.sync()" > < i class = "fa fa-circle-notch fa-spin" ng-show = "externalLdap.syncBusy" > < / i > {{ 'users.externalLdap.syncAction' | tr }}< / button >
< a class = "btn btn-primary pull-right" ng-show = "externalLdap.taskId" ng-href = "/logs.html?taskId={{ externalLdap.taskId }}" target = "_blank" > {{ 'users.externalLdap.showLogsAction' | tr }}< / a >
2020-02-13 15:30:31 +01:00
< / div >
2019-08-29 09:59:57 +02:00
< / div >
< / div >
2020-02-13 15:30:31 +01:00
2019-08-29 09:59:57 +02:00
< / div >
2018-01-22 13:01:38 -08:00
< / div >