From 1decb19bbaa5beecf580aa8aeff11182194f8d24 Mon Sep 17 00:00:00 2001 From: javier Date: Thu, 25 Jun 2026 14:18:21 +0200 Subject: [PATCH] =?UTF-8?q?feat(templates):=20exponer=20importaci=C3=B3n?= =?UTF-8?q?=20desde=20otro=20proyecto=20y=20desde=20CSV/Excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El TemplateManager ya implementaba ambos flujos pero la vista no los exponΓ­a. AΓ±adidos a la cabecera los botones "Importar de proyecto" e "Importar CSV/Excel" y sus modales: - CSV/Excel: nombre + fichero, vista previa de campos detectados, crear; con enlace para descargar CSV de ejemplo. - Otro proyecto: selecciΓ³n de proyecto accesible + checklist de plantillas a importar. Tests: TemplateImportTest (importar de proyecto y desde CSV). Suite 81 passing. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../inspections/template-manager.blade.php | 135 +++++++++++++++++- tests/Feature/TemplateImportTest.php | 79 ++++++++++ 2 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 tests/Feature/TemplateImportTest.php diff --git a/resources/views/livewire/inspections/template-manager.blade.php b/resources/views/livewire/inspections/template-manager.blade.php index 572fad0..b0905cd 100644 --- a/resources/views/livewire/inspections/template-manager.blade.php +++ b/resources/views/livewire/inspections/template-manager.blade.php @@ -2,7 +2,15 @@

πŸ“‹ {{ __('Inspection templates') }}

-
+
+ + @@ -159,4 +167,129 @@
+ + {{-- ════════════════════════════════════════════════════════════ + MODAL: Importar desde CSV/Excel + ════════════════════════════════════════════════════════════ --}} + @if($showImportFileModal) +
+
+
+
+

{{ __('Import from CSV/Excel') }}

+ +
+
+

+ {{ __('Columns: name, label, type, required, options, min, max, step') }}. + +

+ +
+ + + @error('importTemplateName'){{ $message }}@enderror +
+ +
+ + +
{{ __('Uploading…') }}
+ @error('importFile'){{ $message }}@enderror +
+ + @if($importError) +
{{ $importError }}
+ @endif + +
+ +
+ + {{-- Vista previa de campos detectados --}} + @if(!empty($importPreviewFields)) +
+

{{ count($importPreviewFields) }} {{ __('fields detected') }}:

+
+ + + + @foreach($importPreviewFields as $f) + + + + + + + @endforeach + +
{{ __('Label') }}{{ __('Name') }}{{ __('Type') }}{{ __('Required') }}
{{ $f['label'] }}{{ $f['name'] }}{{ $f['type'] }}{{ !empty($f['required']) ? 'βœ“' : '' }}
+
+
+ @endif +
+
+ + +
+
+
+ @endif + + {{-- ════════════════════════════════════════════════════════════ + MODAL: Importar desde otro proyecto + ════════════════════════════════════════════════════════════ --}} + @if($showImportProjectModal) +
+
+
+
+

{{ __('Import from another project') }}

+ +
+
+
+ + +
+ + @if($importProjectId) + @if(count($importableTemplates)) +
+ @foreach($importableTemplates as $t) + + @endforeach +
+ @else +

{{ __('This project has no templates.') }}

+ @endif + @endif +
+
+ + +
+
+
+ @endif
diff --git a/tests/Feature/TemplateImportTest.php b/tests/Feature/TemplateImportTest.php new file mode 100644 index 0000000..e18b66b --- /dev/null +++ b/tests/Feature/TemplateImportTest.php @@ -0,0 +1,79 @@ + $ref, 'name' => 'Proyecto ' . $ref, 'address' => 'x', + 'lat' => 40.0, 'lng' => -3.0, 'start_date' => now()->toDateString(), + 'end_date_estimated' => now()->addMonth()->toDateString(), + 'status' => 'in_progress', 'created_by' => $member->id, + ]); + $p->users()->attach($member->id, ['role_in_project' => 'supervisor']); + return $p; + } + + public function test_import_templates_from_another_project(): void + { + $user = User::factory()->create(); + $source = $this->project($user, 'SRC'); + $target = $this->project($user, 'DST'); + + $tpl = InspectionTemplate::create([ + 'project_id' => $source->id, 'name' => 'RecepciΓ³n acero', + 'fields' => [['name' => 'ok', 'label' => 'OK', 'type' => 'boolean']], + ]); + + Livewire::actingAs($user) + ->test(TemplateManager::class, ['project' => $target]) + ->call('openImportProjectModal') + ->set('importProjectId', $source->id) + ->set('selectedImportTemplateIds', [$tpl->id]) + ->call('importFromProject') + ->assertHasNoErrors(); + + $this->assertDatabaseHas('inspection_templates', [ + 'project_id' => $target->id, 'name' => 'RecepciΓ³n acero', + ]); + } + + public function test_import_template_from_csv(): void + { + $user = User::factory()->create(); + $project = $this->project($user, 'CSV'); + + $csv = "name,label,type,required,options,min,max,step\n" + . "resistencia,Resistencia,integer,1,,,,\n" + . "acabado,Acabado,select,0,bueno;regular;malo,,,\n"; + $file = UploadedFile::fake()->createWithContent('campos.csv', $csv); + + Livewire::actingAs($user) + ->test(TemplateManager::class, ['project' => $project]) + ->call('openImportFileModal') + ->set('importTemplateName', 'Plantilla CSV') + ->set('importFile', $file) + ->call('parseImportFile') + ->assertHasNoErrors() + ->call('confirmImportFile'); + + $this->assertDatabaseHas('inspection_templates', [ + 'project_id' => $project->id, 'name' => 'Plantilla CSV', + ]); + $tpl = InspectionTemplate::where('name', 'Plantilla CSV')->first(); + $this->assertCount(2, $tpl->fields); + } +}