Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
734071d
Branch Report Builder initial
nielsdrost7 Jan 8, 2026
dcff0b8
Removed Invoices temporarily
nielsdrost7 Jan 8, 2026
b9ac17e
126: Peppo;l
nielsdrost7 Jan 8, 2026
7790b99
temporary-total
nielsdrost7 Jan 8, 2026
e4cd9d5
temp
nielsdrost7 Jan 8, 2026
a0dfe56
Hope to have resolved some conflicts in the 98-ReportBuilder branch r…
nielsdrost7 Jan 8, 2026
76649e5
Delete Modules/ReportBuilder directory
nielsdrost7 Jan 8, 2026
713f511
temp
nielsdrost7 Jan 8, 2026
34dd81d
Merge branch 'develop' into feature/98-report-builder-only
nielsdrost7 Jan 8, 2026
fbafb61
Composer correct
nielsdrost7 Jan 8, 2026
1545d06
Composer correct
nielsdrost7 Jan 8, 2026
7bdbf52
Update pint.yml
nielsdrost7 Jan 8, 2026
4bf32e2
Fix Filament action imports, grid calculations, and refactor test moc…
Copilot Jan 9, 2026
ddbd4da
Merge branch 'develop' into feature/98-report-builder-only
nielsdrost7 Jan 12, 2026
080d8e6
merged in develop branch
nielsdrost7 Jan 12, 2026
5075fba
Add comprehensive Mason package integration plan
Copilot Feb 24, 2026
18c8257
Update Mason refactor plan with status and next steps
Copilot Feb 24, 2026
cb67526
Implement Mason package integration for ReportBuilder
Copilot Feb 24, 2026
ebbd431
Wire Mason into ReportBuilder and add comprehensive tests
Copilot Feb 24, 2026
db31168
Add 5 new Mason bricks and simplify storage (remove BlockDTO)
Copilot Feb 24, 2026
23ca5fc
Refactor brick actions to use Mason's standard fillForm pattern
Copilot Feb 24, 2026
ed40845
Add 6 new Mason bricks for enhanced reporting capabilities
Copilot Feb 25, 2026
70566e6
Update Modules/Core/Filament/Admin/Resources/ReportTemplates/Pages/Re…
nielsdrost7 Feb 25, 2026
1dca568
Apply suggestions from code review
nielsdrost7 Feb 25, 2026
31b846d
Add authorization and fix XSS vulnerabilities in Mason bricks
Copilot Feb 25, 2026
e109a1e
Update resources/lang/en/ip.php
nielsdrost7 Feb 25, 2026
f8e8fd7
Apply suggestions from code review
nielsdrost7 Feb 25, 2026
1d44866
Update Modules/Core/Services/MasonStorageAdapter.php
nielsdrost7 Feb 25, 2026
c41393b
Fix test assertions, Blade syntax, and unused imports per code review
Copilot Feb 25, 2026
103111a
Add test for MasonTemplateStorage save/load flow
Copilot Feb 25, 2026
9be9bbf
Update Modules/Core/Tests/Feature/ReportBuilderMasonIntegrationTest.php
nielsdrost7 Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
232 changes: 232 additions & 0 deletions .github/REPORT_BUILDER_ENHANCEMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
# Report Builder Enhancements

## Overview

This document describes the enhancements made to the Report Builder functionality in InvoicePlane v2. The changes address several issues and add new capabilities for managing report templates and blocks.

## Problems Solved

### 1. Block Width Options
**Problem**: Report blocks only supported half-width and full-width options.

**Solution**: Extended `ReportBlockWidth` enum to support four width options:
- `ONE_THIRD` (4 columns in 12-column grid)
- `HALF` (6 columns)
- `TWO_THIRDS` (8 columns)
- `FULL` (12 columns)

### 2. Block Edit Form Not Populating
**Problem**: When clicking "Edit" on a block in the Report Builder, the form opened but didn't show the record's data.

