diff --git a/dashboard/src/components/GroupDialog.vue b/dashboard/src/components/GroupDialog.vue new file mode 100644 index 000000000..cb08d6d2d --- /dev/null +++ b/dashboard/src/components/GroupDialog.vue @@ -0,0 +1,109 @@ + + + diff --git a/dashboard/src/models/GroupsModel.js b/dashboard/src/models/GroupsModel.js index c59c8e452..2e3afa745 100644 --- a/dashboard/src/models/GroupsModel.js +++ b/dashboard/src/models/GroupsModel.js @@ -7,16 +7,89 @@ function create() { return { async list() { - let error, result; + let result; try { result = await fetcher.get(`${origin}/api/v1/groups`, { access_token: accessToken }); } catch (e) { - error = e; + return [e]; } - if (error || result.status !== 200) return [error || result]; + if (result.status !== 200) return [result]; return [null, result.body.groups]; }, + async add(name, userIds, appIds) { + let result; + try { + result = await fetcher.post(`${origin}/api/v1/groups`, { name }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 201) return [result]; + + if (userIds.length) { + let resultUserIds; + try { + resultUserIds = await fetcher.put(`${origin}/api/v1/groups/${result.body.id}/members`, { userIds }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (resultUserIds.status !== 200) return [resultUserIds]; + } + + if (appIds.length) { + let resultAppIds; + try { + resultAppIds = await fetcher.put(`${origin}/api/v1/groups/${result.body.id}/apps`, { appIds }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (resultAppIds.status !== 200) return [resultAppIds]; + } + + return [null, result.body]; + }, + async update(id, name, userIds, appIds) { + let result; + try { + result = await fetcher.put(`${origin}/api/v1/groups/${id}/name`, { name }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + + try { + result = await fetcher.put(`${origin}/api/v1/groups/${id}/members`, { userIds }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + + try { + result = await fetcher.put(`${origin}/api/v1/groups/${id}/apps`, { appIds }, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 200) return [result]; + + return [null]; + }, + async remove(id) { + let result; + try { + result = await fetcher.del(`${origin}/api/v1/groups/${id}`, { access_token: accessToken }); + } catch (e) { + return [e]; + } + + if (result.status !== 204) return [result]; + return [null]; + }, }; } diff --git a/dashboard/src/views/UsersView.vue b/dashboard/src/views/UsersView.vue index 9828cfca1..7d042a608 100644 --- a/dashboard/src/views/UsersView.vue +++ b/dashboard/src/views/UsersView.vue @@ -4,10 +4,11 @@ import { useI18n } from 'vue-i18n'; const i18n = useI18n(); const t = i18n.t; -import { ref, onMounted, computed } from 'vue'; -import { Button, ButtonGroup, TextInput, Dropdown, TableView } from 'pankow'; +import { ref, onMounted, computed, useTemplateRef } from 'vue'; +import { Button, ButtonGroup, TextInput, Dropdown, TableView, InputDialog } from 'pankow'; import { ROLES } from '../constants.js'; import Section from '../components/Section.vue'; +import GroupDialog from '../components/GroupDialog.vue'; import UsersModel from '../models/UsersModel.js'; import GroupsModel from '../models/GroupsModel.js'; import ProfileModel from '../models/ProfileModel.js'; @@ -45,6 +46,9 @@ const groups = ref([]); const groupsById = ref({}); const roles = ref([]); +const inputDialog = useTemplateRef('inputDialog'); +const groupDialog = useTemplateRef('groupDialog'); + const filteredUsers = computed(() => { return users.value.filter(u => { return u.username.indexOf(search.value) !== -1 || u.email.indexOf(search.value) !== -1 || u.displayName.indexOf(search.value) !== -1; @@ -109,6 +113,27 @@ 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 onEditOrAddGroup(group = null) { + groupDialog.value.open(group); +} + +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.memberCount }), + 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(); +} + onMounted(async () => { const [error, result] = await profileModel.get(); if (error) return console.error(error); @@ -133,6 +158,9 @@ onMounted(async () => {