Skip to content

Commit 115733d

Browse files
ismoilovdevmlclaude
andcommitted
fix: Fix critical modal backdrop UI bug by removing page-level animations
**Root Cause:** - Page-level animations in ProjectsTab and PipelinesTab were interfering with modal backdrop rendering - `mounted` state with `transition-all duration-700` caused modal backdrops to become invisible - Overview page worked fine because it didn't have these animations **Changes:** 1. **ProjectsTab.tsx** - Removed `mounted` state and page-level animations - Removed `transition-all duration-*` classes - Clean, simple UI without animation interference 2. **PipelinesTab.tsx** - Removed `mounted` state and page-level animations - Removed `transition-all duration-*` classes - Clean, simple UI without animation interference 3. **Modal Components (ProjectDetailsModal, PipelineDetailsModal, PipelineListModal)** - Separated backdrop into dedicated layer - Added `pointer-events-none` to modal container - Added `pointer-events-auto` to modal content - Fixed z-index hierarchy (999 for nested modals) 4. **JobDetailsModal** - Updated z-index to 999 for consistency **Testing:** ✅ npm run lint - passed ✅ TypeScript type check - passed ✅ npm run build - passed ✅ Modal backdrops now visible on all pages ✅ Click outside modal closes properly ✅ Nested modals work correctly **Impact:** This was a critical UI bug that made modals unusable in Projects and Pipelines pages. The fix ensures professional, consistent modal behavior across the entire application. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 4195d89 commit 115733d

File tree

6 files changed

+75
-56
lines changed

6 files changed

+75
-56
lines changed

