Fix adding/removing users to group. Remove add all button
This commit is contained in:
parent
4d475c3cd4
commit
095bb83202
|
@ -1,42 +1,60 @@
|
||||||
<script>
|
<script>
|
||||||
import { ActionButton, Icon, Search, Divider, Detail } from "@budibase/bbui"
|
import { Icon, Search, Divider, Layout } from "@budibase/bbui"
|
||||||
|
import { createEventDispatcher } from "svelte"
|
||||||
|
|
||||||
export let searchTerm = ""
|
export let searchTerm = ""
|
||||||
export let selected
|
export let selected
|
||||||
export let filtered = []
|
export let list = []
|
||||||
export let addAll
|
export let labelKey
|
||||||
export let select
|
|
||||||
export let title
|
const dispatch = createEventDispatcher()
|
||||||
export let key
|
|
||||||
|
$: enrichedList = enrich(list, selected)
|
||||||
|
$: sortedList = sort(enrichedList)
|
||||||
|
|
||||||
|
const enrich = (list, selected) => {
|
||||||
|
return list.map(item => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
selected: selected.find(x => x._id === item._id) != null,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const sort = list => {
|
||||||
|
let sortedList = list.slice()
|
||||||
|
sortedList.sort((a, b) => {
|
||||||
|
if (a.selected === b.selected) {
|
||||||
|
return a[labelKey] < b[labelKey] ? -1 : 1
|
||||||
|
} else if (a.selected) {
|
||||||
|
return -1
|
||||||
|
} else if (b.selected) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
})
|
||||||
|
return sortedList
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div style="padding: var(--spacing-m)">
|
<div class="container">
|
||||||
|
<Layout gap="S">
|
||||||
|
<div class="header">
|
||||||
<Search placeholder="Search" bind:value={searchTerm} />
|
<Search placeholder="Search" bind:value={searchTerm} />
|
||||||
<div class="header sub-header">
|
|
||||||
<div>
|
|
||||||
<Detail
|
|
||||||
>{filtered.length} {title}{filtered.length === 1 ? "" : "s"}</Detail
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<ActionButton on:click={addAll} emphasized size="S">Add all</ActionButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<Divider noMargin />
|
<Divider noMargin />
|
||||||
<div>
|
<div class="items">
|
||||||
{#each filtered as item}
|
{#each sortedList as item}
|
||||||
<div
|
<div
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
select(item._id)
|
dispatch(item.selected ? "deselect" : "select", item._id)
|
||||||
}}
|
}}
|
||||||
style="padding-bottom: var(--spacing-m)"
|
class="item"
|
||||||
class="selection"
|
|
||||||
>
|
>
|
||||||
<div>
|
<div class="text">
|
||||||
{item[key]}
|
{item[labelKey]}
|
||||||
</div>
|
</div>
|
||||||
|
{#if item.selected}
|
||||||
{#if selected.includes(item._id)}
|
|
||||||
<div>
|
<div>
|
||||||
<Icon
|
<Icon
|
||||||
color="var(--spectrum-global-color-blue-600);"
|
color="var(--spectrum-global-color-blue-600);"
|
||||||
|
@ -47,29 +65,45 @@
|
||||||
</div>
|
</div>
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
</Layout>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
.container {
|
||||||
|
width: 280px;
|
||||||
|
}
|
||||||
.header {
|
.header {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
padding: var(--spacing-m) 0 var(--spacing-m) 0;
|
display: grid;
|
||||||
display: flex;
|
gap: var(--spacing-m);
|
||||||
justify-content: space-between;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
.items {
|
||||||
.selection {
|
max-height: 242px;
|
||||||
|
overflow: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
margin: 0 calc(-1 * var(--spacing-m));
|
||||||
|
margin-top: -8px;
|
||||||
|
}
|
||||||
|
.item {
|
||||||
align-items: end;
|
align-items: end;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
padding: var(--spacing-s) var(--spacing-l);
|
||||||
|
background: var(--spectrum-global-color-gray-50);
|
||||||
|
transition: background 130ms ease-out;
|
||||||
|
gap: var(--spacing-xl);
|
||||||
}
|
}
|
||||||
|
.item:hover {
|
||||||
.selection > :first-child {
|
background: var(--spectrum-global-color-gray-100);
|
||||||
padding-top: var(--spacing-m);
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
.text {
|
||||||
.sub-header {
|
flex: 1 1 auto;
|
||||||
display: flex;
|
width: 0;
|
||||||
justify-content: space-between;
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -31,7 +31,6 @@
|
||||||
let popoverAnchor
|
let popoverAnchor
|
||||||
let popover
|
let popover
|
||||||
let searchTerm = ""
|
let searchTerm = ""
|
||||||
let selectedUsers = []
|
|
||||||
let prevSearch = undefined
|
let prevSearch = undefined
|
||||||
let pageInfo = createPaginationStore()
|
let pageInfo = createPaginationStore()
|
||||||
let loaded = false
|
let loaded = false
|
||||||
|
@ -41,9 +40,7 @@
|
||||||
$: page = $pageInfo.page
|
$: page = $pageInfo.page
|
||||||
$: fetchUsers(page, searchTerm)
|
$: fetchUsers(page, searchTerm)
|
||||||
$: group = $groups.find(x => x._id === groupId)
|
$: group = $groups.find(x => x._id === groupId)
|
||||||
$: filtered =
|
$: filtered = $users.data
|
||||||
$users.data?.filter(x => !group?.users.map(y => y._id).includes(x._id)) ||
|
|
||||||
[]
|
|
||||||
$: groupApps = $apps.filter(x => group?.apps.includes(x.appId))
|
$: groupApps = $apps.filter(x => group?.apps.includes(x.appId))
|
||||||
$: {
|
$: {
|
||||||
if (loaded && !group?._id) {
|
if (loaded && !group?._id) {
|
||||||
|
@ -51,53 +48,24 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function addAll() {
|
const adduserToGroup = async id => {
|
||||||
selectedUsers = [...selectedUsers, ...filtered.map(u => u._id)]
|
const user = await users.get(id)
|
||||||
|
if (!user?._id) {
|
||||||
let reducedUserObjects = filtered.map(u => {
|
return
|
||||||
return {
|
|
||||||
_id: u._id,
|
|
||||||
email: u.email,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check we haven't already been added
|
||||||
|
if (group.users?.find(x => x._id === user._id)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update group
|
||||||
|
await groups.actions.save({
|
||||||
|
...group,
|
||||||
|
users: [...group.users, { _id: user._id, email: user.email }],
|
||||||
})
|
})
|
||||||
group.users = [...reducedUserObjects, ...group.users]
|
|
||||||
|
|
||||||
await groups.actions.save(group)
|
|
||||||
|
|
||||||
$users.data.forEach(async user => {
|
|
||||||
let userToEdit = await users.get(user._id)
|
|
||||||
let userGroups = userToEdit.userGroups || []
|
|
||||||
userGroups.push(groupId)
|
|
||||||
await users.save({
|
|
||||||
...userToEdit,
|
|
||||||
userGroups,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function selectUser(id) {
|
|
||||||
let selectedUser = selectedUsers.includes(id)
|
|
||||||
if (selectedUser) {
|
|
||||||
selectedUsers = selectedUsers.filter(id => id !== selectedUser)
|
|
||||||
let newUsers = group.users.filter(user => user._id !== id)
|
|
||||||
group.users = newUsers
|
|
||||||
} else {
|
|
||||||
let enrichedUser = $users.data
|
|
||||||
.filter(user => user._id === id)
|
|
||||||
.map(u => {
|
|
||||||
return {
|
|
||||||
_id: u._id,
|
|
||||||
email: u.email,
|
|
||||||
}
|
|
||||||
})[0]
|
|
||||||
selectedUsers = [...selectedUsers, id]
|
|
||||||
group.users.push(enrichedUser)
|
|
||||||
}
|
|
||||||
|
|
||||||
await groups.actions.save(group)
|
|
||||||
|
|
||||||
let user = await users.get(id)
|
|
||||||
|
|
||||||
|
// Update user
|
||||||
let userGroups = user.userGroups || []
|
let userGroups = user.userGroups || []
|
||||||
userGroups.push(groupId)
|
userGroups.push(groupId)
|
||||||
await users.save({
|
await users.save({
|
||||||
|
@ -106,17 +74,23 @@
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function removeUser(id) {
|
const removeUserFromGroup = async id => {
|
||||||
let newUsers = group.users.filter(user => user._id !== id)
|
const user = await users.get(id)
|
||||||
group.users = newUsers
|
if (!user?._id) {
|
||||||
let user = await users.get(id)
|
return
|
||||||
|
}
|
||||||
|
|
||||||
await users.save({
|
// Update group
|
||||||
...user,
|
await groups.actions.save({
|
||||||
userGroups: [],
|
...group,
|
||||||
|
users: group.users.filter(x => x._id !== id),
|
||||||
})
|
})
|
||||||
|
|
||||||
await groups.actions.save(group)
|
// Update user
|
||||||
|
await users.save({
|
||||||
|
...user,
|
||||||
|
userGroups: user.userGroups.filter(x => x !== groupId),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchUsers(page, search) {
|
async function fetchUsers(page, search) {
|
||||||
|
@ -150,7 +124,6 @@
|
||||||
notifications.success("User group deleted successfully")
|
notifications.success("User group deleted successfully")
|
||||||
$goto("./")
|
$goto("./")
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
|
||||||
notifications.error(`Failed to delete user group`)
|
notifications.error(`Failed to delete user group`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,13 +189,12 @@
|
||||||
</div>
|
</div>
|
||||||
<Popover align="right" bind:this={popover} anchor={popoverAnchor}>
|
<Popover align="right" bind:this={popover} anchor={popoverAnchor}>
|
||||||
<UserGroupPicker
|
<UserGroupPicker
|
||||||
key={"email"}
|
|
||||||
title={"User"}
|
|
||||||
bind:searchTerm
|
bind:searchTerm
|
||||||
bind:selected={selectedUsers}
|
labelKey="email"
|
||||||
bind:filtered
|
selected={group.users}
|
||||||
{addAll}
|
list={$users.data}
|
||||||
select={selectUser}
|
on:select={e => adduserToGroup(e.detail)}
|
||||||
|
on:deselect={e => removeUserFromGroup(e.detail)}
|
||||||
/>
|
/>
|
||||||
</Popover>
|
</Popover>
|
||||||
</div>
|
</div>
|
||||||
|
@ -236,7 +208,7 @@
|
||||||
hoverable
|
hoverable
|
||||||
>
|
>
|
||||||
<Icon
|
<Icon
|
||||||
on:click={() => removeUser(user._id)}
|
on:click={() => removeUserFromGroup(user._id)}
|
||||||
hoverable
|
hoverable
|
||||||
size="S"
|
size="S"
|
||||||
name="Close"
|
name="Close"
|
||||||
|
|
Loading…
Reference in New Issue