RBAC popover complete

This commit is contained in:
Martin McKeaveney 2021-02-10 22:23:27 +00:00
parent 63e0e187a6
commit 20bf34d53c
7 changed files with 116 additions and 41 deletions

View File

@ -30,6 +30,7 @@ export const getBackendUiStore = () => {
const queries = await queriesResponse.json()
const integrationsResponse = await api.get("/api/integrations")
const integrations = await integrationsResponse.json()
const permissionLevels = await store.actions.permissions.fetchLevels()
store.update(state => {
state.selectedDatabase = db
@ -37,6 +38,7 @@ export const getBackendUiStore = () => {
state.datasources = datasources
state.queries = queries
state.integrations = integrations
state.permissionLevels = permissionLevels
return state
})
},
@ -351,6 +353,13 @@ export const getBackendUiStore = () => {
const json = await response.json()
return json
},
delete: async ({ role, resource, level }) => {
const response = await api.delete(
`/api/permission/${role}/${resource}/${level}`
)
const json = await response.json()
return json
},
},
}

View File

@ -48,8 +48,8 @@
title={isUsersTable ? 'Create New User' : 'Create New Row'}
modalContentComponent={isUsersTable ? CreateEditUser : CreateEditRow} />
<CreateViewButton />
<ExportButton view={tableView} />
<ManageAccessButton resourceId={$backendUiStore.selectedTable?._id} />
<ExportButton view={tableView} />
{/if}
{#if isUsersTable}
<EditRolesButton />

View File

@ -54,6 +54,6 @@
{#if view.calculation}
<GroupByButton {view} />
{/if}
<ExportButton {view} />
<ManageAccessButton resourceId={decodeURI(name)} />
<ExportButton {view} />
</Table>

View File

@ -1,5 +1,7 @@
<script>
import { TextButton, Icon, Popover } from "@budibase/bbui"
import { backendUiStore } from "builderStore"
import { Roles } from "constants/backend"
import api from "builderStore/api"
import ManageAccessPopover from "../popovers/ManageAccessPopover.svelte"
@ -7,16 +9,30 @@
let anchor
let dropdown
let levels
let permissions
async function openDropdown() {
permissions = await backendUiStore.actions.permissions.forResource(
resourceId
)
levels = await backendUiStore.actions.permissions.fetchLevels()
dropdown.show()
}
</script>
<div bind:this={anchor}>
<TextButton text small on:click={dropdown.show}>
<TextButton text small on:click={openDropdown}>
<i class="ri-lock-line" />
Manage Access
</TextButton>
</div>
<Popover bind:this={dropdown} {anchor} align="left">
<ManageAccessPopover {resourceId} onClosed={dropdown.hide} />
<ManageAccessPopover
{resourceId}
{levels}
{permissions}
onClosed={dropdown.hide} />
</Popover>
<style>

View File

@ -142,7 +142,7 @@
thin
text="Use as table display column" />
<Label gray small>Search Indexes</Label>
<Label grey small>Search Indexes</Label>
<Toggle
checked={indexes[0] === field.name}
disabled={indexes[1] === field.name}

View File

@ -1,73 +1,94 @@
<script>
import { onMount } from "svelte"
import { backendUiStore } from "builderStore"
import { Roles } from "constants/backend"
import api from "builderStore/api"
import { notifier } from "builderStore/store/notifications"
import { Button, Select } from "@budibase/bbui"
const FORMATS = [
{
name: "CSV",
key: "csv",
},
{
name: "JSON",
key: "json",
},
]
import { Button, Label, Select, Spacer } from "@budibase/bbui"
export let resourceId
export let permissions
export let levels
export let onClosed
let permissions = {}
let levels = []
// Draft level and role for editing
let level = levels[0]
let role = Roles.BASIC
async function exportView() {
onClosed()
}
$: permissionKeys = Object.keys(permissions)
async function changePermission(level, role) {
console.log({ role, resourceId, level })
async function addPermission() {
await backendUiStore.actions.permissions.save({
level,
role,
resource: resourceId,
level,
})
}
onMount(async () => {
// TODO: possibly cleaner
// Show updated permissions in UI
permissions = await backendUiStore.actions.permissions.forResource(
resourceId
)
levels = await backendUiStore.actions.permissions.fetchLevels()
})
notifier.success("Access rule saved.")
// Reset the draft permissions
level = levels[0]
role = Roles.BASIC
}
async function deletePermission(level, role) {
await backendUiStore.actions.permissions.delete({ level, role, resourceId })
delete permissions[role]
notifier.danger("Removed access rule.")
permissions = permissions
}
</script>
<div class="popover">
<h5>Manage Access</h5>
{#each levels as level}
<Select
label={level}
secondary
thin
value={permissions[level]}
on:change={e => changePermission(level, e.target.value)}>
<h5>Who Can Access This Data?</h5>
<Spacer large />
<div class="row">
<Label extraSmall grey>Level</Label>
<Label extraSmall grey>Role</Label>
<div />
{#if permissionKeys.length === 0}
<Label extraSmall>Default Access Rules Applied.</Label>
{/if}
{#each permissionKeys as role}
<Label small>{permissions[role]}</Label>
<Label small>{role}</Label>
<i
class="ri-close-circle-line delete"
on:click={() => deletePermission(permissions[role], role)} />
{/each}
</div>
<Spacer large />
<hr />
<Label small>Add Rule</Label>
<Spacer small />
<div class="draft-permission">
<Select label="Level" secondary thin bind:value={level}>
{#each levels as level}
<option value={level}>{level}</option>
{/each}
</Select>
<Select label="Role" secondary thin bind:value={role}>
{#each $backendUiStore.roles as role}
<option value={role._id}>{role.name}</option>
{/each}
</Select>
{/each}
</div>
<div class="footer">
<Button secondary on:click={onClosed}>Cancel</Button>
<!-- <Button primary on:click={}>Save</Button> -->
<Button primary on:click={addPermission}>Edit Rules</Button>
</div>
</div>
<style>
.popover {
display: grid;
grid-gap: var(--spacing-xl);
width: 400px;
}
h5 {
@ -75,9 +96,30 @@
font-weight: 500;
}
hr {
margin: var(--spacing-s) 0 var(--spacing-m) 0;
}
.footer {
display: flex;
justify-content: flex-end;
gap: var(--spacing-m);
margin-top: var(--spacing-l);
}
.draft-permission {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: var(--spacing-m);
}
.row {
display: grid;
grid-template-columns: 1fr 1fr 20px;
grid-gap: var(--spacing-s);
}
.delete {
cursor: pointer;
}
</style>

View File

@ -92,3 +92,11 @@ export const HostingTypes = {
CLOUD: "cloud",
SELF: "self",
}
export const Roles = {
ADMIN: "ADMIN",
POWER: "POWER",
BASIC: "BASIC",
PUBLIC: "PUBLIC",
BUILDER: "BUILDER",
}