src/components/JobDetailsModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export default function JobDetailsModal({ job, projectId, onClose }: JobDetailsM
193193

194194
return (
195195
<>
196-
<div className={`fixed inset-0 backdrop-blur-sm z-50 flex items-center justify-center p-4 overflow-y-auto ${
196+
<div className={`fixed inset-0 backdrop-blur-sm z-[999] flex items-center justify-center p-4 overflow-y-auto ${
197197
theme === 'light' ? 'bg-black/30' : 'bg-black/80'
198198
}`} onClick={onClose}>
199199
<div

src/components/PipelineDetailsModal.tsx

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,20 @@ export default function PipelineDetailsModal({ pipeline, projectId, onClose }: P
134134

135135

136136
return (
137-
<div className={`fixed inset-0 backdrop-blur-sm z-50 flex items-center justify-center p-4 overflow-y-auto ${
138-
theme === 'light' ? 'bg-black/30' : 'bg-black/80'
139-
}`}>
140-
<div className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-hidden flex flex-col ${surface} ${
141-
theme === 'light' ? 'shadow-2xl' : 'border border-zinc-800'
142-
}`}>
137+
<>
138+
{/* Backdrop overlay */}
139+
<div
140+
className="fixed inset-0 z-[999] bg-black/60 backdrop-blur-sm"
141+
onClick={onClose}
142+
/>
143+
{/* Modal container */}
144+
<div className="fixed inset-0 z-[999] flex items-center justify-center p-4 overflow-y-auto pointer-events-none">
145+
<div
146+
className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-hidden flex flex-col pointer-events-auto ${surface} ${
147+
theme === 'light' ? 'shadow-2xl' : 'border border-zinc-800'
148+
}`}
149+
onClick={(e) => e.stopPropagation()}
150+
>
143151
{/* Header */}
144152
<div className={`p-6 flex items-center justify-between border-b ${
145153
theme === 'light' ? 'border-gray-200 bg-gradient-to-r from-gray-50 to-white' : 'border-zinc-800 bg-gradient-to-r from-zinc-900 to-zinc-800'
@@ -363,20 +371,21 @@ export default function PipelineDetailsModal({ pipeline, projectId, onClose }: P
363371
</div>
364372
</div>
365373

366-
{selectedJob && logs && (
367-
<LogViewer
368-
logs={logs}
369-
jobName={selectedJob.name}
370-
jobStatus={selectedJob.status}
371-
projectId={projectId}
372-
jobId={selectedJob.id}
373-
onClose={() => {
374-
setSelectedJob(null);
375-
setLogs('');
376-
}}
377-
onRefreshLogs={refreshJobLogs}
378-
/>
379-
)}
380-
</div>
374+
{selectedJob && logs && (
375+
<LogViewer
376+
logs={logs}
377+
jobName={selectedJob.name}
378+
jobStatus={selectedJob.status}
379+
projectId={projectId}
380+
jobId={selectedJob.id}
381+
onClose={() => {
382+
setSelectedJob(null);
383+
setLogs('');
384+
}}
385+
onRefreshLogs={refreshJobLogs}
386+
/>
387+
)}
388+
</div>
389+
</>
381390
);
382391
}

src/components/PipelineListModal.tsx

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,19 @@ export default function PipelineListModal({ title, status, onClose }: PipelineLi
8080

8181
return (
8282
<>
83-
<div className={`fixed inset-0 backdrop-blur-sm z-40 flex items-center justify-center p-4 ${
84-
theme === 'light' ? 'bg-black/20' : 'bg-black/80'
85-
}`}>
86-
<div className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-hidden flex flex-col ${
87-
theme === 'light' ? 'bg-white border border-[#d2d2d7] shadow-2xl' : 'bg-zinc-900 border border-zinc-800'
88-
}`}>
83+
{/* Backdrop overlay */}
84+
<div
85+
className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm"
86+
onClick={onClose}
87+
/>
88+
{/* Modal container */}
89+
<div className="fixed inset-0 z-40 flex items-center justify-center p-4 pointer-events-none">
90+
<div
91+
className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-hidden flex flex-col pointer-events-auto ${
92+
theme === 'light' ? 'bg-white border border-[#d2d2d7] shadow-2xl' : 'bg-zinc-900 border border-zinc-800'
93+
}`}
94+
onClick={(e) => e.stopPropagation()}
95+
>
8996
{/* Header */}
9097
<div className={`p-6 border-b flex items-center justify-between ${
9198
theme === 'light' ? 'border-[#d2d2d7]/50' : 'border-zinc-800'

src/components/PipelinesTab.tsx

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,8 @@ export default function PipelinesTab() {
3131
const [currentPage, setCurrentPage] = useState(1);
3232
const [totalPipelines, setTotalPipelines] = useState(0);
3333
const pipelinesPerPage = 20;
34-
const [mounted, setMounted] = useState(false);
3534

3635
useEffect(() => {
37-
setMounted(true);
3836
loadProjects();
3937
// eslint-disable-next-line react-hooks/exhaustive-deps
4038
}, []);
@@ -200,16 +198,16 @@ export default function PipelinesTab() {
200198
const totalPages = Math.ceil(totalPipelines / pipelinesPerPage);
201199

202200
return (
203-
<div className={`space-y-6 transition-all duration-700 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
204-
{/* Header with animation */}
205-
<div className={`transition-all duration-500 delay-100 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-2'}`}>
201+
<div className="space-y-6">
202+
{/* Header */}
203+
<div>
206204
<h1 className={`text-3xl font-bold mb-2 ${textPrimary}`}>Pipelines</h1>
207205
<p className={textSecondary}>Browse and manage CI/CD pipelines</p>
208206
</div>
209207

210208
<div className="grid grid-cols-12 gap-6">
211209
{/* Projects Sidebar */}
212-
<div className={`col-span-3 space-y-4 transition-all duration-500 delay-200 ${mounted ? 'opacity-100 translate-x-0' : 'opacity-0 -translate-x-4'}`}>
210+
<div className="col-span-3 space-y-4">
213211
<div className="relative">
214212
<Search className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${textSecondary}`} />
215213
<input
@@ -277,10 +275,10 @@ export default function PipelinesTab() {
277275
</div>
278276

279277
{/* Pipelines List */}
280-
<div className={`col-span-9 space-y-4 transition-all duration-500 delay-300 ${mounted ? 'opacity-100 translate-x-0' : 'opacity-0 translate-x-4'}`}>
278+
<div className={`col-span-9 space-y-4 `}>
281279
{/* Statistics Cards */}
282280
{selectedProject && (
283-
<div className={`grid grid-cols-2 md:grid-cols-4 gap-4 transition-all duration-500 delay-400 ${mounted ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`}>
281+
<div className={`grid grid-cols-2 md:grid-cols-4 gap-4 `}>
284282
<div className={`rounded-xl p-4 border transition-all ${
285283
theme === 'light'
286284
? 'bg-gradient-to-br from-blue-50 to-blue-100 border-blue-200 hover:from-blue-100 hover:to-blue-200 shadow-sm hover:shadow-md'
@@ -357,7 +355,7 @@ export default function PipelinesTab() {
357355

358356
{/* Pipeline Status Distribution Chart */}
359357
{selectedProject && pipelines.length > 0 && (
360-
<div className={`rounded-xl p-6 ${card} ${theme === 'light' ? 'shadow-sm' : ''} transition-all duration-500 delay-500 ${mounted ? 'opacity-100 scale-100' : 'opacity-0 scale-95'}`}>
358+
<div className={`rounded-xl p-6 ${card} ${theme === 'light' ? 'shadow-sm' : ''} `}>
361359
<h3 className={`text-lg font-semibold mb-4 flex items-center gap-2 ${textPrimary}`}>
362360
<BarChart3 className="w-5 h-5 text-orange-500" />
363361
Pipeline Status Distribution
@@ -441,7 +439,7 @@ export default function PipelinesTab() {
441439
)}
442440

443441
{/* Filters and Actions */}
444-
<div className={`flex items-center justify-between gap-4 transition-all duration-500 delay-600 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
442+
<div className={`flex items-center justify-between gap-4 `}>
445443
<div className="flex items-center gap-4">
446444
{/* Status Filter */}
447445
<div className="relative">
@@ -489,7 +487,7 @@ export default function PipelinesTab() {
489487

490488
{!selectedPipeline ? (
491489
<>
492-
<div className={`grid grid-cols-1 lg:grid-cols-2 gap-4 transition-all duration-500 delay-700 ${mounted ? 'opacity-100' : 'opacity-0'}`}>
490+
<div className={`grid grid-cols-1 lg:grid-cols-2 gap-4 `}>
493491
{pipelines.length > 0 ? (
494492
pipelines.map((pipeline) => (
495493
<PipelineCard

src/components/ProjectDetailsModal.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,12 +56,20 @@ export default function ProjectDetailsModal({ project, onClose }: ProjectDetails
5656

5757
return (
5858
<>
59-
<div className={`fixed inset-0 backdrop-blur-sm z-40 flex items-center justify-center p-4 ${
60-
theme === 'light' ? 'bg-black/20' : 'bg-black/80'
61-
}`}>
62-
<div className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-y-auto ${
63-
theme === 'light' ? 'bg-white border border-[#d2d2d7] shadow-2xl' : 'bg-zinc-900 border border-zinc-800'
64-
}`}>
59+
{/* Backdrop overlay */}
60+
<div
61+
className="fixed inset-0 z-40 bg-black/50 backdrop-blur-sm"
62+
onClick={onClose}
63+
/>
64+
{/* Modal container */}
65+
<div className="fixed inset-0 z-40 flex items-center justify-center p-4 pointer-events-none">
66+
67+
<div
68+
className={`rounded-xl w-full max-w-7xl max-h-[90vh] overflow-y-auto pointer-events-auto ${
69+
theme === 'light' ? 'bg-white border border-[#d2d2d7] shadow-2xl' : 'bg-zinc-900 border border-zinc-800'
70+
}`}
71+
onClick={(e) => e.stopPropagation()}
72+
>
6573
{/* Header */}
6674
<div className={`sticky top-0 p-6 flex items-center justify-between ${
6775
theme === 'light' ? 'bg-white border-b border-[#d2d2d7]/50' : 'bg-zinc-900 border-b border-zinc-800'

src/components/ProjectsTab.tsx

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,8 @@ export default function ProjectsTab() {
1515
const [starringProjects, setStarringProjects] = useState<Set<number>>(new Set());
1616
const [searchTerm, setSearchTerm] = useState('');
1717
const [visibilityFilter, setVisibilityFilter] = useState<string>('all');
18-
const [mounted, setMounted] = useState(false);
1918

2019
useEffect(() => {
21-
setMounted(true);
2220
loadProjects();
2321
// eslint-disable-next-line react-hooks/exhaustive-deps
2422
}, []);
@@ -110,14 +108,14 @@ export default function ProjectsTab() {
110108
}, [projects]);
111109

112110
return (
113-
<div className={`space-y-6 transition-all duration-700 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
114-
<div className={`transition-all duration-500 delay-100 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 -translate-y-2'}`}>
111+
<div className="space-y-6">
112+
<div>
115113
<h1 className={`text-3xl font-bold mb-2 ${textPrimary}`}>Projects</h1>
116114
<p className={textSecondary}>All your GitLab projects</p>
117115
</div>
118116

119117
{/* Statistics Cards - Only Essential */}
120-
<div className={`grid grid-cols-1 md:grid-cols-3 gap-4 transition-all duration-500 delay-200 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
118+
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
121119
<button
122120
onClick={() => {
123121
setVisibilityFilter('all');
@@ -186,7 +184,7 @@ export default function ProjectsTab() {
186184
</div>
187185

188186
{/* Filters */}
189-
<div className={`flex flex-wrap items-center gap-4 transition-all duration-500 delay-300 ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-4'}`}>
187+
<div className="flex flex-wrap items-center gap-4">
190188
<div className="flex-1 min-w-[200px] relative">
191189
<Search className={`absolute left-3 top-1/2 transform -translate-y-1/2 w-4 h-4 ${textSecondary}`} />
192190
<input
@@ -219,17 +217,16 @@ export default function ProjectsTab() {
219217
</div>
220218
</div>
221219

222-
<div className={`grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4 transition-all duration-500 delay-400 ${mounted ? 'opacity-100' : 'opacity-0'}`}>
223-
{filteredProjects.map((project, index) => (
220+
<div className="grid grid-cols-1 lg:grid-cols-2 xl:grid-cols-3 gap-4">
221+
{filteredProjects.map((project) => (
224222
<div
225223
key={project.id}
226224
onClick={() => setSelectedProject(project)}
227-
className={`rounded-2xl p-4 transition-all duration-500 group cursor-pointer border-2 ${
225+
className={`rounded-2xl p-4 transition-all group cursor-pointer border-2 ${
228226
theme === 'light'
229227
? 'bg-white border-gray-200 hover:border-orange-400 shadow-sm hover:shadow-lg'
230228
: 'bg-zinc-900/50 border-zinc-800 hover:border-orange-500/50 backdrop-blur-sm'
231-
} ${mounted ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8'}`}
232-
style={{ transitionDelay: `${400 + index * 50}ms` }}
229+
}`}
233230
>
234231
{/* Header with Avatar and Name */}
235232
<div className="flex items-start gap-3 mb-3">

0 commit comments

Comments
 (0)