**Solution**:
- Fixed `configureBlockAction()` in `ReportBuilder.php` to properly lookup blocks using `block_type`
- Added proper form population in both `fillForm()` and `mountUsing()` methods
- Added logging (`Log::info`) for debugging purposes to help identify data issues

### 3. Debugging Visibility
**Problem**: Using `dd()` in Livewire/Alpine context didn't show debug output.

**Solution**: Replaced debug dumps with `Log::info()` calls that write to Laravel's log files:
```php
Log::info('Block data for edit:', $data);
Log::info('Mounting block config with data:', $data);
```

### 4. Field Drag/Drop Canvas
**Problem**: No way to configure which fields appear in a block or their layout.

**Solution**:
- Created a drag-and-drop field canvas interface
- Added `fields-canvas.blade.php` view component
- Integrated canvas into the block editor slideover panel
- Fields can be dragged from "Available Fields" to the canvas
- Field configurations are saved to JSON files

### 5. Block Width Rendering
**Problem**: Blocks in the init() function didn't respect their configured widths (e.g., full-width invoice_items showed as half-width).

**Solution**: Updated the Alpine.js template in `design-report-template.blade.php` to properly calculate grid-column spans based on block widths:
```javascript
grid-column: span ${block.position.width >= 12 ? '2' : (block.position.width >= 8 ? '2' : '1')}
```

## Technical Implementation

### Enum Enhancement
```php
enum ReportBlockWidth: string
{
case ONE_THIRD = 'one_third';
case HALF = 'half';
case TWO_THIRDS = 'two_thirds';
case FULL = 'full';

public function getGridWidth(): int
{
return match ($this) {
self::ONE_THIRD => 4,
self::HALF => 6,
self::TWO_THIRDS => 8,
self::FULL => 12,
};
}
}
```

### Field Storage Architecture
Fields are stored separately from blocks:
- **Block Records**: Stored in `report_blocks` database table with metadata
- **Field Configurations**: Stored in JSON files at `storage/app/report_blocks/{slug}.json`

This separation allows:
- Fast block queries without loading heavy field data
- Easy version control and backup of field configurations
- Flexibility to extend field properties without schema changes

### ReportBlockService Methods
```php
// Save fields to JSON file
saveBlockFields(ReportBlock $block, array $fields): void

// Load fields from JSON file
loadBlockFields(ReportBlock $block): array

// Get complete configuration including fields
getBlockConfiguration(ReportBlock $block): array
```

### Field Canvas Component
The drag/drop canvas supports:
- Dragging available fields to canvas
- Removing fields from canvas
- Preserving field positions and dimensions
- Complex field metadata (styles, visibility, etc.)
- Real-time sync with Livewire component state

## Database Changes

### Migration: report_blocks table
Updated default values and column comments:
```php
// Updated width column to support 4 options
$table->string('width')->default('half'); // one_third, half, two_thirds, or full

// Added data_source default
$table->string('data_source')->default('invoice');
```

**Note on Configuration Storage:**
Block field configurations are **not** stored in the database. Instead, they are stored as JSON files in the filesystem at `storage/app/report_blocks/{slug}.json`. This separates the block metadata (in database) from the field layout configuration (in files), allowing for easier version control and more flexible configuration management.

## Testing

All new functionality is covered by comprehensive PHPUnit tests (marked as incomplete per requirements):

### Unit Tests
- `ReportBlockWidthTest`: Tests enum values and grid width calculations (6 tests)
- `ReportBlockServiceFieldsTest`: Tests JSON field storage/loading (9 tests)

### Feature Tests
- `ReportBuilderBlockWidthTest`: Tests width rendering in designer (8 tests)
- `ReportBuilderBlockEditTest`: Tests form data population (8 tests)
- `ReportBuilderFieldCanvasIntegrationTest`: Tests field canvas workflow (8 tests)

**Total: 39 test cases**

