{ if (hasChildren) onToggle(node); }}
+ onClick={(e) => {
+ if (e.ctrlKey || e.metaKey || e.shiftKey) {
+ e.stopPropagation();
+ onSelect(node, e);
+ } else if (hasChildren) {
+ onToggle(node);
+ }
+ }}
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
+ draggable
+ onDragStart={(e) => {
+ e.stopPropagation();
+ if (selectedKeys.size > 1 && isSelected) {
+ const items = Array.from(selectedKeys).map(k => ({ key: k, ...(_dragPayload) }));
+ e.dataTransfer.setData('application/datasource', JSON.stringify(items));
+ } else {
+ e.dataTransfer.setData('application/datasource', JSON.stringify(_dragPayload));
+ }
+ e.dataTransfer.setData('text/plain', node.label);
+ e.dataTransfer.effectAllowed = 'copy';
+ }}
style={{
display: 'flex',
alignItems: 'center',
@@ -1140,7 +1073,13 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
paddingBottom: 3,
cursor: hasChildren ? 'pointer' : 'default',
borderRadius: 3,
- background: hovered ? 'var(--hover-bg, #f5f5f5)' : 'transparent',
+ background: ds
+ ? (hovered ? `${connColor}28` : `${connColor}10`)
+ : isSelected
+ ? 'var(--selection-bg, rgba(242, 88, 67, 0.12))'
+ : (hovered ? 'var(--hover-bg, #f5f5f5)' : 'transparent'),
+ borderLeft: ds ? `3px solid ${connColor}` : undefined,
+ outline: isSelected && !ds ? '1px solid var(--primary-color, #F25843)' : undefined,
transition: 'background 0.1s',
userSelect: 'none',
}}
@@ -1153,31 +1092,72 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
flex: 1, minWidth: 0, overflow: 'hidden',
textOverflow: 'ellipsis', whiteSpace: 'nowrap',
fontSize: 12,
- fontWeight: node.type === 'connection' ? 600 : 400,
+ fontWeight: (node.type === 'connection' || ds) ? 600 : 400,
}}>
{node.label}
- {canAdd && hovered && !alreadyAdded && (
+
+ {/* Chat-Senden: always visible */}
+
+
+ {/* Scope: own DS → cycle, no DS → create DS then cycle */}
+
+
+ {/* Neutralize: own DS → toggle, no DS → create DS then toggle */}
+
+
+ {/* Remove: only when DS exists */}
+ {ds && (
)}
- {canAdd && alreadyAdded && (
-
- {'\u2713'}
-
- )}
+
{node.expanded && node.children && node.children.length > 0 && (
@@ -1188,9 +1168,19 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
node={child}
depth={depth + 1}
onToggle={onToggle}
- onAdd={onAdd}
+ onEnsureDs={onEnsureDs}
isAdded={isAdded}
addingPath={addingPath}
+ dataSources={dataSources}
+ onCycleScope={onCycleScope}
+ onToggleNeutralize={onToggleNeutralize}
+ onRemoveDs={onRemoveDs}
+ onSendToChat={onSendToChat}
+ scopeCycleTitle={scopeCycleTitle}
+ selectedKeys={selectedKeys}
+ onSelect={onSelect}
+ inheritedScope={childInheritedScope}
+ inheritedNeutralize={childInheritedNeutralize}
/>
))}
@@ -1207,11 +1197,20 @@ const _TreeNodeView: React.FC<_TreeNodeViewProps> = ({
/* ─── MandateGroupView (mandate + feature instances) ─────────────────── */
-interface _MandateGroupViewProps {
+interface _FdsActionProps {
+ featureDataSources: UdbFeatureDataSource[];
+ onCycleScope: (fds: UdbFeatureDataSource) => void;
+ onToggleNeutralize: (fds: UdbFeatureDataSource) => void;
+ onToggleNeutralizeField: (fds: UdbFeatureDataSource, fieldName: string) => void;
+ onRemoveFds: (fdsId: string) => void;
+ featureTree: MandateGroupNode[];
+}
+
+interface _MandateGroupViewProps extends _FdsActionProps {
group: MandateGroupNode;
onToggleGroup: (mandateId: string) => void;
onToggleFeature: (node: FeatureConnectionNode) => void;
- onAddTable: (node: FeatureConnectionNode, table: FeatureTableNode) => void;
+ onEnsureFds: (node: FeatureConnectionNode, table: FeatureTableNode) => Promise