Fix multiple issues in user details page

This commit is contained in:
Andrew Kingston 2022-08-04 15:33:51 +01:00
parent 06cd87aa2e
commit 136bb5742f
4 changed files with 115 additions and 134 deletions

View File

@ -16,7 +16,7 @@
return list.map(item => {
return {
...item,
selected: selected.find(x => x._id === item._id) != null,
selected: selected.find(x => x === item._id) != null,
}
})
}

View File

@ -48,51 +48,6 @@
}
}
const adduserToGroup = async id => {
const user = await users.get(id)
if (!user?._id) {
return
}
// 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 }],
})
// Update user
let userGroups = user.userGroups || []
userGroups.push(groupId)
await users.save({
...user,
userGroups,
})
}
const removeUserFromGroup = async id => {
const user = await users.get(id)
if (!user?._id) {
return
}
// Update group
await groups.actions.save({
...group,
users: group.users.filter(x => x._id !== id),
})
// Update user
await users.save({
...user,
userGroups: user.userGroups.filter(x => x !== groupId),
})
}
async function fetchUsers(page, search) {
if ($pageInfo.loading) {
return
@ -191,10 +146,10 @@
<UserGroupPicker
bind:searchTerm
labelKey="email"
selected={group.users}
selected={group.users?.map(user => user._id)}
list={$users.data}
on:select={e => adduserToGroup(e.detail)}
on:deselect={e => removeUserFromGroup(e.detail)}
on:select={e => groups.actions.addUser(groupId, e.detail)}
on:deselect={e => groups.actions.removeUser(groupId, e.detail)}
/>
</Popover>
</div>
@ -209,7 +164,7 @@
>
<Icon
on:click={e => {
removeUserFromGroup(user._id)
groups.actions.removeUser(groupId, user._id)
e.stopPropagation()
}}
hoverable

View File

@ -22,7 +22,6 @@
StatusLight,
} from "@budibase/bbui"
import { onMount } from "svelte"
import { fetchData } from "helpers"
import { users, auth, groups, apps } from "stores/portal"
import { roles } from "stores/backend"
import { Constants } from "@budibase/frontend-core"
@ -38,28 +37,23 @@
let popoverAnchor
let searchTerm = ""
let popover
let selectedGroups = []
let allAppList = []
let user
let loaded = false
$: fetchUser(userId)
$: fullName = $userFetch?.data?.firstName
? $userFetch?.data?.firstName + " " + $userFetch?.data?.lastName
: ""
$: nameLabel = getNameLabel($userFetch)
$: fullName = user?.firstName ? user?.firstName + " " + user?.lastName : ""
$: nameLabel = getNameLabel(user)
$: initials = getInitials(nameLabel)
$: filteredGroups = getFilteredGroups($groups, searchTerm)
$: allAppList = $apps
.filter(x => {
if ($userFetch.data?.roles) {
return Object.keys($userFetch.data.roles).find(y => {
return x.appId === apps.extractAppId(y)
})
}
return Object.keys(user?.roles || {}).find(y => {
return x.appId === apps.extractAppId(y)
})
})
.map(app => {
let roles = Object.fromEntries(
Object.entries($userFetch.data.roles).filter(([key]) => {
Object.entries(user?.roles).filter(([key]) => {
return apps.extractAppId(key) === app.appId
})
)
@ -70,27 +64,27 @@
roles,
}
})
// Used for searching through groups in the add group popover
$: filteredGroups = $groups.filter(
group =>
selectedGroups &&
group?.name?.toLowerCase().includes(searchTerm.toLowerCase())
)
$: userGroups = $groups.filter(x => {
return x.users?.find(y => {
return y._id === userId
})
})
$: globalRole = $userFetch?.data?.admin?.global
$: globalRole = user?.admin?.global
? "admin"
: $userFetch?.data?.builder?.global
: user?.builder?.global
? "developer"
: "appUser"
const userFetch = fetchData(`/api/global/users/${userId}`)
const getFilteredGroups = (groups, search) => {
if (!search) {
return groups
}
search = search.toLowerCase()
return groups.filter(group => group.name?.toLowerCase().includes(search))
}
const getNameLabel = userFetch => {
const { firstName, lastName, email } = userFetch?.data || {}
const getNameLabel = user => {
const { firstName, lastName, email } = user || {}
if (!firstName && !lastName) {
return email || ""
}
@ -136,24 +130,17 @@
}
async function updateUserFirstName(evt) {
try {
await users.save({ ...$userFetch?.data, firstName: evt.target.value })
await userFetch.refresh()
await users.save({ ...user, firstName: evt.target.value })
await fetchUser()
} catch (error) {
notifications.error("Error updating user")
}
}
async function removeGroup(id) {
let updatedGroup = $groups.find(x => x._id === id)
let newUsers = updatedGroup.users.filter(user => user._id !== userId)
updatedGroup.users = newUsers
groups.actions.save(updatedGroup)
}
async function updateUserLastName(evt) {
try {
await users.save({ ...$userFetch?.data, lastName: evt.target.value })
await userFetch.refresh()
await users.save({ ...user, lastName: evt.target.value })
await fetchUser()
} catch (error) {
notifications.error("Error updating user")
}
@ -169,25 +156,8 @@
}
}
async function addGroup(groupId) {
let selectedGroup = selectedGroups.includes(groupId)
let group = $groups.find(group => group._id === groupId)
if (selectedGroup) {
selectedGroups = selectedGroups.filter(id => id === selectedGroup)
let newUsers = group.users.filter(groupUser => user._id !== groupUser._id)
group.users = newUsers
} else {
selectedGroups = [...selectedGroups, groupId]
group.users.push(user)
}
await groups.actions.save(group)
}
async function fetchUser(userId) {
let userPromise = users.get(userId)
user = await userPromise
async function fetchUser() {
user = await users.get(userId)
if (!user?._id) {
$goto("./")
}
@ -195,17 +165,31 @@
async function toggleFlags(detail) {
try {
await users.save({ ...$userFetch?.data, ...detail })
await userFetch.refresh()
await users.save({ ...user, ...detail })
await fetchUser()
} catch (error) {
notifications.error("Error updating user")
}
}
function addAll() {}
const addGroup = async groupId => {
await groups.actions.addUser(groupId, userId)
await fetchUser()
}
const removeGroup = async groupId => {
await groups.actions.removeUser(groupId, userId)
await fetchUser()
}
onMount(async () => {
try {
await Promise.all([groups.actions.init(), apps.load(), roles.fetch()])
await Promise.all([
fetchUser(),
groups.actions.init(),
apps.load(),
roles.fetch(),
])
loaded = true
} catch (error) {
notifications.error("Error getting user groups")
@ -228,8 +212,8 @@
<Avatar size="XXL" {initials} />
<div class="subtitle">
<Heading size="S">{nameLabel}</Heading>
{#if nameLabel !== $userFetch?.data?.email}
<Body size="S">{$userFetch?.data?.email}</Body>
{#if nameLabel !== user?.email}
<Body size="S">{user?.email}</Body>
{/if}
</div>
</div>
@ -256,21 +240,15 @@
<div class="fields">
<div class="field">
<Label size="L">Email</Label>
<Input disabled value={$userFetch?.data?.email} />
<Input disabled value={user?.email} />
</div>
<div class="field">
<Label size="L">First name</Label>
<Input
value={$userFetch?.data?.firstName}
on:blur={updateUserFirstName}
/>
<Input value={user?.firstName} on:blur={updateUserFirstName} />
</div>
<div class="field">
<Label size="L">Last name</Label>
<Input
value={$userFetch?.data?.lastName}
on:blur={updateUserLastName}
/>
<Input value={user?.lastName} on:blur={updateUserLastName} />
</div>
<!-- don't let a user remove the privileges that let them be here -->
{#if userId !== $auth.user._id}
@ -304,13 +282,12 @@
</div>
<Popover align="right" bind:this={popover} anchor={popoverAnchor}>
<UserGroupPicker
key={"name"}
title={"User group"}
labelKey="name"
bind:searchTerm
bind:selected={selectedGroups}
bind:filtered={filteredGroups}
{addAll}
select={addGroup}
list={filteredGroups}
selected={user.userGroups}
on:select={e => addGroup(e.detail)}
on:deselect={e => removeGroup(e.detail)}
/>
</Popover>
</div>
@ -325,7 +302,10 @@
on:click={() => $goto(`../groups/${group._id}`)}
>
<Icon
on:click={removeGroup(group._id)}
on:click={e => {
removeGroup(group._id)
e.stopPropagation()
}}
hoverable
size="S"
name="Close"
@ -370,13 +350,10 @@
{/if}
<Modal bind:this={deleteModal}>
<DeleteUserModal user={$userFetch.data} />
<DeleteUserModal {user} />
</Modal>
<Modal bind:this={resetPasswordModal}>
<ForceResetPasswordModal
user={$userFetch.data}
on:update={userFetch.refresh}
/>
<ForceResetPasswordModal {user} on:update={fetchUser} />
</Modal>
<style>

View File

@ -1,6 +1,6 @@
import { writable, get } from "svelte/store"
import { API } from "api"
import { auth } from "stores/portal"
import { auth, users } from "stores/portal"
export function createGroupsStore() {
const store = writable([])
@ -10,8 +10,8 @@ export function createGroupsStore() {
// only init if these is a groups license, just to be sure but the feature will be blocked
// on the backend anyway
if (get(auth).groupsEnabled) {
const users = await API.getGroups()
store.set(users)
const groups = await API.getGroups()
store.set(groups)
}
},
@ -41,6 +41,55 @@ export function createGroupsStore() {
return state
})
},
addUser: async (groupId, userId) => {
// Sanity check
const user = await users.get(userId)
const group = get(store).find(x => x._id === groupId)
if (!group?._id || !user?._id) {
return
}
// Check we haven't already been added
if (group.users?.find(x => x._id === userId)) {
return
}
// Update group
await actions.save({
...group,
users: [...group.users, { _id: userId, email: user.email }],
})
// Update user
let userGroups = user.userGroups || []
userGroups.push(groupId)
await users.save({
...user,
userGroups,
})
},
removeUser: async (groupId, userId) => {
// Sanity check
const user = await users.get(userId)
const group = get(store).find(x => x._id === groupId)
if (!group?._id || !user?._id) {
return
}
// Update group
await actions.save({
...group,
users: group.users.filter(x => x._id !== userId),
})
// Update user
await users.save({
...user,
userGroups: user.userGroups.filter(x => x !== groupId),
})
},
}
return {