To run the tests:
```bash
php artisan test --filter=ReportBlock
php artisan test --filter=ReportBuilder
```

## Usage Examples

### Creating a Block with Custom Width
```php
$block = ReportBlock::create([
'block_type' => 'custom_block',
'name' => 'Custom Block',
'width' => ReportBlockWidth::TWO_THIRDS,
'data_source' => 'invoice',
'default_band' => 'header',
]);
```

### Saving Field Configuration
```php
$service = app(ReportBlockService::class);

$fields = [
[
'id' => 'company_name',
'label' => 'Company Name',
'x' => 0,
'y' => 0,
'width' => 200,
'height' => 40,
],
[
'id' => 'company_address',
'label' => 'Company Address',
'x' => 0,
'y' => 50,
'width' => 200,
'height' => 60,
],
];

$service->saveBlockFields($block, $fields);
```

### Loading Field Configuration
```php
$fields = $service->loadBlockFields($block);
```

## Files Modified

### Core Files
- `Modules/Core/Enums/ReportBlockWidth.php` - Enhanced enum
- `Modules/Core/Models/ReportBlock.php` - Added HasFactory trait
- `Modules/Core/Models/ReportTemplate.php` - Added HasFactory trait
- `Modules/Core/Services/ReportTemplateService.php` - Updated width calculation
- `Modules/Core/Services/ReportBlockService.php` - Added field management methods

### Filament Resources
- `Modules/Core/Filament/Admin/Resources/ReportTemplates/Pages/ReportBuilder.php` - Fixed form population
- `Modules/Core/Filament/Admin/Resources/ReportBlocks/Schemas/ReportBlockForm.php` - Added field canvas

### Views
- `Modules/Core/resources/views/filament/admin/resources/report-template-resource/pages/design-report-template.blade.php` - Fixed width rendering
- `Modules/Core/resources/views/filament/admin/resources/report-blocks/fields-canvas.blade.php` - New canvas view

### Database
- `Modules/Core/Database/Migrations/2026_01_01_184544_create_report_blocks_table.php` - Added config column
- `Modules/Core/Database/Factories/ReportBlockFactory.php` - New factory
- `Modules/Core/Database/Factories/ReportTemplateFactory.php` - New factory

### Tests
- `Modules/Core/Tests/Unit/ReportBlockWidthTest.php` - New
- `Modules/Core/Tests/Unit/ReportBlockServiceFieldsTest.php` - New
- `Modules/Core/Tests/Feature/ReportBuilderBlockWidthTest.php` - New
- `Modules/Core/Tests/Feature/ReportBuilderBlockEditTest.php` - New
- `Modules/Core/Tests/Feature/ReportBuilderFieldCanvasIntegrationTest.php` - New

## Future Enhancements

Potential areas for future improvement:
1. Visual field editor with WYSIWYG preview
2. Field templates/presets for common layouts
3. Conditional field visibility based on data
4. Field validation rules
5. Custom field types (QR codes, barcodes, charts)
6. Multi-language field labels
7. Export/import field configurations

## Notes

- All tests are marked as incomplete (`markTestIncomplete()`) by default as requested
- Tests have working implementations and can be unmarked when ready to run
- Field JSON files are stored in `storage/app/report_blocks/` directory
- Logging can be monitored at `storage/logs/laravel.log`
- Block widths automatically map to grid columns using `getGridWidth()` method
40 changes: 40 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,46 @@ The factory automatically selects handlers with fallback logic and proper loggin
- **Extract complex conditions** into well-named methods.
- **Use meaningful method names** that describe what they do.

### Internationalization & Translations

**CRITICAL:** InvoicePlane v2 uses `trans()` for all translations, NOT `__()`.

```php
// ❌ WRONG - Do not use __()
$label = __('ip.invoice_total');

// ✅ CORRECT - Always use trans()
$label = trans('ip.invoice_total');
```

