Skip to content

Commit 2b2820a

Browse files
committed
Adapt component display to show all info in one row
1 parent f828a14 commit 2b2820a

File tree

12 files changed

+282
-69
lines changed

12 files changed

+282
-69
lines changed

bundle/Controller/Admin/Components/Index.php

Lines changed: 22 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Netgen\Bundle\LayoutsIbexaBundle\Controller\Admin\Controller;
1515
use Netgen\Layouts\Ibexa\AdminUI\ComponentLayoutsLoader;
1616
use Netgen\Layouts\Ibexa\Form\ComponentFilterType;
17+
use Netgen\Layouts\Ibexa\Search\Contracts\Criterion\IsComponentUsed;
1718
use Pagerfanta\Adapter\AdapterInterface;
1819
use Pagerfanta\Pagerfanta;
1920
use Pagerfanta\PagerfantaInterface;
@@ -23,7 +24,6 @@
2324

2425
use function array_keys;
2526
use function array_values;
26-
use function ksort;
2727
use function max;
2828

2929
final class Index extends Controller
@@ -54,10 +54,9 @@ public function __invoke(Request $request): Response
5454
return $this->render(
5555
'@NetgenLayoutsIbexa/admin/components/index.html.twig',
5656
[
57-
'components' => $this->extractComponents($pager),
57+
'components' => $pager,
5858
'component_layouts' => $this->componentLayoutsLoader->loadLayoutsData(),
5959
'filter_form' => $filterForm->createView(),
60-
'pager' => $pager,
6160
],
6261
);
6362
}
@@ -85,40 +84,32 @@ private function getComponentsQuery(FormInterface $form): LocationQuery
8584
'netgen_layouts',
8685
);
8786

88-
$locationQuery = new LocationQuery();
89-
$locationQuery->filter = new Criterion\LogicalAnd(
90-
[
91-
new Criterion\ParentLocationId(array_values($parentLocationsConfig)),
92-
new Criterion\Location\IsMainLocation(Criterion\Location\IsMainLocation::MAIN),
93-
new Criterion\ContentTypeIdentifier(
94-
$form->get('contentType')->getData() ?? array_keys($parentLocationsConfig),
95-
),
96-
],
97-
);
98-
99-
$locationQuery->sortClauses = [
100-
new SortClause\ContentName(Query::SORT_ASC),
87+
$criteria = [
88+
new Criterion\ParentLocationId(array_values($parentLocationsConfig)),
89+
new Criterion\Location\IsMainLocation(Criterion\Location\IsMainLocation::MAIN),
90+
new Criterion\ContentTypeIdentifier(
91+
$form->get('contentType')->getData() ?? array_keys($parentLocationsConfig),
92+
),
10193
];
10294

103-
return $locationQuery;
104-
}
95+
if ((bool) $form->get('showOnlyUnused')->getData()) {
96+
$criteria[] = new IsComponentUsed(false);
97+
}
10598

106-
/**
107-
* @return array<string, \Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo[]>
108-
*/
109-
private function extractComponents(PagerfantaInterface $pager): array
110-
{
111-
$components = [];
99+
$locationQuery = new LocationQuery();
100+
$locationQuery->filter = new Criterion\LogicalAnd($criteria);
112101

113-
foreach ($pager->getCurrentPageResults() as $location) {
114-
/** @var \Ibexa\Contracts\Core\Repository\Values\Content\Location $location */
115-
$contentTypeName = $location->getContentInfo()->getContentType()->getName();
116-
$components[$contentTypeName][] = $location->getContentInfo();
117-
}
102+
$sortClause = match ($form->get('sortType')->getData()) {
103+
'name' => SortClause\ContentName::class,
104+
'last_modified' => SortClause\DateModified::class,
105+
default => SortClause\ContentName::class,
106+
};
118107

119-
ksort($components);
108+
$locationQuery->sortClauses = [
109+
new $sortClause($form->get('sortDirection')->getData() ?? Query::SORT_ASC),
110+
];
120111

121-
return $components;
112+
return $locationQuery;
122113
}
123114

124115
private function buildPager(AdapterInterface $adapter, Request $request): PagerfantaInterface
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
parameters:
22
netgen_layouts.app.ibexa.item_preview_template: '@@nglayouts_admin/app/item/nglayouts_app_preview.html.twig'
33
netgen_layouts.ibexa.admin.pagelayout: '@@NetgenLayoutsIbexa/admin/pagelayout.html.twig'
4-
netgen_layouts.ibexa.components.limit: 10
4+
netgen_layouts.ibexa.components.limit: 50
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
services:
2+
netgen_layouts.ibexa.search.persistence.criterion_handler.is_component_used:
3+
parent: Ibexa\Core\Search\Legacy\Content\Common\Gateway\CriterionHandler
4+
class: Netgen\Layouts\Ibexa\Search\Persistence\CriterionHandler\IsComponentUsed
5+
tags:
6+
- { name: ibexa.search.legacy.gateway.criterion_handler.content }
7+
- { name: ibexa.search.legacy.gateway.criterion_handler.location }

