From 2e614f29291e38ea461e94358b1a9e405a58ca2a Mon Sep 17 00:00:00 2001 From: mrKamoo Date: Mon, 24 Aug 2026 08:18:57 +0200 Subject: [PATCH] =?UTF-8?q?Permet=20de=20d=C3=A9placer=20sch=C3=A9mas=20et?= =?UTF-8?q?=20dossiers=20par=20glisser-d=C3=A9poser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reprend le mécanisme du module Documents (drag & drop + menu déroulant "Déplacer vers"), scopé aux documents de type diagram pour rester isolé du navigateur Documents. Co-Authored-By: Claude Sonnet 5 --- .../infrastructure/⚡index.blade.php | 96 ++++++++++++++++++- tests/Feature/InfrastructureTest.php | 60 ++++++++++++ 2 files changed, 153 insertions(+), 3 deletions(-) diff --git a/resources/views/components/infrastructure/⚡index.blade.php b/resources/views/components/infrastructure/⚡index.blade.php index c4b807e..f7ae421 100644 --- a/resources/views/components/infrastructure/⚡index.blade.php +++ b/resources/views/components/infrastructure/⚡index.blade.php @@ -80,6 +80,42 @@ new class extends Component session()->flash('status', "« {$document->name} » supprimé."); } + public function moveDocument(int $documentId, ?int $targetFolderId): void + { + $document = $this->organization->documents()->where('type', 'diagram')->findOrFail($documentId); + + if ($document->id === $targetFolderId) { + return; + } + + if ($targetFolderId !== null) { + $targetFolder = $this->organization->documents()->where('type', 'diagram')->find($targetFolderId); + + if (! $targetFolder || ! $targetFolder->isFolder()) { + return; + } + + // Prevent moving a folder into itself or one of its own descendants. + if ($document->isFolder()) { + $walk = $targetFolder; + while ($walk) { + if ($walk->id === $document->id) { + return; + } + $walk = $walk->folder; + } + } + } + + if ($document->folder_id === $targetFolderId) { + return; + } + + $document->update(['folder_id' => $targetFolderId]); + + session()->flash('status', "« {$document->name} » déplacé."); + } + private function folderTree(\Illuminate\Support\Collection $allFolders): \Illuminate\Support\Collection { $byParent = $allFolders->groupBy('folder_id'); @@ -190,7 +226,11 @@ new class extends Component @endif -
+ @if ($items->isNotEmpty()) +

Astuce : glissez-déposez un élément sur un dossier pour le déplacer.

+ @endif + +
@@ -203,7 +243,17 @@ new class extends Component @forelse ($items as $item) @php $isFolder = $item->isFolder(); @endphp - + -
@if ($isFolder) @@ -217,10 +267,40 @@ new class extends Component {{ $isFolder ? '—' : ($item->location?->name ?? '—') }} {{ $item->updated_at->diffForHumans() }} + @unless ($isFolder) Ouvrir @endunless + @php + // Exclude the item's own subtree (if it's a folder) so it can't be moved into itself or a descendant. + $excludedIds = [$item->id, $item->folder_id]; + if ($isFolder) { + $stack = [$item->id]; + while ($stack) { + $id = array_pop($stack); + foreach ($folderTree as $node) { + if ($node['folder']->folder_id === $id) { + $excludedIds[] = $node['folder']->id; + $stack[] = $node['folder']->id; + } + } + } + } + $moveTargets = $folderTree->reject(fn ($node) => in_array($node['folder']->id, $excludedIds, true)); + @endphp + @if ($moveTargets->isNotEmpty() || $item->folder_id !== null) + + @endif
+ + @if ($currentFolder) +
+ ⬆️ Glisser ici pour remonter au dossier parent +
+ @endif
diff --git a/tests/Feature/InfrastructureTest.php b/tests/Feature/InfrastructureTest.php index b0c9633..a63ca8b 100644 --- a/tests/Feature/InfrastructureTest.php +++ b/tests/Feature/InfrastructureTest.php @@ -159,4 +159,64 @@ class InfrastructureTest extends TestCase Livewire::test('infrastructure.index', ['organization' => $org, 'locationId' => $otherLocation->id]) ->assertDontSee('Schéma test'); } + + public function test_can_move_a_diagram_into_a_folder_and_back_to_the_root(): void + { + $user = User::factory()->create(); + $org = Organization::create(['name' => 'Test Commune', 'slug' => 'test-commune', 'org_type' => 'client']); + + $folder = $org->documents()->create(['name' => 'Réseau', 'type' => 'diagram', 'is_folder' => true, 'created_by' => $user->id]); + $diagram = $org->documents()->create([ + 'name' => 'Schéma test', 'type' => 'diagram', 'content' => '', + 'current_version' => 1, 'created_by' => $user->id, + ]); + + $this->actingAs($user); + + Livewire::test('infrastructure.index', ['organization' => $org]) + ->call('moveDocument', $diagram->id, $folder->id); + + $this->assertSame($folder->id, $diagram->refresh()->folder_id); + + Livewire::test('infrastructure.index', ['organization' => $org]) + ->call('moveDocument', $diagram->id, null); + + $this->assertNull($diagram->refresh()->folder_id); + } + + public function test_cannot_move_a_folder_into_its_own_descendant(): void + { + $user = User::factory()->create(); + $org = Organization::create(['name' => 'Test Commune', 'slug' => 'test-commune', 'org_type' => 'client']); + + $parent = $org->documents()->create(['name' => 'Parent', 'type' => 'diagram', 'is_folder' => true, 'created_by' => $user->id]); + $child = $org->documents()->create(['name' => 'Enfant', 'type' => 'diagram', 'is_folder' => true, 'folder_id' => $parent->id, 'created_by' => $user->id]); + + $this->actingAs($user); + + Livewire::test('infrastructure.index', ['organization' => $org]) + ->call('moveDocument', $parent->id, $child->id); + + $this->assertNull($parent->refresh()->folder_id); + } + + public function test_moving_an_item_is_scoped_to_diagram_type_documents(): void + { + $user = User::factory()->create(); + $org = Organization::create(['name' => 'Test Commune', 'slug' => 'test-commune', 'org_type' => 'client']); + + $regularFolder = $org->documents()->create(['name' => 'Dossier documents', 'is_folder' => true, 'created_by' => $user->id]); + $diagram = $org->documents()->create([ + 'name' => 'Schéma test', 'type' => 'diagram', 'content' => '', + 'current_version' => 1, 'created_by' => $user->id, + ]); + + $this->actingAs($user); + + // A plain (non-diagram) folder must not be a valid drop target from Infrastructure. + Livewire::test('infrastructure.index', ['organization' => $org]) + ->call('moveDocument', $diagram->id, $regularFolder->id); + + $this->assertNull($diagram->refresh()->folder_id); + } }