Add display name, color and descriptions to roles. Allow row CRUD via new UI
This commit is contained in:
parent
a5520a973c
commit
a81d9c6dd1
|
@ -45,10 +45,22 @@ export class Role implements RoleDoc {
|
||||||
inherits?: string
|
inherits?: string
|
||||||
version?: string
|
version?: string
|
||||||
permissions = {}
|
permissions = {}
|
||||||
|
displayName?: string
|
||||||
|
color?: string
|
||||||
|
description?: string
|
||||||
|
|
||||||
constructor(id: string, name: string, permissionId: string) {
|
constructor(
|
||||||
|
id: string,
|
||||||
|
displayName: string,
|
||||||
|
description: string,
|
||||||
|
color: string,
|
||||||
|
permissionId: string
|
||||||
|
) {
|
||||||
this._id = id
|
this._id = id
|
||||||
this.name = name
|
this.name = id
|
||||||
|
this.displayName = displayName
|
||||||
|
this.color = color
|
||||||
|
this.description = description
|
||||||
this.permissionId = permissionId
|
this.permissionId = permissionId
|
||||||
// version for managing the ID - removing the role_ when responding
|
// version for managing the ID - removing the role_ when responding
|
||||||
this.version = RoleIDVersion.NAME
|
this.version = RoleIDVersion.NAME
|
||||||
|
@ -63,21 +75,39 @@ export class Role implements RoleDoc {
|
||||||
const BUILTIN_ROLES = {
|
const BUILTIN_ROLES = {
|
||||||
ADMIN: new Role(
|
ADMIN: new Role(
|
||||||
BUILTIN_IDS.ADMIN,
|
BUILTIN_IDS.ADMIN,
|
||||||
"Admin",
|
"App admin",
|
||||||
|
"Can do everything",
|
||||||
|
"var(--spectrum-global-color-static-red-400)",
|
||||||
BuiltinPermissionID.ADMIN
|
BuiltinPermissionID.ADMIN
|
||||||
).addInheritance(BUILTIN_IDS.POWER),
|
).addInheritance(BUILTIN_IDS.POWER),
|
||||||
POWER: new Role(
|
POWER: new Role(
|
||||||
BUILTIN_IDS.POWER,
|
BUILTIN_IDS.POWER,
|
||||||
"Power",
|
"App power user",
|
||||||
|
"An app user with more access",
|
||||||
|
"var(--spectrum-global-color-static-orange-400)",
|
||||||
BuiltinPermissionID.POWER
|
BuiltinPermissionID.POWER
|
||||||
).addInheritance(BUILTIN_IDS.BASIC),
|
).addInheritance(BUILTIN_IDS.BASIC),
|
||||||
BASIC: new Role(
|
BASIC: new Role(
|
||||||
BUILTIN_IDS.BASIC,
|
BUILTIN_IDS.BASIC,
|
||||||
"Basic",
|
"App user",
|
||||||
|
"Any logged in user",
|
||||||
|
"var(--spectrum-global-color-static-green-400)",
|
||||||
BuiltinPermissionID.WRITE
|
BuiltinPermissionID.WRITE
|
||||||
).addInheritance(BUILTIN_IDS.PUBLIC),
|
).addInheritance(BUILTIN_IDS.PUBLIC),
|
||||||
PUBLIC: new Role(BUILTIN_IDS.PUBLIC, "Public", BuiltinPermissionID.PUBLIC),
|
PUBLIC: new Role(
|
||||||
BUILDER: new Role(BUILTIN_IDS.BUILDER, "Builder", BuiltinPermissionID.ADMIN),
|
BUILTIN_IDS.PUBLIC,
|
||||||
|
"Public user",
|
||||||
|
"Accessible to anyone",
|
||||||
|
"var(--spectrum-global-color-static-blue-400)",
|
||||||
|
BuiltinPermissionID.PUBLIC
|
||||||
|
),
|
||||||
|
BUILDER: new Role(
|
||||||
|
BUILTIN_IDS.BUILDER,
|
||||||
|
"Builder user",
|
||||||
|
"Users that can edit this app",
|
||||||
|
"var(--spectrum-global-color-static-magenta-600)",
|
||||||
|
BuiltinPermissionID.ADMIN
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getBuiltinRoles(): { [key: string]: RoleDoc } {
|
export function getBuiltinRoles(): { [key: string]: RoleDoc } {
|
||||||
|
|
|
@ -2,29 +2,28 @@
|
||||||
import { Button, Helpers, ActionButton } from "@budibase/bbui"
|
import { Button, Helpers, ActionButton } from "@budibase/bbui"
|
||||||
import { useSvelteFlow, Position } from "@xyflow/svelte"
|
import { useSvelteFlow, Position } from "@xyflow/svelte"
|
||||||
import { getContext, tick } from "svelte"
|
import { getContext, tick } from "svelte"
|
||||||
import { autoLayout } from "./layout"
|
import { autoLayout, roleToNode } from "./layout"
|
||||||
import { ZoomDuration } from "./constants"
|
import { ZoomDuration } from "./constants"
|
||||||
|
import { getSequentialName } from "helpers/duplicate"
|
||||||
|
import { roles } from "stores/builder"
|
||||||
|
import { Roles } from "constants/backend"
|
||||||
|
|
||||||
const { nodes, edges } = getContext("flow")
|
const { nodes, edges } = getContext("flow")
|
||||||
const flow = useSvelteFlow()
|
const flow = useSvelteFlow()
|
||||||
|
|
||||||
const addRole = async () => {
|
const addRole = async () => {
|
||||||
nodes.update(state => [
|
const role = {
|
||||||
...state,
|
name: Helpers.uuid(),
|
||||||
{
|
displayName: getSequentialName($nodes, "New role ", {
|
||||||
id: Helpers.uuid(),
|
getName: x => x.data.displayName,
|
||||||
sourcePosition: Position.Right,
|
}),
|
||||||
targetPosition: Position.Left,
|
|
||||||
type: "role",
|
|
||||||
data: {
|
|
||||||
displayName: "New role",
|
|
||||||
description: "Custom role",
|
|
||||||
custom: true,
|
|
||||||
color: "var(--spectrum-global-color-gray-700)",
|
color: "var(--spectrum-global-color-gray-700)",
|
||||||
},
|
description: "Custom role",
|
||||||
position: { x: 0, y: 0 },
|
permissionId: "write",
|
||||||
},
|
inherits: Roles.BASIC,
|
||||||
])
|
}
|
||||||
|
const savedRole = await roles.save(role)
|
||||||
|
nodes.update(state => [...state, roleToNode(savedRole)])
|
||||||
await doAutoLayout()
|
await doAutoLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +35,6 @@
|
||||||
flow.fitView({
|
flow.fitView({
|
||||||
maxZoom: 1,
|
maxZoom: 1,
|
||||||
duration: ZoomDuration,
|
duration: ZoomDuration,
|
||||||
includeHiddenNodes: true,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { SvelteFlow, Background, BackgroundVariant } from "@xyflow/svelte"
|
import { SvelteFlow, Background, BackgroundVariant } from "@xyflow/svelte"
|
||||||
import "@xyflow/svelte/dist/style.css"
|
import "@xyflow/svelte/dist/style.css"
|
||||||
import RoleNode from "./RoleNode.svelte"
|
import RoleNode from "./RoleNode.svelte"
|
||||||
import { defaultLayout, autoLayout } from "./layout"
|
import { rolesToNodes, autoLayout } from "./layout"
|
||||||
import { onMount, setContext } from "svelte"
|
import { onMount, setContext } from "svelte"
|
||||||
import Controls from "./Controls.svelte"
|
import Controls from "./Controls.svelte"
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
setContext("flow", { nodes, edges })
|
setContext("flow", { nodes, edges })
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
const layout = autoLayout(defaultLayout())
|
const layout = autoLayout(rolesToNodes())
|
||||||
nodes.set(layout.nodes)
|
nodes.set(layout.nodes)
|
||||||
edges.set(layout.edges)
|
edges.set(layout.edges)
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
import { Roles } from "constants/backend"
|
import { Roles } from "constants/backend"
|
||||||
import { NodeWidth, NodeHeight } from "./constants"
|
import { NodeWidth, NodeHeight } from "./constants"
|
||||||
import { getContext, tick } from "svelte"
|
import { getContext, tick } from "svelte"
|
||||||
import { autoLayout } from "./layout"
|
import { autoLayout, nodeToRole } from "./layout"
|
||||||
|
import { roles } from "stores/builder"
|
||||||
|
|
||||||
export let data
|
export let data
|
||||||
export let isConnectable
|
export let isConnectable
|
||||||
|
@ -27,9 +28,8 @@
|
||||||
let tempDescription
|
let tempDescription
|
||||||
let tempColor
|
let tempColor
|
||||||
|
|
||||||
$: color = data.color || RoleUtils.getRoleColour(id)
|
|
||||||
|
|
||||||
const deleteNode = async () => {
|
const deleteNode = async () => {
|
||||||
|
await roles.delete(nodeToRole({ id, data }))
|
||||||
flow.deleteElements({
|
flow.deleteElements({
|
||||||
nodes: [{ id }],
|
nodes: [{ id }],
|
||||||
})
|
})
|
||||||
|
@ -40,11 +40,12 @@
|
||||||
const openPopover = () => {
|
const openPopover = () => {
|
||||||
tempDisplayName = data.displayName
|
tempDisplayName = data.displayName
|
||||||
tempDescription = data.description
|
tempDescription = data.description
|
||||||
tempColor = color
|
tempColor = data.color
|
||||||
modal.show()
|
modal.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
const saveChanges = () => {
|
const saveChanges = async () => {
|
||||||
|
await roles.save(nodeToRole({ id, data }))
|
||||||
flow.updateNodeData(id, {
|
flow.updateNodeData(id, {
|
||||||
displayName: tempDisplayName,
|
displayName: tempDisplayName,
|
||||||
description: tempDescription,
|
description: tempDescription,
|
||||||
|
@ -63,7 +64,7 @@
|
||||||
<div
|
<div
|
||||||
class="node"
|
class="node"
|
||||||
class:selected={false}
|
class:selected={false}
|
||||||
style={`--color:${color}; --width:${NodeWidth}px; --height:${NodeHeight}px;`}
|
style={`--color:${data.color}; --width:${NodeWidth}px; --height:${NodeHeight}px;`}
|
||||||
bind:this={anchor}
|
bind:this={anchor}
|
||||||
>
|
>
|
||||||
<div class="color" />
|
<div class="color" />
|
||||||
|
|
|
@ -6,15 +6,36 @@ import { Roles } from "constants/backend"
|
||||||
import { get } from "svelte/store"
|
import { get } from "svelte/store"
|
||||||
import { Helpers } from "@budibase/bbui"
|
import { Helpers } from "@budibase/bbui"
|
||||||
|
|
||||||
|
// Converts a role doc into a node structure
|
||||||
|
export const roleToNode = role => ({
|
||||||
|
id: role._id,
|
||||||
|
sourcePosition: Position.Right,
|
||||||
|
targetPosition: Position.Left,
|
||||||
|
type: "role",
|
||||||
|
position: { x: 0, y: 0 },
|
||||||
|
data: {
|
||||||
|
displayName: role.displayName || role.name,
|
||||||
|
description: role.description || "Custom role",
|
||||||
|
color: role.color || "var(--spectrum-global-color-static-magenta-400)",
|
||||||
|
custom: !role._id.match(/[A-Z]+/),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Converts a node structure back into a role doc
|
||||||
|
export const nodeToRole = node => {
|
||||||
|
const role = get(roles).find(x => x._id === node.id)
|
||||||
|
return {
|
||||||
|
...role,
|
||||||
|
displayName: node.data.displayName,
|
||||||
|
color: node.data.color,
|
||||||
|
description: node.data.description,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Generates a flow compatible structure of nodes and edges from the current roles
|
// Generates a flow compatible structure of nodes and edges from the current roles
|
||||||
export const defaultLayout = () => {
|
export const rolesToNodes = () => {
|
||||||
const ignoredRoles = [Roles.PUBLIC]
|
const ignoredRoles = [Roles.PUBLIC]
|
||||||
const $roles = get(roles)
|
const $roles = get(roles)
|
||||||
const descriptions = {
|
|
||||||
[Roles.BASIC]: "Basic user",
|
|
||||||
[Roles.POWER]: "Power user",
|
|
||||||
[Roles.ADMIN]: "Can do everything",
|
|
||||||
}
|
|
||||||
|
|
||||||
let nodes = []
|
let nodes = []
|
||||||
let edges = []
|
let edges = []
|
||||||
|
@ -23,19 +44,11 @@ export const defaultLayout = () => {
|
||||||
if (ignoredRoles.includes(role._id)) {
|
if (ignoredRoles.includes(role._id)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
nodes.push({
|
|
||||||
id: role._id,
|
|
||||||
sourcePosition: Position.Right,
|
|
||||||
targetPosition: Position.Left,
|
|
||||||
type: "role",
|
|
||||||
data: {
|
|
||||||
displayName: role.displayName || role.name || "",
|
|
||||||
description: descriptions[role._id] || "Custom role",
|
|
||||||
color: role.color,
|
|
||||||
custom: !role._id.match(/[A-Z]+/),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
// Add node for this role
|
||||||
|
nodes.push(roleToNode(role))
|
||||||
|
|
||||||
|
// Add edges for this role
|
||||||
let inherits = []
|
let inherits = []
|
||||||
if (role.inherits) {
|
if (role.inherits) {
|
||||||
inherits = Array.isArray(role.inherits) ? role.inherits : [role.inherits]
|
inherits = Array.isArray(role.inherits) ? role.inherits : [role.inherits]
|
||||||
|
@ -60,40 +73,6 @@ export const defaultLayout = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts the flow structure of ndes and edges back into an array of roles
|
|
||||||
export const layoutToRoles = ({ nodes, edges }) => {
|
|
||||||
// Clone and wipe existing inheritance
|
|
||||||
let newRoles = Helpers.cloneDeep(get(roles)).map(role => {
|
|
||||||
return { ...role, inherits: [] }
|
|
||||||
})
|
|
||||||
|
|
||||||
// Copy over names and colours
|
|
||||||
for (let node of nodes) {
|
|
||||||
let role = newRoles.find(x => x._id === node.id)
|
|
||||||
if (role) {
|
|
||||||
role.name = node.data.label
|
|
||||||
role.color = node.data.color
|
|
||||||
} else {
|
|
||||||
// New role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build inheritance
|
|
||||||
for (let edge of edges) {
|
|
||||||
let role = newRoles.find(x => x._id === edge.target)
|
|
||||||
if (role) {
|
|
||||||
role.inherits.push(edge.source)
|
|
||||||
} else {
|
|
||||||
// New role
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure basic is correct
|
|
||||||
newRoles.find(x => x._id === Roles.BASIC).inherits = [Roles.BASIC]
|
|
||||||
|
|
||||||
return newRoles
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates positions of nodes and edges into a nice graph structure
|
// Updates positions of nodes and edges into a nice graph structure
|
||||||
const dagreLayout = ({ nodes, edges }) => {
|
const dagreLayout = ({ nodes, edges }) => {
|
||||||
const dagreGraph = new dagre.graphlib.Graph()
|
const dagreGraph = new dagre.graphlib.Graph()
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
<script>
|
<script>
|
||||||
import { RoleUtils } from "@budibase/frontend-core"
|
import { RoleUtils } from "@budibase/frontend-core"
|
||||||
import { StatusLight } from "@budibase/bbui"
|
import { StatusLight } from "@budibase/bbui"
|
||||||
|
import { roles } from "stores/builder"
|
||||||
|
|
||||||
export let id
|
export let id
|
||||||
export let size = "M"
|
export let size = "M"
|
||||||
export let disabled = false
|
export let disabled = false
|
||||||
|
|
||||||
$: color = RoleUtils.getRoleColour(id)
|
$: color =
|
||||||
|
$roles.find(x => x._id === id)?.color ||
|
||||||
|
"var(--spectrum-global-color-static-magenta-400)"
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<StatusLight square {disabled} {size} {color} />
|
<StatusLight square {disabled} {size} {color} />
|
||||||
|
|
|
@ -99,7 +99,7 @@
|
||||||
if (role._id === Constants.Roles.CREATOR || role._id === RemoveID) {
|
if (role._id === Constants.Roles.CREATOR || role._id === RemoveID) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return RoleUtils.getRoleColour(role._id)
|
return role.color || "var(--spectrum-global-color-static-magenta-400)"
|
||||||
}
|
}
|
||||||
|
|
||||||
const getIcon = role => {
|
const getIcon = role => {
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
options={$roles}
|
options={$roles}
|
||||||
getOptionLabel={role => role.name}
|
getOptionLabel={role => role.name}
|
||||||
getOptionValue={role => role._id}
|
getOptionValue={role => role._id}
|
||||||
getOptionColour={role => RoleUtils.getRoleColour(role._id)}
|
getOptionColour={role =>
|
||||||
|
role.color || "var(--spectrum-global-color-static-magenta-400)"}
|
||||||
{placeholder}
|
{placeholder}
|
||||||
{error}
|
{error}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
let showTooltip = false
|
let showTooltip = false
|
||||||
|
|
||||||
$: color = RoleUtils.getRoleColour(roleId)
|
$: color = role.color || "var(--spectrum-global-color-static-magenta-400)"
|
||||||
$: role = $roles.find(role => role._id === roleId)
|
$: role = $roles.find(role => role._id === roleId)
|
||||||
$: tooltip =
|
$: tooltip =
|
||||||
roleId === Roles.PUBLIC
|
roleId === Roles.PUBLIC
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
export let value
|
export let value
|
||||||
|
|
||||||
|
$: role = $roles.find(x => x._id === roleId)
|
||||||
|
|
||||||
const getRoleLabel = roleId => {
|
const getRoleLabel = roleId => {
|
||||||
const role = $roles.find(x => x._id === roleId)
|
|
||||||
return roleId === Constants.Roles.CREATOR
|
return roleId === Constants.Roles.CREATOR
|
||||||
? capitalise(Constants.Roles.CREATOR.toLowerCase())
|
? capitalise(Constants.Roles.CREATOR.toLowerCase())
|
||||||
: role?.name || "Custom role"
|
: role?.name || "Custom role"
|
||||||
|
@ -17,7 +18,10 @@
|
||||||
{#if value === Constants.Roles.CREATOR}
|
{#if value === Constants.Roles.CREATOR}
|
||||||
Can edit
|
Can edit
|
||||||
{:else}
|
{:else}
|
||||||
<StatusLight square color={RoleUtils.getRoleColour(value)}>
|
<StatusLight
|
||||||
|
square
|
||||||
|
color={role?.color || "var(--spectrum-global-color-static-magenta-400)"}
|
||||||
|
>
|
||||||
Can use as {getRoleLabel(value)}
|
Can use as {getRoleLabel(value)}
|
||||||
</StatusLight>
|
</StatusLight>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
import { writable } from "svelte/store"
|
import { writable } from "svelte/store"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import { RoleUtils } from "@budibase/frontend-core"
|
import { RoleUtils } from "@budibase/frontend-core"
|
||||||
import { Roles } from "constants/backend"
|
|
||||||
|
|
||||||
const ROLE_NAMES = {
|
|
||||||
[Roles.ADMIN]: "App admin",
|
|
||||||
[Roles.POWER]: "App power user",
|
|
||||||
[Roles.BASIC]: "App user",
|
|
||||||
[Roles.PUBLIC]: "Public user",
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createRolesStore() {
|
export function createRolesStore() {
|
||||||
const { subscribe, update, set } = writable([])
|
const { subscribe, update, set } = writable([])
|
||||||
|
@ -25,16 +17,7 @@ export function createRolesStore() {
|
||||||
|
|
||||||
const actions = {
|
const actions = {
|
||||||
fetch: async () => {
|
fetch: async () => {
|
||||||
let roles = await API.getRoles()
|
const roles = await API.getRoles()
|
||||||
|
|
||||||
// Update labels
|
|
||||||
for (let [roleId, name] of Object.entries(ROLE_NAMES)) {
|
|
||||||
const idx = roles.findIndex(x => x._id === roleId)
|
|
||||||
if (idx !== -1) {
|
|
||||||
roles[idx].name = name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setRoles(roles)
|
setRoles(roles)
|
||||||
},
|
},
|
||||||
fetchByAppId: async appId => {
|
fetchByAppId: async appId => {
|
||||||
|
@ -51,7 +34,13 @@ export function createRolesStore() {
|
||||||
save: async role => {
|
save: async role => {
|
||||||
const savedRole = await API.saveRole(role)
|
const savedRole = await API.saveRole(role)
|
||||||
await actions.fetch()
|
await actions.fetch()
|
||||||
return savedRole
|
|
||||||
|
// When saving a role we get back an _id prefixed by role_, but the API does not want this
|
||||||
|
// in future requests
|
||||||
|
return {
|
||||||
|
...savedRole,
|
||||||
|
_id: savedRole._id.replace("role_", ""),
|
||||||
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,20 +7,7 @@ const RolePriorities = {
|
||||||
[Roles.BASIC]: 2,
|
[Roles.BASIC]: 2,
|
||||||
[Roles.PUBLIC]: 1,
|
[Roles.PUBLIC]: 1,
|
||||||
}
|
}
|
||||||
const RoleColours = {
|
|
||||||
[Roles.ADMIN]: "var(--spectrum-global-color-static-red-400)",
|
|
||||||
[Roles.CREATOR]: "var(--spectrum-global-color-static-magenta-600)",
|
|
||||||
[Roles.POWER]: "var(--spectrum-global-color-static-orange-400)",
|
|
||||||
[Roles.BASIC]: "var(--spectrum-global-color-static-green-400)",
|
|
||||||
[Roles.PUBLIC]: "var(--spectrum-global-color-static-blue-400)",
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getRolePriority = role => {
|
export const getRolePriority = role => {
|
||||||
return RolePriorities[role] ?? 0
|
return RolePriorities[role] ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getRoleColour = roleId => {
|
|
||||||
return (
|
|
||||||
RoleColours[roleId] ?? "var(--spectrum-global-color-static-magenta-400)"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -62,7 +62,16 @@ export async function find(ctx: UserCtx<void, FindRoleResponse>) {
|
||||||
|
|
||||||
export async function save(ctx: UserCtx<SaveRoleRequest, SaveRoleResponse>) {
|
export async function save(ctx: UserCtx<SaveRoleRequest, SaveRoleResponse>) {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
let { _id, name, inherits, permissionId, version } = ctx.request.body
|
let {
|
||||||
|
_id,
|
||||||
|
name,
|
||||||
|
displayName,
|
||||||
|
description,
|
||||||
|
color,
|
||||||
|
inherits,
|
||||||
|
permissionId,
|
||||||
|
version,
|
||||||
|
} = ctx.request.body
|
||||||
let isCreate = false
|
let isCreate = false
|
||||||
const isNewVersion = version === roles.RoleIDVersion.NAME
|
const isNewVersion = version === roles.RoleIDVersion.NAME
|
||||||
|
|
||||||
|
@ -88,7 +97,13 @@ export async function save(ctx: UserCtx<SaveRoleRequest, SaveRoleResponse>) {
|
||||||
ctx.throw(400, "Cannot change custom role name")
|
ctx.throw(400, "Cannot change custom role name")
|
||||||
}
|
}
|
||||||
|
|
||||||
const role = new roles.Role(_id, name, permissionId).addInheritance(inherits)
|
const role = new roles.Role(
|
||||||
|
_id,
|
||||||
|
displayName || name,
|
||||||
|
description || "Custom role",
|
||||||
|
color || "var(--spectrum-global-color-static-magenta-400)",
|
||||||
|
permissionId
|
||||||
|
).addInheritance(inherits)
|
||||||
if (ctx.request.body._rev) {
|
if (ctx.request.body._rev) {
|
||||||
role._rev = ctx.request.body._rev
|
role._rev = ctx.request.body._rev
|
||||||
}
|
}
|
||||||
|
|
|
@ -208,6 +208,9 @@ export function roleValidator() {
|
||||||
name: Joi.string()
|
name: Joi.string()
|
||||||
.regex(/^[a-zA-Z0-9_]*$/)
|
.regex(/^[a-zA-Z0-9_]*$/)
|
||||||
.required(),
|
.required(),
|
||||||
|
displayName: Joi.string().optional(),
|
||||||
|
color: Joi.string().optional(),
|
||||||
|
description: Joi.string().optional(),
|
||||||
// this is the base permission ID (for now a built in)
|
// this is the base permission ID (for now a built in)
|
||||||
permissionId: Joi.string()
|
permissionId: Joi.string()
|
||||||
.valid(...Object.values(permissions.BuiltinPermissionID))
|
.valid(...Object.values(permissions.BuiltinPermissionID))
|
||||||
|
|
|
@ -4,6 +4,9 @@ export interface SaveRoleRequest {
|
||||||
_id?: string
|
_id?: string
|
||||||
_rev?: string
|
_rev?: string
|
||||||
name: string
|
name: string
|
||||||
|
displayName?: string
|
||||||
|
color?: string
|
||||||
|
description?: string
|
||||||
inherits: string
|
inherits: string
|
||||||
permissionId: string
|
permissionId: string
|
||||||
version: string
|
version: string
|
||||||
|
|
|
@ -6,4 +6,7 @@ export interface Role extends Document {
|
||||||
permissions: { [key: string]: string[] }
|
permissions: { [key: string]: string[] }
|
||||||
version?: string
|
version?: string
|
||||||
name: string
|
name: string
|
||||||
|
displayName?: string
|
||||||
|
color?: string
|
||||||
|
description?: string
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue