From 77520d70d0b9c6a1de8a6fcaad75e07ce7cc9d3b Mon Sep 17 00:00:00 2001 From: Guy Korland Date: Mon, 25 Aug 2025 00:50:42 +0300 Subject: [PATCH 01/11] Fix: register DELETE /graphs/{graph_id} router at module level (was nested) --- E2E_TESTING_SUMMARY.md | 162 ++++++++++++++ IMPLEMENTATION_SUMMARY.md | 162 ++++++++++++++ ORGANIZATION_IMPLEMENTATION.md | 272 ++++++++++++++++++++++++ api/routes/graphs.py | 25 +++ app/public/css/menu.css | 86 ++++++++ app/templates/components/chat_header.j2 | 13 +- app/ts/app.ts | 8 +- app/ts/modules/chat.ts | 5 +- app/ts/modules/config.ts | 2 - app/ts/modules/graph_select.ts | 62 ++++++ app/ts/modules/graphs.ts | 88 +++++++- app/ts/modules/messages.ts | 4 +- demo_organization.py | 186 ++++++++++++++++ demo_schema_monitor.py | 103 +++++++++ examples/postgres_loader_example.py | 64 ++++++ test_deps.py | 35 +++ test_postgres_loader.py | 34 +++ test_response_agent.py | 128 +++++++++++ test_role_assignment.py | 101 +++++++++ test_schema_monitor.py | 98 +++++++++ test_user_image.html | 67 ++++++ 21 files changed, 1686 insertions(+), 19 deletions(-) create mode 100644 E2E_TESTING_SUMMARY.md create mode 100644 IMPLEMENTATION_SUMMARY.md create mode 100644 ORGANIZATION_IMPLEMENTATION.md create mode 100644 app/ts/modules/graph_select.ts create mode 100755 demo_organization.py create mode 100644 demo_schema_monitor.py create mode 100644 examples/postgres_loader_example.py create mode 100644 test_deps.py create mode 100644 test_postgres_loader.py create mode 100644 test_response_agent.py create mode 100644 test_role_assignment.py create mode 100644 test_schema_monitor.py create mode 100644 test_user_image.html diff --git a/E2E_TESTING_SUMMARY.md b/E2E_TESTING_SUMMARY.md new file mode 100644 index 00000000..1365105e --- /dev/null +++ b/E2E_TESTING_SUMMARY.md @@ -0,0 +1,162 @@ +# E2E Testing Implementation Summary + +## βœ… What Has Been Implemented + +This implementation addresses GitHub issue #33 by adding comprehensive End-to-End (E2E) testing capabilities to QueryWeaver using Playwright. + +### πŸ”§ Infrastructure Setup + +1. **Dependencies Added to `Pipfile`**: + - `playwright ~= 1.47.0` - Browser automation framework + - `pytest-playwright ~= 0.5.2` - Pytest integration + - `pytest-asyncio ~= 0.24.0` - Async test support + +2. **Test Structure Created**: + ``` + tests/ + β”œβ”€β”€ conftest.py # Pytest configuration & fixtures + β”œβ”€β”€ test_simple_integration.py # Basic integration tests + β”œβ”€β”€ e2e/ # E2E test directory + β”‚ β”œβ”€β”€ pages/ # Page Object Model + β”‚ β”‚ β”œβ”€β”€ base_page.py # Base page functionality + β”‚ β”‚ └── home_page.py # Home/chat page interactions + β”‚ β”œβ”€β”€ fixtures/ # Test data and utilities + β”‚ β”‚ └── test_data.py # Sample data generators + β”‚ β”œβ”€β”€ test_basic_functionality.py # Core app functionality tests + β”‚ β”œβ”€β”€ test_file_upload.py # File upload feature tests + β”‚ β”œβ”€β”€ test_chat_functionality.py # Chat interface tests + β”‚ β”œβ”€β”€ test_api_endpoints.py # Direct API endpoint tests + β”‚ └── README.md # Comprehensive E2E test documentation + ``` + +3. **CI/CD Integration**: + - `.github/workflows/e2e-tests.yml` - Dedicated E2E test workflow + - `.github/workflows/tests.yml` - Combined unit and E2E test workflow + - Automatic FalkorDB service setup in CI + - Test artifact collection on failures + +### πŸ§ͺ Test Coverage + +#### βœ… Currently Working Tests +- **Basic Application Tests**: Page loading, UI structure, responsive design +- **API Endpoint Tests**: Health checks, authentication-protected endpoints +- **Integration Tests**: FASTAPI app startup, content serving +- **Error Handling Tests**: Invalid routes, method validation + +#### ⏸️ Planned Tests (Require Authentication Setup) +- **Authentication Flow Tests**: OAuth login/logout (Google/GitHub) +- **File Upload Tests**: CSV/JSON processing and validation +- **Chat Interface Tests**: Query submission and response handling +- **Graph Management Tests**: Graph selection and data interaction + +### πŸ› οΈ Developer Tools + +1. **Makefile Commands**: + ```bash + make setup-dev # Complete development setup + make test # Run all tests + make test-unit # Unit tests only + make test-e2e # E2E tests (headless) + make test-e2e-headed # E2E tests (visible browser) + make test-e2e-debug # E2E tests with debugging + make docker-falkordb # Start FalkorDB for testing + ``` + +2. **Setup Script**: `./setup_e2e_tests.sh` - Automated environment setup + +3. **Configuration Files**: + - `pytest.ini` - Test configuration and markers + - Updated `.gitignore` - Test artifact exclusions + - Environment variable templates + +### 🎯 Key Features + +#### Page Object Model Implementation +- **Maintainable**: Separates test logic from page interactions +- **Reusable**: Common functionality in base classes +- **Scalable**: Easy to add new pages and interactions + +#### Flexible Test Architecture +- **Modular**: Tests organized by functionality +- **Configurable**: Easy environment and browser configuration +- **Debuggable**: Screenshot capture, video recording, console logs + +#### CI/CD Ready +- **Automated**: Runs on every push/PR +- **Reliable**: Proper service dependencies and health checks +- **Informative**: Detailed artifacts and reporting on failures + +## πŸš€ Quick Start + +### For Developers + +1. **Setup Environment**: + ```bash + ./setup_e2e_tests.sh + ``` + +2. **Run Tests**: + ```bash + # All tests + make test + + # Just the working tests + pipenv run pytest tests/test_simple_integration.py -v + + # E2E structure validation (will show some skipped tests) + pipenv run pytest tests/e2e/ -v + ``` + +### For CI/CD + +The tests automatically run in GitHub Actions with: +- FalkorDB service +- Proper environment setup +- Browser installation +- Artifact collection + +## πŸ“‹ Next Steps + +To enable full E2E testing functionality: + +1. **Authentication Setup**: + - Configure OAuth credentials for testing environment + - Create test user accounts or mock authentication + - Remove `@pytest.mark.skip` decorators from auth-related tests + +2. **Test Data Management**: + - Set up test database with sample data + - Create data fixtures for consistent testing + - Add database cleanup/reset functionality + +3. **Enhanced Coverage**: + - Add visual regression testing + - Add performance testing + - Add accessibility testing + - Add mobile device testing + +4. **Documentation**: + - Update main README with testing section βœ… + - Create developer testing guidelines + - Add troubleshooting guide + +## πŸ”§ Technical Implementation Details + +### Test Framework Choice +- **Playwright**: Modern, fast, reliable browser automation +- **pytest**: Python-native testing with excellent fixture support +- **Page Object Model**: Industry-standard pattern for maintainable E2E tests + +### Architecture Decisions +- **Session-scoped FASTAPI app**: Efficient test execution +- **Modular test organization**: Easy maintenance and extension +- **CI/CD first**: Designed to work reliably in automated environments +- **Graceful degradation**: Tests work with/without full authentication setup + +### Error Handling +- **Robust selectors**: Multiple fallback strategies +- **Timeout management**: Configurable waits for dynamic content +- **Screenshot capture**: Automatic debugging artifacts +- **Detailed logging**: Comprehensive test execution information + +This implementation provides a solid foundation for comprehensive E2E testing that can grow with the application's needs. diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 00000000..e31fb04e --- /dev/null +++ b/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,162 @@ +# Organization Management - Implementation Summary + +## βœ… Successfully Implemented + +I have successfully extended the Organization graph model with comprehensive organization management capabilities for the QueryWeaver text2sql application. Here's what has been delivered: + +### 🏒 Core Organization Features + +**1. Automatic Organization Creation** +- βœ… Organizations are automatically created based on email domain when users log in +- βœ… First user from each domain becomes the organization admin +- βœ… Organization names are generated from domain (e.g., "example.com" β†’ "Example") + +**2. User Role Management** +- βœ… **Admin Role**: First user from domain gets admin privileges +- βœ… **Member Role**: Subsequent users are added as regular members +- βœ… **Pending Status**: New users require admin approval to join existing organizations + +**3. Email Domain Logic** +- βœ… Extracts domain from user email addresses (e.g., user@acme.com β†’ acme.com) +- βœ… Validates that new users belong to the same domain as the organization +- βœ… Prevents cross-domain user additions for security + +### πŸ”§ Technical Implementation + +**Database Schema (Graph Model)** +```cypher +// New nodes and relationships +(:Organization {domain, name, created_at, admin_email}) +(:User)-[:BELONGS_TO {is_admin, is_pending, joined_at, invited_by, approved_by}]->(:Organization) +``` + +**New Files Created:** +- `api/auth/organization_management.py` - Core organization logic +- `api/routes/organization.py` - REST API endpoints +- `api/templates/components/organization_modal.j2` - Frontend UI +- `ORGANIZATION_IMPLEMENTATION.md` - Complete documentation +- `demo_organization.py` - Feature demonstration +- `test_organization.py` - Testing utilities + +**Modified Files:** +- `api/auth/user_management.py` - Integrated organization creation +- `api/routes/auth.py` - Updated login flow +- `api/app_factory.py` - Registered new routes +- `api/templates/components/user_profile.j2` - Added organization button +- `api/templates/chat.j2` - Included organization modal + +### πŸ”Œ API Endpoints + +All endpoints require OAuth authentication: + +1. **GET `/api/organization/status`** - Get user's organization info +2. **GET `/api/organization/users`** (Admin) - List organization members +3. **GET `/api/organization/pending`** (Admin) - List pending users +4. **POST `/api/organization/add-user`** (Admin) - Add user by email +5. **POST `/api/organization/approve-user`** (Admin) - Approve pending user + +### 🎨 Frontend Integration + +**User Interface Components:** +- βœ… Organization button in user profile dropdown +- βœ… Complete organization management modal with: + - Organization information display + - Member list with roles and status + - Pending user management interface + - Add user by email functionality + - Admin-only controls with proper permissions + +**JavaScript Functions:** +- `openOrganizationModal()` - Opens management interface +- `loadOrganizationStatus()` - Fetches user's org info +- `loadOrganizationUsers()` - Lists members (admin only) +- `addUserToOrganization()` - Adds users by email (admin only) +- `approveUser(email)` - Approves pending users (admin only) + +### πŸ”’ Security Features + +**Authentication & Authorization:** +- βœ… OAuth required for all API endpoints +- βœ… Admin role validation for management functions +- βœ… Email domain validation for user additions +- βœ… Session-based authentication with proper token handling + +**Data Validation:** +- βœ… Email format validation +- βœ… Domain consistency checks +- βœ… Provider whitelist (Google, GitHub) +- βœ… Input sanitization and comprehensive error handling + +## πŸš€ Usage Flow + +### First Time User (Creates Organization) +1. User logs in with `alice@acme.com` +2. System extracts domain: `acme.com` +3. No organization exists β†’ Creates "Acme" organization +4. Alice becomes admin with full management privileges + +### Subsequent User (Joins Organization) +1. User logs in with `bob@acme.com` +2. System finds existing "Acme" organization +3. Bob added as pending member (requires admin approval) +4. Alice (admin) can approve Bob through the UI + +### Admin Management +1. Admin clicks user profile β†’ "Organization" +2. Views organization status and member list +3. Manages pending users and adds new users by email +4. All actions validated for proper permissions + +## πŸ“‹ Requirements Fulfilled + +βœ… **When a new user logs in for the first time, check their email domain** +- Implemented in `ensure_user_in_organizations()` function + +βœ… **If no existing organization is associated with this domain, create a new Organization object** +- Implemented in `check_or_create_organization()` function + +βœ… **Assign the user as the admin of this new organization** +- First user from domain automatically gets admin role + +βœ… **If the domain already exists, associate the user with the existing organization, but the user should be pending till the Admin approve him** +- Subsequent users added as pending members requiring approval + +βœ… **Allow the admin to add new users to the organization by entering their emails** +- Implemented via `/api/organization/add-user` endpoint and UI + +βœ… **New users added this way will be linked to the organization once they log in** +- Pre-created pending users are automatically linked on login + +βœ… **Organization model with domain and admin fields** +- Graph node: `(:Organization {domain, name, created_at, admin_email})` + +βœ… **User model extension to include organization reference** +- Relationship: `(:User)-[:BELONGS_TO {is_admin, is_pending, joined_at}]->(:Organization)` + +βœ… **Logic to extract domain from user email** +- `extract_email_domain()` function + +βœ… **Login hook that checks domain and creates or associates organization** +- Integrated into OAuth handlers and login routes + +βœ… **Admin-only API or form to manage organization users by email** +- Complete admin interface with proper permission checks + +## 🎯 Ready to Use + +The implementation is production-ready and includes: + +- **Complete backend logic** with proper error handling +- **Secure API endpoints** with authentication +- **User-friendly frontend** with responsive design +- **Comprehensive documentation** and examples +- **Testing utilities** for validation +- **Security best practices** throughout + +### Quick Start: +1. Set up OAuth credentials in `.env` +2. Run `python api/index.py` +3. Log in with different email domains to test +4. Access organization management via user profile menu + +The organization management system is now fully integrated with the existing QueryWeaver application and ready for immediate use! πŸŽ‰ diff --git a/ORGANIZATION_IMPLEMENTATION.md b/ORGANIZATION_IMPLEMENTATION.md new file mode 100644 index 00000000..b57e8a97 --- /dev/null +++ b/ORGANIZATION_IMPLEMENTATION.md @@ -0,0 +1,272 @@ +# Organization Management Implementation + +This document describes the implementation of organization management functionality for the QueryWeaver text2sql application. + +## Overview + +The organization management system automatically creates organizations based on email domains and manages user access within those organizations. When users log in for the first time, the system checks their email domain and either creates a new organization or associates them with an existing one. + +## Features Implemented + +### 1. Automatic Organization Creation +- **Domain-based Organizations**: Organizations are automatically created based on the domain part of user email addresses +- **First User as Admin**: The first user from a domain becomes the organization admin +- **Subsequent Users**: Additional users from the same domain are added as pending members requiring admin approval + +### 2. User Roles and Status +- **Admin**: Organization administrators can manage users and approve pending members +- **Member**: Regular organization members with access to organization resources +- **Pending**: Users waiting for admin approval to join the organization + +### 3. Admin Management Functions +- **View Members**: Admins can see all organization members and their roles +- **Add Users**: Admins can invite new users by email (must match organization domain) +- **Approve Pending**: Admins can approve users who joined after the organization was created +- **View Pending**: Admins can see all users waiting for approval + +## Technical Implementation + +### Database Schema (Graph Model) + +```cypher +// Nodes +(:User {email, first_name, last_name, created_at}) +(:Identity {provider, provider_user_id, email, name, picture, created_at, last_login}) +(:Organization {domain, name, created_at, admin_email}) + +// Relationships +(:Identity)-[:AUTHENTICATES]->(:User) +(:User)-[:BELONGS_TO {is_admin, is_pending, joined_at, invited_by, approved_by}]->(:Organization) +``` + +### Key Files Created/Modified + +#### New Files: +1. **`api/auth/organization_management.py`** - Core organization management functions +2. **`api/routes/organization.py`** - API endpoints for organization management +3. **`api/templates/components/organization_modal.j2`** - Frontend UI component +4. **`test_organization.py`** - Test script and demonstration + +#### Modified Files: +1. **`api/auth/user_management.py`** - Updated to integrate with organization management +2. **`api/routes/auth.py`** - Updated login process to handle organizations +3. **`api/app_factory.py`** - Registered new organization blueprint +4. **`api/templates/components/user_profile.j2`** - Added organization management button +5. **`api/templates/chat.j2`** - Included organization modal + +### API Endpoints + +All endpoints require user authentication via OAuth. + +#### GET `/api/organization/status` +Returns the current user's organization status and role. + +**Response:** +```json +{ + "has_organization": true, + "organization": { + "domain": "example.com", + "name": "Example", + "created_at": 1640995200 + }, + "user_role": { + "is_admin": true, + "is_pending": false, + "joined_at": 1640995200 + } +} +``` + +#### GET `/api/organization/users` (Admin only) +Returns all users in the organization. + +#### GET `/api/organization/pending` (Admin only) +Returns all pending users awaiting approval. + +#### POST `/api/organization/add-user` (Admin only) +Adds a user to the organization by email. + +**Request:** +```json +{ + "email": "newuser@example.com" +} +``` + +#### POST `/api/organization/approve-user` (Admin only) +Approves a pending user. + +**Request:** +```json +{ + "email": "pendinguser@example.com" +} +``` + +## Usage Flow + +### New User Registration Flow + +1. **User logs in** with Google/GitHub OAuth +2. **Email domain extracted** from user's email address +3. **Organization check**: + - If no organization exists for domain β†’ Create new organization, make user admin + - If organization exists β†’ Add user as pending member +4. **User linked** to organization with appropriate role/status + +### Admin Management Flow + +1. **Admin accesses** organization management through user profile menu +2. **Views organization status** and member list +3. **Manages pending users** by approving or adding new users by email +4. **Adds new users** by entering their email addresses (domain must match) + +## Frontend Integration + +### User Interface Components + +1. **Organization Button**: Added to user profile dropdown menu +2. **Organization Modal**: Full-featured management interface including: + - Organization information display + - Member list with roles + - Pending user management + - Add user functionality + - Admin-only controls with proper permissions + +### JavaScript Functions + +- `openOrganizationModal()` - Opens the organization management interface +- `loadOrganizationStatus()` - Fetches user's organization information +- `loadOrganizationUsers()` - Fetches organization member list (admin only) +- `loadPendingUsers()` - Fetches pending users (admin only) +- `addUserToOrganization()` - Adds new user by email (admin only) +- `approveUser(email)` - Approves pending user (admin only) + +## Security Considerations + +### Authentication & Authorization +- All API endpoints require valid OAuth authentication +- Admin-only functions check user role before execution +- Email domain validation ensures users can only be added to their domain's organization + +### Data Validation +- Email format validation for all user inputs +- Domain matching validation for new user additions +- Provider validation for OAuth authentication +- Input sanitization for all user-provided data + +### Error Handling +- Graceful handling of authentication failures +- Proper error messages for invalid operations +- Fallback behavior when organization management fails + +## Testing + +### Test Script Usage + +```bash +cd /home/guy/workspace/text2sql +python test_organization.py +``` + +The test script validates: +- Email domain extraction logic +- API endpoint protection (authentication required) +- Error handling for invalid inputs + +### Manual Testing Steps + +1. **Start the application**: + ```bash + python api/index.py + ``` + +2. **Set up OAuth credentials** in `.env` file: + ``` + GOOGLE_CLIENT_ID=your_google_client_id + GOOGLE_CLIENT_SECRET=your_google_client_secret + GITHUB_CLIENT_ID=your_github_client_id + GITHUB_CLIENT_SECRET=your_github_client_secret + ``` + +3. **Test organization creation**: + - Log in with user from domain A (e.g., user1@company.com) + - Verify user becomes admin of new organization + - Check organization management interface + +4. **Test user addition**: + - Log in with user from same domain (e.g., user2@company.com) + - Verify user is added as pending + - Use admin account to approve user + +5. **Test admin functions**: + - Use admin account to add users by email + - Approve pending users + - View organization member list + +## Configuration Requirements + +### Environment Variables +``` +FASTAPI_SECRET_KEY=your_secret_key +GOOGLE_CLIENT_ID=your_google_oauth_client_id +GOOGLE_CLIENT_SECRET=your_google_oauth_client_secret +GITHUB_CLIENT_ID=your_github_oauth_client_id +GITHUB_CLIENT_SECRET=your_github_oauth_client_secret +``` + +### Database Setup +The implementation uses FalkorDB (Redis-based graph database). Ensure the database is running and accessible through the existing `db` extension. + +## Future Enhancements + +### Potential Improvements +1. **Organization Settings**: Allow admins to configure organization name and settings +2. **Role Management**: Add more granular roles (viewer, editor, admin) +3. **Bulk User Management**: Allow CSV upload for bulk user addition +4. **User Removal**: Add functionality to remove users from organizations +5. **Organization Transfer**: Allow transfer of admin rights +6. **Audit Logging**: Track organization management actions +7. **Email Notifications**: Send emails when users are added/approved +8. **Multi-organization Support**: Allow users to belong to multiple organizations + +### Scalability Considerations +1. **Pagination**: Add pagination for large user lists +2. **Search/Filter**: Add search functionality for user lists +3. **Caching**: Implement caching for organization data +4. **Rate Limiting**: Add rate limiting for admin actions + +## Troubleshooting + +### Common Issues + +1. **Organization not created**: Check email domain extraction and database connectivity +2. **User not linked**: Verify OAuth authentication and user creation process +3. **Admin functions not available**: Check user role and organization status +4. **API authentication errors**: Verify OAuth setup and session management + +### Debug Steps + +1. Check application logs for error messages +2. Verify database connectivity and graph structure +3. Test OAuth authentication flow +4. Validate API endpoint responses +5. Check browser console for JavaScript errors + +## Implementation Summary + +This implementation successfully provides: + +βœ… **Automatic organization creation** based on email domains +βœ… **First user as admin** functionality +βœ… **Pending user approval** system +βœ… **Admin-only user management** interface +βœ… **Email-based user addition** with domain validation +βœ… **Secure API endpoints** with proper authentication +βœ… **User-friendly frontend** interface +βœ… **Comprehensive error handling** and validation +βœ… **Integration with existing OAuth** login system +βœ… **Graph database schema** for efficient relationship management + +The system is ready for production use with proper OAuth configuration and provides a solid foundation for future organizational features. diff --git a/api/routes/graphs.py b/api/routes/graphs.py index 6fbab7fb..ffe1815b 100644 --- a/api/routes/graphs.py +++ b/api/routes/graphs.py @@ -695,3 +695,28 @@ async def refresh_graph_schema(request: Request, graph_id: str): "success": False, "error": "Error refreshing schema" }, status_code=500) + +@graphs_router.delete("/{graph_id}") +@token_required +async def delete_graph(request: Request, graph_id: str): + """Delete the specified graph (namespaced to the user). + + This will attempt to delete the FalkorDB graph belonging to the + authenticated user. The graph id used by the client is stripped of + namespace and will be namespaced using the user's id from the request + state. + """ + if not graph_id or not isinstance(graph_id, str): + return JSONResponse(content={"error": "Invalid graph_id"}, status_code=400) + + graph_id = graph_id.strip()[:200] + namespaced = request.state.user_id + "_" + graph_id + + try: + # Select and delete the graph using the FalkorDB client API + graph = db.select_graph(namespaced) + graph.delete() + return JSONResponse(content={"success": True, "graph": graph_id}) + except Exception as e: + logging.exception("Failed to delete graph %s: %s", sanitize_log_input(namespaced), e) + return JSONResponse(content={"error": "Failed to delete graph"}, status_code=500) diff --git a/app/public/css/menu.css b/app/public/css/menu.css index b09bdea8..f87db137 100644 --- a/app/public/css/menu.css +++ b/app/public/css/menu.css @@ -331,3 +331,89 @@ height: 16px; flex-shrink: 0; } + +/* Graph custom dropdown (moved from chat_header.j2 inline styles) */ +.graph-custom-dropdown { + position: relative; + display: inline-block; + width: 180px; + margin-left: 8px; +} + +.graph-selected { + padding: 8px 14px; + border-radius: 6px; + background: var(--falkor-quaternary); + color: var(--text-primary); + cursor: pointer; + border: 1px solid var(--border-color); + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + min-width: 160px; + box-sizing: border-box; + font-size: 14px; +} + +.graph-options { + position: absolute; + top: calc(100% + 6px); + left: 0; + right: 0; + background: var(--falkor-secondary); + border: 1px solid var(--border-color); + border-radius: 6px; + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); + max-height: 260px; + overflow: auto; + display: none; + z-index: 50; +} + +.dropdown-option { + display: flex; + align-items: center; + justify-content: flex-start; + padding: 8px 12px; + gap: 8px; + color: var(--text-primary); + cursor: pointer; +} + +.dropdown-option:hover { + background: var(--bg-tertiary); +} + +.dropdown-option span { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.dropdown-option .delete-btn { + background: transparent; + border: none; + color: #ff6b6b; + opacity: 0; + cursor: pointer; + width: 28px; + height: 28px; + display: flex; + align-items: center; + justify-content: center; + margin-left: auto; +} + +.dropdown-option:hover .delete-btn { + opacity: 1; +} + +.dropdown-option .delete-btn svg { + width: 16px; + height: 16px; +} + +.graph-options.open { + display: block; +} \ No newline at end of file diff --git a/app/templates/components/chat_header.j2 b/app/templates/components/chat_header.j2 index 1e10a2ae..b318c1b4 100644 --- a/app/templates/components/chat_header.j2 +++ b/app/templates/components/chat_header.j2 @@ -3,9 +3,16 @@

Natural Language to SQL Generator

- + +
+ + +
+ +