Skip to content

Commit 56f497d

Browse files
authored
Merge pull request #33 from maximehuran/feature/improve-lists
2 parents d86c62a + 00f4808 commit 56f497d

File tree

8 files changed

+220
-7
lines changed

8 files changed

+220
-7
lines changed

config/config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
imports:
22
- { resource: 'images.yaml' }
33
- { resource: 'twig_hooks.yaml' }
4+
5+
parameters:
6+
env(MONSIEURBIZ_SYLIUS_MEDIA_MANAGER_PAGINATION_ITEMS_PER_PAGE): 20
7+
monsieurbiz_sylius_media_manager.pagination.items_per_page: '%env(int:MONSIEURBIZ_SYLIUS_MEDIA_MANAGER_PAGINATION_ITEMS_PER_PAGE)%'

src/Components/SelectionModal/FileListManager.php

Lines changed: 94 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use MonsieurBiz\SyliusMediaManagerPlugin\Repository\FileRepositoryInterface;
2323
use MonsieurBiz\SyliusMediaManagerPlugin\Resolver\FilePathResolverInterface;
2424
use MonsieurBiz\SyliusMediaManagerPlugin\Validator\FileValidatorInterface;
25+
use Symfony\Component\DependencyInjection\Attribute\Autowire;
2526
use Symfony\UX\LiveComponent\Attribute\AsLiveComponent;
2627
use Symfony\UX\LiveComponent\Attribute\LiveAction;
2728
use Symfony\UX\LiveComponent\Attribute\LiveArg;
@@ -49,6 +50,15 @@ final class FileListManager
4950
#[LiveProp(updateFromParent: true)]
5051
public ?string $relativeRootDirectoryPath = null;
5152

