Deal with power users

This commit is contained in:
Andrew Kingston 2024-10-03 13:59:50 +01:00
parent a342aa3c31
commit a4aac8aae0
No known key found for this signature in database
2 changed files with 38 additions and 29 deletions

View File

@ -12,6 +12,7 @@
import { getContext } from "svelte" import { getContext } from "svelte"
import { roles } from "stores/builder" import { roles } from "stores/builder"
import ConfirmDialog from "components/common/ConfirmDialog.svelte" import ConfirmDialog from "components/common/ConfirmDialog.svelte"
import { Roles } from "constants/backend"
export let data export let data
export let id export let id
@ -68,7 +69,9 @@
<div <div
class="node" class="node"
class:dragging={$dragging}
class:selected class:selected
class:interactive={data.interactive}
class:custom={data.custom} class:custom={data.custom}
class:selectable={isConnectable} class:selectable={isConnectable}
style={`--color:${data.color}; --width:${NodeWidth}px; --height:${NodeHeight}px;`} style={`--color:${data.color}; --width:${NodeWidth}px; --height:${NodeHeight}px;`}
@ -96,8 +99,7 @@
<Handle <Handle
type="target" type="target"
position={Position.Left} position={Position.Left}
class={targetClasses} isConnectable={isConnectable && $dragging && data.custom}
isConnectable={isConnectable && $dragging}
/> />
<Handle type="source" position={Position.Right} {isConnectable} /> <Handle type="source" position={Position.Right} {isConnectable} />
</div> </div>
@ -222,11 +224,9 @@
.node :global(.svelte-flow__handle.target) { .node :global(.svelte-flow__handle.target) {
background: var(--background-color); background: var(--background-color);
} }
.node :global(.svelte-flow__handle.hidden) { .node:not(.dragging) :global(.svelte-flow__handle.target),
opacity: 0; .node:not(.interactive) :global(.svelte-flow__handle),
pointer-events: none; .node:not(.custom) :global(.svelte-flow__handle.target) {
}
.node:not(.custom) :global(.svelte-flow__handle) {
visibility: hidden; visibility: hidden;
pointer-events: none; pointer-events: none;
} }

View File

@ -13,18 +13,18 @@ import { get } from "svelte/store"
// Calculates the bounds of all custom nodes // Calculates the bounds of all custom nodes
export const getBounds = nodes => { export const getBounds = nodes => {
const customNodes = nodes.filter(node => node.data.custom) const interactiveNodes = nodes.filter(node => node.data.interactive)
// Empty state bounds which line up with bounds after adding first node // Empty state bounds which line up with bounds after adding first node
if (!customNodes.length) { if (!interactiveNodes.length) {
return { return {
x: 0, x: 0,
y: 6.5 * GridResolution, y: -3.5 * GridResolution,
width: 12 * GridResolution, width: 12 * GridResolution,
height: 10 * GridResolution, height: 10 * GridResolution,
} }
} }
return getNodesBounds(customNodes) return getNodesBounds(interactiveNodes)
} }
// Gets the position of the basic role // Gets the position of the basic role
@ -41,25 +41,21 @@ export const getAdminPosition = bounds => ({
// Filters out invalid nodes and edges // Filters out invalid nodes and edges
const preProcessLayout = ({ nodes, edges }) => { const preProcessLayout = ({ nodes, edges }) => {
const ignoredRoles = [Roles.PUBLIC, Roles.POWER] const ignoredIds = [Roles.PUBLIC, Roles.BASIC, Roles.ADMIN, "empty"]
const edglessRoles = [...ignoredRoles, Roles.BASIC, Roles.ADMIN] const targetlessIds = [Roles.POWER]
return { return {
nodes: nodes.filter(node => { nodes: nodes.filter(node => {
// Filter out ignored roles // Filter out ignored IDs
if (ignoredRoles.includes(node.id)) { if (ignoredIds.includes(node.id)) {
return false
}
// Filter out empty state
if (node.id === "empty") {
return false return false
} }
return true return true
}), }),
edges: edges.filter(edge => { edges: edges.filter(edge => {
// Filter out edges from ignored roles // Filter out edges from ignored IDs
if ( if (
edglessRoles.includes(edge.source) || ignoredIds.includes(edge.source) ||
edglessRoles.includes(edge.target) ignoredIds.includes(edge.target)
) { ) {
return false return false
} }
@ -67,6 +63,10 @@ const preProcessLayout = ({ nodes, edges }) => {
if (edge.source === edge.target) { if (edge.source === edge.target) {
return false return false
} }
// Filter out edges which target targetless roles
if (targetlessIds.includes(edge.target)) {
return false
}
return true return true
}), }),
} }
@ -101,10 +101,17 @@ export const dagreLayout = ({ nodes, edges }) => {
} }
const postProcessLayout = ({ nodes, edges }) => { const postProcessLayout = ({ nodes, edges }) => {
// Reposition basic and admin to bound the custom nodes // Add basic and admin nodes at each edge
const bounds = getBounds(nodes) const bounds = getBounds(nodes)
nodes.find(x => x.id === Roles.BASIC).position = getBasicPosition(bounds) const $roles = get(roles)
nodes.find(x => x.id === Roles.ADMIN).position = getAdminPosition(bounds) nodes.push({
...roleToNode($roles.find(role => role._id === Roles.BASIC)),
position: getBasicPosition(bounds),
})
nodes.push({
...roleToNode($roles.find(role => role._id === Roles.ADMIN)),
position: getAdminPosition(bounds),
})
// Add custom edges for basic and admin brackets // Add custom edges for basic and admin brackets
edges.push({ edges.push({
@ -121,7 +128,7 @@ const postProcessLayout = ({ nodes, edges }) => {
}) })
// Add empty state node if required // Add empty state node if required
if (!nodes.filter(node => node.data.custom).length) { if (!nodes.some(node => node.data.interactive)) {
nodes.push({ nodes.push({
id: "empty", id: "empty",
type: "empty", type: "empty",
@ -152,6 +159,7 @@ export const autoLayout = ({ nodes, edges }) => {
// Converts a role doc into a node structure // Converts a role doc into a node structure
export const roleToNode = role => { export const roleToNode = role => {
const custom = !role._id.match(/[A-Z]+/) const custom = !role._id.match(/[A-Z]+/)
const interactive = custom || role._id === Roles.POWER
return { return {
id: role._id, id: role._id,
sourcePosition: Position.Right, sourcePosition: Position.Right,
@ -161,15 +169,16 @@ export const roleToNode = role => {
data: { data: {
...role.uiMetadata, ...role.uiMetadata,
custom, custom,
interactive,
}, },
measured: { measured: {
width: NodeWidth, width: NodeWidth,
height: NodeHeight, height: NodeHeight,
}, },
deletable: custom, deletable: custom,
draggable: custom, draggable: interactive,
connectable: custom, connectable: interactive,
selectable: custom, selectable: interactive,
} }
} }