Skip to content

Commit 003a4d2

Browse files
-
1 parent 403308e commit 003a4d2

File tree

8 files changed

+181
-5
lines changed

8 files changed

+181
-5
lines changed

docs/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Elasticsearch is a trademark of Elasticsearch BV, registered in the U.S. and in
7373
- License [5.0]: read, status / start trial / revert to basic [6.6], features
7474
- Index graveyard [5.0]: list
7575
- Dangling indices [7.9]: list, import, delete
76-
- Data streams [7.9]: list, read, delete, stats
76+
- Data streams [7.9]: list, create, read, delete, stats
7777

7878
# Screenshots
7979

src/Controller/ElasticsearchDataStreamController.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use App\Controller\AbstractAppController;
66
use App\Exception\CallException;
7+
use App\Form\Type\ElasticsearchDataStreamType;
78
use App\Form\Type\ElasticsearchDataStreamFilterType;
89
use App\Manager\ElasticsearchDataStreamManager;
910
use App\Model\CallRequestModel;
@@ -58,6 +59,42 @@ public function index(Request $request): Response
5859
]);
5960
}
6061

62+
/**
63+
* @Route("/data-streams/create", name="data_streams_create")
64+
*/
65+
public function create(Request $request): Response
66+
{
67+
$this->denyAccessUnlessGranted('DATA_STREAMS_CREATE', 'global');
68+
69+
if (false === $this->callManager->hasFeature('data_streams')) {
70+
throw new AccessDeniedException();
71+
}
72+
73+
$dataStream = new ElasticsearchDataStreamModel();
74+
$form = $this->createForm(ElasticsearchDataStreamType::class, $dataStream);
75+
76+
$form->handleRequest($request);
77+
78+
if ($form->isSubmitted() && $form->isValid()) {
79+
try {
80+
$callRequest = new CallRequestModel();
81+
$callRequest->setMethod('PUT');
82+
$callRequest->setPath('/_data_stream/'.$dataStream->getName());
83+
$callResponse = $this->callManager->call($callRequest);
84+
85+
$this->addFlash('info', json_encode($callResponse->getContent()));
86+
87+
return $this->redirectToRoute('data_streams_read', ['name' => $dataStream->getName()]);
88+
} catch (CallException $e) {
89+
$this->addFlash('danger', $e->getMessage());
90+
}
91+
}
92+
93+
return $this->renderAbstract($request, 'Modules/data_stream/data_stream_create.html.twig', [
94+
'form' => $form->createView(),
95+
]);
96+
}
97+
6198
/**
6299
* @Route("/data-streams/{name}", name="data_streams_read")
63100
*/
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
<?php
2+
3+
namespace App\Form\Type;
4+
5+
use App\Manager\ElasticsearchDataStreamManager;
6+
use App\Model\CallRequestModel;
7+
use App\Model\ElasticsearchDataStreamModel;
8+
use Symfony\Component\HttpFoundation\Response;
9+
use Symfony\Component\Form\AbstractType;
10+
use Symfony\Component\Form\FormBuilderInterface;
11+
use Symfony\Component\Form\Extension\Core\Type\TextType;
12+
use Symfony\Component\Form\FormEvent;
13+
use Symfony\Component\Form\FormEvents;
14+
use Symfony\Component\Form\FormError;
15+
use Symfony\Component\OptionsResolver\OptionsResolver;
16+
use Symfony\Component\Validator\Constraints\NotBlank;
17+
use Symfony\Contracts\Translation\TranslatorInterface;
18+
19+
class ElasticsearchDataStreamType extends AbstractType
20+
{
21+
public function __construct(ElasticsearchDataStreamManager $elasticsearchDataStreamManager, TranslatorInterface $translator)
22+
{
23+
$this->elasticsearchDataStreamManager = $elasticsearchDataStreamManager;
24+
$this->translator = $translator;
25+
}
26+
27+
public function buildForm(FormBuilderInterface $builder, array $options)
28+
{
29+
$fields = [];
30+
31+
if ('create' == $options['context']) {
32+
$fields[] = 'name';
33+
}
34+
35+
foreach ($fields as $field) {
36+
switch ($field) {
37+
case 'name':
38+
$builder->add('name', TextType::class, [
39+
'label' => 'name',
40+
'required' => true,
41+
'constraints' => [
42+
new NotBlank(),
43+
],
44+
'attr' => [
45+
'data-break-after' => 'yes',
46+
],
47+
]);
48+
break;
49+
}
50+
}
51+
52+
$builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use ($options) {
53+
$form = $event->getForm();
54+
55+
if ('create' == $options['context']) {
56+
if ($form->has('name') && $form->get('name')->getData()) {
57+
$index = $this->elasticsearchDataStreamManager->getByName($form->get('name')->getData());
58+
59+
if ($index) {
60+
$form->get('name')->addError(new FormError(
61+
$this->translator->trans('name_already_used')
62+
));
63+
}
64+
}
65+
}
66+
});
67+
}
68+
69+
public function configureOptions(OptionsResolver $resolver)
70+
{
71+
$resolver->setDefaults([
72+
'data_class' => ElasticsearchDataStreamModel::class,
73+
'context' => 'create',
74+
]);
75+
}
76+
77+
public function getBlockPrefix()
78+
{
79+
return 'data';
80+
}
81+
}