bundle/Resources/translations/nglayouts_admin.en.yaml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,20 @@ layout_resolver.rule.target_header.ibexa_semantic_path_info_prefix: 'Applied to
88
menu.main_menu.ibexa.components: 'Components'
99

1010
components.title: 'Components'
11-
components.filter_form.content_type.placeholder: 'Select content type'
11+
components.filter_form.content_type.placeholder: 'All content types'
1212
components.filter_form.content_type.label: 'Content type'
13+
components.filter_form.show_only_unused.label: 'Show only unused'
14+
components.filter_form.sort_type.label: 'Sort type'
15+
components.filter_form.sort_type.name: 'Name'
16+
components.filter_form.sort_type.last_modified: 'Last modified'
17+
components.filter_form.sort_direction.label: 'Sort direction'
18+
components.filter_form.sort_direction.ascending: 'Ascending'
19+
components.filter_form.sort_direction.descending: 'Descending'
1320
components.filter_form.button.submit: 'Submit'
1421
components.no_components: 'No components'
1522
components.not_used: 'Not used in any layout'
23+
components.component.name: 'Name'
24+
components.component.content_type: 'Content type'
25+
components.component.last_modified: 'Last modified'
26+
components.component.usage_count: 'Usage count'
27+
components.component.used_in: 'Used in'

bundle/Resources/views/admin/components/index.html.twig

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,44 +16,74 @@
1616

1717
<div class="nl-components-head">
1818
<form method="get">
19-
{{ form_row(filter_form.contentType, {placeholder: 'components.filter_form.content_type.placeholder'}) }}
19+
<div class="filter">
20+
{{ form_row(filter_form.contentType, {placeholder: 'components.filter_form.content_type.placeholder'}) }}
21+
{{ form_row(filter_form.showOnlyUnused) }}
22+
</div>
23+
24+
<div class="sort">
25+
{{ form_row(filter_form.sortType) }}
26+
{{ form_row(filter_form.sortDirection) }}
27+
</div>
28+
2029
{{ form_rest(filter_form) }}
2130

2231
<button type="submit">{{ 'components.filter_form.button.submit'|trans }}</button>
2332
</form>
2433
</div>
2534

2635
<div class="nl-components">
27-
{% for component_type, content_list in components %}
28-
<h1>{{ component_type }}</h1>
29-
36+
{% if components|length > 0 %}
3037
<table>
31-
{% for content in content_list %}
32-
{% set has_layouts = component_layouts[content.id] is defined %}
33-
38+
<thead>
3439
<tr>
35-
<td>
36-
<a href="{{ ibexa_path(content) }}" target="_blank">{{ content.name }}</a>
37-
</td>
38-
<td>
39-
{% if has_layouts %}
40-
{% for layout in component_layouts[content.id]['layouts'] %}
41-
<a href="{{ macros.layout_path(layout.uuid) }}" class="js-open-ngl" target="_blank">{{ layout.name }}</a><br>
42-
{% endfor %}
43-
{% else %}
44-
{{ 'components.not_used'|trans }}
45-
{% endif %}
46-
</td>
40+
<th>{{ 'components.component.name'|trans }}</th>
41+
<th>{{ 'components.component.content_type'|trans }}</th>
42+
<th>{{ 'components.component.last_modified'|trans }}</th>
43+
<th>{{ 'components.component.usage_count'|trans }}</th>
44+
<th>{{ 'components.component.used_in'|trans }}</th>
4745
</tr>
48-
{% endfor %}
46+
</thead>
47+
<tbody>
48+
{% for component in components %}
49+
{% set has_layouts = component_layouts[component.content.id] is defined %}
50+
51+
<tr>
52+
<td>
53+
<a href="{{ ibexa_path(component) }}" target="_blank">{{ component.content.name }}</a>
54+
</td>
55+
<td>
56+
{{ component.content.contentType.name }}
57+
</td>
58+
<td>
59+
{{ component.content.contentInfo.modificationDate|nglayouts_format_datetime }}
60+
</td>
61+
<td>
62+
{{ component_layouts[component.content.id].count|default(0) }}
63+
</td>
64+
<td>
65+
{% if has_layouts %}
66+
{% for layout_data in component_layouts[component.content.id]['layouts'] %}
67+
<p>
68+
<a href="{{ macros.layout_path(layout_data.uuid) }}" class="js-open-ngl" target="_blank">{{ layout_data.name }}</a><br>
69+
{{ layout_data.view_types|map(v => v|humanize)|join(', ') }}
70+
</p>
71+
{% endfor %}
72+
{% else %}
73+
{{ 'components.not_used'|trans }}
74+
{% endif %}
75+
</td>
76+
</tr>
77+
{% endfor %}
78+
</tbody>
4979
</table>
5080
{% else %}
5181
<p class="nl-no-items">{{ 'components.no_components'|trans }}</p>
52-
{% endfor %}
82+
{% endif %}
5383

54-
{% if pager.haveToPaginate() %}
84+
{% if components.haveToPaginate() %}
5585
<div class="paging">
56-
{{ pagerfanta(pager) }}
86+
{{ pagerfanta(components) }}
5787
</div>
5888
{% endif %}
5989
</div>

