Skip to content

Commit 774b3e7

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents c96e933 + 9653977 commit 774b3e7

10 files changed

Lines changed: 243 additions & 15 deletions

File tree

src/Entity/Client.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class Client
1818
#[ORM\Column(type: 'uuid')]
1919
private ?Uuid $id = null;
2020

21-
#[ORM\Column(length: 64, nullable: true)]
21+
#[ORM\Column(length: 64, unique: true, nullable: true)]
2222
private ?string $alias = null;
2323

2424
#[ORM\Column(length: 255, nullable: true)]

src/Model/Topbar/TopbarLiveSearch.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class TopbarLiveSearch extends Topbar
88
{
99
/**
10-
* @var array<string, array{route: string, routeParameters: array<string, string|int>, label: string}>
10+
* @var array<string, array{route: string, routeparameters: array<string, string|int>, label: string}>
1111
*/
1212
protected array $data = [];
1313

@@ -31,7 +31,7 @@ public function __construct(
3131
}
3232

3333
/**
34-
* @param array<string, array{route: string, routeParameters: array<string, string|int>, label: string}> $data
34+
* @param array<string, array{route: string, routeparameters: array<string, string|int>, label: string}> $data
3535
*/
3636
public function setData(array $data): void
3737
{
@@ -40,7 +40,7 @@ public function setData(array $data): void
4040
}
4141

4242
/**
43-
* @param array<string, array{route: string, routeParameters: array<string, string|int>, label: string}> $data
43+
* @param array<string, array{route: string, routeparameters: array<string, string|int>, label: string}> $data
4444
*/
4545
public function addData(array $data): void
4646
{
@@ -49,7 +49,7 @@ public function addData(array $data): void
4949
}
5050

5151
/**
52-
* @return array<string, array{route: string, routeParameters: array<string, string|int>, label: string}> $data
52+
* @return array<string, array{route: string, routeparameters: array<string, string|int>, label: string}> $data
5353
*/
5454
public function getData(): array
5555
{
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace JBSNewMedia\VisBundle\Model\Topbar;
6+
7+
use JBSNewMedia\VisBundle\Service\Vis;
8+
9+
class TopbarLiveSearchClients extends TopbarLiveSearch
10+
{
11+
protected Vis $vis;
12+
13+
protected bool $dataSet = false;
14+
15+
public function __construct(
16+
string $tool,
17+
string $id = 'dropdown_clients_end',
18+
string $position = 'end',
19+
) {
20+
parent::__construct($tool, $id);
21+
$this->setPosition($position);
22+
$this->setClass('btn btn-link justify-content-center align-items-center avalynx-simpleadmin-header-button');
23+
$this->setContent('<i class="fa-solid fa-building fa-fw"></i>');
24+
$this->setLabel('Clients');
25+
$this->setLabelSearch('Search');
26+
$this->setOrder(90);
27+
$this->setContentFilter('raw');
28+
$this->setTemplate('@Vis/topbar/livesearch_clients.html.twig');
29+
}
30+
31+
public function getLabel(): string
32+
{
33+
$title = $this->getVis()->getSelectedClientTitle();
34+
if ($title) {
35+
return $title;
36+
}
37+
38+
return $this->getVis()->getTranslator()->trans('main.livesearch.client_select', domain: 'vis');
39+
}
40+
41+
public function getContent(): string
42+
{
43+
return '<i class="fa-solid fa-building fa-fw"></i>';
44+
}
45+
46+
public function setVis(Vis $vis): void
47+
{
48+
$this->vis = $vis;
49+
}
50+
51+
public function getVis(): Vis
52+
{
53+
return $this->vis;
54+
}
55+
56+
protected function isDataSet(): bool
57+
{
58+
return $this->dataSet;
59+
}
60+
61+
protected function setVisData(): void
62+
{
63+
$this->dataSet = true;
64+
$data = [];
65+
$selectedId = $this->getVis()->getSelectedClientId();
66+
foreach ($this->getVis()->getClients() as $id => $title) {
67+
$data[$id] = [
68+
'route' => 'vis_api_client',
69+
'routeparameters' => ['id' => $id],
70+
'label' => $title,
71+
];
72+
}
73+
$this->setData($data);
74+
$this->setDataKey($selectedId);
75+
}
76+
77+
public function getDataCounter(): int
78+
{
79+
if (true !== $this->isDataSet()) {
80+
$this->setVisData();
81+
}
82+
83+
return parent::getDataCounter();
84+
}
85+
}

src/Model/Topbar/TopbarLiveSearchTools.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ protected function setVisData(): void
4949
foreach ($this->getVis()->getTools() as $tool) {
5050
$data[$tool->getId()] = [
5151
'route' => 'vis_'.$tool->getId(),
52-
'routeParameters' => [],
52+
'routeparameters' => [],
5353
'label' => $tool->getTitle(),
5454
];
5555
}

src/Service/Vis.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use JBSNewMedia\VisBundle\Model\Topbar\TopbarDropdownLocale;
1313
use Symfony\Bundle\SecurityBundle\Security;
1414
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
15+
use Symfony\Component\HttpFoundation\RequestStack;
1516
use Symfony\Contracts\Translation\TranslatorInterface;
1617

1718
class Vis
@@ -26,6 +27,11 @@ class Vis
2627

2728
protected string $toolId = '';
2829

30+
/**
31+
* @var array<string, string>
32+
*/
33+
protected array $clients = [];
34+
2935
protected int $toolsCounter = 0;
3036

3137
/**
@@ -45,13 +51,16 @@ class Vis
4551

4652
protected bool $sidebarClosed = false;
4753

54+
protected string $selectedClientId = '';
55+
4856
/**
4957
* @param string[] $locales
5058
*/
5159
public function __construct(
5260
protected TranslatorInterface $translator,
5361
protected UrlGeneratorInterface $router,
5462
protected Security $security,
63+
protected RequestStack $requestStack,
5564
protected array $locales = ['en'],
5665
protected string $defaultLocale = 'en',
5766
) {
@@ -131,6 +140,42 @@ public function getTools(): array
131140
return $this->tools;
132141
}
133142

143+
/**
144+
* @param array<string, string> $clients
145+
*/
146+
public function setClients(array $clients): void
147+
{
148+
$this->clients = $clients;
149+
}
150+
151+
/**
152+
* @return array<string, string>
153+
*/
154+
public function getClients(): array
155+
{
156+
return $this->clients;
157+
}
158+
159+
public function setSelectedClientId(string $clientId): void
160+
{
161+
$this->selectedClientId = $clientId;
162+
$this->requestStack->getSession()->set('_vis_client_id', $clientId);
163+
}
164+
165+
public function getSelectedClientId(): string
166+
{
167+
if ($this->selectedClientId === '') {
168+
$this->selectedClientId = (string) $this->requestStack->getSession()->get('_vis_client_id', '');
169+
}
170+
return $this->selectedClientId;
171+
}
172+
173+
public function getSelectedClientTitle(): ?string
174+
{
175+
$id = $this->getSelectedClientId();
176+
return $this->clients[$id] ?? null;
177+
}
178+
134179
protected function incToolsCounter(): void
135180
{
136181
++$this->toolsCounter;

templates/topbar/livesearch.html.twig

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,18 @@
66
{{ item.content|dynamic_filter(item.contentFilter) }}
77
{% endif %}
88
</button>
9-
<ul class="dropdown-menu dropdown-menu-end rounded-0 me-1 avalynx-simpleadmin-livesearch{% if vis.toolscounter > item.countForSearch %} avalynx-simpleadmin-livesearch-show{% endif %}" aria-labelledby="{{ item.id }}">
10-
<li>
11-
<span class="dropdown-item-text">
12-
<input type="text" class="form-control avalynx-simpleadmin-livesearch-input" placeholder="{{ item.labelSearch }}">
13-
</span>
14-
</li>
9+
<ul class="dropdown-menu dropdown-menu-end rounded-0 me-1 avalynx-simpleadmin-livesearch{% if item.dataCounter > item.countForSearch %} avalynx-simpleadmin-livesearch-show avalynx-simpleadmin-livesearch-results{% endif %}" aria-labelledby="{{ item.id }}">
10+
{% if item.dataCounter > item.countForSearch %}
11+
<li>
12+
<span class="dropdown-item-text">
13+
<input type="text" class="form-control avalynx-simpleadmin-livesearch-input" placeholder="{{ item.labelSearch }}">
14+
</span>
15+
</li>
16+
{% else %}
17+
<li aria-hidden="true" class="vis-livesearch-placeholder"></li>
18+
{% endif %}
1519
{% for data_id, data_details in item.data %}
16-
<li class="d-none">
20+
<li class="{% if item.dataCounter > item.countForSearch and item.dataKey != data_id %}d-none {% endif %}vis-livesearch-item">
1721
<a class="dropdown-item{% if item.dataKey == data_id %} active{% endif %}" href="{{ path(data_details.route, data_details.routeparameters|default({})) }}">{{ data_details.label }}</a>
1822
</li>
1923
{% endfor %}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
{% if item.dataCounter > 0 %}
2+
<button class="{{ item.class }}" data-bs-toggle="dropdown" aria-expanded="false" title="{{ item.label }}" id="{{ item.id }}">
3+
{% if item.contentFilter == '' %}
4+
{{ item.content }}
5+
{% else %}
6+
{{ item.content|dynamic_filter(item.contentFilter) }}
7+
{% endif %}
8+
</button>
9+
<ul class="dropdown-menu dropdown-menu-end rounded-0 me-1 avalynx-simpleadmin-livesearch{% if item.dataCounter > item.countForSearch %} avalynx-simpleadmin-livesearch-show avalynx-simpleadmin-livesearch-results{% endif %}" aria-labelledby="{{ item.id }}">
10+
{% if item.dataCounter > item.countForSearch %}
11+
<li>
12+
<span class="dropdown-item-text">
13+
<input type="text" class="form-control avalynx-simpleadmin-livesearch-input" placeholder="{{ item.labelSearch }}">
14+
</span>
15+
</li>
16+
{% else %}
17+
<li aria-hidden="true" class="vis-livesearch-placeholder"></li>
18+
{% endif %}
19+
{% for data_id, data_details in item.data %}
20+
<li class="{% if item.dataCounter > item.countForSearch and item.dataKey != data_id %}d-none {% endif %}vis-livesearch-item">
21+
<div class="dropdown-item vis-client-item{% if item.dataKey == data_id %} active{% endif %}" style="cursor: pointer;" onclick="changeClient('{{ path(data_details.route, (data_details.routeParameters|default(data_details.routeparameters|default({})))|merge({'timestamp': '__TIMESTAMP__'})) }}'.replace('__TIMESTAMP__', Date.now()))">
22+
{{ data_details.label }}
23+
</div>
24+
</li>
25+
{% endfor %}
26+
</ul>
27+
28+
<script>
29+
if (typeof changeClient !== 'function') {
30+
function changeClient(url) {
31+
fetch(url, {
32+
method: 'GET',
33+
headers: {
34+
'X-Requested-With': 'XMLHttpRequest'
35+
}
36+
})
37+
.then(response => response.json())
38+
.then(data => {
39+
if (data.success) {
40+
location.reload();
41+
}
42+
})
43+
.catch(error => {
44+
console.error('Error changing client:', error);
45+
});
46+
}
47+
}
48+
</script>
49+
{% endif %}

tests/Model/Topbar/TopbarLiveSearchTest.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,15 @@ public function testData(): void
2626
$data = [
2727
'tool1' => [
2828
'route' => 'vis_tool1',
29-
'routeParameters' => [],
29+
'routeparameters' => [],
3030
'label' => 'Tool 1'
3131
]
3232
];
3333
$search->setData($data);
3434
$this->assertEquals($data, $search->getData());
3535
$this->assertEquals(1, $search->getDataCounter());
3636

37-
$search->addData(['tool2' => ['route' => 'vis_tool2', 'routeParameters' => [], 'label' => 'Tool 2']]);
37+
$search->addData(['tool2' => ['route' => 'vis_tool2', 'routeparameters' => [], 'label' => 'Tool 2']]);
3838
$this->assertCount(2, $search->getData());
3939
$this->assertEquals(2, $search->getDataCounter());
4040
}
@@ -89,3 +89,44 @@ public function testSetVisAndDataLoading(): void
8989
$this->assertEquals('Title 1', $data['tool1']['label']);
9090
}
9191
}
92+
93+
class TopbarLiveSearchClientsTest extends TestCase
94+
{
95+
public function testConstructor(): void
96+
{
97+
$clientsSearch = new \JBSNewMedia\VisBundle\Model\Topbar\TopbarLiveSearchClients('test_tool');
98+
$this->assertEquals('dropdown_clients_end', $clientsSearch->getId());
99+
$this->assertEquals('end', $clientsSearch->getPosition());
100+
$this->assertEquals(90, $clientsSearch->getOrder());
101+
}
102+
103+
public function testSetVisAndDataLoading(): void
104+
{
105+
$vis = $this->createMock(Vis::class);
106+
$vis->method('getClients')->willReturn(['id1' => 'Client 1', 'id2' => 'Client 2']);
107+
$vis->method('getSelectedClientId')->willReturn('id1');
108+
$vis->method('getSelectedClientTitle')->willReturn('Client 1');
109+
$translator = $this->createMock(\Symfony\Contracts\Translation\TranslatorInterface::class);
110+
$vis->method('getTranslator')->willReturn($translator);
111+
112+
$clientsSearch = new \JBSNewMedia\VisBundle\Model\Topbar\TopbarLiveSearchClients('test_tool');
113+
$clientsSearch->setVis($vis);
114+
$this->assertSame($vis, $clientsSearch->getVis());
115+
116+
// getDataCounter triggers setVisData
117+
$count = $clientsSearch->getDataCounter();
118+
$this->assertEquals(2, $count);
119+
120+
$data = $clientsSearch->getData();
121+
$this->assertArrayHasKey('id1', $data);
122+
$this->assertEquals('vis_api_client', $data['id1']['route']);
123+
$this->assertEquals(['id' => 'id1'], $data['id1']['routeparameters']);
124+
$this->assertEquals('Client 1', $data['id1']['label']);
125+
126+
$content = $clientsSearch->getContent();
127+
$this->assertEquals('<i class="fa-solid fa-building fa-fw"></i>', $content);
128+
129+
$label = $clientsSearch->getLabel();
130+
$this->assertEquals('Client 1', $label);
131+
}
132+
}

translations/vis.de.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ main:
1010
sidebar: "Sidebar umschalten"
1111
livesearch:
1212
tools: "Tool wechseln"
13+
clients: "Mandant wechseln"
14+
client_select: "Mandant wählen"
1315
placeholder: "Suchen..."
1416
profile:
1517
default: "Profil"

translations/vis.en.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ main:
1010
sidebar: "Toggle sidebar"
1111
livesearch:
1212
tools: "Change tool"
13+
clients: "Change client"
14+
client_select: "Select client"
1315
placeholder: "Search..."
1416
profile:
1517
default: "Profile"

0 commit comments

Comments
 (0)