src/Manager/AppRoleManager.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class AppRoleManager extends AbstractAppManager
1717
'CLUSTER_SETTINGS', 'CLUSTER_SETTING_EDIT', 'CLUSTER_SETTING_REMOVE', 'CLUSTER_DISK_THRESHOLDS', 'CLUSTER_ALLOCATION_EXPLAIN', 'CLUSTER_AUDIT',
1818
'NODES', 'NODES_STATS', 'NODES_RELOAD_SECURE_SETTINGS',
1919
'INDICES', 'INDICES_STATS', 'INDICES_CREATE', 'INDICES_REINDEX', 'INDICES_FORCE_MERGE', 'INDICES_CACHE_CLEAR', 'INDICES_FLUSH', 'INDICES_REFRESH',
20-
'DATA_STREAMS',
20+
'DATA_STREAMS', 'DATA_STREAMS_CREATE',
2121
'SHARDS', 'SHARDS_STATS', 'SHARDS_REROUTE',
2222
'MENU_CONFIGURATION',
2323
'INDEX_TEMPLATES_LEGACY', 'INDEX_TEMPLATES_LEGACY_CREATE',
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{% extends 'base.html.twig' %}
2+
{% import 'Import/app_import.html.twig' as appImport %}
3+
4+
{% block head_title %}{{ 'data_streams'|trans }} - {{ 'create_data_stream'|trans }}{% endblock %}
5+
6+
{% block heading_1 %}
7+
{{ appImport.heading({'level': 1, 'title': 'data_streams'|trans}) }}
8+
{% endblock %}
9+
10+
{% block tabs %}
11+
{% include 'Modules/data_stream/data_stream_tabs.html.twig' with {'active': 'create_data_stream'} %}
12+
{% endblock %}
13+
14+
{% block main_content %}
15+
{% embed 'Embed/card_embed.html.twig' %}
16+
{% import 'Import/app_import.html.twig' as appImport %}
17+
{% block content %}
18+
{{ appImport.heading({'level': 3, 'title': 'create_data_stream'|trans}) }}
19+
20+
{% embed 'Embed/buttons_embed.html.twig' %}
21+
{% import 'Import/app_import.html.twig' as appImport %}
22+
{% block content %}
23+
<a class="btn btn-secondary btn-sm" rel="noreferrer" target="_blank" href="https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-create-data-stream.html">
24+
{{ 'help'|trans }}
25+
</a>
26+
{% endblock %}
27+
{% endembed %}
28+
29+
{{ appImport.form({'form': form}) }}
30+
{% endblock %}
31+
{% endembed %}
32+
{% endblock %}
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
<ul class="nav nav-tabs mb-4">
2-
<li class="nav-item">
3-
<a class="nav-link{% if 'list' == active %} active{% endif %}" href="{{ path('data_streams') }}">{{ 'list'|trans }}</a>
4-
</li>
2+
{% if is_granted('DATA_STREAMS', 'global') %}
3+
<li class="nav-item">
4+
<a class="nav-link{% if 'list' == active %} active{% endif %}" href="{{ path('data_streams') }}">{{ 'list'|trans }}</a>
5+
</li>
6+
{% endif %}
7+
8+
{% if is_granted('DATA_STREAMS_CREATE', 'global') %}
9+
<li class="nav-item">
10+
<a class="nav-link{% if 'create_data_stream' == active %} active{% endif %}" href="{{ path('data_streams_create') }}">{{ 'create_data_stream'|trans }}</a>
11+
</li>
12+
{% endif %}
513
</ul>

tests/Controller/ElasticsearchDataStreamControllerTest.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,23 @@ public function testIndex()
2424
}
2525
}
2626

27+
/**
28+
* @Route("/data-streams/create", name="data_streams_create")
29+
*/
30+
public function testCreate()
31+
{
32+
$this->client->request('GET', '/admin/data-streams/create');
33+
34+
if (false == $this->callManager->hasFeature('data_streams')) {
35+
$this->assertResponseStatusCodeSame(403);
36+
} else {
37+
$this->assertResponseStatusCodeSame(200);
38+
$this->assertPageTitleSame('Data streams - Create data stream');
39+
$this->assertSelectorTextSame('h1', 'Data streams');
40+
$this->assertSelectorTextSame('h3', 'Create data stream');
41+
}
42+
}
43+
2744
/**
2845
* @Route("/data-streams/{name}", name="data_streams_read")
2946
*/

translations/messages.en.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ coordinator_stats: "Coordinator stats"
180180
cpu: "CPU"
181181
create_component_template: "Create component template"
182182
create_enrich_policy: "Create enrich policy"
183+
create_data_stream: "Create data stream"
183184
create_index: "Create index"
184185
create_index_template: "Create composable index template"
185186
create_index_template_legacy: "Create legacy index template"

0 commit comments

Comments
 (0)