Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 109 additions & 115 deletions packages/web-app-admin-settings/src/components/Users/AddToGroupsModal.vue
Original file line number Diff line number Diff line change
@@ -1,143 +1,137 @@
<template>
<group-select
:selected-groups="selectedOptions"
:group-options="groups"
:group-options="availableGroups"
:position-fixed="true"
required-mark
@selected-option-change="changeSelectedGroupOption"
/>
</template>

<script lang="ts">
import { defineComponent, PropType, Ref, ref, unref, watch } from 'vue'
<script setup lang="ts">
import { computed, Ref, ref, unref, watch } from 'vue'
import { useGettext } from 'vue3-gettext'
import { Group, User } from '@opencloud-eu/web-client/graph/generated'
import GroupSelect from './GroupSelect.vue'
import { useClientService, Modal, useMessages } from '@opencloud-eu/web-pkg'
import { useUserSettingsStore } from '../../composables/stores/userSettings'

export default defineComponent({
name: 'AddToGroupsModal',
components: { GroupSelect },
props: {
modal: { type: Object as PropType<Modal>, required: true },
groups: {
type: Array as PropType<Group[]>,
required: true
},
users: {
type: Array as PropType<User[]>,
required: true
}
},
emits: ['update:confirmDisabled'],
setup(props, { emit, expose }) {
const { showMessage, showErrorMessage } = useMessages()
const clientService = useClientService()
const { $gettext, $ngettext } = useGettext()
const userSettingsStore = useUserSettingsStore()

const selectedOptions: Ref<Group[]> = ref([])
const changeSelectedGroupOption = (options: Group[]) => {
selectedOptions.value = options
}
const { groups, users } = defineProps<{
modal: Modal
groups: Group[]
users: User[]
}>()

watch(
selectedOptions,
() => {
emit('update:confirmDisabled', !unref(selectedOptions).length)
},
{ immediate: true }
)
const emit = defineEmits<{
(e: 'update:confirmDisabled', value: boolean): void
}>()

const onConfirm = async () => {
const client = clientService.graphAuthenticated
const usersToFetch: string[] = []
const promises = unref(selectedOptions).reduce((acc, group) => {
for (const user of props.users) {
if (!user.memberOf.find((userGroup) => userGroup.id === group.id)) {
acc.push(client.groups.addMember(group.id, user.id))
if (!usersToFetch.includes(user.id)) {
usersToFetch.push(user.id)
}
}
}
return acc
}, [])

if (!promises.length) {
const title = $ngettext(
'Group assignment already added',
'Group assignments already added',
props.users.length * unref(selectedOptions).length
)
showMessage({ title })
return
}
const { showMessage, showErrorMessage } = useMessages()
const clientService = useClientService()
const { $gettext, $ngettext } = useGettext()
const userSettingsStore = useUserSettingsStore()

const results = await Promise.allSettled(promises)

const succeeded = results.filter((r) => r.status === 'fulfilled')
if (succeeded.length) {
const title =
succeeded.length === 1 && unref(selectedOptions).length === 1 && props.users.length === 1
? $gettext('Group assignment "%{group}" was added successfully', {
group: unref(selectedOptions)[0].displayName
})
: $ngettext(
'%{groupAssignmentCount} group assignment was added successfully',
'%{groupAssignmentCount} group assignments were added successfully',
succeeded.length,
{ groupAssignmentCount: succeeded.length.toString() },
true
)
showMessage({ title })
}
const selectedOptions: Ref<Group[]> = ref([])
const changeSelectedGroupOption = (options: Group[]) => {
selectedOptions.value = options
}

const failed = results.filter((r) => r.status === 'rejected')
if (failed.length) {
failed.forEach(console.error)

const title =
failed.length === 1 && unref(selectedOptions).length === 1 && props.users.length === 1
? $gettext('Failed to add group assignment "%{group}"', {
group: unref(selectedOptions)[0].displayName
})
: $ngettext(
'Failed to add %{groupAssignmentCount} group assignment',
'Failed to add %{groupAssignmentCount} group assignments',
failed.length,
{ groupAssignmentCount: failed.length.toString() },
true
)
showErrorMessage({
title,
errors: (failed as PromiseRejectedResult[]).map((f) => f.reason)
})
}
const availableGroups = computed(() => {
if (users.length > 1) {
// return all groups if multiple users are selected since we don't want to compute the intersection
return groups
}
return groups.filter(
(group) => !users.some((user) => user.memberOf.some(({ id }) => id === group.id))
)
})

try {
const usersResponse = await Promise.all(
usersToFetch.map((userId) => client.users.getUser(userId))
)
watch(
selectedOptions,
() => {
emit('update:confirmDisabled', !unref(selectedOptions).length)
},
{ immediate: true }
)

usersResponse.forEach((user) => {
userSettingsStore.upsertUser(user)
})
} catch (e) {
console.error(e)
const onConfirm = async () => {
const client = clientService.graphAuthenticated
const usersToFetch: string[] = []
const promises = unref(selectedOptions).reduce((acc, group) => {
for (const user of users) {
if (!user.memberOf.find((userGroup) => userGroup.id === group.id)) {
acc.push(client.groups.addMember(group.id, user.id))
if (!usersToFetch.includes(user.id)) {
usersToFetch.push(user.id)
}
}
}
return acc
}, [])

expose({ onConfirm })
if (!promises.length) {
const title = $ngettext(
'Group assignment already added',
'Group assignments already added',
users.length * unref(selectedOptions).length
)
showMessage({ title })
return
}

return {
selectedOptions,
changeSelectedGroupOption,
const results = await Promise.allSettled(promises)

// unit tests
onConfirm
}
const succeeded = results.filter((r) => r.status === 'fulfilled')
if (succeeded.length) {
const title =
succeeded.length === 1 && unref(selectedOptions).length === 1 && users.length === 1
? $gettext('Group assignment "%{group}" was added successfully', {
group: unref(selectedOptions)[0].displayName
})
: $ngettext(
'%{groupAssignmentCount} group assignment was added successfully',
'%{groupAssignmentCount} group assignments were added successfully',
succeeded.length,
{ groupAssignmentCount: succeeded.length.toString() },
true
)
showMessage({ title })
}
})

const failed = results.filter((r) => r.status === 'rejected')
if (failed.length) {
failed.forEach(console.error)

const title =
failed.length === 1 && unref(selectedOptions).length === 1 && users.length === 1
? $gettext('Failed to add group assignment "%{group}"', {
group: unref(selectedOptions)[0].displayName
})
: $ngettext(
'Failed to add %{groupAssignmentCount} group assignment',
'Failed to add %{groupAssignmentCount} group assignments',
failed.length,
{ groupAssignmentCount: failed.length.toString() },
true
)
showErrorMessage({
title,
errors: (failed as PromiseRejectedResult[]).map((f) => f.reason)
})
}

try {
const usersResponse = await Promise.all(
usersToFetch.map((userId) => client.users.getUser(userId))
)

usersResponse.forEach((user) => {
userSettingsStore.upsertUser(user)
})
} catch (e) {
console.error(e)
}
}

defineExpose({ onConfirm })
</script>
Loading