Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/main/frontend/app/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
--color-foreground-muted: inherit;
--color-foreground-active: inherit;
--color-error: inherit;
--color-error-background: inherit;
--color-info: inherit;
--color-success: inherit;
--color-warning: inherit;
Expand All @@ -33,6 +34,7 @@
--color-foreground-muted: var(--color-neutral-600);
--color-foreground-active: var(--color-brand);
--color-error: #ff2424;
--color-error-background: #ffcbcb;
--color-info: #1389ff;
--color-warning: var(--color-brand);
--color-success: #247d12;
Expand Down Expand Up @@ -87,7 +89,8 @@
--color-foreground: var(--color-neutral-100);
--color-foreground-muted: var(--color-neutral-400);
--color-foreground-active: var(--color-brand);
--color-error: #ff2424;
--color-error: #ffcbcb;
--color-error-background: #ff2424;
--color-info: #1389ff;
--color-warning: var(--color-brand);
--color-success: #247d12;
Expand Down
2 changes: 1 addition & 1 deletion src/main/frontend/app/components/toast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const defaultStyle = 'items-end justify-end pointer-events-none'
const toastStyles = {
ERROR: {
container: defaultStyle,
card: `${toastBaseCard} bg-error`,
card: `${toastBaseCard} bg-error-background`,
icon: '',
defaultDuration: 2000,
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { useState } from 'react'

interface MissingRequirementsProps {
missingChildren: string[]
isFulfilled: boolean
}

function parseRequirement(item: string) {
if (item.startsWith('One of:')) {
const values = item
.replace('One of:', '')
.split(',')
.map((v) => v.trim())

return {
label: 'One of',
values,
}
}

return {
label: null,
values: [item],
}
}

export default function MissingRequirements({ missingChildren, isFulfilled }: MissingRequirementsProps) {
const [expandedMap, setExpandedMap] = useState<Record<number, boolean>>({})

if (isFulfilled || missingChildren.length === 0) return null

const toggle = (index: number) => {
setExpandedMap((prev) => ({
...prev,
[index]: !prev[index],
}))
}

return (
<div className="border-error bg-error-background m-2 w-[95%] self-start rounded border-l-4 p-2">
<p className="text-error text-sm font-semibold">This node is missing mandatory children:</p>

<ul className="text-error mt-1 list-disc pl-4 text-sm">
{missingChildren.map((item, index) => {
const { label, values } = parseRequirement(item)
const expanded = expandedMap[index] || false

return (
<li key={index} className="mb-1 cursor-pointer" onClick={() => toggle(index)}>
<div
title={values.join(', ')}
className={
expanded
? '' // expanded = normal wrapping
: 'truncate' // collapsed = single line ellipsis
}
>
{label && <span className="font-medium">{label}: </span>}
{values.join(', ')}
</div>

{expanded && <span className="hover:text-foreground-active ml-2 text-xs italic">(show less)</span>}
</li>
)
})}
</ul>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
import { showWarningToast } from '~/components/toast'
import { useHandleTypes } from '~/hooks/use-handle-types'
import AddSubcomponentModal from '~/components/flow/add-subcomponent-modal'
import { fetchFrankConfigXsd } from '~/services/xsd-service'
import {
type Requirement,
getElementRequirements,
getMissingRequirements,
isRequirementFulfilled,
parseXsd,
} from '~/utils/xsd-utils'
import MissingRequirements from './components/missing-requirements'

export type FrankNodeType = Node<{
subtype: string
Expand Down Expand Up @@ -74,6 +83,9 @@

return Object.values(recordElements).filter((element) => canAcceptChildStatic(frankElement, element.name, filters))
}, [elements, frankElement, filters])
const [mandatoryChildren, setMandatoryChildren] = useState<Requirement[]>([])
const [mandatoryChildrenFulfilled, setMandatoryChildrenFulfilled] = useState(false)
const [missingChildren, setMissingChildren] = useState<string[]>([])

const updateNodeInternals = useUpdateNodeInternals()
const [isHandleMenuOpen, setIsHandleMenuOpen] = useState(false)
Expand Down Expand Up @@ -110,6 +122,24 @@
}
}, [dragOver, properties.id, updateNodeInternals])

useEffect(() => {
fetchFrankConfigXsd().then((xsd) => {
const doc = parseXsd(xsd)
const mandatory = getElementRequirements(doc, properties.data.subtype)
setMandatoryChildren(mandatory)
})
}, [properties.data.subtype])

useEffect(() => {
const children = properties.data.children

const allFulfilled = isRequirementFulfilled(mandatoryChildren, children)
setMandatoryChildrenFulfilled(allFulfilled)

const missing = getMissingRequirements(mandatoryChildren, children)
setMissingChildren(missing)
}, [mandatoryChildren, properties.data.children])

useLayoutEffect(() => {
if (containerReference.current) {
const measuredHeight = containerReference.current.offsetHeight
Expand Down Expand Up @@ -273,7 +303,7 @@

addChild(properties.id, child)
},
[

Check warning on line 306 in src/main/frontend/app/routes/studio/canvas/nodetypes/frank-node.tsx

View workflow job for this annotation

GitHub Actions / Build & Run All Tests

React Hook useCallback has missing dependencies: 'setAttributes' and 'setNodeId'. Either include them or remove the dependency array
properties.id,
addChild,
setIsNewNode,
Expand Down Expand Up @@ -443,6 +473,9 @@
</div>
</div>
)}
{/* Show missing mandatory children if the node is missing any */}
<MissingRequirements missingChildren={missingChildren} isFulfilled={mandatoryChildrenFulfilled} />

{possibleChildren.length > 0 && (
<div
className="hover:text-foreground-active text-foreground/30 flex cursor-pointer gap-1 self-start p-1"
Expand Down
Loading
Loading