53+
#[LiveProp]
54+
public int $currentPage = 1;
55+
56+
#[LiveProp]
57+
public int $itemsPerPage = 20;
58+
59+
#[LiveProp]
60+
public int $totalItems = 0;
61+
5262
#[LiveProp]
5363
/**
5464
* @var File[]
@@ -59,7 +69,10 @@ public function __construct(
5969
private readonly FilePathResolverInterface $filePathResolver,
6070
private readonly FileRepositoryInterface $fileRepository,
6171
private readonly FileValidatorInterface $fileValidator,
72+
#[Autowire(param: 'monsieurbiz_sylius_media_manager.pagination.items_per_page')]
73+
int $defaultItemsPerPage = 20,
6274
) {
75+
$this->itemsPerPage = $defaultItemsPerPage;
6376
}
6477

6578
public function __invoke(): void
@@ -70,9 +83,12 @@ public function __invoke(): void
7083

7184
try {
7285
$relativeDirectoryPath = $this->filePathResolver->getRelativeFilePath($this->absoluteDirectoryPath);
86+
$this->totalItems = $this->fileRepository->countFromPath($this->absoluteDirectoryPath);
7387
$this->fileList = $this->fileRepository->findAllFromPath(
7488
$this->absoluteDirectoryPath,
75-
$relativeDirectoryPath !== $this->relativeRootDirectoryPath
89+
$relativeDirectoryPath !== $this->relativeRootDirectoryPath,
90+
$this->currentPage,
91+
$this->itemsPerPage,
7692
);
7793
} catch (CannotReadFolderException) {
7894
$this->emit('displayError', [
@@ -95,6 +111,7 @@ public function setCurrentDirectory(#[LiveArg] string $absoluteDirectoryPath): v
95111
'absoluteDirectoryPath' => $absoluteDirectoryPath,
96112
], 'MediaManager:SelectionModal');
97113
$this->loaded = false;
114+
$this->currentPage = 1; // Reset to first page when changing directory
98115
}
99116

100117
/**
@@ -150,4 +167,80 @@ public function deleteFile(#[LiveArg] string $fileName): void
150167
'openModalAfterClose' => self::SELECTION_MODAL_NAME,
151168
], 'MediaManager:ConfirmationModal');
152169
}
170+
171+
#[LiveAction]
172+
public function onFileDeleted(): void
173+
{
174+
// Refresh the file list and check if we need to go to previous page
175+
$this->loaded = false;
176+
177+
// If current page becomes empty (except for first page), go to previous page
178+
$totalPages = $this->getTotalPages();
179+
if ($this->currentPage > 1 && $this->currentPage > $totalPages) {
180+
$this->currentPage = max(1, $totalPages);
181+
}
182+
}
183+
184+
#[LiveAction]
185+
public function changeItemsPerPage(#[LiveArg] int $itemsPerPage): void
186+
{
187+
$this->itemsPerPage = $itemsPerPage;
188+
$this->currentPage = 1;
189+
$this->loaded = false;
190+
$this->__invoke();
191+
}
192+
193+
#[LiveAction]
194+
public function goToPage(#[LiveArg] int $page): void
195+
{
196+
$totalPages = $this->getTotalPages();
197+
if ($page < 1) {
198+
$page = 1;
199+
} elseif ($page > $totalPages) {
200+
$page = $totalPages;
201+
}
202+
203+
$this->currentPage = $page;
204+
$this->loaded = false;
205+
}
206+
207+
#[LiveAction]
208+
public function previousPage(): void
209+
{
210+
if ($this->currentPage > 1) {
211+
--$this->currentPage;
212+
$this->loaded = false;
213+
$this->__invoke();
214+
}
215+
}
216+
217+
#[LiveAction]
218+
public function nextPage(): void
219+
{
220+
if ($this->currentPage < $this->getTotalPages()) {
221+
++$this->currentPage;
222+
$this->loaded = false;
223+
$this->__invoke();
224+
}
225+
}
226+
227+
public function getTotalPages(): int
228+
{
229+
return (int) ceil($this->totalItems / $this->itemsPerPage);
230+
}
231+
232+
public function hasMultiplePages(): bool
233+
{
234+
return $this->getTotalPages() > 1;
235+
}
236+
237+
public function hasPreviousPage(): bool
238+
{
239+
return $this->currentPage > 1;
240+
}
241+
242+
public function hasNextPage(): bool
243+
{
244+
return $this->currentPage < $this->getTotalPages();
245+
}
153246
}

src/Repository/FileRepository.php

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,14 @@ public function __construct(
3131
* @inheritDoc
3232
*
3333
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
34+
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
3435
*/
35-
public function findAllFromPath(string $absoluteDirectoryPath, bool $withParentLink = true): array
36-
{
36+
public function findAllFromPath(
37+
string $absoluteDirectoryPath,
38+
bool $withParentLink = true,
39+
int $page = 1,
40+
int $itemsPerPage = 20,
41+
): array {
3742
$elements = [];
3843

3944
if (!is_dir($absoluteDirectoryPath)) {
@@ -44,12 +49,40 @@ public function findAllFromPath(string $absoluteDirectoryPath, bool $withParentL
4449
$elements[] = $this->fileFactory->createParentLinkFile($absoluteDirectoryPath);
4550
}
4651

47-
$list = (new Finder())->in($absoluteDirectoryPath)->depth(0)->sortByName();
52+
$list = (new Finder())->in($absoluteDirectoryPath)->depth(0);
53+
$allFiles = [];
4854
foreach ($list as $file) {
49-
$elements[] = $this->fileFactory->createFromSplFileInfo($file);
55+
$allFiles[] = $this->fileFactory->createFromSplFileInfo($file);
56+
}
57+
58+
// Put folders before files then sort by name case insensitive
59+
usort(
60+
$allFiles,
61+
static fn (FileInterface $fileA, FileInterface $fileB): int => (
62+
FileInterface::TYPE_FOLDER === $fileA->getType() ? 0 : 1
63+
) <=> (FileInterface::TYPE_FOLDER === $fileB->getType() ? 0 : 1)
64+
?: strcasecmp($fileA->getName(), $fileB->getName())
65+
);
66+
67+
// Apply pagination
68+
$offset = ($page - 1) * $itemsPerPage;
69+
$paginatedFiles = \array_slice($allFiles, $offset, $itemsPerPage);
70+
71+
return array_merge($elements, $paginatedFiles);
72+
}
73+
74+
/**
75+
* @inheritDoc
76+
*/
77+
public function countFromPath(string $absoluteDirectoryPath): int
78+
{
79+
if (!is_dir($absoluteDirectoryPath)) {
80+
throw new CannotReadFolderException($absoluteDirectoryPath);
5081
}
5182

52-
return $elements;
83+
$list = (new Finder())->in($absoluteDirectoryPath)->depth(0);
84+
85+
return $list->count();
5386
}
5487

5588
/**

src/Repository/FileRepositoryInterface.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@ interface FileRepositoryInterface
2626
*
2727
* @SuppressWarnings(PHPMD.BooleanArgumentFlag)
2828
*/
29-
public function findAllFromPath(string $absoluteDirectoryPath, bool $withParentLink = true): array;
29+
public function findAllFromPath(string $absoluteDirectoryPath, bool $withParentLink = true, int $page = 1, int $itemsPerPage = 20): array;
30+
31+
/**
32+
* @throws CannotReadFolderException
33+
*/
34+
public function countFromPath(string $absoluteDirectoryPath): int;
3035

3136
/**
3237
* @throws FileNotFoundException

templates/components/SelectionModal/DirectoryManager.html.twig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
class="text-sm cursor-pointer "
1515
data-action="live#action"
1616
data-live-action-param="enabledDirectoryRenameMode"
17+
title="{{ 'monsieurbiz_sylius_media_manager.ui.rename'|trans|escape('html_attr') }}"
1718
>
1819
{{ ux_icon('tabler:pencil') }}
1920
</a>
@@ -24,6 +25,7 @@
2425
class="text-sm cursor-pointer ms-1"
2526
data-action="live#action"
2627
data-live-action-param="enabledDirectoryAddMode"
28+
title="{{ 'monsieurbiz_sylius_media_manager.ui.create_folder'|trans|escape('html_attr') }}"
2729
>
2830
{{ ux_icon('tabler:folder-plus') }}
2931
</a>

templates/components/SelectionModal/FileListManager.html.twig

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,78 @@
5757
</div>
5858
{% endfor %}
5959
</div>
60+
61+
{% if this.hasMultiplePages or this.totalItems > 10 %}
62+
<div class="d-flex justify-content-between align-items-center mt-3">
63+
{% if this.totalItems > 10 %}
64+
<div class="d-flex align-items-center gap-2">
65+
<small class="text-muted">{{ 'monsieurbiz_sylius_media_manager.ui.items_per_page'|trans }}:</small>
66+
<div class="btn-group" role="group">
67+
<button
68+
type="button"
69+
class="btn btn-sm {% if this.itemsPerPage == 10 %}btn-primary{% else %}btn-outline-secondary{% endif %}"
70+
data-action="live#action"
71+
data-live-action-param="changeItemsPerPage"
72+
data-live-items-per-page-param="10"
73+
>10</button>
74+
<button
75+
type="button"
76+
class="btn btn-sm {% if this.itemsPerPage == 20 %}btn-primary{% else %}btn-outline-secondary{% endif %}"
77+
data-action="live#action"
78+
data-live-action-param="changeItemsPerPage"
79+
data-live-items-per-page-param="20"
80+
>20</button>
81+
<button
82+
type="button"
83+
class="btn btn-sm {% if this.itemsPerPage == 50 %}btn-primary{% else %}btn-outline-secondary{% endif %}"
84+
data-action="live#action"
85+
data-live-action-param="changeItemsPerPage"
86+
data-live-items-per-page-param="50"
87+
>50</button>
88+
<button
89+
type="button"
90+
class="btn btn-sm {% if this.itemsPerPage == 100 %}btn-primary{% else %}btn-outline-secondary{% endif %}"
91+
data-action="live#action"
92+
data-live-action-param="changeItemsPerPage"
93+
data-live-items-per-page-param="100"
94+
>100</button>
95+
</div>
96+
</div>
97+
{% else %}
98+
<div></div>
99+
{% endif %}
100+
101+
{% if this.hasMultiplePages %}
102+
<div class="d-flex justify-content-center align-items-center gap-2">
103+
<button
104+
class="btn btn-sm btn-outline-secondary"
105+
data-action="live#action"
106+
data-live-action-param="previousPage"
107+
{% if not this.hasPreviousPage %}disabled{% endif %}
108+
>
109+
{{ ux_icon('tabler:chevron-left') }}
110+
</button>
111+
112+
<span class="text-muted small">
113+
{{ 'monsieurbiz_sylius_media_manager.ui.pagination_info'|trans({
114+
'%current%': this.currentPage,
115+
'%total%': this.totalPages,
116+
'%items%': this.totalItems
117+
}) }}
118+
</span>
119+
120+
<button
121+
class="btn btn-sm btn-outline-secondary"
122+
data-action="live#action"
123+
data-live-action-param="nextPage"
124+
{% if not this.hasNextPage %}disabled{% endif %}
125+
>
126+
{{ ux_icon('tabler:chevron-right') }}
127+
</button>
128+
</div>
129+
{% endif %}
130+
</div>
131+
{% endif %}
60132
{% endif %}
61133
{% endif %}
62134
</div>

translations/messages.en.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ monsieurbiz_sylius_media_manager:
3737
remove_favicon: Remove favicon
3838
remove_confirmation: Are you sure you want to remove this value ? File will not be deleted from server.
3939
empty_folder: This folder is empty. Upload file or create a new folder.
40+
pagination_info: 'Page %current% of %total% (%items% items)'
41+
items_per_page: 'Items per page'
4042
error:
4143
cannot_create_folder: Cannot create the folder.
4244
cannot_delete_folder: Cannot delete the folder.

translations/messages.fr.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ monsieurbiz_sylius_media_manager:
3737
remove_favicon: Retirer l'icône
3838
remove_confirmation: Êtes-vous sûr de vouloir retirer cette valeur ? Le fichier ne sera pas supprimé du serveur.
3939
empty_folder: Ce dossier est vide. Téléchargez un fichier ou créez un nouveau dossier.
40+
pagination_info: 'Page %current% sur %total% (%items% éléments)'
41+
items_per_page: 'Éléments par page'
4042
error:
4143
cannot_create_folder: Impossible de créer le dossier.
4244
cannot_delete_folder: Impossible de supprimer le dossier.

0 commit comments

Comments
 (0)