diff --git a/dashboard/public/translation/da.json b/dashboard/public/translation/da.json index ad94a9958..d8115841f 100644 --- a/dashboard/public/translation/da.json +++ b/dashboard/public/translation/da.json @@ -281,7 +281,6 @@ "failed": "Følgende brugere blev ikke importeret:", "sendInviteCheckbox": "Send en e-mail med invitation til importerede brugere" }, - "title": "Brugerkatalog", "newUserAction": "Ny bruger", "users": { "user": "Bruger", diff --git a/dashboard/public/translation/de.json b/dashboard/public/translation/de.json index bb7aba9d9..d4760faf8 100644 --- a/dashboard/public/translation/de.json +++ b/dashboard/public/translation/de.json @@ -216,7 +216,6 @@ } }, "users": { - "title": "User Verzeichnis", "externalLdap": { "errorSelfSignedCert": "Server benutzt ein ungültiges selbst signiertes Zertifikat.", "bindPassword": "Bind Passwort (optional)", diff --git a/dashboard/public/translation/en.json b/dashboard/public/translation/en.json index f815b66c3..84b436a25 100644 --- a/dashboard/public/translation/en.json +++ b/dashboard/public/translation/en.json @@ -95,7 +95,8 @@ "never": "Never" }, "navbar": { - "users": "Users" + "users": "Users", + "groups": "Groups" }, "disableAction": "Disable", "enableAction": "Enable", @@ -193,7 +194,6 @@ } }, "users": { - "title": "User Directory", "newUserAction": "New User", "users": { "user": "User", @@ -410,7 +410,8 @@ "all": "All Users", "active": "Active Users", "inactive": "Inactive Users" - } + }, + "title": "Users & Groups" }, "profile": { "title": "Profile", @@ -2114,5 +2115,8 @@ "removeDialog": { "description": "Really remove this registry?" } + }, + "userDirectory": { + "title": "User Directory" } } diff --git a/dashboard/public/translation/es.json b/dashboard/public/translation/es.json index 4238189a2..568f6e4ba 100644 --- a/dashboard/public/translation/es.json +++ b/dashboard/public/translation/es.json @@ -262,7 +262,6 @@ "count": "Total usuarios: {{ count }}" }, "newUserAction": "Nuevo Usuario", - "title": "Directorio de Usuarios", "transferOwnershipDialog": { "description": "Esto hará que el usuario seleccionado sea el propietario y administrador de este Cloudron y eliminará los derechos de administrador del propietario actual.", "title": "¿Realmente quieres transferir la propiedad?", diff --git a/dashboard/public/translation/fr.json b/dashboard/public/translation/fr.json index 1d0c43470..b569b62fa 100644 --- a/dashboard/public/translation/fr.json +++ b/dashboard/public/translation/fr.json @@ -95,7 +95,6 @@ "saveAction": "Sauvegarde" }, "users": { - "title": "Annuaire des utilisateurs", "users": { "user": "Utilisateur", "notActivatedYetTooltip": "Utilisateur pas encore activé", diff --git a/dashboard/public/translation/it.json b/dashboard/public/translation/it.json index 3bab5b854..c446cd9bc 100644 --- a/dashboard/public/translation/it.json +++ b/dashboard/public/translation/it.json @@ -970,7 +970,6 @@ "transferOwnershipTooltip": "Trasferisci Proprietà" }, "newUserAction": "Nuovo Utente", - "title": "Utenti", "transferOwnershipDialog": { "transferAction": "Trasferisci la proprietà", "description": "L'utente selezionato e l'amministratore di questo Cloudron acquisiranno i permessi di ammministrazione, mentre l'attuale proprietario li perderà.", diff --git a/dashboard/public/translation/nl.json b/dashboard/public/translation/nl.json index fe5a259bb..c02a9fd6e 100644 --- a/dashboard/public/translation/nl.json +++ b/dashboard/public/translation/nl.json @@ -193,7 +193,6 @@ } }, "users": { - "title": "Gebruikerslijst", "newUserAction": "Nieuwe gebruiker", "users": { "user": "Gebruiker", diff --git a/dashboard/public/translation/pt.json b/dashboard/public/translation/pt.json index e67381f5e..e292b8769 100644 --- a/dashboard/public/translation/pt.json +++ b/dashboard/public/translation/pt.json @@ -493,7 +493,6 @@ "active": "Utilizadores Ativos", "inactive": "Utilizadores Inativos" }, - "title": "Diretoria do Utilizador", "newUserAction": "Novo Utilizador", "settings": { "title": "Definições do Utilizador", diff --git a/dashboard/public/translation/ru.json b/dashboard/public/translation/ru.json index 247db41b5..b97a9029b 100644 --- a/dashboard/public/translation/ru.json +++ b/dashboard/public/translation/ru.json @@ -212,7 +212,6 @@ "mailmanagerTooltip": "Этот пользователь может управлять другими пользователями и почтовыми ящиками", "count": "Всего пользователей: {{ count }}" }, - "title": "Каталог пользователей", "newUserAction": "Новый пользователь", "groups": { "title": "Группы", diff --git a/dashboard/public/translation/vi.json b/dashboard/public/translation/vi.json index 58a0d99b2..a884fa2ce 100644 --- a/dashboard/public/translation/vi.json +++ b/dashboard/public/translation/vi.json @@ -293,7 +293,6 @@ "emptyPlaceholder": "Chưa có nhóm nào cả" }, "newUserAction": "Người dùng mới", - "title": "Chỉ mục Người dùng", "editGroupDialog": { "title": "Chỉnh sửa nhóm {{ name }}", "externalLdapWarning": "Nhóm này được đồng bộ từ thư mục LDAP ngoài." diff --git a/dashboard/public/translation/zh_Hans.json b/dashboard/public/translation/zh_Hans.json index b3c24eb02..fc719f889 100644 --- a/dashboard/public/translation/zh_Hans.json +++ b/dashboard/public/translation/zh_Hans.json @@ -389,7 +389,6 @@ "searchPlaceholder": "使用应用名称如 Github, Dropbox, Slack, Trello, ... 来搜索替代品" }, "users": { - "title": "用户目录", "newUserAction": "新用户", "users": { "user": "用户", diff --git a/dashboard/src/Index.vue b/dashboard/src/Index.vue index fbea85b44..bb9a15807 100644 --- a/dashboard/src/Index.vue +++ b/dashboard/src/Index.vue @@ -39,6 +39,7 @@ import UserDirectorySettingsView from './views/UserDirectorySettingsView.vue'; import UserDirectoryLdapServerView from './views/UserDirectoryLdapServerView.vue'; import UserDirectoryOpenIdProviderView from './views/UserDirectoryOpenIdProviderView.vue'; import UsersView from './views/UsersView.vue'; +import GroupsView from './views/GroupsView.vue'; import VolumesView from './views/VolumesView.vue'; const VIEWS = { @@ -69,6 +70,7 @@ const VIEWS = { USER_DIRECTORY_LDAP_SERVER: 'user-directory-ldap-server', USER_DIRECTORY_OPENID_PROVIDER: 'user-directory-openid-provider', USERS: 'users', + GROUPS: 'users-groups', VOLUMES: 'volumes', }; @@ -135,6 +137,7 @@ function onHashChange() { else if (activeSidebarItem.value.indexOf('email') === 0) activeSidebarGroup.value = 'email'; else if (activeSidebarItem.value.indexOf('system') === 0) activeSidebarGroup.value = 'system'; else if (activeSidebarItem.value.indexOf('user-directory') === 0) activeSidebarGroup.value = 'user-directory'; + else if (activeSidebarItem.value.indexOf('users') === 0) activeSidebarGroup.value = 'users'; else activeSidebarGroup.value = ''; if (v === VIEWS.APPS) { @@ -191,6 +194,8 @@ function onHashChange() { view.value = VIEWS.USER_DIRECTORY_OPENID_PROVIDER; } else if (v === VIEWS.USERS && profile.value.isAtLeastUserManager) { view.value = VIEWS.USERS; + } else if (v === VIEWS.GROUPS && profile.value.isAtLeastUserManager) { + view.value = VIEWS.GROUPS; } else if (v === VIEWS.VOLUMES && profile.value.isAtLeastAdmin) { view.value = VIEWS.VOLUMES; } else { @@ -300,8 +305,11 @@ onMounted(async () => { {{ $t('emails.settings.title') }} + {{ $t('network.title') }} + {{ $t('services.title') }} + - {{ $t('main.navbar.users') }} - + + + + + + + + {{ $t('volumes.title') }} +
+ {{ $t('system.title') }} {{ $t('settings.appstoreAccount.title') }} @@ -358,6 +377,7 @@ onMounted(async () => { + diff --git a/dashboard/src/views/GroupsView.vue b/dashboard/src/views/GroupsView.vue new file mode 100644 index 000000000..7aaecaf9d --- /dev/null +++ b/dashboard/src/views/GroupsView.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/dashboard/src/views/UsersView.vue b/dashboard/src/views/UsersView.vue index 4480f3d6f..28e853567 100644 --- a/dashboard/src/views/UsersView.vue +++ b/dashboard/src/views/UsersView.vue @@ -9,7 +9,6 @@ import { Button, Menu, TextInput, SingleSelect, TableView, InputDialog } from '@ import { ROLES } from '../constants.js'; import Section from '../components/Section.vue'; import UserDialog from '../components/UserDialog.vue'; -import GroupDialog from '../components/GroupDialog.vue'; import ImpersonateDialog from '../components/ImpersonateDialog.vue'; import InvitationDialog from '../components/InvitationDialog.vue'; import PasswordResetDialog from '../components/PasswordResetDialog.vue'; @@ -76,35 +75,6 @@ function onUserActionMenu(user, event) { actionMenuElement.value.open(event, event.currentTarget); } -const groupsColumns = { - name: { - label: t('users.groups.name'), - sort: true - }, - users: { - label: t('users.groups.users'), - sort: true, - hideMobile: true, - }, - actions: {} -}; - -function onGroupActionMenu(group, event) { - actionMenuModel.value = [{ - icon: 'fa-solid fa-pencil-alt', - label: t('main.action.edit'), - action: onEditOrAddGroup.bind(null, group), - }, { - separator: true, - }, { - icon: 'fa-solid fa-trash-alt', - label: t('main.action.remove'), - action: onRemoveGroup.bind(null, group), - }]; - - actionMenuElement.value.open(event, event.currentTarget); -} - const profile = ref({}); const busy = ref(true); const filterOptions = ref([ @@ -125,7 +95,6 @@ const subscriptionRequiredDialog = inject('subscriptionRequiredDialog'); const inputDialog = useTemplateRef('inputDialog'); const userDialog = useTemplateRef('userDialog'); -const groupDialog = useTemplateRef('groupDialog'); const impersonateDialog = useTemplateRef('impersonateDialog'); const passwordResetDialog = useTemplateRef('passwordResetDialog'); @@ -190,10 +159,6 @@ function isMe(user) { return user.username === profile.value.username; } -function groupMembers(group) { - return group.userIds.filter(function (uid) { return !!usersById.value[uid]; }).map(function (uid) { return usersById.value[uid].username || usersById.value[uid].email; }).join(' '); -} - function onImpersonate(user) { impersonateDialog.value.open(user); } @@ -212,28 +177,6 @@ function onInvitation(user) { invitationDialog.value.open(user); } -function onEditOrAddGroup(group = null) { - if (group || features.value.userGroups) groupDialog.value.open(group); - else subscriptionRequiredDialog.value.open(); -} - -async function onRemoveGroup(group) { - const yes = await inputDialog.value.confirm({ - title: t('users.deleteGroupDialog.title', { name: group.name }), - message: t('users.deleteGroupDialog.description', { memberCount: group.userIds.length }), - confirmStyle: 'danger', - confirmLabel: t('users.deleteGroupDialog.deleteAction'), - rejectLabel: t('main.dialog.cancel') - }); - - if (!yes) return; - - const [error] = await groupsModel.remove(group.id); - if (error) console.error(error); - - await refreshGroups(); -} - async function onRemoveUser(user) { const yes = await inputDialog.value.confirm({ title: t('users.deleteUserDialog.title', { username: (user.username || user.email) }), @@ -279,7 +222,6 @@ onMounted(async () => { - @@ -320,28 +262,6 @@ onMounted(async () => { - -
- - - - - - - -
-
{{ $t('users.groups.count', { count: groups.length }) }}
-