**Translation Key Conventions:**
- Main translation file: `resources/lang/en/ip.php`
- Prefix keys with `ip.` (e.g., `ip.invoice_total`, `ip.payment_method`)
- Use snake_case for key names
- In Blade: Use `{{ trans('ip.key') }}` or `@lang('ip.key')`

**UI Text Translation Requirements:**
ALL user-facing text must use trans():
- Form field labels: `->label(trans('ip.field_label'))`
- Placeholders: `->placeholder(trans('ip.placeholder'))`
- Helper text: `->helperText(trans('ip.help_text'))`
- Section titles: `Section::make(trans('ip.section_title'))`
- Button labels: `trans('ip.button_text')`
- Table headers: `trans('ip.column_name')`
- Tooltips & hints: `trans('ip.tooltip')`
- Success/error messages: `trans('ip.message')`

**Example:**
```php
TextInput::make('name')
->label(trans('ip.report_block_name'))
->placeholder(trans('ip.report_block_name_placeholder'))
->helperText(trans('ip.report_block_name_help'));

Section::make(trans('ip.section_general'))
->schema([...]);
```

## PHPStan Type Safety Guidelines

### Float Array Keys (CRITICAL)
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/crowdin-sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ jobs:
download_translations: false
localization_branch_name: master
config: 'crowdin.yml'
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

- name: Download translations from Crowdin
if: github.event.inputs.action == 'download-translations' || github.event.inputs.action == 'sync-bidirectional' || github.event_name == 'schedule'
Expand Down Expand Up @@ -87,9 +88,9 @@ jobs:
crowdin
automated-pr
config: 'crowdin.yml'
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
env:
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
GITHUB_TOKEN: ${{ secrets.PAT_TOKEN }}

- name: Workflow summary
Expand Down
78 changes: 78 additions & 0 deletions .junie/guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,84 @@ public function it_sends_invoice_to_peppol_successfully(): void

---

## Internationalization & Translations

### Translation Function Usage
**CRITICAL:** InvoicePlane v2 uses `trans()` for all translations, NOT `__()`.

```php
// ❌ WRONG - Do not use __()
$label = __('ip.invoice_total');
$message = __('ip.payment_successful');

// ✅ CORRECT - Always use trans()
$label = trans('ip.invoice_total');
$message = trans('ip.payment_successful');
```

**Blade Templates:**
```blade
{{-- ✅ CORRECT --}}
{{ trans('ip.total') }}
@lang('ip.total') {{-- @lang() is acceptable in Blade --}}
```

### Translation Key Conventions
- Main translation file: `resources/lang/en/ip.php`
- Prefix all keys with `ip.` for InvoicePlane-specific translations
- Use snake_case for key names
- Group related translations logically
- Example keys: `ip.invoice_total`, `ip.payment_method`, `ip.report_field_company_name`

### UI Text Translation Requirements
**ALL user-facing text must be translatable:**

**Form Fields:**
```php
// Labels
TextInput::make('name')
->label(trans('ip.field_label'))

// Placeholders
TextInput::make('email')
->placeholder(trans('ip.email_placeholder'))

// Helper Text
TextInput::make('vat_id')
->helperText(trans('ip.vat_id_help'))

// Section Titles
Section::make(trans('ip.section_general'))
```

**Required Translation Coverage:**
- ✅ Form field labels
- ✅ Form placeholders
- ✅ Helper text and hints
- ✅ Tips and tooltips
- ✅ Button labels
- ✅ Section titles
- ✅ Table column headers
- ✅ Success/error messages
- ✅ Validation messages
- ✅ Menu items
- ✅ Page titles

### Service Translation Pattern
When services load translatable content from config files:
```php
// Load from config and translate
$label = trans(config('some-config.label'));

// In service methods
public function getTranslatedLabel(): string
{
return trans($this->configKey);
}
```

---

## Development Workflow

### Commands
Expand Down
Loading
Loading