Commit Graph

53 Commits

Author SHA1 Message Date
Dries Peeters 8afeedeb79 feat: mobile shell, own-entry timer edits, invoice/quote form borders
- Allow schedule edits (project, task, start/end, break) for users with
  edit_own_time_entries on their own entries in API update_entry and
  timer edit; scope project lists for subcontractors; admin-only source
  dropdown on edit timer form.
- App shell: min-width/overflow fixes, header layout, compact bottom nav
  on very narrow viewports (#573), dashboard timer block responsive layout.
- Invoice and quote edit: min-w-0 on grids/cells; scoped stronger neutral
  borders for .form-input on #editInvoiceForm and #quote-form (#574).
2026-03-27 06:40:17 +01:00
Dries Peeters 8bb42ddd02 feat(app): recurring invoices, gantt/reporting services, license UI
- Add RecurringInvoiceRepository and RecurringInvoiceService; refactor recurring_invoice model
- Add GanttService and move gantt logic from route to service
- Expand ReportingService and simplify reports route
- Add license_utils and user license template/settings
- Refactor routes to use scope_filter, api_responses, and services (API v1, timer, admin, invoices, etc.)
- Extend invoice_service for recurring; cache and scope_filter utils; base/template updates
2026-03-15 09:37:00 +01:00
Dries Peeters 3b020e6c05 fix(timer): recalculate worked time after date/time commit (fixes #559)
Defer manual entry worked-time recalculation to the next microtask so
the DOM has the latest start/end date and time before reading. Add
input listeners so recalculation runs on every date/time change.

Fixes incorrect duration when end date is in the past (e.g. yesterday)
until the user reselected the end date.
2026-03-12 21:38:21 +01:00
Dries Peeters 1ad899834b fix(time-entries): apply date filter and export by current filters (Issue #555)
- Add visible Apply filters button in filter header so users can apply
  Start/End date and other filters without scrolling; expand panel if collapsed
- Keep CSV/PDF export links in sync with current filters: set href from URL
  on load and update on form change so export (including right-click Open in
  new tab / Save link as) always uses the filtered date range
- Document fix in CHANGELOG under [Unreleased]
2026-03-11 18:48:29 +01:00
Dries Peeters c36736d063 feat(break-time): add Pause/Resume and break UI (Issue #561)
- Dashboard: Pause/Resume buttons, break and Paused badge, elapsed uses break-adjusted duration
- Timer page: Pause/Resume/Stop, break display
- Floating bar: paused state, Resume on click when paused; use server current_duration when paused
- Manual entry: Break field (HH:MM), Suggest button using default break rules
- Edit time entry: Break field (HH:MM) for admins
2026-03-11 17:59:03 +01:00
Dries Peeters 147da2949f Fix(web): prevent mobile browser freeze on Log Time page (Issue #557)
On viewports <=767px, skip loading Toast UI Editor for the notes field on manual entry and edit timer pages; use a plain textarea instead. Toast UI is heavy and was freezing/crashing mobile Safari and Chrome. Desktop behavior unchanged. Document in CHANGELOG and MOBILE_IMPROVEMENTS.md.
2026-03-11 16:37:31 +01:00
Dries Peeters f93103c578 fix(time-entries): add Apply filters button and make export use current filters
Issue #555: Users could set start/end date but had no visible way to apply filters, and CSV/PDF export could ignore the date range if applied before the AJAX filter ran.

- Add explicit 'Apply filters' submit button so date and other filters are applied on click (and on Enter).

- Export CSV/PDF: on click, build URL from current form params so export always reflects the selected date range and filters.

- Initialize export links from form state on load so they match visible filters.

Fixes #555
2026-03-11 12:48:21 +01:00
Dries Peeters 463704f054 feat(ui): refresh shared layout patterns and responsive screens
Unify buttons, cards, headers, toasts, and form treatments across the app so screens feel consistent and are easier to scan on desktop and mobile. Update the broader template set to use the shared UI primitives and responsive spacing patterns introduced in this refresh.
2026-03-06 22:15:06 +01:00
Dries Peeters 07186d7b6b feat(web): base-init, PWA, keyboard shortcuts, onboarding, and template updates
- Add base-init.js for shared keyboard/sidebar init; single PWA registration in pwa-enhancements
- Update keyboard-shortcuts, onboarding, enhanced-search, service-worker
- Template updates: base, list pages, dashboard, mileage/gps, timer; fix duplicate IDs and a11y
2026-03-06 15:45:50 +01:00
Dries Peeters 5593c9742f Redesign Log Time Manually page for clearer, more professional UI
- Group form into sections: Project & task, Date & time, Details (with headings and icons)
- Upgrade main card to rounded-xl and shadow-lg; add section borders and spacing
- Unify form labels and helper text to app design tokens
- Style primary Log Time and secondary Clear buttons to match dashboard
- Apply rounded-xl to duplicate-entry info banner
- Document change in CHANGELOG under [Unreleased]
2026-02-17 20:23:31 +01:00
Dries Peeters 4f05c3d540 feat(header): group Chat, Timer, Help as aligned round buttons
- Group Chat, Timer, and Help in header as round icon buttons
- Vertically aligned, evenly spaced (gap-2), consistent w-10 h-10
- Header timer: one-click start/stop from any page via floating-timer-bar.js
- Fix timer manual entry URL (use /timer/manual, not /timer/manual_entry)
- Add Help button linking to help page
- Update FEATURES_COMPLETE (Header Quick Access, One-Click Timers)
- Update help page Time Tracking section with header timer tip
- Update CHANGELOG
2026-02-16 09:31:07 +01:00
Dries Peeters e68f231b91 feat: API v1 CRM/approvals, api_responses, templates, version & RBAC docs
- REST API v1: add deals, leads, contacts, time-entry-approvals (CRUD + approve/reject/cancel/bulk-approve). New scopes and /info entries.
- Standardize API errors: use error_response, forbidden_response, not_found_response in api_v1 (projects + new CRM/approval routes).
- Consolidate templates: move root templates/ into app/templates/, remove ChoiceLoader and legacy root files.
- Version: README/FEATURES_COMPLETE/CHANGELOG/mobile docs reference setup.py as single source (4.19.0); add [4.19.0] changelog entry.
- Docs: SERVICE_LAYER_AND_BASE_CRUD.md, RBAC_PERMISSION_MODEL.md; base_crud_service docstring points to service-layer doc.
- Mark projects_refactored_example, timer_refactored, invoices_refactored as REFERENCE ONLY in docstrings.
2026-02-13 21:43:09 +01:00
Dries Peeters 115db52b2b feat(time-approvals): complete time entry approval workflow and fix bugs
- Fix approve crash: make _mark_entry_approved a no-op (approval state from
  TimeEntryApproval only; TimeEntry has no metadata column).
- Fix PostgreSQL enum: use values_callable on ApprovalStatus so DB receives
  'pending' not 'PENDING' (matches approvalstatus enum).
- Fix approval templates: use requester/approver, request_comment,
  time_entry.notes; reject form field name 'reason'; add can_approve to
  view and pass from route.
- Filter get_pending_approvals by current approver (policy/project fallback).
- Add Time Approvals nav link under Work in base.html (module-enabled).
- Add Request approval in time entries list (icon) and view_timer (sidebar);
  redirect to list_approvals after request.
- Fix empty_state calls in approvals/list.html (use icon_class positional
  args to match components/ui.html macro).
2026-02-13 21:06:18 +01:00
Dries Peeters ab14e4352a feat: time entry requirements in API and timer; import skips requirements
- API: include time_entry_requirements in GET /users/me (require_task, require_description, min length)
- Timer: validate task/description requirements when starting timer; pass time_approvals_enabled and can_request_approval to view_timer; pass entry_ids_with_pending_approval to time_entries_overview
- Import: pass skip_entry_requirements=True when creating entries from CSV import
2026-02-13 20:57:54 +01:00
Dries Peeters 2c2833eccf feat: date/week preferences, time entry notes fix, PDF export wrapping (#497)
- Respect user date format and week start: Flatpickr on user-date-input
  fields, get_resolved_week_start_day for calendar/pickers, Week Starts On
  from My Settings. Update CALENDAR_FEATURES_README.
- Fix time entry notes not saving on edit: sync Toast UI editor to hidden
  textarea on all forms so the submitted form gets the current note (edit_timer).
- Time entries PDF export: wrap Task, Client, and Project columns like Notes
  so long text breaks across lines (Issue #489).

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-08 21:01:53 +01:00
Dries Peeters bd00e01876 Add configurable date/time format and misc fixes
- Settings: add date_format and time_format (model, migration 119, admin UI)

- Use user date/time prefs in templates, calendar, and PDF export

- Expense: eager-load client instead of category in repo, service, and API

- Mobile: clarify server URL and certificate docs, bump to 4.18.0, improve connection diagnostics

- Ignore mobile/android/.gradle/

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 08:22:34 +01:00
Dries Peeters 8b6e61873b Use system date/time format by default with optional user override
Display formats for dates and times now follow the system settings (Admin
settings) by default. Users can override in their profile (User settings) or
choose "Use system default" so their view matches the rest of the system.

Backend:
- User.date_format and User.time_format are nullable; null means use system.
- Migration 120 makes these columns nullable (existing rows unchanged).
- get_resolved_date_format_key() and get_resolved_time_format_key() in
  timezone utils return the effective key (user or system) for templates and API.
- Context processor injects resolved_date_format_key and resolved_time_format_key
  so base.html and JS (window.userPrefs) always see the resolved format.
- User settings form: "Use system default" option and save logic for null.
- User.to_dict() includes resolved date_format, time_format, and timezone for
  API clients (e.g. mobile).

Web:
- base.html uses resolved keys for window.userPrefs (no hardcoded fallback).
- Replaced display-only strftime() in templates with |user_date, |user_datetime,
  |user_time, and |format_date so all visible dates/times respect settings.
  Left <input type="date"> values and URL/API params as YYYY-MM-DD where required.

Mobile:
- ApiClient.getCurrentUser() and user prefs provider load resolved prefs from
  /api/v1/users/me.
- date_format_utils maps API keys to intl patterns; formatDate, formatTime,
  formatDateTime, formatDateRange used for display.
- Time entries screen (filter dialog), time entry form, time entry card, and
  home dashboard use user prefs for formatting; API requests still send ISO dates.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-07 08:20:08 +01:00
Dries Peeters 1ebfbf39de refactor: comprehensive code quality, security, and performance improvements
Performance:
- Fix N+1 queries in reports.py with joinedload for TimeEntry.project,
  TimeEntry.user, TimeEntry.task, and Project.client across 6 query locations
- Replace per-task time_entries loops with batch UPDATE queries in tasks.py
- Use efficient subquery for favorite project IDs in projects.py

Architecture:
- Add get_by_id() and get_by_name() methods to ProjectService and ClientService
- Route project/client lookups through service layer in timer.py, projects.py,
  and clients.py instead of direct Model.query calls

Security:
- Add sanitize_input() with length limits to form inputs in clients.py,
  projects.py, timer.py, issues.py, and auth.py
- Add email format validation for client creation
- Warn at startup when SECRET_KEY uses the default value or is too short
  in ProductionConfig
- Replace 7 bare except: pass clauses with specific exception types
  (OSError, IOError, TypeError, ValueError) in admin.py, settings.py,
  and invoice.py

Authorization:
- Migrate all @admin_required decorators to @admin_or_permission_required()
  with granular permissions (manage_roles, manage_kanban, manage_webhooks,
  manage_api_tokens, manage_integrations, access_admin) across permissions.py,
  kanban.py, webhooks.py, and admin.py (28 routes total)

Frontend:
- Remove 40+ console.log debug statements across 18 JS files
- Replace 42 inline onclick/onchange handlers in base.html with delegated
  event listeners using data-dropdown and data-no-propagation attributes
- Migrate 6 inline handlers in time_entries_overview.html to addEventListener
- Extract shared typing detection into typing-utils.js, eliminating 5
  duplicate isTyping() implementations across keyboard shortcut files
- Add missing aria-label attributes to icon-only buttons

Dependencies:
- Migrate from pytz to stdlib zoneinfo (Python 3.9+) across all 6 files
  that used pytz; replace pytz with tzdata in requirements.txt
- Separate dev/test dependencies into requirements-dev.txt
- Configure RotatingFileHandler (10MB, 5 backups) for app and JSON logs

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-06 07:56:23 +01:00
Dries Peeters 5949670c65 fix(time-entries): improve user filter and stop auto-adding client filter
- Fix user dropdown selection: use explicit type-safe comparison
  (filters.user_id|string == user.id|string) so the correct user
  stays selected after pagination or page reload
- Exclude client_id from filter URL when it is auto-selected
  (single client or locked client): add data-auto-client attribute
  to client_select hidden inputs and skip them in getFilterParams
  so filtering by user alone no longer forces client_id=1 into the URL

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 20:54:39 +01:00
Dries Peeters 0d25a6e45b fix(timer): allow combining worked time with start date on manual entry
- Keep date/time fields always editable when duration (HH:MM) is entered
- Backend: when duration and start date+time are provided, use
  end = start + duration instead of requiring full start/end or duration-only
- Update help text to explain duration can be used with a specific date

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 20:44:24 +01:00
Dries Peeters 42a5d746e8 fix(timer): time entries overview filter order, export note, param collection
- Move start/end date filters before project/client for clearer layout
- Add note that exports use current filters; flex-wrap on filter bar
- Explicitly read filter fields (including hidden from client_select) before
  FormData so CSV/PDF export and bulk actions get correct params

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 19:12:01 +01:00
Dries Peeters a97b519128 fix(timer): use scriptRoot for tasks API URL on timer and edit pages
Build tasks URL from request.script_root so reverse-proxy and subpath
configurations work correctly when loading project tasks.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 19:11:56 +01:00
Dries Peeters f6399ea391 fix(timer): manual entry client select, task API URL, tojson, 404 handling
- Show client as normal dropdown; pre-select only from URL param
- Use scriptRoot for tasks API URL instead of url_for template
- Use tojson for all JS-translated strings to avoid syntax errors
- Handle 404 when loading tasks (project not found/inactive)
- Clear client when project is selected (mutual exclusivity)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-05 19:11:53 +01:00
Dries Peeters a53f5a6163 fix(timer): use url_for for task API URLs and improve timer page init
Build task API URLs from url_for in timer page, bulk entry, edit timer, and time entry template edit to support subpath deployment. Wrap timer page script in DOMContentLoaded, load tasks when project is pre-selected, expose selectRecentProject on window, and fix client/project select attachment logic.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-04 22:10:31 +01:00
Dries Peeters 50a0c848a7 fix(time-entry): improve task dropdown and filter robustness (fixes #489)
Log Time - Task dropdown:
- Detect session expiry when API returns HTML instead of JSON
- Show clearer error message suggesting page refresh
- Include HTTP status in error messages
- Add console.error with URL and project ID for debugging

Time Entries - Filters:
- Fallback to explicitly read select/hidden inputs in getFilterParams
- Add console.debug for filter params and URL (helps diagnose issues)
- Use DOMParser as fallback when response parsing fails
- Only set lastUrl on successful parse to allow retries
- Trigger filter apply on text input change (custom fields)

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-04 21:23:36 +01:00
Dries Peeters 2b1e043580 fix(timer): support duration-only entries and stable filtering
- Add duration-only manual entry flow with explicit duration override support.
- Harden manual-entry task loading and base-path compatibility.
- Fix time entries filter flakiness and add filtered PDF export.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-03 22:21:27 +01:00
Dries Peeters 1e780f5bd0 fix(timer): stabilize time entry UX and filtering
Fixes manual time entry task loading, adds a worked-time helper, makes Time Entries filters reliable, and adds CSV export for the current filtered view.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-03 20:27:52 +01:00
Dries Peeters 3c01fb34c8 feat(modules): lock client selection and make Clients admin-only
- Add settings.locked_client_id and admin UI to select locked client
- Allow disabling Clients for non-admins while keeping admin access
- Gate Clients UI routes and API endpoints when module is disabled
- Auto-select and enforce the locked client across filters and form submissions

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-02 19:20:48 +01:00
Dries Peeters 689700d260 fix(timer): load tasks when selecting project on Timer and Log Time
- Use /api/projects/<id>/tasks instead of /api/tasks?project_id= so task
  loading matches the working Edit Logged Time flow.
- Add credentials: 'same-origin' and response.ok checks for reliable
  session auth and error handling.
- Render JS-embedded i18n strings with |tojson to avoid breakage in
  non-English locales.

Fixes #480

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-02 14:11:02 +01:00
Dries Peeters 8be9d82c16 feat: auto-select and gray out client when only one exists (#467)
When a single-client team has only one active client, pre-fill and disable
the client selection across manual time logging, project creation, and
similar forms to reduce friction.

- Add reusable client_select macro for single vs multi-client rendering
- Pass only_one_client and single_client to all relevant forms
- Invalidate dashboard cache on client create/archive/activate/delete
- Restore single client when project selection is cleared (timer forms)
- Add tests for single-client manual entry form
2026-01-30 17:26:14 +01:00
Dries Peeters ee5a9b948f feat(timer): allow multiple image selection in time log notes
- Enable selecting and uploading multiple images at once when adding
  images to time entry notes (manual entry, edit entry, dashboard)
- Replace ToastUI getUI() usage with DOM queries to find toolbar and
  image button (getUI is not available in this editor version)
- Use setAttribute('multiple') and explicit toolbar lookup for reliable
  multiple-file picker on desktop and mobile
- Insert images via getMarkdown/setMarkdown so they render correctly
  in WYSIWYG mode instead of insertText (which did not render images)
- Add retry logic and multiple selectors for image button interception
- Add file type validation (PNG, JPG, GIF, WebP) and user feedback
- Use regular function expressions and safety checks to avoid syntax
  errors in older runtimes

Addresses GitHub Discussion #455 (Add image/picture insertion on time
log note) - client requested ability to add multiple photos at once.
2026-01-28 18:36:02 +01:00
Dries Peeters 73afe58c48 feat: Add multiple image upload support and mobile improvements for markdown editors
- Implement multiple image upload functionality in ToastUI markdown editors
  - Replace single image upload with bulk upload capability
  - Intercept image button click to use custom file input with multiple attribute
  - Upload multiple images via new bulk upload endpoint
  - Insert all uploaded images as markdown at cursor position
  - Include fallback to single image upload if interception fails

- Add mobile-responsive styles for ToastUI Editor modals
  - Adjust modal sizing and positioning for mobile devices
  - Make file inputs and buttons touch-friendly (min-height: 44px)
  - Prevent iOS zoom on input focus (font-size: 16px)
  - Improve modal accessibility on small screens

- Apply changes to dashboard, manual entry, and edit timer pages
- Normalize line endings for calendar.js and calendar.html
2026-01-28 08:49:50 +01:00
Dries Peeters d8d1757e55 feat: Add image insertion support to time log notes
Implement image/picture insertion capability in time log notes by
replacing plain textareas with ToastUI Editor (markdown editor with
image upload support), similar to task descriptions.

Changes:
- Replace textarea with markdown editor in manual time entry form
- Replace textarea with markdown editor in edit time entry form
- Replace textarea with markdown editor in dashboard timer start form
- Update all display views to render markdown with images
- Add image upload support via existing /api/uploads/images endpoint
- Support dark mode theme switching in editors

Features:
- Drag-and-drop or toolbar button image upload
- Full markdown support (headings, bold, italic, lists, links, code, tables, images)
- Backward compatible with existing plain text notes
- Images stored in app/static/uploads/editor/ directory

This addresses GitHub discussion #455 and allows users to add visual
proof/documentation to time entries, particularly useful for
maintenance tasks and general work tracking.

Files modified:
- app/templates/timer/manual_entry.html
- templates/timer/edit_timer.html
- app/templates/main/dashboard.html
- app/templates/timer/view_timer.html
- app/templates/timer/_time_entries_list.html
- app/templates/tasks/view.html
- app/templates/projects/time_entries_overview.html
- app/templates/clients/view.html
- app/templates/client_portal/approval_detail.html
2026-01-27 21:03:07 +01:00
Dries Peeters dd1441c17d fix(timer): use local date for manual entry default instead of UTC
- Compute 'today' from local getFullYear/getMonth/getDate so timezones ahead of
  UTC no longer show the wrong default date in the manual entry form.
2026-01-26 14:47:41 +01:00
Dries Peeters 7dcd58608a feat: Enhance TimeEntry audit logging with comprehensive tracking
Add comprehensive audit logging for TimeEntry operations including:
- Client/project context and creation timestamps
- Full entity state before/after changes
- User-provided reasons for deletions and modifications
- Enhanced UI for entering reasons in delete/edit dialogs

Database Changes:
- Add migration 114: reason, entity_metadata, full_old_state, full_new_state columns
- Use JSON column type for entity_metadata for better type handling

Model Updates:
- Extend AuditLog model with new fields and helper methods
- Update log_change() to accept reason, metadata, and full states
- Add get_entity_metadata(), get_full_old_state(), get_full_new_state() methods
- Use JSON column for entity_metadata (returns dict/list directly)

Service Layer:
- Update TimeTrackingService to capture full TimeEntry state and metadata
- Accept reason parameter in delete_entry() and update_entry()
- Create comprehensive audit logs with all context

API Routes:
- Update api.py, api_v1.py, and timer.py routes to accept reason parameter
- Refactor routes to use service layer for consistent audit logging
- Add reason support to bulk delete operations

UI Enhancements:
- Add reason textarea to bulk delete confirmation dialog
- Add reason textarea to time entry edit forms (admin and regular users)
- Update JavaScript to handle reason submission

Audit Log Display:
- Show client/project information and creation timestamp in list view
- Display full old/new states, reason, and metadata in detail view
- Format JSON states for better readability

Bug Fixes:
- Fix duration_seconds reference in timer stop route
- Improve error handling in timer operations with proper exception handling
- Add dashboard cache invalidation after manual entry creation
2026-01-22 13:36:04 +01:00
Dries Peeters 0635a46de5 fix(routes): resolve 500 on /time-entries pagination links (#438)
Pagination used url_for(..., **filters) which included:
- client_custom_field (a dict): URL encoding cannot handle dict values
- page: overwrote the explicit page param in Prev/Next links

Introduce url_filters: exclude client_custom_field and page, expand
client_custom_field into custom_field_<key> query params. Use url_filters
in _time_entries_list.html for all pagination url_for calls.
2026-01-20 19:58:25 +01:00
Dries Peeters f3a3a40480 Add project custom fields and file attachments for projects and clients
This commit introduces two major features:

1. Project Custom Fields: Add custom_fields JSON column to projects table (migration 085), support for flexible custom data storage, display and edit in project views

2. File Attachments System: Add project_attachments and client_attachments tables (migration 086), new ProjectAttachment and ClientAttachment models, full CRUD operations, file upload/download/delete, client-visible attachments support

Additional improvements: Enhanced data tables, updated project/client/invoice/timer views, improved UI for attachments and custom fields management
2025-12-03 08:30:15 +01:00
Dries Peeters f87da99781 feat: Add custom field filtering and display for clients, projects, and time entries
- Extend client list table to display custom field columns
  - Add custom field columns dynamically based on active CustomFieldDefinition entries
  - Support link templates for clickable custom field values
  - Enable column visibility toggle for custom field columns
  - Update search functionality to include custom fields (PostgreSQL JSONB and SQLite fallback)

- Add custom field filtering to Projects list
  - Extend ProjectService.list_projects() to filter by client custom fields
  - Add custom field filter inputs to projects list template
  - Support filtering by client custom field values (e.g., debtor_number, ERP IDs)
  - Handle both PostgreSQL (JSONB) and SQLite (Python fallback) filtering

- Add custom field filtering to Time Entries list
  - Extend time entries route to filter by client custom fields
  - Add custom field filter inputs to time entries overview template
  - Enable filtering time entries by client custom field values
  - Support distinguishing clients with same name but different custom field values

- Database compatibility
  - PostgreSQL: Use efficient JSONB operators for database-level filtering
  - SQLite: Fallback to Python-based filtering after initial query
  - Both approaches ensure accurate results across database backends

This enhancement allows users to filter and search by custom field values,
making it easier to distinguish between clients with identical names but
different identifiers (e.g., debtor numbers, ERP IDs).
2025-12-01 19:25:05 +01:00
Dries Peeters de266dbf7d feat: Add time entries overview page with AJAX filters and bulk mark as paid
- Add new /time-entries route with comprehensive filtering
  - Filter by user (admin only), project, client, date range
  - Filter by paid/unpaid status and billable status
  - Search in notes and tags
  - Pagination support (50 entries per page)

- Implement bulk mark as paid/unpaid functionality
  - Select multiple entries with checkboxes
  - Bulk actions menu to mark selected entries as paid or unpaid
  - Preserves filters after bulk operations
  - Activity logging for bulk changes

- Add AJAX filtering similar to projects/tasks pages
  - Auto-apply filters on dropdown/date changes (100ms debounce)
  - Auto-apply search as you type (500ms debounce)
  - Updates URL without page reload
  - Partial template rendering for AJAX requests

- Add navigation menu link in sidebar under Work section
- Extend bulk entries API to support set_paid action
- Add summary cards showing total hours, billable hours, paid hours, and entry count
- Permission-based access: admins see all entries, regular users see only their own
2025-12-01 14:15:58 +01:00
Dries Peeters ac465d9612 feat: Enhance UI/UX with improved form validation and error handling
- Add comprehensive form validation system with real-time feedback
- Implement enhanced error handling with retry mechanisms and offline support
- Update route handlers for improved error responses
- Enhance list templates with better error handling and validation
- Update dashboard, timer, and report templates with enhanced UI
- Improve project service with better error handling
- Update config manager utilities
- Bump version to 4.2.0

Files updated:
- Routes: auth, clients, invoices, projects, quotes, tasks, timer, custom_reports
- Templates: base, dashboard, all list views, timer pages, reports
- Static: enhanced-ui.js, error-handling-enhanced.js, form-validation.js
- Services: project_service.py
- Utils: config_manager.py
- Version: setup.py
2025-11-30 10:51:09 +01:00
Dries Peeters dcbdfcc288 feat: Add client custom fields, link templates, UI feature flags, and client billing support
Add client custom fields (JSON) for flexible data storage

Implement link templates system for dynamic URL generation from custom fields

Add client_id support to time entries for direct client billing (project_id now nullable)

Implement user-level UI feature flags for customizable navigation visibility

Add system-wide UI feature flags in settings for admin control

Fix metadata column naming (user_badges.achievement_metadata, leaderboard_entries.entry_metadata)

Update templates and routes to support new features

Add comprehensive UI feature flag management in admin and user settings

Enhance client views with custom fields and link template integration

Update time entry forms to support client billing

Add tests for system UI flags

Migrations: 075-080 for custom fields, link templates, UI flags, client billing, and metadata fixes
2025-11-29 06:17:07 +01:00
Dries Peeters 1596537512 Complete translation system implementation and fixes
This commit implements comprehensive internationalization (i18n) support
across the entire TimeTracker application, ensuring all user-facing strings
are properly translatable.

## Translation Implementation

### Route Files (Flash Messages)
- Fixed all untranslated flash messages in route files:
  * app/routes/admin.py (36 messages)
  * app/routes/tasks.py (43 messages)
  * app/routes/timer.py (44 messages)
  * app/routes/projects.py (33 messages)
  * app/routes/payments.py (28 messages)
  * app/routes/clients.py (25 messages)
  * app/routes/invoices.py (24 messages)
  * Plus all other route files (recurring_invoices, kanban, reports, etc.)
- Added missing `from flask_babel import _` imports to:
  * app/routes/setup.py
  * app/routes/budget_alerts.py
  * app/routes/saved_filters.py
  * app/routes/reports.py
  * app/routes/time_entry_templates.py

### Template Files
- Fixed headers and labels in templates:
  * admin/user_form.html
  * audit_logs/view.html
  * timer/timer_page.html
  * reports/index.html
  * reports/user_report.html
  * time_entry_templates/view.html
  * recurring_invoices/view.html
- Fixed form placeholders in:
  * expense_categories/form.html
  * expenses/form.html
  * mileage/form.html
  * per_diem/form.html
  * per_diem/rate_form.html
- Fixed button and link text in list views:
  * invoices/list.html
  * payments/list.html
  * expenses/list.html
  * per_diem/list.html
  * projects/list.html
- Fixed title attributes for accessibility

### Email Templates
- Added translation support to all email templates:
  * quote_sent.html, quote_rejected.html, quote_expired.html
  * quote_expiring.html, quote_approved.html, quote_accepted.html
  * quote_approval_request.html, quote_approval_rejected.html
  * invoice.html, overdue_invoice.html
  * task_assigned.html, comment_mention.html
  * client_portal_password_setup.html
  * weekly_summary.html, test_email.html
  * quote.html

### Component Templates
- Fixed save_filter_widget.html with translated text
- Updated JavaScript strings in quote_pdf_layout.html

## Translation Files

### Extraction and Updates
- Extracted all new translatable strings using pybabel
- Updated all language catalogs (.po files) with new strings
- Languages updated: en, nl, de, fr, it, fi, es, ar, he, nb, no

### Automatic Translation
- Created scripts/complete_all_translations.py for automatic translation
- Translated ~3,100 strings per language using Google Translate API
- Translation completion rates:
  * Dutch (NL): 99.97% (3,098/3,099)
  * German (DE): 99.94% (3,097/3,099)
  * French (FR): 99.97% (3,098/3,099)
  * Italian (IT): 99.90% (3,096/3,099)
  * Finnish (FI): 99.06% (3,070/3,099)
  * Spanish (ES): 99.97% (3,098/3,099)
  * Arabic (AR): 99.97% (3,098/3,099)
  * Hebrew (HE): 99.90% (3,096/3,099)
  * Norwegian Bokmål (NB): 99.94% (3,097/3,099)
  * Norwegian (NO): 99.94% (3,097/3,099)

### Placeholder Fixes
- Created scripts/fix_translation_placeholders.py
- Fixed 281 placeholder name errors across all languages
- Preserved original English placeholder names (e.g., %(error)s, %(rate)s)
- Fixed format specifier issues (e.g., %(rate).2f%%)

## Bug Fixes

### Code Fixes
- Fixed indentation error in app/routes/timer.py (line 458)
- Fixed missing translation function imports in route files

### Translation Compilation
- All translation catalogs now compile successfully
- No compilation errors remaining
- All .mo files generated correctly

## Scripts Added

- scripts/complete_all_translations.py: Automatic translation using deep-translator
- scripts/fix_translation_placeholders.py: Fix placeholder names in translations

## Impact

- All user-facing strings are now translatable
- Application supports 11 languages with >99% translation coverage
- Improved user experience for non-English speakers
- Consistent translation system across all application components
2025-11-24 14:01:31 +01:00
Dries Peeters 5ace391bd9 feat(i18n): Add comprehensive translation support across all templates
- Replace hardcoded English strings with translation function calls in 36 template files
- Update translation files for all supported languages (ar, de, es, fi, fr, he, it, nb, nl, no)
- Add over 55,000 new translation entries across all language files
- Update extract_translations.py to use 'python -m babel.messages.frontend' instead of pybabel
- Improve internationalization coverage for UI elements including:
  * Skip to content links
  * Sidebar toggle buttons
  * Command palette placeholders
  * Admin dashboard elements
  * Form labels and buttons
  * Report templates
  * Payment and invoice views

This commit significantly improves the application's multilingual support
by making previously hardcoded strings translatable.
2025-11-18 11:35:57 +01:00
Dries Peeters 3f73cb35c8 feat(i18n): Add Norwegian translation support and improve internationalization
- Add Norwegian (Norsk) language support with locale code normalization (no -> nb)
- Create Norwegian translation files (translations/nb/ and translations/no/)
- Fill empty Norwegian translation strings with English fallback values
- Add locale normalization for Flask-Babel compatibility (no -> nb mapping)
- Update context processor to correctly display 'Norsk' label instead of 'NB'

Translation improvements:
- Wrap all hardcoded strings in templates with _() translation function
- Add missing translations for setup, timer, tasks, invoices, and admin templates
- Ensure brandnames 'drytrix' and 'TimeTracker' remain untranslated across all languages
- Add new translation strings to all language files (en, de, nl, fr, it, fi, es, no, ar, he)
- Update translation files for: initial_setup, manual_entry, tasks/list, email_templates, etc.

Bug fixes:
- Add missing /api/summary/today endpoint for daily summary notifications
- Fix 'Response body already consumed' error in smart-notifications.js
- Improve translation compilation logging and error handling
- Add debug endpoint /debug/i18n for troubleshooting translation issues

Technical changes:
- Improve ensure_translations_compiled() with better logging
- Add locale normalization function for Norwegian locale handling
- Update context processor to reverse-map normalized locales for display
- Fix JavaScript fetch error handling to check response.ok before reading body
2025-11-17 19:21:24 +01:00
Dries Peeters f8f269047e Complete partially implemented features: templates, activity feed, and logging
ented features that were missingUI components, integrations, or proper error handling:1. Time Entry Templates UI Integration   - Added template selector to timer page (timer_page.html)   - Updated timer route to load user templates   - Added JavaScript function to apply templates with one-click   - Created missing view.html template for template details   - Templates now appear on timer page sorted by most recently used2. Activity Feed Widget Real-time Updates   - Added WebSocket integration to Activity model for real-time events   - Activity.log() now emits 'activity_created' SocketIO events   - Updated activity feed widget to listen for WebSocket events   - Feed automatically refreshes when new activities match current filter   - Added proper error handling for WebSocket connection failures3. Invoice Routes Logging Improvements   - Replaced all print() statements with proper logging in invoices.py   - Added structured logging with appropriate log levels (info, debug, warning, error)   - Improved error handling with full traceback logging using exc_info=True   - All PDF export debug statements now use logger.debug/info/errorFiles changed:- app/routes/timer.py: Added template loading for timer page- app/templates/timer/timer_page.html: Added template selector UI and applyTemplate function- app/models/activity.py: Added WebSocket event emission on activity creation- app/templates/components/activity_feed_widget.html: Added WebSocket listener for real-time updates- app/routes/invoices.py: Replaced print statements with proper logging- app/templates/time_entry_templates/view.html: Created missing view template
2025-11-12 11:53:18 +01:00
Dries Peeters 14ae197266 Improve timezone handling for system and personal preferences
- share a centralized timezone list across admin and user settings
- allow admins to pick from the same list when setting the system default
- let users clear their personal override to fall back to the global default
- add regression tests covering the new helper and reset path
2025-11-11 14:04:39 +01:00
Dries Peeters d5417501e8 feat: Enhance UI with timer page, projects grid view, invoice filters, and reports improvements
This commit implements comprehensive UI enhancements across multiple pages
with improved user experience, visual feedback, and functionality.

Timer Page (/timer):
- Add dedicated timer page with visual SVG progress ring
- Implement real-time timer display with animated progress indicator
- Add quick project/task selection dropdown with dynamic task loading
- Display recent projects quick access (last 5 projects used in 30 days)
- Add timer duration estimation based on average session duration
- Show today's stats sidebar with total hours and active timer status

Projects List (/projects):
- Add grid/list view toggle with localStorage persistence
- Create project cards with budget and hours progress indicators
- Add quick actions on hover (View, Edit, Favorite) for grid view
- Display project status badges (Active/Inactive/Archived) on cards
- Show client information and billable status on cards
- Implement responsive grid layout (1/2/3 columns based on screen size)

Invoice List (/invoices):
- Add visual status filter buttons with icons (Draft, Sent, Paid, Overdue)
- Add payment status filter dropdown (Unpaid, Partially Paid, Fully Paid, Overpaid)
- Display payment status icons with color-coded badges
- Implement due date highlighting with red border for overdue invoices
- Add quick invoice actions dropdown (View, Edit, Download PDF, Send Email, Delete)
- Enhance invoice status badges with icons for better visual recognition

Reports (/reports):
- Add date range presets (Today, This Week, This Month, This Year)
- Implement comparison view API endpoint for month/year comparisons
- Add export format selection dropdown (CSV, Excel, PDF)
- Create scheduled reports management modal UI
- Display comparison results with current vs previous period metrics
- Add custom date range picker with apply button

Bug Fixes:
- Fix datetime import shadowing issue in reports route causing UnboundLocalError
- Fix invoice template date.today() Jinja template error
- Fix timer route db.case() SQLAlchemy syntax for recent projects ordering
- Fix projects template missing </script> tag causing JavaScript errors
- Fix mileage page date parsing error when start_date/end_date are empty
- Fix budget alerts user_project_ids undefined error for admin users
- Fix skip tour button z-index issue - confirmation dialog now appears above mask

Technical Improvements:
- Add proper error handling for date parsing in mileage route
- Improve z-index management for onboarding tooltip and confirmation dialogs
- Add proper variable initialization in budget alerts route
- Enhance template syntax for overdue date calculation
- Add timedelta import to timer route for date calculations

All features include:
- Responsive design for mobile and desktop
- Dark mode support throughout
- Smooth transitions and animations
- Accessibility considerations
- No linting errors
2025-11-05 11:41:16 +01:00
Dries Peeters b4b8bafb9a feat: Add comprehensive form validation system with real-time feedback
Implement a reusable form validation system that provides immediate,
contextual feedback to users with inline error messages and visual indicators.

Features:
- Real-time validation on input, blur, and submit events
- Inline error and success messages displayed near form fields
- Visual indicators for required vs optional fields (asterisks)
- Subtle validation styling with softer colors and smaller icons
- Phone number validation for tel/phone fields (7-15 digits, optional country code)
- Email, URL, number, date, and pattern validation support
- Debounced validation to reduce performance impact
- Form-level error messages on submit
- Automatic focus management for invalid fields

Technical improvements:
- Prevent duplicate initialization with form and field flags
- Smart message container insertion that respects existing form structure
- Better detection of existing required indicators to prevent duplicates
- Hidden messages take zero space (height: 0) to prevent layout shifts
- Graceful error handling with try-catch blocks

Styling:
- Subtle visual feedback with green-300/red-300 borders (softer than before)
- Smaller validation icons (0.875rem) and reduced padding (2rem)
- Reduced opacity for messages (0.75-0.85) for less intrusive appearance
- Lighter focus shadows (0.08 opacity) for subtle feedback
- Dark mode support with appropriate color adjustments

Applied to all forms:
- Projects (create/edit)
- Clients (create/edit)
- Tasks (create/edit)
- Invoices (create/edit)
- Payments (create/edit)
- Expenses, Mileage, Per Diem forms
- Time Entry (manual entry)
- Weekly Goals

Fixes:
- Prevent duplicate message containers and layout breaks
- Better insertion logic that respects existing help text
- Improved container detection to avoid duplicates
- Fixed required indicator duplication issues
- Enhanced form submission handler management

The validation system automatically initializes on forms with
data-validate-form attribute or novalidate attribute, providing
consistent validation UX across the application.
2025-11-05 08:02:30 +01:00
Dries Peeters 890df2f4bc Fix: Preserve task selection when duplicating time entries
Fix: Preserve task selection when duplicating time entriesWhen duplicating a time entry with an assigned task, the task was notbeing pre-selected in the duplicate form. This was caused by thetemplate application code interfering with the duplication logic.The template code would run after duplication data was set, overwritingthe `data-selected-task-id` attribute and clearing the task selectioneven when no template was being applied.Changes:- Added isDuplicating flag check in manual_entry.html to prevent  template application code from running during duplication- Template functionality continues to work normally for non-duplicate  manual entries- Added comprehensive test to verify task pre-selection is preserved- Updated documentation with fix notes and changelog entryImpact:- Users can now duplicate time entries with tasks and the task will be  correctly pre-selected, saving time and improving UX- No breaking changes - all existing tests pass (54/54)- Clean separation between duplication and template featuresTests:- test_duplicate_with_task_not_overridden_by_template_code (new)- All 22 duplication tests passing- All 32 template tests passing
2025-10-31 13:22:24 +01:00
Dries Peeters 12d3b9fb1b feat: Add comprehensive Import/Export system and standardize UI headers
## New Features

### Import/Export System
- Add DataImport and DataExport models for tracking operations
- Implement CSV import for bulk time entry data
- Add support for importing from Toggl and Harvest (placeholder)
- Implement GDPR-compliant full data export (JSON format)
- Add filtered export functionality with date/project filters
- Create backup/restore functionality for database migrations
- Build migration wizard UI for seamless data transitions
- Add comprehensive test coverage (unit and integration tests)
- Create user documentation (IMPORT_EXPORT_GUIDE.md)

### Database Changes
- Add migration 040: Create data_imports and data_exports tables
- Track import/export operations with status, logs, and file paths
- Support automatic file expiration for temporary downloads

## UI/UX Improvements

### Navigation Menu Restructure
- Rename "Work" to "Time Tracking" for clarity
- Rename "Finance" to "Finance & Expenses"
- Add "Tools & Data" submenu with Import/Export and Saved Filters
- Reorganize Time Tracking submenu: prioritize Log Time, add icons to all items
- Expand Finance submenu: add Mileage, Per Diem, and Budget Alerts
- Add icons to all Admin submenu items for better visual scanning
- Fix Weekly Goals not keeping Time Tracking menu open

### Standardized Page Headers
Apply consistent page_header macro across 26+ pages:
- **Time Tracking**: Tasks, Projects, Clients, Kanban, Weekly Goals, Templates, Manual Entry
- **Finance**: Invoices, Payments, Expenses, Mileage, Per Diem, Budget Alerts, Reports
- **Admin**: Dashboard, Users, Roles, Permissions, Settings, API Tokens, Backups, System Info, OIDC
- **Tools**: Import/Export, Saved Filters, Calendar
- **Analytics**: Dashboard

Each page now includes:
- Descriptive icon (Font Awesome)
- Clear title and subtitle
- Breadcrumb navigation
- Consistent action button placement
- Responsive design with dark mode support

## Bug Fixes

### Routing Errors
- Fix endpoint name: `per_diem.list_per_diems` → `per_diem.list_per_diem`
- Fix endpoint name: `reports.index` → `reports.reports`
- Fix endpoint name: `timer.timer` → `timer.manual_entry`
- Add missing route registration for import_export blueprint

### User Experience
- Remove duplicate "Test Configuration" button from OIDC debug page
- Clean up user dropdown menu (remove redundant Import/Export link)
- Improve menu item naming ("Profile" → "My Profile", "Settings" → "My Settings")

## Technical Details

### New Files
- `app/models/import_export.py` - Import/Export models
- `app/utils/data_import.py` - Import business logic
- `app/utils/data_export.py` - Export business logic
- `app/routes/import_export.py` - API endpoints
- `app/templates/import_export/index.html` - User interface
- `tests/test_import_export.py` - Integration tests
- `tests/models/test_import_export_models.py` - Model tests
- `docs/IMPORT_EXPORT_GUIDE.md` - User documentation
- `docs/import_export/README.md` - Quick reference
- `migrations/versions/040_add_import_export_tables.py` - Database migration

### Modified Files
- `app/__init__.py` - Register import_export blueprint
- `app/models/__init__.py` - Export new models
- `app/templates/base.html` - Restructure navigation menu
- 26+ template files - Standardize headers with page_header macro

## Breaking Changes
None. All changes are backward compatible.

## Testing
- All existing tests pass
- New test coverage for import/export functionality
- Manual testing of navigation menu changes
- Verified consistent UI across all updated pages
2025-10-31 09:56:49 +01:00