Split group users component

This commit is contained in:
Adria Navarro 2023-05-05 20:10:54 +01:00
parent f8ccee80df
commit e4b0c55aa6
2 changed files with 179 additions and 146 deletions

View File

@ -1,62 +1,28 @@
<script> <script>
import { url, goto } from "@roxi/routify"
import { import {
Button, ActionMenu,
Layout,
Heading, Heading,
Icon, Icon,
Popover, Layout,
notifications,
Table,
ActionMenu,
MenuItem, MenuItem,
Modal, Modal,
Pagination, Table,
notifications,
} from "@budibase/bbui" } from "@budibase/bbui"
import { fetchData } from "@budibase/frontend-core" import { goto, url } from "@roxi/routify"
import { API } from "api"
import UserGroupPicker from "components/settings/UserGroupPicker.svelte"
import { createPaginationStore } from "helpers/pagination"
import { users, apps, groups, auth, features } from "stores/portal"
import { onMount, setContext } from "svelte"
import { roles } from "stores/backend"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { Breadcrumb, Breadcrumbs } from "components/portal/page"
import { roles } from "stores/backend"
import { apps, auth, features, groups } from "stores/portal"
import { onMount, setContext } from "svelte"
import AppNameTableRenderer from "../users/_components/AppNameTableRenderer.svelte"
import AppRoleTableRenderer from "../users/_components/AppRoleTableRenderer.svelte"
import CreateEditGroupModal from "./_components/CreateEditGroupModal.svelte" import CreateEditGroupModal from "./_components/CreateEditGroupModal.svelte"
import GroupIcon from "./_components/GroupIcon.svelte" import GroupIcon from "./_components/GroupIcon.svelte"
import { Breadcrumbs, Breadcrumb } from "components/portal/page" import GroupUsers from "./_components/GroupUsers.svelte"
import AppNameTableRenderer from "../users/_components/AppNameTableRenderer.svelte"
import RemoveUserTableRenderer from "./_components/RemoveUserTableRenderer.svelte"
import AppRoleTableRenderer from "../users/_components/AppRoleTableRenderer.svelte"
import ScimBanner from "../_components/SCIMBanner.svelte"
export let groupId export let groupId
const fetchGroupUsers = fetchData({
API,
datasource: {
type: "groupUser",
},
options: {
query: {
groupId,
},
},
})
$: userSchema = {
email: {
width: "1fr",
},
...(readonly
? {}
: {
_id: {
displayName: "",
width: "auto",
borderLeft: true,
},
}),
}
const appSchema = { const appSchema = {
name: { name: {
width: "2fr", width: "2fr",
@ -65,12 +31,6 @@
width: "1fr", width: "1fr",
}, },
} }
const customUserTableRenderers = [
{
column: "_id",
component: RemoveUserTableRenderer,
},
]
const customAppTableRenderers = [ const customAppTableRenderers = [
{ {
column: "name", column: "name",
@ -82,18 +42,11 @@
}, },
] ]
let popoverAnchor
let popover
let searchTerm = ""
let prevSearch = undefined
let searchUsersPageInfo = createPaginationStore()
let loaded = false let loaded = false
let editModal, deleteModal let editModal, deleteModal
$: scimEnabled = $features.isScimEnabled $: scimEnabled = $features.isScimEnabled
$: readonly = !$auth.isAdmin || scimEnabled $: readonly = !$auth.isAdmin || scimEnabled
$: page = $searchUsersPageInfo.page
$: searchUsers(page, searchTerm)
$: group = $groups.find(x => x._id === groupId) $: group = $groups.find(x => x._id === groupId)
$: groupApps = $apps $: groupApps = $apps
.filter(app => .filter(app =>
@ -111,25 +64,6 @@
} }
} }
async function searchUsers(page, search) {
if ($searchUsersPageInfo.loading) {
return
}
// need to remove the page if they've started searching
if (search && !prevSearch) {
searchUsersPageInfo.reset()
page = undefined
}
prevSearch = search
try {
searchUsersPageInfo.loading()
await users.search({ page, email: search })
searchUsersPageInfo.fetched($users.hasNextPage, $users.nextPage)
} catch (error) {
notifications.error("Error getting user list")
}
}
async function deleteGroup() { async function deleteGroup() {
try { try {
await groups.actions.delete(group) await groups.actions.delete(group)
@ -148,18 +82,9 @@
} }
} }
const removeUser = async id => {
await groups.actions.removeUser(groupId, id)
fetchGroupUsers.refresh()
}
const removeApp = async app => { const removeApp = async app => {
await groups.actions.removeApp(groupId, apps.getProdAppID(app.devId)) await groups.actions.removeApp(groupId, apps.getProdAppID(app.devId))
} }
setContext("users", {
removeUser,
})
setContext("roles", { setContext("roles", {
updateRole: () => {}, updateRole: () => {},
removeRole: removeApp, removeRole: removeApp,
@ -201,65 +126,7 @@
</div> </div>
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<div class="header"> <GroupUsers {groupId} />
<Heading size="S">Users</Heading>
{#if !scimEnabled}
<div bind:this={popoverAnchor}>
<Button disabled={readonly} on:click={popover.show()} cta
>Add user</Button
>
</div>
{:else}
<ScimBanner />
{/if}
<Popover align="right" bind:this={popover} anchor={popoverAnchor}>
<UserGroupPicker
bind:searchTerm
labelKey="email"
selected={group.users?.map(user => user._id)}
list={$users.data}
on:select={async e => {
await groups.actions.addUser(groupId, e.detail)
fetchGroupUsers.getInitialData()
}}
on:deselect={async e => {
await groups.actions.removeUser(groupId, e.detail)
fetchGroupUsers.getInitialData()
}}
/>
</Popover>
</div>
<Table
schema={userSchema}
data={$fetchGroupUsers?.rows}
allowEditRows={false}
customPlaceholder
customRenderers={customUserTableRenderers}
on:click={e => $goto(`../users/${e.detail._id}`)}
>
<div class="placeholder" slot="placeholder">
<Heading size="S">This user group doesn't have any users</Heading>
</div>
</Table>
<div class="pagination">
<Pagination
page={$fetchGroupUsers.pageNumber + 1}
hasPrevPage={$fetchGroupUsers.loading
? false
: $fetchGroupUsers.hasPrevPage}
hasNextPage={$fetchGroupUsers.loading
? false
: $fetchGroupUsers.hasNextPage}
goToPrevPage={$fetchGroupUsers.loading
? null
: fetchGroupUsers.prevPage}
goToNextPage={$fetchGroupUsers.loading
? null
: fetchGroupUsers.nextPage}
/>
</div>
</Layout> </Layout>
<Layout noPadding gap="S"> <Layout noPadding gap="S">

View File

@ -0,0 +1,166 @@
<script>
import {
Button,
Heading,
Pagination,
Popover,
Table,
notifications,
} from "@budibase/bbui"
import { fetchData } from "@budibase/frontend-core"
import { goto } from "@roxi/routify"
import { API } from "api"
import UserGroupPicker from "components/settings/UserGroupPicker.svelte"
import { createPaginationStore } from "helpers/pagination"
import { auth, features, groups, users } from "stores/portal"
import { setContext } from "svelte"
import ScimBanner from "../../_components/SCIMBanner.svelte"
import RemoveUserTableRenderer from "../_components/RemoveUserTableRenderer.svelte"
export let groupId
const fetchGroupUsers = fetchData({
API,
datasource: {
type: "groupUser",
},
options: {
query: {
groupId,
},
},
})
$: userSchema = {
email: {
width: "1fr",
},
...(readonly
? {}
: {
_id: {
displayName: "",
width: "auto",
borderLeft: true,
},
}),
}
const customUserTableRenderers = [
{
column: "_id",
component: RemoveUserTableRenderer,
},
]
let popoverAnchor
let popover
let searchTerm = ""
let prevSearch = undefined
let searchUsersPageInfo = createPaginationStore()
$: scimEnabled = $features.isScimEnabled
$: readonly = !$auth.isAdmin || scimEnabled
$: page = $searchUsersPageInfo.page
$: searchUsers(page, searchTerm)
$: group = $groups.find(x => x._id === groupId)
async function searchUsers(page, search) {
if ($searchUsersPageInfo.loading) {
return
}
// need to remove the page if they've started searching
if (search && !prevSearch) {
searchUsersPageInfo.reset()
page = undefined
}
prevSearch = search
try {
searchUsersPageInfo.loading()
await users.search({ page, email: search })
searchUsersPageInfo.fetched($users.hasNextPage, $users.nextPage)
} catch (error) {
notifications.error("Error getting user list")
}
}
const removeUser = async id => {
await groups.actions.removeUser(groupId, id)
fetchGroupUsers.refresh()
}
setContext("users", {
removeUser,
})
</script>
<div class="header">
<Heading size="S">Users</Heading>
{#if !scimEnabled}
<div bind:this={popoverAnchor}>
<Button disabled={readonly} on:click={popover.show()} cta>Add user</Button
>
</div>
{:else}
<ScimBanner />
{/if}
<Popover align="right" bind:this={popover} anchor={popoverAnchor}>
<UserGroupPicker
bind:searchTerm
labelKey="email"
selected={group.users?.map(user => user._id)}
list={$users.data}
on:select={async e => {
await groups.actions.addUser(groupId, e.detail)
fetchGroupUsers.getInitialData()
}}
on:deselect={async e => {
await groups.actions.removeUser(groupId, e.detail)
fetchGroupUsers.getInitialData()
}}
/>
</Popover>
</div>
<Table
schema={userSchema}
data={$fetchGroupUsers?.rows}
allowEditRows={false}
customPlaceholder
customRenderers={customUserTableRenderers}
on:click={e => $goto(`../users/${e.detail._id}`)}
>
<div class="placeholder" slot="placeholder">
<Heading size="S">This user group doesn't have any users</Heading>
</div>
</Table>
<div class="pagination">
<Pagination
page={$fetchGroupUsers.pageNumber + 1}
hasPrevPage={$fetchGroupUsers.loading
? false
: $fetchGroupUsers.hasPrevPage}
hasNextPage={$fetchGroupUsers.loading
? false
: $fetchGroupUsers.hasNextPage}
goToPrevPage={$fetchGroupUsers.loading ? null : fetchGroupUsers.prevPage}
goToNextPage={$fetchGroupUsers.loading ? null : fetchGroupUsers.nextPage}
/>
</div>
<style>
.header {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: center;
gap: var(--spacing-l);
}
.header :global(.spectrum-Heading) {
flex: 1 1 auto;
}
.placeholder {
width: 100%;
text-align: center;
}
</style>