ci: bump docker/setup-buildx-action from 3 to 4#28
Open
dependabot[bot] wants to merge 155 commits intomainfrom
Open
ci: bump docker/setup-buildx-action from 3 to 4#28dependabot[bot] wants to merge 155 commits intomainfrom
dependabot[bot] wants to merge 155 commits intomainfrom
Conversation
Backend (8th module: oe_ai):
- AI Settings model — per-user API keys for Anthropic/OpenAI/Gemini
- AI Estimate Job — tracks requests with status/timing/token usage
- AI Client — async httpx calls to 3 providers (no SDK deps)
- Anthropic Claude (with vision support)
- OpenAI GPT-4 (with vision)
- Google Gemini (with vision)
- Prompt templates — professional estimator prompts for text + photo
- Robust JSON extraction from AI responses
- Quick Estimate: text description → AI → BOQ items
- Photo Estimate: building photo → Claude Vision → BOQ items
- Create BOQ from estimate → saves as real positions
- API key masking in responses (only shows key_set: bool)
Frontend:
- AI Quick Estimate page with description input, location/currency selectors
- Loading animation during AI generation
- Results table with generated BOQ items
- "Save as BOQ" to persist in project
- AI Settings in Settings page — provider selection, API key input
- Sidebar: "AI Estimate" with sparkle icon (top position)
Endpoints: GET/PATCH /ai/settings, POST /ai/quick-estimate,
POST /ai/photo-estimate, POST /ai/estimate/{id}/create-boq,
GET /ai/estimate/{id}
User journey documented in docs/USER-JOURNEY.md
8 modules, 89+ API endpoints, 190+ files, 31,000+ lines
BOQ Templates (backend + frontend):
- 8 building types: Residential (35 pos), Office (17), Warehouse (13),
School (15), Hospital (16), Hotel (11), Retail (11), Infrastructure (14)
- 132 total positions with realistic rates and qty_factors
- GET /boqs/templates — list all templates
- POST /boqs/from-template — create BOQ from template with area input
- Frontend: beautiful gallery with icons, configuration panel, preview
- Quantities calculated: qty_factor × area_m²
Activity Log:
- ActivityLog model (oe_boq_activity_log) — who/when/what/changes
- Event bus subscriber creates log entries on all BOQ mutations
- GET /boqs/{id}/activity — paginated activity feed
- Frontend: collapsible panel in BOQ editor with icons, relative time
- 16 action types with color-coded icons
Print CSS:
- Professional A4 landscape output (Ctrl+P from BOQ editor)
- Hides sidebar, header, buttons; shows clean table
- Section headers with background, repeated table headers per page
- Totals with bold borders, clean typography
- All animations/shadows stripped for clean print
Smart Autocomplete in BOQ Editor:
- Type 2+ chars in description → dropdown with matching cost items
- Shows: description, unit, rate from cost database
- Click suggestion → auto-fills description, unit, unit_rate
- Debounced (300ms), max 8 suggestions
- GET /costs/autocomplete?q=...&limit=8
AI Chat Panel in BOQ Editor:
- Toggle "AI Assistant" panel (right sidebar, 320px)
- Chat with AI: "add MEP for 5-story building"
- AI generates BOQ items as mini-table
- "Add all to BOQ" or select individual items
- POST /boqs/{id}/ai-chat
- Requires AI API key configured
Onboarding Wizard (4 steps):
- Step 1: Welcome screen with animated logo
- Step 2: Region selection (8 cards with flags → auto-set currency/standard)
- Step 3: AI setup (optional — enter API key, test connection)
- Step 4: Create first project from template
- Full-screen, progress dots, smooth transitions
- Shows only on first login (localStorage flag)
Database Import:
- POST /costs/import/file — upload Excel/CSV pricing database
- Flexible column detection (EN/DE aliases)
- European number format support
- Auto-generates codes for missing ones
- Frontend: drag-and-drop page with preview and results
- "Import Database" button added to Cost Database page
Replaced bar chart icon with a modern calculator design: - Calculator body with rounded corners - Screen showing "1.2M" (cost estimate) - 3x3 button grid with subtle styling - Blue "=" button at bottom - Animated button-by-button entrance - Updated favicon to match
Frontend sent 'name' but backend expected 'boq_name' in BOQFromTemplateRequest schema. Fixed the interface and mutation call.
Backend: POST /boqs/{id}/import/smart
- Accepts ANY file: Excel, CSV, PDF, photos (JPG/PNG), scans
- Auto-detects file type and chooses best extraction method:
- Excel/CSV: direct structured parsing (no AI needed)
- PDF: pdfplumber table/text extraction → AI parsing
- Images: base64 → AI Vision (Claude/GPT-4/Gemini)
- AI prompt optimized for construction BOQ extraction:
- Multi-language support (DE/EN/RU/FR/ES)
- Preserves original descriptions
- Auto-numbers ordinals, detects units from context
- Extracts ALL items even without prices
- Returns: {imported, errors, total_items, method (direct/ai)}
Frontend:
- Import button in BOQ Editor toolbar
- Smart Import modal with drag-and-drop
- Accepts .xlsx, .csv, .pdf, .jpg, .jpeg, .png, .tiff
- Shows "AI-powered" badge when AI parsing used
- Preview results before confirming
- Toast notifications on success/error
- Also updated Project Dashboard import dialog
Backend: - cad_import.py: DDC converter integration - find_converter() searches multiple paths for .exe - convert_cad_to_excel() async subprocess with 5min timeout - parse_cad_excel() extracts elements (category, type, volume, area) - summarize_cad_elements() creates text for AI processing - Smart import now accepts .rvt, .ifc, .dwg, .dgn files - 200MB file size limit for CAD (15MB for other types) - CAD_IMPORT_PROMPT: specialized for BIM element → BOQ mapping - If no converter found: returns download link to DDC GitHub releases Frontend: - Import dialogs accept CAD file types - CAD-specific result display (element count, format) - Missing converter → clickable GitHub download link - Toast shows "CAD + AI provider" method info Supported formats: - Revit .rvt (2017-2025) - IFC .ifc (2x3, 4x, 4.3) - AutoCAD .dwg (2007-2024) - MicroStation .dgn
Root cause: Activity log event handler writes to DB concurrently with the main request, causing SQLite "database is locked" errors. Fix: Enable WAL (Write-Ahead Logging) journal mode and set busy_timeout=5000ms via SQLAlchemy engine connect event. This allows concurrent reads during writes, eliminating lock errors in development. Production PostgreSQL is unaffected. Tested: all 12 core endpoints return 200 OK.
Added missing translation keys: - assemblies.title → "Assemblies" - schedule.title → "4D Schedule" - nav.5d_cost_model → "5D Cost Model" - nav.templates → "Templates" Sidebar AI Estimate button: - Purple gradient background (from-violet to-cyan) - "AI" badge with gradient pill - Visually distinct from other nav items
Complete rewrite of AI Estimate page with tabbed interface: Input types (2 rows × 3 cards): Row 1: - Text Description — describe project, AI generates full BOQ - Photo / Scan — upload building photo, AI Vision analyzes - PDF Document — upload BOQ/specs, AI extracts positions Row 2: - Excel / CSV — upload spreadsheet, direct parse or AI - CAD / BIM — upload .rvt/.ifc/.dwg/.dgn, DDC converter + AI - Paste — copy-paste from Excel/Word, AI parses Features: - 2×3 card grid with icons, descriptions, click to select - Selected card: blue border with subtle background - File tabs: drag-and-drop upload area with format hints - Image preview for photos - File info display (name, size, type badge) - Shared results table across all input types - Save as BOQ dialog with project selector - Loading shimmer animation during AI processing - AI-powered / Direct parse badge on results
Replaced pill tab bar with beautiful 2×3 card grid: - Each source type is a large clickable card with: - Colored gradient icon (blue, violet, red, green, amber, slate) - Bold label + description text - Hover lift animation (-translate-y-0.5) - Active state: blue border, subtle background, checkmark badge - Press animation (scale 0.98) - Responsive: 2 columns mobile, 3 columns desktop - Staggered entrance animation per card
Problem: When switching to non-English languages, new keys (assemblies.title, schedule.title, nav.5d_cost_model, etc.) showed as raw key names because backend locale files didn't have them, and the bundled English fallback got overwritten by backend's incomplete English response. Fix: Skip loading English from backend API — always use the bundled English fallback which contains ALL keys. Other languages still load from backend and fall back to English for any missing keys.
Redesigned 2×3 grid from vertical cards to horizontal: - Icon on left (40×40px), text on right - Compact height, professional look - Active: blue icon bg with white icon, blue text - Inactive: subtle bg, gray icon, hover darkens - Less visual noise: single blue accent color - Truncated descriptions for clean layout
Added prominent card on /costs/import page: - "CWICR Cost Database — 55,000+ items" with DDC branding - GitHub download button linking to releases page - Badges: 55,719 items, 9 languages, Excel/CSV - Blue gradient background with database icon - "or upload your own file" divider below - Instruction to download then upload
AI Estimate page (/ai-estimate): - Not configured: prominent setup card with sparkle icon, "Connect your AI to get started" message, Configure button, provider list (Anthropic/OpenAI/Gemini) - Configured: green status bar with pulsing dot, "AI Connected", model name, green indicators for Text/Photo/PDF/CAD - Fixed isConfigured check to use actual API response (anthropic_api_key_set boolean, not status string) Settings page: - Fixed AISettings interface to match backend response (anthropic_api_key_set: boolean instead of anthropic_api_key: string) - Fixed provider key display (shows masked "sk-••••" when set) - Fixed all TypeScript errors from type mismatch
Import page: 3×3 grid of regional databases
Backend: POST /costs/load-cwicr/{db_id} — reads from DDC Toolkit
Priority: Parquet > Excel for reliability
Changes: - Renamed ENG_TORONTO to "English (International)" with UK flag - Added "Popular" badge to English and German databases - Added regions: "DACH", "CIS", "LatAm", "Gulf", "South Asia" - Progress panel during import: - Shimmer progress bar with elapsed time counter - Estimated duration message (1-3 min) - Log output (monospace, color-coded: green=success, red=error) - Result summary after completion: imported/skipped counts, filename - Timer shows seconds elapsed during import
- Cost import page: flagcdn.com PNG flags for all 9 databases - Language switcher: flagcdn.com PNG flags for all 20 languages - Added 'country' code to SUPPORTED_LANGUAGES for flag mapping - Removed emoji flags — consistent real flag images everywhere - Removed "Popular" badge from databases
- English database: US flag, "English (US / UK / Canada)" - All language names in native script: Deutsch, Français, Español, Português, Русский, العربية, 中文, हिन्दी - Reordered: English first, then by popularity
Major rewrite of load-cwicr endpoint: - Deduplicates by rate_code (900K rows → 55K unique items) - Combines rate_original_name + rate_final_name for rich descriptions - Bulk insert with batch commits (500 items per batch) - 13 seconds vs 41 minutes (180x faster) - Returns: imported, skipped, unique_items, duration_seconds New endpoints: - DELETE /costs/clear-database?source=cwicr — delete imported items - GET /costs/export/excel — download entire cost DB as Excel
Fixes:
- Export: use raw SQL query instead of CostSearchQuery (limit 500 cap)
- Delete: moved to /actions/clear-database to avoid /{item_id} conflict
- Export: moved to /actions/export-excel
- Bulk import: pass real dicts {} [] not strings "{}" "[]" for JSON fields
Tested:
- Import 55,719 items: 28.5s ✅
- Search "concrete": 200, 3 results ✅
- Autocomplete "con": 200, 3 results ✅
- Export Excel: 200, 2.3MB file ✅
- Delete cwicr: 200, 55,719 deleted ✅
Onboarding Wizard (4 steps): 1. Welcome — logo, title, get started 2. Cost Database — 9 CWICR databases with flags, one-click load, progress bar with elapsed time, checkmark on completion 3. AI Provider — Anthropic/OpenAI/Gemini selection, API key input, test connection, feature list 4. First Project — name, region/currency/standard (auto-synced) Cost Import Page: - "Loaded Databases" section showing total items + which DBs loaded - Export Excel button (downloads cost_database.xlsx) - Clear Database button with confirmation - localStorage tracking of loaded databases - CWICRDatabaseGrid persists loaded state Costs Page: - Total items count badge in header - Export + Import buttons in header
Step 1 — Validation:
- Professional validation dashboard with score circle, summary,
filterable results, suggestions, tooltips
- Score labels: Excellent/Good/Needs Review/Poor
Step 2 — Tendering (9th module):
- Backend: TenderPackage + TenderBid models, CRUD endpoints,
bid comparison, status workflow (draft→issued→awarded)
- Frontend: package list, bid entry, comparison table
- Manifest: oe_tendering, depends on [oe_projects, oe_boq]
Step 3 — Reports:
- Reports center page with 2×3 card grid
- BOQ Report (PDF/Excel), Cost Report, GAEB XML,
Validation Report, Schedule, 5D (coming soon)
- Download via authenticated fetch + blob URL
- Toast notifications on success/failure
Step 4 — GAEB XML Export:
- GET /boqs/{id}/export/gaeb — valid GAEB DA XML 3.3 (DP 83)
- Maps sections → BoQCtgy, positions → Items
- Unit conversion (pcs→Stk, lsum→psch)
- Returns .X83 filename
Sidebar updated: Reports nav item with FileBarChart icon
9 backend modules, 100+ API endpoints
Tested: Validate 200, PDF 200, Excel 200, CSV 200, GAEB 200
Root causes fixed: 1. Removed cross-module ForeignKey constraints (SQLite incompatible) 2. Changed relationship lazy="selectin" to lazy="raise" to avoid MissingGreenlet errors with SQLite async 3. Added try/catch for bids access in response builder 4. Made boq_id nullable in both model and response schema 5. Disabled wildcard event handler (causes greenlet conflicts) 6. Commented out event publishing in tendering service Tested: POST /tendering/packages/ → 201 Created ✅
PDF Takeoff Viewer (/takeoff):
- Upload PDF construction drawings
- AI analysis to extract elements and quantities
- Results with category summaries (walls, doors, windows)
- Select items → add to BOQ
- Quick measurements manual entry
- Project + BOQ selector
CO2 Sustainability Calculator (/sustainability):
- GET /boqs/{id}/sustainability — calculates CO2 from BOQ materials
- 10 material CO2 factors (concrete 250kg/m3, steel 1800kg/t, etc.)
- SVG donut chart breakdown by material
- Rating system: A (<80), B (80-150), C (150-250), D (>250) kg CO2/m2
- Benchmark per m2
Branding polish:
- App name: "OpenEstimator.io" everywhere (was "OpenEstimate")
- Tagline: "Professional construction cost estimation platform"
- Backend config, i18n (all 20 languages), frontend fallback updated
Sidebar: added PDF Takeoff (FileSearch) + Sustainability (Leaf) nav items
KPI Dashboard: - AnalyticsSection with SVG bar chart (value by project) - StatusDonut SVG chart (BOQ status distribution) - Aggregate stats: total projects, BOQs, value API Audit (27 endpoints tested): - Auth: Me 200 ✅ - Projects: List/Get 200 ✅ - BOQ: List/Get/Structured/Templates/Validate/CSV/Excel/PDF/GAEB/Activity 200 ✅ - BOQ: Sustainability 200 ✅ (12.5t CO2, Rating A) - Costs: Search/Autocomplete 200 ✅ - Assemblies: List 200 ✅ - Schedule: List 200 ✅ - 5D: Dashboard/S-Curve/Budget 200 ✅ - AI: Settings 200 ✅ - Tendering: List 200 ✅ - System: Health/Modules/Rules/Locales 200 ✅ 27/27 PASSED ✅
…lies Backend: - Authorization: ownership checks on all CRUD endpoints (projects, BOQ, schedule, tendering) - CORS tightened: explicit methods/headers instead of wildcard - Admin permission bypass logging - Error response sanitization (no type exposure) - Pagination standardized (max 100 across all modules) - Cost DB import: ProcessPoolExecutor (no GIL blocking), micro-batch SQLite inserts - Cost DB: UNIQUE(code,region) constraint, full components in import - Vector indexing: ProcessPoolExecutor for ONNX embeddings - DELETE cost item: MissingGreenlet fix (save code before expire_all) - Assembly AI generation endpoint (search cost DB by description) - Assembly paginated response with component_count - In-memory cache for region stats/categories (30s TTL) - DB indexes: region, is_active, source, unit, description Frontend: - CostsPage: search debounce 300ms, column sorting, pagination with page numbers, clear filters button, active filter count badge, delete confirmation, Custom badge, component type i18n, empty states for favourites/recent - ImportDatabasePage: sync loaded state with API, i18n for all strings, fire-and-forget vector indexing - AssembliesPage: search debounce, pagination, component count on cards, AI Generate dialog, template library (8 templates), loading spinner, i18n for CreateAssemblyPage - AssemblyEditorPage: delete confirmation, project/BOQ dropdown picker, regional factors UI, total rate label clarification, save BOQ→Assembly - CAD Takeoff: full converter cards with install/uninstall on /cad-takeoff - Header: i18n time ago, notification Escape handler - Accessibility: aria-modal, Escape handlers, aria-labels on search inputs - Mobile: responsive grids, touch targets 44px minimum - Shared types file (models.ts)
Schedule: - Generate from BOQ uses real labor_hours from position resources - Formula: (quantity × labor_hours) / (workers × hours_per_day) - Regional work calendars: DACH 8h Mon-Fri, Gulf 10h Mon-Sat, Nordic 7.5h - Fixed all MissingGreenlet bugs (ORM objects saved as dicts) - Gantt: synchronized scroll, Today marker, SVG arrows fixed - Gantt: progress slider debounce 500ms, theme colors for critical path - Left panel reduced from 420px to 280px - 2 demo BOQs: Residential House + Office Renovation with labor resources Layout: - Global project switcher dropdown in Header (works on all pages) - Content max-width increased 1120px → 1440px - Padding reduced for more working space
… cleanup Schedule: - Fixed MissingGreenlet in CPM calculation (snapshot ORM objects as dicts) - Fixed MissingGreenlet in generate_from_boq (all ORM→dict) - 11 regional work calendars (France 7h, Gulf 10h 6d, Brazil/China/India 6d) - Work calendar badge in UI showing hours/days per region - Overall project progress bar - Activity filter (All/Critical/Delayed/In Progress) - Export schedule as TSV - Reset schedule button for regeneration - CPM: 4 critical activities, 51 days duration - PERT: P50=51d, P80=57d, P95=64d, buffer +6d Layout: - Cleaned 138 duplicate test projects - Removed German-only demo BOQs
…"Точка"→"Этап" Punch List: - Header: single row (title left, project+button right) - Modal: two-column grid, inline priority radio buttons - Kanban: priority stripe on left edge (red/orange/yellow/gray) - Overdue: subtle red tint background Requirements: - Header: single compact row with icon - Toolbar: all buttons in one non-wrapping row, icon-only on mobile - RU: "Точка" → "Этап" for quality gate labels
…ents & AI - Sidebar: two separate nav items with distinct icons (Ruler / FileSearch) - /takeoff?tab=measurements — direct link to measurements view - /takeoff?tab=documents — direct link to documents & AI view - Active state correctly highlights only the matching tab - Translations: nav.measurements + nav.documents_ai on all 21 languages
- 31 markups.* keys (add_markup, types, stamps, delete, export, etc.) - 6 punch.* keys (no_project, no_results, title_required) - 23 requirements.* keys (export, import CSV/JSON, regex hints, preview) - All 21 languages: EN, DE, FR, ES, PT, RU, ZH, AR, HI, TR, IT, NL, PL, CS, JA, KO, SV, NO, DA, FI, BG
… restore proxy to 8000
- Tips & Hints panel only shown on empty BOQ (not when working) - Removed "How it works" hint from work page (unnecessary noise) - Reduced header spacing (mb-6→mb-4, space-y-3→2, text-2xl→xl) - Cleaner workspace for construction professionals
…orce, PDF export Backend (oe_fieldreports): - FieldReport model: weather, workforce, delays, safety, photos, signatures - 10 endpoints: CRUD, submit/approve workflow, calendar view, PDF export - Weather API integration (OpenWeatherMap, graceful fallback) - Status: draft → submitted → approved Frontend: - Calendar view: monthly grid with colored dots by status - List view: filterable table with weather icons - Report form: weather, workforce by trade, work performed, delays - Stats cards: total, by status, workforce hours, delay hours - Route: /field-reports, sidebar: Tools > Field Reports Tests: 472 passed, 0 failed
Backend (extends oe_documents):
- ProjectPhoto model: filename, caption, GPS lat/lon, tags, category, taken_at
- 8 endpoints: upload, list, gallery, timeline, file serve, update, delete
- MIME validation, path traversal protection, 50MB limit
- Storage: ~/.openestimator/photos/{project_id}/
Frontend:
- Gallery grid: responsive 2-4 columns with thumbnails
- Drag-drop upload with EXIF extraction (date, GPS)
- Lightbox: keyboard nav, caption, GPS, edit/delete
- Grid + Timeline view toggle
- Category filter: site/progress/defect/delivery/safety
- Route: /photos, sidebar: Tools > Project Photos
Tests: 472 passed, 0 failed. Build clean.
Punch List (CRITICAL): - PunchItem interface: 6 fields renamed to match backend exactly - assigned_to_id → assigned_to, photos_count → photos.length - location string → location_x/location_y numbers - Removed non-existent fields: assigned_to_name, document_name, created_by_name Field Reports: - Added projectId guards to fetchFieldReportSummary and fetchFieldReportCalendar Photos: - Added projectId guard to uploadPhoto Tests: 472 passed, 0 failed
…endpoints Backend: - TakeoffMeasurement model: type, group, points, value, unit, depth, volume, BOQ link - 9 endpoints: CRUD, bulk create (500 max), export CSV/JSON, summary, link-to-boq - MeasurementRepository with project/document/page/group/type filters - TakeoffService with export and aggregation - Schemas with validation (Pydantic v2) Tests: 472 passed, 0 failed
Polyline measurement: - Multi-segment distance (click N points, double-click to finish) - Cumulative distance label, segment midpoint labels - Full undo support (per-point) Volume measurement: - Polygon + depth input dialog → V = area × depth (m³) - Display: "V = X.XX m³ (A: Y.YY m² × D: Z.ZZ m)" - Scale-aware recalculation Measurement groups/layers: - 8 predefined groups: General, Structural, Electrical, Plumbing, HVAC, Finishing, Excavation, Concrete - Group color coding on canvas - Visibility toggle per group (eye icon) - Collapsible group headers with subtotals - Group selector dropdown in sidebar Excel export: - CSV with Group/Type/Annotation/Value/Unit/Page columns - Group subtotals per measurement type TakeoffViewerModule: 1204 → 1647 lines Tests: 472 passed, 0 failed. Build clean.
8 test sections: - Field Reports: 10/10 (CRUD, submit, approve, calendar, summary, PDF) - Photo Gallery: 8/8 (list, gallery, timeline, filters, category) - Takeoff Measurements: 11/11 (CRUD, bulk, export, summary, link-to-boq) - Requirements: 8/8 (CRUD, gates 1-4, export, import, stats) - Markups: 8/8 (CRUD, stamps, scales, summary, export, link-to-boq) - Punch List: 8/8 (CRUD, full workflow, summary) - Cross-module Integration: 5/5 (measurement→BOQ, markup→BOQ, req→BOQ) - Regression: 15/15 (all 20 modules, auth, security) Fix: global PROJECT_ID declaration in main() for proper test context
…dpoint Classification mapper: - Revit/IFC → DIN 276 (26 categories), NRM (12), MasterFormat (12) - Batch classification: map_elements_to_classification() - Deterministic lookup, no AI needed IFC QTO presets (5 total): - Standard, Detailed, By Storey, By Material, Summary New endpoint: - POST /boqs/classify-elements — classify CAD elements against DIN 276/NRM/MasterFormat - Returns mapped/unmapped counts Tests: 472 passed, 0 failed
… dashboard
Pin-to-plan (Punch List):
- POST /items/{id}/pin-to-sheet — attach punch item to drawing location
- Links document_id, page, location_x/y in one call
Document links (Field Reports):
- POST /reports/{id}/link-documents — link reports to documents
- GET /reports/{id}/documents — get linked document metadata
- document_ids JSON field added to FieldReport model
Project dashboard (ALL modules in one call):
- GET /projects/{id}/dashboard — aggregated cross-module data
- BOQ stats, requirements coverage, punch items by status
- Field reports (total + this week), photos, measurements
- Schedule activities, risks, change orders
Tests: 512 passed, 0 failed
…version control
Sheet model (oe_documents_sheet):
- sheet_number, sheet_title, discipline, revision, scale, is_current
- version chain via previous_version_id
PDF splitting:
- POST /sheets/split-pdf — upload multi-page PDF → auto-split into sheets
- pdfplumber page extraction + thumbnail generation
- Regex-based sheet info detection (number, title, scale, revision)
Discipline auto-detection:
- A=Architectural, S=Structural, M=Mechanical, E=Electrical
- P=Plumbing, C=Civil, L=Landscape
Endpoints:
- GET /sheets (list with filters), GET /sheets/{id}, PATCH /sheets/{id}
- GET /sheets/disciplines, GET /sheets/{id}/versions (full chain)
Tests: 40 new unit tests (discipline detection, regex patterns, schemas)
Total: 512 passed, 0 failed
… pages Buttons: - All icons have shrink-0, buttons whitespace-nowrap - Fixed variant="outline" → "secondary" in Field Reports - Wrapped text in <span> for consistent inline layout API guards: - Added projectId guards to: markups fetchMarkups/fetchSummary, punchlist fetchSummary/fetchTeamMembers, requirements fetchStats Empty states (3 variants per page): - No project: "Select a project..." - No data: "Create your first..." with action button - No results: "No matching items, adjust filters" - Applied to: Requirements, Field Reports, Markups, Photos, Punch List Build: clean (0 errors)
…asurement + markup 5 new annotation tools alongside existing measurements: - Cloud: revision cloud with scalloped arcs (click points, double-click to finish) - Arrow: line with arrowhead (2 clicks) - Text: click to place, inline text input overlay - Rectangle: two-corner rectangle outline - Highlight: semi-transparent filled rectangle Color system: - 6 preset annotation colors (Red, Blue, Green, Orange, Purple, Yellow) - Auto-default per type (cloud=Red, arrow=Blue, text=Black) - Color picker in sidebar when annotation tool active Unified experience: - Measurements AND annotations in one PDF viewer - Both stored in same array, persisted to localStorage - Separate sidebar sections (Measurements by group, Annotations) - Undo/redo works for all operations - Annotations skipped from BOQ export (measurement-only) TakeoffViewerModule: 1647 → 2231 lines (+584) Tests: 512 passed. Build clean.
…ment hint when empty
…ence Column confidence: - Each column shows % of elements with non-null values (e.g. "volume 65%") - Helps users understand data quality before grouping Hierarchical tree view: - Toggle Flat/Tree when group_by has 2+ columns - Parent rows: first group column with aggregate sums - Expand/collapse children with chevron icons - Connector lines for visual hierarchy Element detail panel: - Click any group row → slide-over shows all elements in that group - Full table with ALL columns, numeric totals at bottom - Up to 500 elements per view with truncation warning Backend: POST /cad-group/elements endpoint Tests: 512 passed, 0 failed. Build clean.
Persistent sessions: - CadExtractionSession model in DB (was 5-min in-memory) - 24-hour TTL, dual storage (memory + DB fallback) - Survives server restarts Create BOQ from QTO: - POST /cad-group/create-boq — one-click BOQ creation - Project selector + BOQ name in UI - Auto-navigate to BOQ editor after creation - Graceful session expiry handling Excel export: - GET /cad-group/export — professional Excel with formatting - Header row, data rows, bold grand total - Auto-fitted column widths - Browser download as .xlsx Tests: 512 passed, 0 failed. Build clean.
- useProjectContextStore(s => s.activeProject) → s.activeProjectId (property didn't exist)
- EmptyState icon={ClipboardList} → icon={<ClipboardList size={48} />} (ReactNode, not component ref)
- Removed unused Project interface
This bug made the entire Field Reports page always show empty — projectId was always ''
Bumps [docker/setup-buildx-action](https://github.com/docker/setup-buildx-action) from 3 to 4. - [Release notes](https://github.com/docker/setup-buildx-action/releases) - [Commits](docker/setup-buildx-action@v3...v4) --- updated-dependencies: - dependency-name: docker/setup-buildx-action dependency-version: '4' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com>
Author
LabelsThe following labels could not be found: Please fix the above issues or remove invalid values from |
f72a0c9 to
b290423
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bumps docker/setup-buildx-action from 3 to 4.
Release notes
Sourced from docker/setup-buildx-action's releases.
... (truncated)
Commits
4d04d5dMerge pull request #485 from docker/dependabot/npm_and_yarn/docker/actions-to...cd74e05chore: update generated contenteee38ecbuild(deps): bump@docker/actions-toolkitfrom 0.77.0 to 0.79.07a83f65Merge pull request #484 from docker/dependabot/github_actions/docker/setup-qe...a5aa967Merge pull request #464 from crazy-max/rm-deprecatede73d53fbuild(deps): bump docker/setup-qemu-action from 3 to 428a438eMerge pull request #483 from crazy-max/node24034e9d3chore: update generated contentb4664d8remove deprecated inputs/outputsa8257denode 24 as default runtimeDependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting
@dependabot rebase.Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR:
@dependabot rebasewill rebase this PR@dependabot recreatewill recreate this PR, overwriting any edits that have been made to it@dependabot show <dependency name> ignore conditionswill show all of the ignore conditions of the specified dependency@dependabot ignore this major versionwill close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this minor versionwill close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)@dependabot ignore this dependencywill close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)