fix: refine validation UI with updated colors and spacing in upload component, and other fixes

This commit is contained in:
vee1e 2025-07-29 01:07:47 +05:30
parent 6841e1e3a4
commit 30167af8d4
11 changed files with 56 additions and 37 deletions

1
.gitignore vendored
View file

@ -22,3 +22,4 @@ dist/
tests/
project-plans/
.DS_Store
.cursorrules

View file

@ -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.

View file

@ -26,4 +26,4 @@ async def connect_to_mongo():
async def close_mongo_connection():
"""Close MongoDB connection"""
async_client.close()
async_client.close()

View file

@ -1,3 +1,3 @@
"""
Models package for form-related data structures
"""
"""

View file

@ -59,4 +59,4 @@ class ParsedForm(BaseModel):
version: str
groups: List[FormGroup]
settings: Optional[Dict[str, Any]] = None
metadata: Optional[Dict[str, Any]] = None
metadata: Optional[Dict[str, Any]] = None

View file

@ -1,3 +1,3 @@
"""
Services package for business logic implementations
"""
"""

View file

@ -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
return False

View file

@ -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 {

View file

@ -177,7 +177,7 @@ import { MatIconModule } from '@angular/material/icon';
export class SearchComponent implements OnInit, OnDestroy {
@Output() search = new EventEmitter<string>();
@ViewChild('searchInput') searchInput!: ElementRef<HTMLInputElement>;
searchQuery = '';
ngOnInit() {

View file

@ -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'],

3
run.sh
View file

@ -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"