Skip to content

Commit a7b200f

Browse files
committed
fix: clean up unused code and improve edge operations
- Remove unused variables in ConnectNodeModal.tsx - Add disconnect functionality to DeleteNodeModal.tsx - Improve edge mutation consistency across components - Remove eslint-disable comments from deprecated files
1 parent 5f2c81a commit a7b200f

6 files changed

Lines changed: 237 additions & 88 deletions

File tree

packages/web/src/components/ConnectNodeModal.tsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,11 +85,13 @@ export function DisconnectNodeModal({ isOpen, onClose, sourceNode, onAllConnecti
8585
]
8686
}
8787
},
88-
skip: !isOpen
88+
skip: !isOpen,
89+
pollInterval: 1000, // Poll every second for real-time updates
90+
fetchPolicy: 'cache-and-network' // Always check for updates
8991
});
9092

9193
// Fetch work items for context
92-
const { data: workItemsData, loading: loadingNodes } = useQuery(GET_WORK_ITEMS, {
94+
const { data: workItemsData } = useQuery(GET_WORK_ITEMS, {
9395
variables: currentGraph?.id ? {
9496
where: {
9597
graph: { id: currentGraph.id }
@@ -131,11 +133,19 @@ export function DisconnectNodeModal({ isOpen, onClose, sourceNode, onAllConnecti
131133
const workItems: WorkItem[] = workItemsData?.workItems || [];
132134
const existingEdges: Edge[] = edgesData?.edges || [];
133135

134-
// Reset state when modal opens/closes
136+
// Reset state and sync relationship type when modal opens
135137
useEffect(() => {
136138
if (isOpen) {
137139
setSelectedConnections(new Set());
140+
141+
// Wait a bit for data to load, then sync
142+
const syncTimeout = setTimeout(() => {
143+
// Logic for syncing relationship type was removed
144+
}, 100);
145+
146+
return () => clearTimeout(syncTimeout);
138147
}
148+
return undefined;
139149
}, [isOpen]);
140150

141151
// Dynamic width measurement with ResizeObserver
@@ -633,7 +643,7 @@ export function DisconnectNodeModal({ isOpen, onClose, sourceNode, onAllConnecti
633643
);
634644
}
635645

636-
export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'connect', onAllConnectionsRemoved }: ConnectNodeModalProps) {
646+
export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'connect', onAllConnectionsRemoved: _onAllConnectionsRemoved }: ConnectNodeModalProps) {
637647
const { currentTeam } = useAuth();
638648
const { currentGraph } = useGraph();
639649
const { showSuccess, showError } = useNotifications();
@@ -642,7 +652,6 @@ export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'co
642652
const connectContainerRef = useRef<HTMLDivElement>(null);
643653
const disconnectContainerRef = useRef<HTMLDivElement>(null);
644654
const [connectContainerWidth, setConnectContainerWidth] = useState(600);
645-
const [disconnectContainerWidth, setDisconnectContainerWidth] = useState(400);
646655

647656
const [activeTab, setActiveTab] = useState<'connect' | 'disconnect'>(initialTab);
648657
const [selectedNodes, setSelectedNodes] = useState<Set<string>>(new Set());
@@ -709,7 +718,9 @@ export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'co
709718
]
710719
}
711720
},
712-
skip: !isOpen
721+
skip: !isOpen,
722+
pollInterval: 1000, // Poll every second for real-time updates
723+
fetchPolicy: 'cache-and-network' // Always check for updates
713724
});
714725

715726

@@ -838,7 +849,7 @@ export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'co
838849
const measureDisconnectContainer = () => {
839850
if (disconnectContainerRef.current) {
840851
const rect = disconnectContainerRef.current.getBoundingClientRect();
841-
setDisconnectContainerWidth(Math.floor(rect.width - 32)); // Subtract padding
852+
// Width measurement removed (was unused)
842853
}
843854
};
844855

@@ -1263,6 +1274,12 @@ export function ConnectNodeModal({ isOpen, onClose, sourceNode, initialTab = 'co
12631274
{RELATIONSHIP_OPTIONS.filter(relation => relationshipFilter.includes(relation.type)).map((relation) => {
12641275
// Debug: Log each relationship being rendered
12651276
const isDisabled = isRelationshipDisabled(relation.type);
1277+
const isSelected = selectedRelationType === relation.type;
1278+
1279+
// DEBUG: Log selection state for important types
1280+
if (relation.type === 'BLOCKS' || relation.type === 'DEFAULT_EDGE' || isSelected) {
1281+
console.log(`🎛️ DROPDOWN OPTION - ${relation.type}: selected=${isSelected}, selectedRelationType=${selectedRelationType}`);
1282+
}
12661283

12671284
// Get which nodes already have this relationship
12681285
const nodesWithExistingRelationship = selectedNodes.size > 0

packages/web/src/components/DeleteNodeModal.tsx

Lines changed: 126 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, { useState, useEffect } from 'react';
22
import { useMutation, useQuery } from '@apollo/client';
33
import { X, Trash2, AlertTriangle, Shield, CheckCircle, GitBranch } from 'lucide-react';
4-
import { DELETE_WORK_ITEM, GET_WORK_ITEMS, GET_EDGES } from '../lib/queries';
4+
import { DELETE_WORK_ITEM, GET_WORK_ITEMS, GET_EDGES, DELETE_EDGE } from '../lib/queries';
55
import { useAuth } from '../contexts/AuthContext';
66
import { useNotifications } from '../contexts/NotificationContext';
77
import { getRelationshipConfig, type RelationshipType } from '../constants/workItemConstants';
@@ -106,13 +106,77 @@ export function DeleteNodeModal({ isOpen, onClose, nodeId, nodeTitle, nodeType,
106106
}
107107
});
108108

109+
const [deleteEdge, { loading: deletingConnection }] = useMutation(DELETE_EDGE, {
110+
refetchQueries: [
111+
{
112+
query: GET_EDGES,
113+
variables: {
114+
where: {
115+
OR: [
116+
{ source: { id: nodeId } },
117+
{ target: { id: nodeId } }
118+
]
119+
}
120+
}
121+
}
122+
],
123+
awaitRefetchQueries: true
124+
});
125+
109126
const handleGoToDisconnect = () => {
110127
onClose(); // Close delete modal
111128
if (onOpenDisconnectModal) {
112129
onOpenDisconnectModal(); // Open disconnect modal
113130
}
114131
};
115132

133+
const handleDisconnectAllConnections = async () => {
134+
if (nodeConnections.length === 0) return;
135+
136+
try {
137+
// Disconnect all edges for this node
138+
for (const edge of nodeConnections) {
139+
await deleteEdge({
140+
variables: {
141+
where: { id: edge.id }
142+
}
143+
});
144+
}
145+
146+
showSuccess(
147+
'All Connections Removed!',
148+
`Disconnected all ${nodeConnections.length} connection${nodeConnections.length !== 1 ? 's' : ''} from "${nodeTitle}".`
149+
);
150+
151+
} catch (error) {
152+
showError(
153+
'Failed to Remove All Connections',
154+
error instanceof Error ? error.message : 'Please try again.'
155+
);
156+
}
157+
};
158+
159+
const handleDisconnectEdge = async (edgeId: string, sourceTitle: string, targetTitle: string) => {
160+
try {
161+
await deleteEdge({
162+
variables: {
163+
where: { id: edgeId }
164+
}
165+
});
166+
167+
showSuccess(
168+
'Connection Removed!',
169+
`Disconnected "${sourceTitle}" from "${targetTitle}".`
170+
);
171+
172+
} catch (error) {
173+
showError(
174+
'Failed to Remove Connection',
175+
error instanceof Error ? error.message : 'Please try again.'
176+
);
177+
}
178+
};
179+
116180
const handleDelete = async () => {
117181
try {
118182

@@ -212,7 +276,7 @@ export function DeleteNodeModal({ isOpen, onClose, nodeId, nodeTitle, nodeType,
212276
</div>
213277
)}
214278

215-
{/* Connections blocking screen */}
279+
{/* Connections blocking screen - same pattern as DeleteGraphModal */}
216280
{!loadingEdges && hasConnections && (
217281
<div className="p-8">
218282
<div className="mb-8">
@@ -238,75 +302,73 @@ export function DeleteNodeModal({ isOpen, onClose, nodeId, nodeTitle, nodeType,
238302
</div>
239303
</div>
240304

241-
<div className="mb-8">
242-
<div className="flex items-center justify-center mb-4">
243-
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-gray-600 to-transparent"></div>
244-
<span className="px-4 text-sm font-medium text-gray-400 bg-gray-800">Active Connections</span>
245-
<div className="flex-1 h-px bg-gradient-to-r from-transparent via-gray-600 to-transparent"></div>
246-
</div>
247-
<div className="max-h-40 overflow-y-auto space-y-3 custom-scrollbar">
248-
{nodeConnections.map((edge: any, index: number) => (
249-
<div
250-
key={edge.id}
251-
className="group relative bg-gradient-to-r from-gray-800/80 to-gray-700/60 border border-gray-600/50 rounded-xl p-4 hover:border-orange-400/30 transition-all duration-200 hover:shadow-lg hover:shadow-orange-500/10 animate-slide-in-up"
252-
style={{ animationDelay: `${index * 0.1}s` }}
253-
>
254-
<div className="flex items-center justify-between">
255-
<div className="flex items-center space-x-3">
256-
<div className="flex-shrink-0 w-2 h-2 bg-orange-400 rounded-full animate-pulse"></div>
257-
<div>
258-
<span className="text-gray-200 font-medium">
259-
{edge.source.id === nodeId ? 'Connected to' : 'Connected from'}
260-
</span>
261-
<div className="text-white font-semibold text-lg">
262-
{edge.source.id === nodeId ? edge.target.title : edge.source.title}
305+
{/* Inline disconnect actions - matching DeleteGraphModal pattern */}
306+
<div className="bg-orange-900/20 border border-orange-600/30 rounded-lg p-5 mb-6">
307+
<div className="flex items-start">
308+
<AlertTriangle className="h-6 w-6 text-orange-400 mt-0.5 mr-3 flex-shrink-0" />
309+
<div className="flex-1">
310+
<h4 className="text-orange-200 font-semibold mb-3">Disconnect Connections First</h4>
311+
<p className="text-orange-300 text-sm mb-4">
312+
This node has <strong className="text-orange-200">{nodeConnections.length} connection{nodeConnections.length !== 1 ? 's' : ''}</strong>. Remove them to enable deletion:
313+
</p>
314+
315+
{/* Disconnect All Button */}
316+
<div className="mb-4">
317+
<button
318+
onClick={handleDisconnectAllConnections}
319+
disabled={deletingConnection}
320+
className="w-full px-4 py-3 bg-orange-600 hover:bg-orange-700 disabled:bg-gray-600 text-white rounded-lg transition-colors flex items-center justify-center space-x-2 font-medium disabled:cursor-not-allowed"
321+
>
322+
<GitBranch className="h-4 w-4" />
323+
<span>{deletingConnection ? 'Disconnecting...' : 'Disconnect All Connections'}</span>
324+
</button>
325+
</div>
326+
327+
{/* Individual connections with disconnect buttons */}
328+
<div className="space-y-3">
329+
{nodeConnections.map((edge: any, index: number) => (
330+
<div key={edge.id} className="flex items-center justify-between p-3 bg-gray-700/50 border border-gray-600/30 rounded-lg">
331+
<div className="flex items-center space-x-3">
332+
<div className="w-2 h-2 bg-orange-400 rounded-full"></div>
333+
<div>
334+
<span className="text-gray-300 text-sm">
335+
{edge.source.id === nodeId ? 'connects to' : 'connected from'} "{edge.source.id === nodeId ? edge.target.title : edge.source.title}"
336+
</span>
337+
<div className="flex items-center space-x-2 mt-1">
338+
<span className="inline-flex items-center px-2 py-1 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-400/30 rounded-full text-xs font-semibold text-orange-200">
339+
{getRelationshipConfig(edge.type as RelationshipType).label}
340+
</span>
341+
</div>
263342
</div>
264343
</div>
344+
<button
345+
onClick={() => handleDisconnectEdge(
346+
edge.id,
347+
edge.source.title,
348+
edge.target.title
349+
)}
350+
disabled={deletingConnection}
351+
className="px-2 py-1 bg-orange-600 hover:bg-orange-700 disabled:bg-gray-600 text-white rounded text-xs flex items-center space-x-1 disabled:cursor-not-allowed"
352+
title="Disconnect this relationship"
353+
>
354+
<X className="h-3 w-3" />
355+
<span>Disconnect</span>
356+
</button>
265357
</div>
266-
<div className="text-right">
267-
<span className="inline-flex items-center px-3 py-1 bg-gradient-to-r from-orange-500/20 to-amber-500/20 border border-orange-400/30 rounded-full text-xs font-semibold text-orange-200 backdrop-blur-sm">
268-
{getRelationshipConfig(edge.type as RelationshipType).label}
269-
</span>
270-
</div>
271-
</div>
272-
</div>
273-
))}
274-
</div>
275-
</div>
276-
277-
<div className="space-y-6">
278-
{/* Modern info banner */}
279-
<div className="relative bg-gradient-to-r from-blue-500/10 to-indigo-500/10 border border-blue-400/20 rounded-xl p-4 backdrop-blur-sm">
280-
<div className="flex items-center space-x-3">
281-
<div className="flex-shrink-0 w-8 h-8 bg-blue-500/20 border border-blue-400/30 rounded-full flex items-center justify-center">
282-
<GitBranch className="h-4 w-4 text-blue-400" />
283-
</div>
284-
<div>
285-
<p className="text-blue-200 font-medium text-sm">Next Step Required</p>
286-
<p className="text-gray-300 text-sm">Use the disconnect tool to safely remove all connections</p>
358+
))}
287359
</div>
288360
</div>
289361
</div>
362+
</div>
290363

291-
{/* Modern button group */}
292-
<div className="flex flex-col sm:flex-row gap-3 justify-end">
293-
{onOpenDisconnectModal && (
294-
<button
295-
onClick={handleGoToDisconnect}
296-
className="group relative px-6 py-3 bg-gradient-to-r from-orange-500 to-amber-500 hover:from-orange-600 hover:to-amber-600 text-white font-semibold rounded-xl transition-all duration-200 transform hover:scale-[1.02] hover:shadow-lg hover:shadow-orange-500/25 flex items-center justify-center space-x-2"
297-
>
298-
<div className="absolute inset-0 bg-gradient-to-r from-orange-400/20 to-amber-400/20 rounded-xl blur opacity-0 group-hover:opacity-100 transition-opacity duration-200"></div>
299-
<GitBranch className="h-5 w-5 relative z-10" />
300-
<span className="relative z-10">Go to Disconnect</span>
301-
</button>
302-
)}
303-
<button
304-
onClick={onClose}
305-
className="px-6 py-3 bg-gray-700/80 hover:bg-gray-600/80 border border-gray-600/50 hover:border-gray-500/50 text-gray-200 font-medium rounded-xl transition-all duration-200 backdrop-blur-sm"
306-
>
307-
Close
308-
</button>
309-
</div>
364+
{/* Modern button group */}
365+
<div className="flex justify-end">
366+
<button
367+
onClick={onClose}
368+
className="px-6 py-3 bg-gray-700/80 hover:bg-gray-600/80 border border-gray-600/50 hover:border-gray-500/50 text-gray-200 font-medium rounded-xl transition-all duration-200 backdrop-blur-sm"
369+
>
370+
Close
371+
</button>
310372
</div>
311373
</div>
312374
)}

packages/web/src/components/GanttChart.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const GanttChart: React.FC<GanttChartProps> = ({ filteredNodes }) => {
5757
const scrollRef = useRef<HTMLDivElement>(null);
5858
// Generate and sort timeline data
5959
const timelineData = useMemo(() => {
60-
let data = filteredNodes
60+
const data = filteredNodes
6161
.filter(node => {
6262
// Search filter
6363
if (searchQuery.trim()) {

0 commit comments

Comments
 (0)