Merge branch 'feature/beta-release' into renovate/feature/beta-release-weekly-non-major-updates
This commit is contained in:
257
docs/issues/created/20260204-modal_dropdown_handoff_contract.md
Normal file
257
docs/issues/created/20260204-modal_dropdown_handoff_contract.md
Normal file
@@ -0,0 +1,257 @@
|
||||
# Modal Dropdown Fix - Local Environment Handoff Contract
|
||||
|
||||
**Date**: 2026-02-04
|
||||
**Status**: Implementation Complete - Testing Required
|
||||
**Environment**: Codespace → Local Development Environment
|
||||
|
||||
---
|
||||
|
||||
## IMPLEMENTATION COMPLETED ✅
|
||||
|
||||
### Frontend Changes Made
|
||||
All 7 P0 critical modal components have been updated with the 3-layer modal architecture:
|
||||
|
||||
1. ✅ **ProxyHostForm.tsx** - ACL selector, Security Headers dropdowns fixed
|
||||
2. ✅ **UsersPage.tsx** - InviteUserModal role/permission dropdowns fixed
|
||||
3. ✅ **UsersPage.tsx** - EditPermissionsModal dropdowns fixed
|
||||
4. ✅ **Uptime.tsx** - CreateMonitorModal & EditMonitorModal type dropdowns fixed
|
||||
5. ✅ **RemoteServerForm.tsx** - Provider dropdown fixed
|
||||
6. ✅ **CrowdSecConfig.tsx** - BanIPModal duration dropdown fixed
|
||||
|
||||
### Technical Changes Applied
|
||||
- **3-Layer Modal Pattern**: Separated overlay (z-40) / container (z-50) / content (pointer-events-auto)
|
||||
- **DOM Restructuring**: Split single overlay div into proper layered architecture
|
||||
- **Event Handling**: Preserved modal close behavior (backdrop click, ESC key)
|
||||
- **CSS Classes**: Added `pointer-events-none/auto` for proper interaction handling
|
||||
|
||||
---
|
||||
|
||||
## LOCAL ENVIRONMENT TESTING REQUIRED 🧪
|
||||
|
||||
### Prerequisites for Testing
|
||||
```bash
|
||||
# Required for E2E testing
|
||||
docker --version # Must be available
|
||||
docker-compose --version # Must be available
|
||||
node --version # v18+ required
|
||||
npm --version # Latest stable
|
||||
```
|
||||
|
||||
### Step 1: Environment Setup
|
||||
```bash
|
||||
# 1. Switch to local environment
|
||||
cd /path/to/charon
|
||||
|
||||
# 2. Ensure on correct branch
|
||||
git checkout feature/beta-release
|
||||
git pull origin feature/beta-release
|
||||
|
||||
# 3. Install dependencies
|
||||
npm install
|
||||
cd frontend && npm install && cd ..
|
||||
|
||||
# 4. Build frontend
|
||||
cd frontend && npm run build && cd ..
|
||||
```
|
||||
|
||||
### Step 2: Start E2E Environment
|
||||
```bash
|
||||
# CRITICAL: Rebuild E2E container with new code
|
||||
.github/skills/scripts/skill-runner.sh docker-rebuild-e2e
|
||||
|
||||
# OR manual rebuild if skill script unavailable:
|
||||
docker-compose -f .docker/compose/docker-compose.yml down
|
||||
docker-compose -f .docker/compose/docker-compose.yml build --no-cache
|
||||
docker-compose -f .docker/compose/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
### Step 3: Manual Testing (30-45 minutes)
|
||||
|
||||
#### Test Each Modal Component
|
||||
|
||||
**A. ProxyHostForm (Priority 1)**
|
||||
```bash
|
||||
# Navigate to: http://localhost:8080/proxy-hosts
|
||||
# 1. Click "Add Proxy Host"
|
||||
# 2. Test ACL dropdown - should open and allow selection
|
||||
# 3. Test Security Headers dropdown - should open and allow selection
|
||||
# 4. Fill form and submit - should work normally
|
||||
# 5. Edit existing proxy host - repeat dropdown tests
|
||||
```
|
||||
|
||||
**B. User Management Modals**
|
||||
```bash
|
||||
# Navigate to: http://localhost:8080/users
|
||||
# 1. Click "Invite User"
|
||||
# 2. Test Role dropdown (User/Admin) - should work
|
||||
# 3. Test Permission Mode dropdown - should work
|
||||
# 4. Click existing user "Edit Permissions"
|
||||
# 5. Test permission dropdowns - should work
|
||||
```
|
||||
|
||||
**C. Uptime Monitor Modals**
|
||||
```bash
|
||||
# Navigate to: http://localhost:8080/uptime
|
||||
# 1. Click "Create Monitor"
|
||||
# 2. Test Monitor Type dropdown (HTTP/TCP) - should work
|
||||
# 3. Save monitor, then click "Configure"
|
||||
# 4. Test Monitor Type dropdown in edit mode - should work
|
||||
```
|
||||
|
||||
**D. Remote Servers**
|
||||
```bash
|
||||
# Navigate to: http://localhost:8080/remote-servers
|
||||
# 1. Click "Add Server"
|
||||
# 2. Test Provider dropdown (Generic/Docker/Kubernetes) - should work
|
||||
```
|
||||
|
||||
**E. CrowdSec IP Bans**
|
||||
```bash
|
||||
# Navigate to: http://localhost:8080/security/crowdsec
|
||||
# 1. Click "Ban IP"
|
||||
# 2. Test Duration dropdown - should work and allow selection
|
||||
```
|
||||
|
||||
### Step 4: Automated E2E Testing
|
||||
```bash
|
||||
# MUST run after manual testing confirms dropdowns work
|
||||
|
||||
# 1. Test proxy host ACL integration (primary test case)
|
||||
npx playwright test tests/integration/proxy-acl-integration.spec.ts --project=chromium
|
||||
|
||||
# 2. Run full E2E suite
|
||||
npx playwright test --project=chromium --project=firefox --project=webkit
|
||||
|
||||
# 3. Check for specific dropdown-related failures
|
||||
npx playwright test --grep "dropdown|select|acl|security.headers" --project=chromium
|
||||
```
|
||||
|
||||
### Step 5: Cross-Browser Verification
|
||||
```bash
|
||||
# Test in each browser for compatibility
|
||||
npx playwright test tests/integration/proxy-acl-integration.spec.ts --project=chromium
|
||||
npx playwright test tests/integration/proxy-acl-integration.spec.ts --project=firefox
|
||||
npx playwright test tests/integration/proxy-acl-integration.spec.ts --project=webkit
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SUCCESS CRITERIA ✅
|
||||
|
||||
### Must Pass Before Merge
|
||||
- [ ] **All 7 modal dropdowns** open and allow selection
|
||||
- [ ] **Modal close behavior** works (backdrop click, ESC key)
|
||||
- [ ] **Form submission** works with selected dropdown values
|
||||
- [ ] **E2E tests pass** - especially proxy-acl-integration.spec.ts
|
||||
- [ ] **Cross-browser compatibility** (Chrome, Firefox, Safari)
|
||||
- [ ] **No console errors** in browser dev tools
|
||||
- [ ] **No TypeScript errors** - `npm run type-check` passes
|
||||
|
||||
### Verification Commands
|
||||
```bash
|
||||
# Frontend type check
|
||||
cd frontend && npm run type-check
|
||||
|
||||
# Backend tests (should be unaffected)
|
||||
cd backend && go test ./...
|
||||
|
||||
# Full test suite
|
||||
npm test
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ROLLBACK PLAN 🔄
|
||||
|
||||
If any issues are discovered:
|
||||
|
||||
```bash
|
||||
# Quick rollback - revert all modal changes
|
||||
git log --oneline -5 # Find modal fix commit hash
|
||||
git revert <commit-hash> # Revert the modal changes
|
||||
git push origin feature/beta-release # Push rollback
|
||||
|
||||
# Test rollback worked
|
||||
npx playwright test tests/integration/proxy-acl-integration.spec.ts --project=chromium
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## EXPECTED ISSUES & SOLUTIONS 🔧
|
||||
|
||||
### Issue: E2E Container Won't Start
|
||||
```bash
|
||||
# Solution: Clean rebuild
|
||||
docker-compose down -v
|
||||
docker system prune -f
|
||||
.github/skills/scripts/skill-runner.sh docker-rebuild-e2e --clean
|
||||
```
|
||||
|
||||
### Issue: Frontend Build Fails
|
||||
```bash
|
||||
# Solution: Clean install
|
||||
cd frontend
|
||||
rm -rf node_modules package-lock.json
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
|
||||
### Issue: Tests Still Fail
|
||||
```bash
|
||||
# Solution: Check if environment variables are set
|
||||
cat .env | grep -E "(EMERGENCY|ENCRYPTION)"
|
||||
# Should show EMERGENCY_TOKEN and ENCRYPTION_KEY
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## COMMIT MESSAGE TEMPLATE 📝
|
||||
|
||||
When testing is complete and successful:
|
||||
|
||||
```
|
||||
fix: resolve modal dropdown z-index conflicts across application
|
||||
|
||||
Restructure 7 modal components to use 3-layer architecture preventing
|
||||
native select dropdown menus from being blocked by modal overlays.
|
||||
|
||||
Components fixed:
|
||||
- ProxyHostForm: ACL selector and Security Headers dropdowns
|
||||
- User management: Role and permission mode selection
|
||||
- Uptime monitors: Monitor type selection (HTTP/TCP)
|
||||
- Remote servers: Provider selection dropdown
|
||||
- CrowdSec: IP ban duration selection
|
||||
|
||||
The fix separates modal background overlay (z-40) from form container
|
||||
(z-50) and enables pointer events only on form content, allowing
|
||||
native dropdown menus to render above all modal layers.
|
||||
|
||||
Resolves user inability to select security policies, user roles,
|
||||
monitor types, and other critical configuration options through
|
||||
the UI interface.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## QA REQUIREMENTS 📋
|
||||
|
||||
### Definition of Done
|
||||
- [ ] Manual testing completed for all 7 components
|
||||
- [ ] All E2E tests passing
|
||||
- [ ] Cross-browser verification complete
|
||||
- [ ] No console errors or TypeScript issues
|
||||
- [ ] Code review approved (if applicable)
|
||||
- [ ] Commit message follows conventional format
|
||||
|
||||
### Documentation Updates
|
||||
- [ ] Update component documentation if modal patterns changed
|
||||
- [ ] Add note to design system about correct modal z-index patterns
|
||||
- [ ] Consider adding ESLint rule to catch future modal z-index anti-patterns
|
||||
|
||||
---
|
||||
|
||||
**🎯 READY FOR LOCAL ENVIRONMENT TESTING**
|
||||
|
||||
All implementation work is complete. The modal dropdown z-index fix has been applied comprehensively across all 7 affected components. Testing in the local Docker environment will validate the fix works as designed.
|
||||
|
||||
**Next Actions**: Move to local environment, run the testing checklist above, and merge when all success criteria are met.
|
||||
206
docs/plans/comprehensive_modal_fix_spec.md
Normal file
206
docs/plans/comprehensive_modal_fix_spec.md
Normal file
@@ -0,0 +1,206 @@
|
||||
# Comprehensive Modal Z-Index Fix Plan
|
||||
|
||||
**Date**: 2026-02-04
|
||||
**Issue**: Widespread modal overlay z-index pattern breaking dropdown interactions
|
||||
**Scope**: 11 modal components across the application
|
||||
**Fix Strategy**: Unified 3-layer modal restructuring
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Multiple modal components throughout the application use the same problematic pattern:
|
||||
```tsx
|
||||
<div className="fixed inset-0 bg-black/50 ... z-50">
|
||||
{/* Form with dropdowns inside */}
|
||||
</div>
|
||||
```
|
||||
|
||||
This pattern creates a z-index stacking context that blocks native HTML `<select>` dropdown menus from rendering properly, making them unclickable.
|
||||
|
||||
---
|
||||
|
||||
## Affected Components by Priority
|
||||
|
||||
### P0 - CRITICAL: Modals with SELECT Dropdowns (Completely Broken)
|
||||
|
||||
| Component | File | Line | Dropdowns | Impact |
|
||||
|-----------|------|------|-----------|--------|
|
||||
| **ProxyHostForm** | `frontend/src/components/ProxyHostForm.tsx` | 514 | ACL selector, Security Headers | **CRITICAL**: Users cannot assign security policies |
|
||||
| **EditMonitorModal** | `frontend/src/pages/Uptime.tsx` | 230 | Monitor type (HTTP/TCP) | **HIGH**: Users cannot edit monitor configuration |
|
||||
| **CreateMonitorModal** | `frontend/src/pages/Uptime.tsx` | 339 | Monitor type (HTTP/TCP) | **HIGH**: Users cannot create new monitors |
|
||||
| **InviteUserModal** | `frontend/src/pages/UsersPage.tsx` | 171 | Role, Permission mode | **HIGH**: Admin cannot invite users with roles |
|
||||
| **EditPermissionsModal** | `frontend/src/pages/UsersPage.tsx` | 434 | Permission mode, Allowed/Blocked hosts | **HIGH**: Admin cannot modify user permissions |
|
||||
| **BanIPModal** | `frontend/src/pages/CrowdSecConfig.tsx` | 1175 | Ban duration | **MEDIUM**: Admin cannot set custom ban durations |
|
||||
| **RemoteServerForm** | `frontend/src/components/RemoteServerForm.tsx` | 69 | Provider (Generic/Docker/K8s) | **MEDIUM**: Users cannot add remote servers |
|
||||
|
||||
### P1 - HIGH: Modals with Other Interactive Elements
|
||||
|
||||
| Component | File | Line | Elements | Impact |
|
||||
|-----------|------|------|----------|--------|
|
||||
| **PasswordPromptModal** | `frontend/src/pages/Account.tsx` | 473 | Password input, buttons | **LOW**: Simple inputs work |
|
||||
| **EmailConfirmModal** | `frontend/src/pages/Account.tsx` | 523 | Buttons only | **NONE**: No form inputs |
|
||||
|
||||
### P2 - MEDIUM: Modal Pattern Analysis Required
|
||||
|
||||
| Component | File | Line | Status | Impact |
|
||||
|-----------|------|------|--------|--------|
|
||||
| **ConfirmDialog** | `frontend/src/pages/WafConfig.tsx` | 72 | Buttons only | **NONE**: No form inputs |
|
||||
| **SecurityNotificationModal** | `frontend/src/components/SecurityNotificationSettingsModal.tsx` | 58 | **TBD** - Need analysis | **UNKNOWN** |
|
||||
| **ImportSitesModal** | `frontend/src/components/ImportSitesModal.tsx` | 75 | **TBD** - Need analysis | **UNKNOWN** |
|
||||
| **CertificateCleanupDialog** | `frontend/src/components/dialogs/CertificateCleanupDialog.tsx` | 27 | Buttons only | **NONE**: No form inputs |
|
||||
| **ImportSuccessModal** | `frontend/src/components/dialogs/ImportSuccessModal.tsx` | 30 | Display only | **NONE**: No form inputs |
|
||||
|
||||
---
|
||||
|
||||
## Unified Fix Strategy
|
||||
|
||||
### Solution: 3-Layer Modal Architecture
|
||||
|
||||
Replace the problematic single-layer pattern:
|
||||
```tsx
|
||||
// ❌ BROKEN: Single layer blocks dropdown menus
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
||||
<form>
|
||||
<select> {/* BROKEN: Can't click */} </select>
|
||||
</form>
|
||||
</div>
|
||||
```
|
||||
|
||||
With the 3-layer pattern:
|
||||
```tsx
|
||||
// ✅ FIXED: Separate layers for proper z-index stacking
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onCancel} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="... pointer-events-auto">
|
||||
<form className="pointer-events-auto">
|
||||
<select> {/* WORKS: Dropdown renders above all layers */} </select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Plan
|
||||
|
||||
### Phase 1: P0 Critical Components (4-6 hours)
|
||||
|
||||
**Priority Order** (most business-critical first):
|
||||
1. **ProxyHostForm.tsx** (30 min) - Security policy assignment
|
||||
2. **UsersPage.tsx** - InviteUserModal (20 min) - User management
|
||||
3. **UsersPage.tsx** - EditPermissionsModal (30 min) - Permission management
|
||||
4. **Uptime.tsx** - Both modals (45 min) - Monitor management
|
||||
5. **RemoteServerForm.tsx** (20 min) - Infrastructure management
|
||||
6. **CrowdSecConfig.tsx** - BanIPModal (20 min) - Security management
|
||||
|
||||
### Phase 2: P1 Components (1-2 hours)
|
||||
|
||||
Analysis and fix of remaining interactive modals if needed.
|
||||
|
||||
### Phase 3: Testing & Validation (2-3 hours)
|
||||
|
||||
- Manual testing of all dropdown interactions
|
||||
- E2E test updates
|
||||
- Cross-browser verification
|
||||
|
||||
**Total Estimated Time: 7-11 hours**
|
||||
|
||||
---
|
||||
|
||||
## Testing Strategy
|
||||
|
||||
### Manual Testing Checklist
|
||||
|
||||
For each P0 component:
|
||||
- [ ] Modal opens correctly
|
||||
- [ ] Background overlay click-to-close works
|
||||
- [ ] All dropdown menus open and respond to clicks
|
||||
- [ ] Dropdown options are selectable
|
||||
- [ ] Form submission works with selected values
|
||||
- [ ] ESC key closes modal
|
||||
- [ ] Tab navigation works through form elements
|
||||
|
||||
### Automated Testing
|
||||
|
||||
**E2E Tests to Update:**
|
||||
- `tests/integration/proxy-acl-integration.spec.ts` - ProxyHostForm dropdowns
|
||||
- `tests/security/user-management.spec.ts` - UsersPage modals
|
||||
- `tests/uptime/*.spec.ts` - Uptime monitor modals
|
||||
- Any tests interacting with the affected modals
|
||||
|
||||
**Unit Tests:**
|
||||
- Modal rendering tests should continue to pass
|
||||
- Form submission tests should continue to pass
|
||||
|
||||
---
|
||||
|
||||
## Risk Assessment
|
||||
|
||||
**Risk Level: LOW-MEDIUM**
|
||||
|
||||
**Mitigating Factors:**
|
||||
✅ Non-breaking change (only CSS/DOM structure)
|
||||
✅ Identical fix pattern across all components
|
||||
✅ Well-understood solution (already documented in ConfigReloadOverlay)
|
||||
✅ Only affects modal presentation layer
|
||||
|
||||
**Risk Areas:**
|
||||
⚠️ Multiple files being modified simultaneously
|
||||
⚠️ Modal close behavior could be affected
|
||||
⚠️ CSS specificity or responsive behavior could change
|
||||
|
||||
**Mitigation Strategy:**
|
||||
- Fix components one at a time
|
||||
- Test each component thoroughly before moving to next
|
||||
- Keep changes minimal and focused
|
||||
- Maintain existing CSS classes and styling
|
||||
|
||||
---
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- [ ] All P0 modal dropdowns are clickable and functional
|
||||
- [ ] Modal open/close behavior unchanged
|
||||
- [ ] Background overlay click-to-close still works
|
||||
- [ ] ESC key behavior unchanged
|
||||
- [ ] All existing E2E tests pass
|
||||
- [ ] No new console errors or warnings
|
||||
- [ ] Cross-browser compatibility maintained (Chrome, Firefox, Safari, Edge)
|
||||
|
||||
---
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
**CSS Classes to Add:**
|
||||
- `pointer-events-none` on form container layers
|
||||
- `pointer-events-auto` on form content elements
|
||||
|
||||
**CSS Classes to Modify:**
|
||||
- Change overlay z-index from `z-50` to `z-40`
|
||||
- Keep form container at `z-50`
|
||||
|
||||
**Accessibility:**
|
||||
- Maintain `role="dialog"` and `aria-modal="true"` attributes
|
||||
- Ensure Tab navigation still works correctly
|
||||
- Preserve ESC key handling
|
||||
|
||||
---
|
||||
|
||||
## Post-Implementation Actions
|
||||
|
||||
1. **Documentation Update**: Update modal component patterns in design system docs
|
||||
2. **Code Review Guidelines**: Add z-index modal pattern to code review checklist
|
||||
3. **Linting Rule**: Consider ESLint rule to detect problematic modal patterns
|
||||
4. **Design System**: Create reusable Modal component with correct z-index pattern
|
||||
|
||||
---
|
||||
|
||||
*This comprehensive fix addresses the root cause across the entire application, preventing future occurrences of the same issue.*
|
||||
2392
docs/plans/current_spec.docker-cicd-backup.md
Normal file
2392
docs/plans/current_spec.docker-cicd-backup.md
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -511,8 +511,15 @@ export default function ProxyHostForm({ host, onSubmit, onCancel }: ProxyHostFor
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
||||
<div className="bg-dark-card rounded-lg border border-gray-800 max-w-2xl w-full max-h-[90vh] overflow-y-auto">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onCancel} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-dark-card rounded-lg border border-gray-800 max-w-2xl w-full max-h-[90vh] overflow-y-auto pointer-events-auto">
|
||||
<div className="p-6 border-b border-gray-800">
|
||||
<h2 className="text-2xl font-bold text-white">
|
||||
{host ? 'Edit Proxy Host' : 'Add Proxy Host'}
|
||||
@@ -1360,6 +1367,8 @@ export default function ProxyHostForm({ host, onSubmit, onCancel }: ProxyHostFor
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -66,15 +66,22 @@ export default function RemoteServerForm({ server, onSubmit, onCancel }: Props)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
||||
<div className="bg-dark-card rounded-lg border border-gray-800 max-w-lg w-full">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onCancel} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-dark-card rounded-lg border border-gray-800 max-w-lg w-full pointer-events-auto">
|
||||
<div className="p-6 border-b border-gray-800">
|
||||
<h2 className="text-2xl font-bold text-white">
|
||||
{server ? 'Edit Remote Server' : 'Add Remote Server'}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-6">
|
||||
<form onSubmit={handleSubmit} className="p-6 space-y-6 pointer-events-auto">
|
||||
{error && (
|
||||
<div className="bg-red-900/20 border border-red-500 text-red-400 px-4 py-3 rounded">
|
||||
{error}
|
||||
@@ -199,7 +206,8 @@ export default function RemoteServerForm({ server, onSubmit, onCancel }: Props)
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1172,9 +1172,15 @@ export default function CrowdSecConfig() {
|
||||
|
||||
{/* Ban IP Modal */}
|
||||
{showBanModal && (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div className="absolute inset-0 bg-black/60" onClick={() => setShowBanModal(false)} />
|
||||
<div className="relative bg-dark-card rounded-lg p-6 w-[480px] max-w-full">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/60 z-40" onClick={() => setShowBanModal(false)} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-dark-card rounded-lg p-6 w-[480px] max-w-full pointer-events-auto">
|
||||
<h3 className="text-xl font-semibold text-white mb-4 flex items-center gap-2">
|
||||
<ShieldOff className="h-5 w-5 text-red-400" />
|
||||
{t('crowdsecConfig.banModal.title')}
|
||||
|
||||
@@ -227,8 +227,15 @@ const EditMonitorModal: FC<{ monitor: UptimeMonitor; onClose: () => void; t: (ke
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
||||
<div className="bg-gray-800 rounded-lg border border-gray-700 max-w-md w-full p-6 shadow-xl">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onClose} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-gray-800 rounded-lg border border-gray-700 max-w-md w-full p-6 shadow-xl pointer-events-auto">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-xl font-bold text-white">{t('uptime.configureMonitor')}</h2>
|
||||
<button onClick={onClose} className="text-gray-400 hover:text-white">
|
||||
@@ -236,7 +243,7 @@ const EditMonitorModal: FC<{ monitor: UptimeMonitor; onClose: () => void; t: (ke
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<form onSubmit={handleSubmit} className="space-y-4 pointer-events-auto">
|
||||
<div>
|
||||
<label htmlFor="monitor-name" className="block text-sm font-medium text-gray-300 mb-1">
|
||||
{t('common.name')}
|
||||
@@ -303,8 +310,9 @@ const EditMonitorModal: FC<{ monitor: UptimeMonitor; onClose: () => void; t: (ke
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -336,16 +344,23 @@ const CreateMonitorModal: FC<{ onClose: () => void; t: (key: string) => string }
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
|
||||
<div className="bg-gray-800 rounded-lg border border-gray-700 max-w-md w-full p-6 shadow-xl">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-xl font-bold text-white">{t('uptime.createMonitor')}</h2>
|
||||
<button onClick={onClose} className="text-gray-400 hover:text-white" aria-label={t('common.close')}>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onClose} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center p-4 pointer-events-none z-50">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-gray-800 rounded-lg border border-gray-700 max-w-md w-full p-6 shadow-xl pointer-events-auto">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-xl font-bold text-white">{t('uptime.createMonitor')}</h2>
|
||||
<button onClick={onClose} className="text-gray-400 hover:text-white" aria-label={t('common.close')}>
|
||||
<X size={24} />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit} className="space-y-4">
|
||||
<form onSubmit={handleSubmit} className="space-y-4 pointer-events-auto">
|
||||
<div>
|
||||
<label htmlFor="create-monitor-name" className="block text-sm font-medium text-gray-300 mb-1">
|
||||
{t('common.name')} *
|
||||
@@ -447,8 +462,9 @@ const CreateMonitorModal: FC<{ onClose: () => void; t: (key: string) => string }
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -168,8 +168,15 @@ function InviteModal({ isOpen, onClose, proxyHosts }: InviteModalProps) {
|
||||
if (!isOpen) return null
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" role="dialog" aria-modal="true" aria-labelledby="invite-modal-title">
|
||||
<div className="bg-dark-card border border-gray-800 rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={handleClose} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center pointer-events-none z-50" role="dialog" aria-modal="true" aria-labelledby="invite-modal-title">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-dark-card border border-gray-800 rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto pointer-events-auto">
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-800">
|
||||
<h3 id="invite-modal-title" className="text-lg font-semibold text-white flex items-center gap-2">
|
||||
<UserPlus className="h-5 w-5" />
|
||||
@@ -358,8 +365,9 @@ function InviteModal({ isOpen, onClose, proxyHosts }: InviteModalProps) {
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -431,8 +439,15 @@ function PermissionsModal({ isOpen, onClose, user, proxyHosts }: PermissionsModa
|
||||
if (!isOpen || !user) return null
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" role="dialog" aria-modal="true" aria-labelledby="permissions-modal-title">
|
||||
<div className="bg-dark-card border border-gray-800 rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto">
|
||||
<>
|
||||
{/* Layer 1: Background overlay (z-40) */}
|
||||
<div className="fixed inset-0 bg-black/50 z-40" onClick={onClose} />
|
||||
|
||||
{/* Layer 2: Form container (z-50, pointer-events-none) */}
|
||||
<div className="fixed inset-0 flex items-center justify-center pointer-events-none z-50" role="dialog" aria-modal="true" aria-labelledby="permissions-modal-title">
|
||||
|
||||
{/* Layer 3: Form content (pointer-events-auto) */}
|
||||
<div className="bg-dark-card border border-gray-800 rounded-lg w-full max-w-lg max-h-[90vh] overflow-y-auto pointer-events-auto">
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-800">
|
||||
<h3 id="permissions-modal-title" className="text-lg font-semibold text-white flex items-center gap-2">
|
||||
<Shield className="h-5 w-5" />
|
||||
@@ -509,8 +524,9 @@ function PermissionsModal({ isOpen, onClose, user, proxyHosts }: PermissionsModa
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user