From 30167af8d401bf026b9f7b2959395a8fbfec6d1f Mon Sep 17 00:00:00 2001 From: vee1e Date: Tue, 29 Jul 2025 01:07:47 +0530 Subject: [PATCH] fix: refine validation UI with updated colors and spacing in upload component, and other fixes --- .gitignore | 1 + README.md | 17 +++--- backend/database.py | 2 +- backend/models/__init__.py | 2 +- backend/models/form.py | 2 +- backend/services/__init__.py | 2 +- backend/services/database_service.py | 4 +- .../app/components/navbar/navbar.component.ts | 6 +-- .../app/components/search/search.component.ts | 2 +- .../app/components/upload/upload.component.ts | 52 +++++++++++++------ run.sh | 3 +- 11 files changed, 56 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index d439664..c3c2407 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ dist/ tests/ project-plans/ .DS_Store +.cursorrules diff --git a/README.md b/README.md index 1a75dac..c3d6899 100644 --- a/README.md +++ b/README.md @@ -163,18 +163,19 @@ mongosh --eval "db.runCommand('ping')" Below is a real example of metrics collected for uploading 10 forms (each with ~400 questions and 3-10 options per question) based on the latest performance data: -| Description | Time | -| ------------------------------------------------ | ----------------------- | -| Time to validate each form file | 45.80-123.20ms (59.98ms) | -| Time to process and save one form | 0.49-288.43ms (126.84ms) | -| Time to process and save all questions in a form | 59.64-82.80ms (64.59ms) | -| Average time to process one question | 0.15-0.20ms (0.16ms) | -| Average time to process one option | 0.15-0.17ms (0.16ms) | +| Description | Time | +| ------------------------------------------------ | -------------------------- | +| Time to validate each form file | 45.80-123.20ms (59.98ms) | +| Time to process and save one form | 0.49-288.43ms (126.84ms) | +| Time to process and save all questions in a form | 59.64-82.80ms (64.59ms) | +| Average time to process one question | 0.15-0.20ms (0.16ms) | +| Average time to process one option | 0.15-0.17ms (0.16ms) | | Time to process all forms in the batch | 228.62-288.43ms (253.00ms) | -| Number of forms processed in the batch | 10 | +| Number of forms processed in the batch | 10 | | Average time to process one form in the batch | 228.62-288.43ms (253.00ms) | **Notes:** + - Metrics collected from backend/metrics.txt on 2025-07-28 - All times are in ms unless specified otherwise - Hardware used is an M3 Pro Macbook Pro, with 18GB unified memory and 512GB of storage. diff --git a/backend/database.py b/backend/database.py index f5d585f..4363fbf 100644 --- a/backend/database.py +++ b/backend/database.py @@ -26,4 +26,4 @@ async def connect_to_mongo(): async def close_mongo_connection(): """Close MongoDB connection""" - async_client.close() \ No newline at end of file + async_client.close() diff --git a/backend/models/__init__.py b/backend/models/__init__.py index b7f4d43..b53ec90 100644 --- a/backend/models/__init__.py +++ b/backend/models/__init__.py @@ -1,3 +1,3 @@ """ Models package for form-related data structures -""" \ No newline at end of file +""" diff --git a/backend/models/form.py b/backend/models/form.py index c649c71..597a753 100644 --- a/backend/models/form.py +++ b/backend/models/form.py @@ -59,4 +59,4 @@ class ParsedForm(BaseModel): version: str groups: List[FormGroup] settings: Optional[Dict[str, Any]] = None - metadata: Optional[Dict[str, Any]] = None \ No newline at end of file + metadata: Optional[Dict[str, Any]] = None diff --git a/backend/services/__init__.py b/backend/services/__init__.py index d107c98..891f32c 100644 --- a/backend/services/__init__.py +++ b/backend/services/__init__.py @@ -1,3 +1,3 @@ """ Services package for business logic implementations -""" \ No newline at end of file +""" diff --git a/backend/services/database_service.py b/backend/services/database_service.py index b489a79..83e1a86 100644 --- a/backend/services/database_service.py +++ b/backend/services/database_service.py @@ -129,7 +129,7 @@ class DatabaseService: return True except Exception as e: logger.error(f"Error deleting all forms: {e}") - return False + return False async def update_form(self, form_id: str, form_data: Dict[str, Any], questions: List[Dict[str, Any]], options: List[Dict[str, Any]]) -> bool: """Update form metadata, questions, and options by form_id""" @@ -159,4 +159,4 @@ class DatabaseService: return True except Exception as e: logger.error(f"Error updating form: {e}") - return False \ No newline at end of file + return False diff --git a/frontend/src/app/components/navbar/navbar.component.ts b/frontend/src/app/components/navbar/navbar.component.ts index 1c6f873..1c0f008 100644 --- a/frontend/src/app/components/navbar/navbar.component.ts +++ b/frontend/src/app/components/navbar/navbar.component.ts @@ -273,9 +273,9 @@ import { Subscription } from 'rxjs'; border-left: 3px solid #ffffff; border: 1px solid rgba(255, 255, 255, 0.1); - &.current-question { - border: 2px solid #ffffff; - background: rgba(255, 255, 255, 0.1); + &.current-question { + border: 2px solid #ffffff; + background: rgba(255, 255, 255, 0.1); } .question-header { diff --git a/frontend/src/app/components/search/search.component.ts b/frontend/src/app/components/search/search.component.ts index 611b563..b0a2b2f 100644 --- a/frontend/src/app/components/search/search.component.ts +++ b/frontend/src/app/components/search/search.component.ts @@ -177,7 +177,7 @@ import { MatIconModule } from '@angular/material/icon'; export class SearchComponent implements OnInit, OnDestroy { @Output() search = new EventEmitter(); @ViewChild('searchInput') searchInput!: ElementRef; - + searchQuery = ''; ngOnInit() { diff --git a/frontend/src/app/components/upload/upload.component.ts b/frontend/src/app/components/upload/upload.component.ts index 765b859..ae5b251 100644 --- a/frontend/src/app/components/upload/upload.component.ts +++ b/frontend/src/app/components/upload/upload.component.ts @@ -309,15 +309,15 @@ import { FormPreviewService } from '../../services/form-preview.service'; } .invalid { - color: white; - background: #F44336; - border: 1px solid #F44336; + color: #ff0000; + background: #1c0000; + border: 1px solid #660000; } } .validation-details { - margin-top: 0.75rem; - padding-top: 0.75rem; + margin-top: 0.00rem; + padding-top: 0.30rem; border-top: 1px solid rgba(255, 255, 255, 0.2); min-height: 0; transition: all 0.3s ease; @@ -352,9 +352,9 @@ import { FormPreviewService } from '../../services/form-preview.service'; } &.warning { - background: rgba(255, 255, 255, 0.1); - border-left: 3px solid #ffffff; - border: 1px solid rgba(255, 255, 255, 0.2); + background: rgba(255, 193, 7, 0.12); + border-left: 3px solid #FFC107; + border: 1px solid rgba(255, 193, 7, 0.25); } .validation-header { @@ -365,8 +365,8 @@ import { FormPreviewService } from '../../services/form-preview.service'; .validation-type { background: rgba(255, 255, 255, 0.1); - padding: 0.125rem 0.375rem; - border-radius: 12px; + padding: 0.0 0.375rem; + border-radius: 6px; font-size: 0.7rem; font-weight: 600; text-transform: uppercase; @@ -513,6 +513,24 @@ import { FormPreviewService } from '../../services/form-preview.service'; display: flex; align-items: center; gap: 0.5rem; + + ::ng-deep .mat-mdc-icon-button { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + + .mat-icon { + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + width: 20px; + height: 20px; + margin: 0; + } + } } ::ng-deep { @@ -521,12 +539,12 @@ import { FormPreviewService } from '../../services/form-preview.service'; background-color: #ffffff !important; color: #000000 !important; } - + .mdc-snackbar__label { color: #000000 !important; font-weight: 500 !important; } - + .mdc-snackbar__actions .mdc-button { color: #000000 !important; font-weight: 600 !important; @@ -538,12 +556,12 @@ import { FormPreviewService } from '../../services/form-preview.service'; background-color: #F44336 !important; color: white !important; } - + .mdc-snackbar__label { color: white !important; font-weight: 500 !important; } - + .mdc-snackbar__actions .mdc-button { color: white !important; font-weight: 600 !important; @@ -889,7 +907,7 @@ export class UploadComponent implements OnInit, OnChanges { if (validationResult.valid) { // Store old form details for comparison const oldFormTitle = this.updateTargetForm!.title; - + // File is valid, proceed with update this.formService.updateForm(this.updateTargetForm!.id, file).subscribe({ next: (updatedFormDetails) => { @@ -897,10 +915,10 @@ export class UploadComponent implements OnInit, OnChanges { this.showFormDetails(updatedFormDetails.form); // Show updated details this.loadingFormId = null; this.updateTargetForm = null; - + // Show success toast with details const toastMessage = `Successfully updated "${oldFormTitle}" to "${updatedFormDetails.form.title}".`; - + this.snackBar.open(toastMessage, 'Close', { duration: 5000, panelClass: ['custom-snackbar'], diff --git a/run.sh b/run.sh index d87b6e5..f21ef4f 100755 --- a/run.sh +++ b/run.sh @@ -3,7 +3,7 @@ PROJECT_ROOT="/Users/verma/Projects/bulk-questionnaire-upload" FRONTEND_PATH="$PROJECT_ROOT/frontend" BACKEND_PATH="$PROJECT_ROOT/backend" -SESSION_NAME="dev-project" +SESSION_NAME="bulk-questionnaire-upload" if ! tmux has-session -t "$SESSION_NAME"; then tmux new-session -s "$SESSION_NAME" -d @@ -20,7 +20,6 @@ if ! tmux has-session -t "$SESSION_NAME"; then tmux send-keys -t "$SESSION_NAME:0.1" "uvicorn main:app --reload" C-m tmux attach-session -t "$SESSION_NAME" - open "http://localhost:4200" else echo "Tmux session '$SESSION_NAME' already exists. Attaching..." tmux attach-session -t "$SESSION_NAME"