Update user and group details pages with new tables
This commit is contained in:
parent
e91ed89d72
commit
3dd5916f24
8 changed files with 155 additions and 131 deletions
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import Field from "./Field.svelte"
|
||||
import Select from "./Core/Select.svelte"
|
||||
import { createEventDispatcher } from "svelte"
|
||||
|
||||
export let value = null
|
||||
export let label = undefined
|
||||
|
@ -20,6 +21,12 @@
|
|||
export let sort = false
|
||||
export let tooltip = ""
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const onChange = e => {
|
||||
value = e.detail
|
||||
dispatch("change", e.detail)
|
||||
}
|
||||
|
||||
const extractProperty = (value, property) => {
|
||||
if (value && typeof value === "object") {
|
||||
return value[property]
|
||||
|
@ -44,7 +51,7 @@
|
|||
{getOptionIcon}
|
||||
{getOptionColour}
|
||||
{isOptionEnabled}
|
||||
on:change
|
||||
on:change={onChange}
|
||||
on:click
|
||||
/>
|
||||
</Field>
|
||||
|
|
|
@ -14,8 +14,8 @@
|
|||
quiet
|
||||
allowRemove
|
||||
allowPublic={false}
|
||||
on:change={e => rolesContext.updateUserRole(e.detail, row._id)}
|
||||
on:remove={() => rolesContext.removeUserRole(row._id)}
|
||||
on:change={e => rolesContext.updateRole(e.detail, row._id)}
|
||||
on:remove={() => rolesContext.removeRole(row._id)}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
<script>
|
||||
import RoleSelect from "components/common/RoleSelect.svelte"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
const rolesContext = getContext("roles")
|
||||
|
||||
export let value
|
||||
export let row
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<RoleSelect
|
||||
{value}
|
||||
quiet
|
||||
allowRemove
|
||||
allowPublic={false}
|
||||
on:change={e => rolesContext.updateGroupRole(e.detail, row._id)}
|
||||
on:remove={() => rolesContext.removeGroupRole(row._id)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
|
@ -16,15 +16,14 @@
|
|||
import { roles } from "stores/backend"
|
||||
import { API } from "api"
|
||||
import { fetchData } from "@budibase/frontend-core"
|
||||
import UserRoleRenderer from "./_components/UserRoleRenderer.svelte"
|
||||
import GroupRoleRenderer from "./_components/GroupRoleRenderer.svelte"
|
||||
import EditableRoleRenderer from "./_components/EditableRoleRenderer.svelte"
|
||||
|
||||
const userSchema = {
|
||||
email: {
|
||||
type: "string",
|
||||
width: "1fr",
|
||||
},
|
||||
userAppRole: {
|
||||
role: {
|
||||
displayName: "Access",
|
||||
width: "150px",
|
||||
borderLeft: true,
|
||||
|
@ -35,7 +34,7 @@
|
|||
type: "string",
|
||||
width: "1fr",
|
||||
},
|
||||
groupAppRole: {
|
||||
role: {
|
||||
displayName: "Access",
|
||||
width: "150px",
|
||||
borderLeft: true,
|
||||
|
@ -43,12 +42,8 @@
|
|||
}
|
||||
const customRenderers = [
|
||||
{
|
||||
column: "userAppRole",
|
||||
component: UserRoleRenderer,
|
||||
},
|
||||
{
|
||||
column: "groupAppRole",
|
||||
component: GroupRoleRenderer,
|
||||
column: "role",
|
||||
component: EditableRoleRenderer,
|
||||
},
|
||||
]
|
||||
|
||||
|
@ -76,7 +71,7 @@
|
|||
const getAppUsers = (users, appId) => {
|
||||
return users.map(user => ({
|
||||
...user,
|
||||
userAppRole: user.roles[Object.keys(user.roles).find(x => x === appId)],
|
||||
role: user.roles[Object.keys(user.roles).find(x => x === appId)],
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -90,13 +85,30 @@
|
|||
})
|
||||
.map(group => ({
|
||||
...group,
|
||||
groupAppRole:
|
||||
group.roles[
|
||||
groups.actions.getGroupAppIds(group).find(x => x === appId)
|
||||
],
|
||||
role: group.roles[
|
||||
groups.actions.getGroupAppIds(group).find(x => x === appId)
|
||||
],
|
||||
}))
|
||||
}
|
||||
|
||||
const updateRole = async (role, id) => {
|
||||
// Check if this is a user or a group
|
||||
if ($usersFetch.rows.some(user => user._id === id)) {
|
||||
await updateUserRole(role, id)
|
||||
} else {
|
||||
await updateGroupRole(role, id)
|
||||
}
|
||||
}
|
||||
|
||||
const removeRole = async id => {
|
||||
// Check if this is a user or a group
|
||||
if ($usersFetch.rows.some(user => user._id === id)) {
|
||||
await removeUserRole(id)
|
||||
} else {
|
||||
await removeGroupRole(id)
|
||||
}
|
||||
}
|
||||
|
||||
const updateUserRole = async (role, userId) => {
|
||||
const user = $usersFetch.rows.find(user => user._id === userId)
|
||||
if (!user) {
|
||||
|
@ -142,10 +154,8 @@
|
|||
}
|
||||
|
||||
setContext("roles", {
|
||||
updateUserRole,
|
||||
removeUserRole,
|
||||
updateGroupRole,
|
||||
removeGroupRole,
|
||||
updateRole,
|
||||
removeRole,
|
||||
})
|
||||
|
||||
onMount(async () => {
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
import { url, isActive } from "@roxi/routify"
|
||||
import { Page } from "@budibase/bbui"
|
||||
import { Content, SideNav, SideNavItem } from "components/portal/page"
|
||||
|
||||
$: narrow = !$isActive("./users/index") && !$isActive("./groups/index")
|
||||
</script>
|
||||
|
||||
<Page narrow>
|
||||
|
|
|
@ -7,10 +7,7 @@
|
|||
Icon,
|
||||
Popover,
|
||||
notifications,
|
||||
List,
|
||||
ListItem,
|
||||
StatusLight,
|
||||
Divider,
|
||||
Table,
|
||||
ActionMenu,
|
||||
MenuItem,
|
||||
Modal,
|
||||
|
@ -18,32 +15,76 @@
|
|||
import UserGroupPicker from "components/settings/UserGroupPicker.svelte"
|
||||
import { createPaginationStore } from "helpers/pagination"
|
||||
import { users, apps, groups } from "stores/portal"
|
||||
import { onMount } from "svelte"
|
||||
import { RoleUtils } from "@budibase/frontend-core"
|
||||
import { onMount, setContext } from "svelte"
|
||||
import { roles } from "stores/backend"
|
||||
import ConfirmDialog from "components/common/ConfirmDialog.svelte"
|
||||
import CreateEditGroupModal from "./_components/CreateEditGroupModal.svelte"
|
||||
import GroupIcon from "./_components/GroupIcon.svelte"
|
||||
import AppAddModal from "./_components/AppAddModal.svelte"
|
||||
import { Breadcrumbs, Breadcrumb } from "components/portal/page"
|
||||
import AppNameTableRenderer from "../users/_components/AppNameTableRenderer.svelte"
|
||||
import RemoveUserTableRenderer from "./_components/RemoveUserTableRenderer.svelte"
|
||||
import AppRoleTableRenderer from "../users/_components/AppRoleTableRenderer.svelte"
|
||||
|
||||
export let groupId
|
||||
|
||||
const userSchema = {
|
||||
email: {
|
||||
width: "1fr",
|
||||
},
|
||||
_id: {
|
||||
displayName: "",
|
||||
width: "auto",
|
||||
borderLeft: true,
|
||||
},
|
||||
}
|
||||
const appSchema = {
|
||||
name: {
|
||||
width: "2fr",
|
||||
},
|
||||
role: {
|
||||
width: "1fr",
|
||||
},
|
||||
}
|
||||
const customUserTableRenderers = [
|
||||
{
|
||||
column: "_id",
|
||||
component: RemoveUserTableRenderer,
|
||||
},
|
||||
]
|
||||
const customAppTableRenderers = [
|
||||
{
|
||||
column: "name",
|
||||
component: AppNameTableRenderer,
|
||||
},
|
||||
{
|
||||
column: "role",
|
||||
component: AppRoleTableRenderer,
|
||||
},
|
||||
]
|
||||
|
||||
let popoverAnchor
|
||||
let popover
|
||||
let searchTerm = ""
|
||||
let prevSearch = undefined
|
||||
let pageInfo = createPaginationStore()
|
||||
let loaded = false
|
||||
let editModal, deleteModal, appAddModal
|
||||
let editModal, deleteModal
|
||||
|
||||
$: page = $pageInfo.page
|
||||
$: fetchUsers(page, searchTerm)
|
||||
$: group = $groups.find(x => x._id === groupId)
|
||||
$: filtered = $users.data
|
||||
$: groupApps = $apps.filter(app =>
|
||||
groups.actions.getGroupAppIds(group).includes(apps.getProdAppID(app.devId))
|
||||
)
|
||||
$: groupApps = $apps
|
||||
.filter(app =>
|
||||
groups.actions
|
||||
.getGroupAppIds(group)
|
||||
.includes(apps.getProdAppID(app.devId))
|
||||
)
|
||||
.map(app => ({
|
||||
...app,
|
||||
role: group?.roles?.[apps.getProdAppID(app.devId)],
|
||||
}))
|
||||
$: console.log(groupApps)
|
||||
$: {
|
||||
if (loaded && !group?._id) {
|
||||
$goto("./")
|
||||
|
@ -93,6 +134,22 @@
|
|||
}
|
||||
}
|
||||
|
||||
const removeUser = async id => {
|
||||
await groups.actions.removeUser(groupId, id)
|
||||
}
|
||||
|
||||
const removeApp = async app => {
|
||||
await groups.actions.removeApp(groupId, apps.getProdAppID(app.devId))
|
||||
}
|
||||
|
||||
setContext("users", {
|
||||
removeUser,
|
||||
})
|
||||
setContext("roles", {
|
||||
updateRole: () => {},
|
||||
removeRole: removeApp,
|
||||
})
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
await Promise.all([groups.actions.init(), apps.load(), roles.fetch()])
|
||||
|
@ -143,76 +200,35 @@
|
|||
/>
|
||||
</Popover>
|
||||
</div>
|
||||
<List>
|
||||
{#if group?.users.length}
|
||||
{#each group.users as user}
|
||||
<ListItem
|
||||
title={user.email}
|
||||
on:click={() => $goto(`../users/${user._id}`)}
|
||||
hoverable
|
||||
>
|
||||
<Icon
|
||||
on:click={e => {
|
||||
groups.actions.removeUser(groupId, user._id)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
hoverable
|
||||
size="S"
|
||||
name="Close"
|
||||
/>
|
||||
</ListItem>
|
||||
{/each}
|
||||
{:else}
|
||||
<ListItem icon="UserGroup" title="This user group has no users" />
|
||||
{/if}
|
||||
</List>
|
||||
|
||||
<Table
|
||||
schema={userSchema}
|
||||
data={group?.users}
|
||||
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>
|
||||
</Layout>
|
||||
|
||||
<Layout noPadding gap="S">
|
||||
<div class="header">
|
||||
<Heading size="S">Apps</Heading>
|
||||
<div>
|
||||
<Button on:click={appAddModal.show()} secondary>Add app</Button>
|
||||
<Heading size="S">Apps</Heading>
|
||||
<Table
|
||||
schema={appSchema}
|
||||
data={groupApps}
|
||||
customPlaceholder
|
||||
allowEditRows={false}
|
||||
customRenderers={customAppTableRenderers}
|
||||
on:click={e => $goto(`../../overview/${e.detail.devId}`)}
|
||||
>
|
||||
<div class="placeholder" slot="placeholder">
|
||||
<Heading size="S">This group doesn't have access to any apps</Heading>
|
||||
</div>
|
||||
</div>
|
||||
<List>
|
||||
{#if groupApps.length}
|
||||
{#each groupApps as app}
|
||||
<ListItem
|
||||
title={app.name}
|
||||
icon={app?.icon?.name || "Apps"}
|
||||
iconColor={app?.icon?.color || ""}
|
||||
on:click={() => $goto(`../../overview/${app.devId}`)}
|
||||
hoverable
|
||||
>
|
||||
<div class="title ">
|
||||
<StatusLight
|
||||
square
|
||||
color={RoleUtils.getRoleColour(
|
||||
group.roles[apps.getProdAppID(app.devId)]
|
||||
)}
|
||||
>
|
||||
{getRoleLabel(app.devId)}
|
||||
</StatusLight>
|
||||
</div>
|
||||
<Icon
|
||||
on:click={e => {
|
||||
groups.actions.removeApp(
|
||||
groupId,
|
||||
apps.getProdAppID(app.devId)
|
||||
)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
hoverable
|
||||
size="S"
|
||||
name="Close"
|
||||
/>
|
||||
</ListItem>
|
||||
{/each}
|
||||
{:else}
|
||||
<ListItem icon="Apps" title="This user group has access to no apps" />
|
||||
{/if}
|
||||
</List>
|
||||
</Table>
|
||||
</Layout>
|
||||
</Layout>
|
||||
{/if}
|
||||
|
@ -221,10 +237,6 @@
|
|||
<CreateEditGroupModal {group} {saveGroup} />
|
||||
</Modal>
|
||||
|
||||
<Modal bind:this={appAddModal}>
|
||||
<AppAddModal {group} />
|
||||
</Modal>
|
||||
|
||||
<ConfirmDialog
|
||||
bind:this={deleteModal}
|
||||
title="Delete user group"
|
||||
|
@ -245,4 +257,8 @@
|
|||
.header :global(.spectrum-Heading) {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
.placeholder {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -14,10 +14,10 @@
|
|||
<ModalContent
|
||||
onConfirm={() => saveGroup(group)}
|
||||
size="M"
|
||||
title="Create User Group"
|
||||
title={group?._rev ? "Edit group" : "Create group"}
|
||||
confirmText="Save"
|
||||
>
|
||||
<Input bind:value={group.name} label="Team name" />
|
||||
<Input bind:value={group.name} label="Name" />
|
||||
<div class="modal-format">
|
||||
<div class="modal-inner">
|
||||
<Body size="XS">Icon</Body>
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
<script>
|
||||
import { ActionButton } from "@budibase/bbui"
|
||||
import { getContext } from "svelte"
|
||||
|
||||
export let value
|
||||
|
||||
const userContext = getContext("users")
|
||||
|
||||
const onClick = e => {
|
||||
e.stopPropagation()
|
||||
userContext.removeUser(value)
|
||||
}
|
||||
</script>
|
||||
|
||||
<ActionButton size="S" on:click={onClick}>Remove</ActionButton>
|
Loading…
Reference in a new issue