bundle/Resources/views/themes/admin/content/tab/nglayouts/component_layouts.html.twig

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,13 @@
1616
<div class="layout-dropdown"></div>
1717
</li>
1818

19-
{% for component_layout in component_layouts %}
20-
{{ nglayouts_render_layout(component_layout, {}, 'ibexa_admin') }}
19+
{% for layout_data in component_layouts %}
20+
{{ nglayouts_render_layout(
21+
layout_data.layout, {
22+
additional_data: layout_data.view_types|map(v => v|humanize)|join(', ')
23+
},
24+
'ibexa_admin'
25+
) }}
2126
{% endfor %}
2227
</ul>
2328
{% else %}

bundle/Resources/views/themes/admin/content/tab/nglayouts/layout.html.twig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@
2828
</ul>
2929
</div>
3030
{% endif %}
31+
32+
{% if additional_data|default('') is not empty %}
33+
<div class="additional-data">
34+
{{ additional_data }}
35+
</div>
36+
{% endif %}
3137
</div>
3238

3339
{% if can_clear_cache %}

lib/AdminUI/ComponentLayoutsLoader.php

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,28 @@
99
use Ibexa\Contracts\Core\Repository\Values\Content\ContentInfo;
1010
use JsonException;
1111
use Netgen\Layouts\API\Service\LayoutService;
12-
use Netgen\Layouts\API\Values\Layout\Layout;
1312
use Netgen\Layouts\API\Values\Value;
1413
use Ramsey\Uuid\Uuid;
1514

15+
use function array_column;
1616
use function array_key_exists;
17-
use function array_map;
17+
use function array_merge;
18+
use function count;
1819
use function json_decode;
1920

2021
use const JSON_THROW_ON_ERROR;
2122

2223
final class ComponentLayoutsLoader
2324
{
2425
/**
25-
* @var array<int, array<string, array<int, array<string, mixed>>>>
26+
* @var array<int, array{
27+
* layouts: array<string, array{
28+
* uuid: string,
29+
* name: string,
30+
* view_types: string[]
31+
* }>,
32+
* count: int
33+
* }>
2634
*/
2735
private array $layoutsData;
2836

@@ -34,7 +42,12 @@ public function __construct(
3442
/**
3543
* Returns all layouts in which the provided content is used as a component, sorted by name.
3644
*
37-
* @return iterable<\Netgen\Layouts\API\Values\Layout\Layout>
45+
* @return array<string, array{
46+
* layout: \Netgen\Layouts\API\Values\Layout\Layout,
47+
* uuid: string,
48+
* name: string,
49+
* view_types: string[]
50+
* }>
3851
*/
3952
public function loadComponentLayouts(ContentInfo $contentInfo): iterable
4053
{
@@ -44,20 +57,30 @@ public function loadComponentLayouts(ContentInfo $contentInfo): iterable
4457
return [];
4558
}
4659

47-
return array_map(
48-
fn (array $layoutData): Layout => $this->layoutService->loadLayout(Uuid::fromString($layoutData['uuid'])),
49-
$this->layoutsData[$contentInfo->id]['layouts'],
50-
);
60+
$layoutsData = $this->layoutsData[$contentInfo->id];
61+
62+
foreach ($layoutsData['layouts'] as $uuid => $layoutData) {
63+
$layoutsData['layouts'][$uuid]['layout'] = $this->layoutService->loadLayout(Uuid::fromString($uuid));
64+
}
65+
66+
return $layoutsData['layouts'];
5167
}
5268

5369
/**
54-
* @return array<int, array<string, array<int, array<string, mixed>>>>
70+
* @return array<int, array{
71+
* layouts: array<string, array{
72+
* uuid: string,
73+
* name: string,
74+
* view_types: string[]
75+
* }>,
76+
* count: int
77+
* }>
5578
*/
5679
public function loadLayoutsData(): array
5780
{
5881
$query = $this->databaseConnection->createQueryBuilder();
5982

60-
$query->select('bt.parameters, l.uuid as layout_uuid, l.name as layout_name')
83+
$query->select('b.view_type, bt.parameters, l.uuid as layout_uuid, l.name as layout_name')
6184
->from('nglayouts_block', 'b')
6285
->innerJoin(
6386
'b',
@@ -95,10 +118,17 @@ public function loadLayoutsData(): array
95118
continue;
96119
}
97120

98-
$layoutsData[(int) $decodedParameters['content']]['layouts'][] = [
121+
$layoutsData[(int) $decodedParameters['content']]['layouts'][$dataRow['layout_uuid']] ??= [
99122
'uuid' => $dataRow['layout_uuid'],
100123
'name' => $dataRow['layout_name'],
124+
'view_types' => [],
101125
];
126+
127+
$layoutsData[(int) $decodedParameters['content']]['layouts'][$dataRow['layout_uuid']]['view_types'][] = $dataRow['view_type'];
128+
}
129+
130+
foreach ($layoutsData as $componentId => $componentData) {
131+
$layoutsData[$componentId]['count'] = count(array_merge(...array_column($componentData['layouts'], 'view_types')));
102132
}
103133

104134
return $layoutsData;

0 commit comments

Comments
 (0)