Merge pull request #7981 from Budibase/feature/group-app-add

Add apps to a group from within groups interface
This commit is contained in:
Michael Drury 2022-09-26 19:18:44 +01:00 committed by GitHub
commit 190c54fb86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 12 deletions

View File

@ -36,6 +36,7 @@ exports.getDevelopmentAppID = appId => {
const rest = split.join(APP_PREFIX) const rest = split.join(APP_PREFIX)
return `${APP_DEV_PREFIX}${rest}` return `${APP_DEV_PREFIX}${rest}`
} }
exports.getDevAppID = exports.getDevelopmentAppID
/** /**
* Convert a development app ID to a deployed app ID. * Convert a development app ID to a deployed app ID.

View File

@ -56,7 +56,7 @@
{ {
title: "Plugins", title: "Plugins",
href: "/builder/portal/manage/plugins", href: "/builder/portal/manage/plugins",
badge: "Beta", badge: "New",
}, },
{ {

View File

@ -25,6 +25,7 @@
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.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 AppAddModal from "./_components/AppAddModal.svelte"
export let groupId export let groupId
@ -34,8 +35,7 @@
let prevSearch = undefined let prevSearch = undefined
let pageInfo = createPaginationStore() let pageInfo = createPaginationStore()
let loaded = false let loaded = false
let editModal let editModal, deleteModal, appAddModal
let deleteModal
$: page = $pageInfo.page $: page = $pageInfo.page
$: fetchUsers(page, searchTerm) $: fetchUsers(page, searchTerm)
@ -182,7 +182,14 @@
</Layout> </Layout>
<Layout noPadding gap="S"> <Layout noPadding gap="S">
<Heading size="S">Apps</Heading> <div class="header">
<Heading size="S">Apps</Heading>
<div>
<Button on:click={appAddModal.show()} icon="ExperienceAdd" cta>
Add app
</Button>
</div>
</div>
<List> <List>
{#if groupApps.length} {#if groupApps.length}
{#each groupApps as app} {#each groupApps as app}
@ -203,6 +210,18 @@
{getRoleLabel(app.appId)} {getRoleLabel(app.appId)}
</StatusLight> </StatusLight>
</div> </div>
<Icon
on:click={e => {
groups.actions.removeApp(
groupId,
apps.getProdAppID(app.appId)
)
e.stopPropagation()
}}
hoverable
size="S"
name="Close"
/>
</ListItem> </ListItem>
{/each} {/each}
{:else} {:else}
@ -216,6 +235,11 @@
<Modal bind:this={editModal}> <Modal bind:this={editModal}>
<CreateEditGroupModal {group} {saveGroup} /> <CreateEditGroupModal {group} {saveGroup} />
</Modal> </Modal>
<Modal bind:this={appAddModal}>
<AppAddModal {group} />
</Modal>
<ConfirmDialog <ConfirmDialog
bind:this={deleteModal} bind:this={deleteModal}
title="Delete user group" title="Delete user group"

View File

@ -0,0 +1,53 @@
<script>
import { Body, ModalContent, Select } from "@budibase/bbui"
import { apps, groups } from "stores/portal"
import { roles } from "stores/backend"
import RoleSelect from "components/common/RoleSelect.svelte"
export let group
$: appOptions = $apps.map(app => ({
label: app.name,
value: app,
}))
$: prodAppId = selectedApp ? apps.getProdAppID(selectedApp.appId) : ""
$: confirmDisabled =
(!selectingRole && !selectedApp) || (selectingRole && !selectedRoleId)
let selectedApp, selectedRoleId
let selectingRole = false
async function appSelected() {
if (!selectingRole) {
selectingRole = true
await roles.fetchByAppId(prodAppId)
// return false to stop closing modal
return false
} else {
await groups.actions.addApp(group._id, prodAppId, selectedRoleId)
}
}
</script>
<ModalContent
onConfirm={appSelected}
size="M"
title="Add app to group"
confirmText={selectingRole ? "Confirm" : "Next"}
showSecondaryButton={selectingRole}
secondaryButtonText="Back"
secondaryAction={() => (selectingRole = false)}
disabled={confirmDisabled}
>
{#if !selectingRole}
<Body
>Select an app to assign roles for members of <i>"{group.name}"</i></Body
>
<Select bind:value={selectedApp} options={appOptions} />
{:else}
<Body
>Select the role that all members of "<i>{group.name}</i>" will have for
<i>"{selectedApp.name}"</i></Body
>
<RoleSelect allowPublic={false} bind:value={selectedRoleId} />
{/if}
</ModalContent>

View File

@ -5,16 +5,24 @@ import { RoleUtils } from "@budibase/frontend-core"
export function createRolesStore() { export function createRolesStore() {
const { subscribe, update, set } = writable([]) const { subscribe, update, set } = writable([])
function setRoles(roles) {
set(
roles.sort((a, b) => {
const priorityA = RoleUtils.getRolePriority(a._id)
const priorityB = RoleUtils.getRolePriority(b._id)
return priorityA > priorityB ? -1 : 1
})
)
}
const actions = { const actions = {
fetch: async () => { fetch: async () => {
const roles = await API.getRoles() const roles = await API.getRoles()
set( setRoles(roles)
roles.sort((a, b) => { },
const priorityA = RoleUtils.getRolePriority(a._id) fetchByAppId: async appId => {
const priorityB = RoleUtils.getRolePriority(b._id) const { roles } = await API.getRolesForApp(appId)
return priorityA > priorityB ? -1 : 1 setRoles(roles)
})
)
}, },
delete: async role => { delete: async role => {
await API.deleteRole({ await API.deleteRole({

View File

@ -29,4 +29,13 @@ export const buildRoleEndpoints = API => ({
url: "/api/roles", url: "/api/roles",
}) })
}, },
/**
* Gets a list of roles within a specified app.
*/
getRolesForApp: async appId => {
return await API.get({
url: `/api/global/roles/${appId}`,
})
},
}) })

View File

@ -2,6 +2,7 @@ const { getAllRoles } = require("@budibase/backend-core/roles")
const { const {
getAllApps, getAllApps,
getProdAppID, getProdAppID,
getDevAppID,
DocumentType, DocumentType,
} = require("@budibase/backend-core/db") } = require("@budibase/backend-core/db")
const { doInAppContext, getAppDB } = require("@budibase/backend-core/context") const { doInAppContext, getAppDB } = require("@budibase/backend-core/context")
@ -34,7 +35,7 @@ exports.fetch = async ctx => {
exports.find = async ctx => { exports.find = async ctx => {
const appId = ctx.params.appId const appId = ctx.params.appId
await doInAppContext(appId, async () => { await doInAppContext(getDevAppID(appId), async () => {
const db = getAppDB() const db = getAppDB()
const app = await db.get(DocumentType.APP_METADATA) const app = await db.get(DocumentType.APP_METADATA)
ctx.body = { ctx.body = {