From 2747fd8f1a666670932104fc8f98947316807b9e Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Tue, 28 Mar 2023 00:28:49 -0400 Subject: [PATCH 1/8] =?UTF-8?q?If=20single=20tab=20mode,=20don=E2=80=99t?= =?UTF-8?q?=20show=20add=20tab=20button.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- resources/js/components/blueprints/Tabs.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/blueprints/Tabs.vue b/resources/js/components/blueprints/Tabs.vue index 9f34a2de72..3b7ef92f83 100644 --- a/resources/js/components/blueprints/Tabs.vue +++ b/resources/js/components/blueprints/Tabs.vue @@ -22,7 +22,7 @@ - + Date: Tue, 28 Mar 2023 00:36:10 -0400 Subject: [PATCH 2/8] Allow user to loop over `{{ sections }}` of fields for rendering `
`s. --- src/Forms/Tags.php | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/Forms/Tags.php b/src/Forms/Tags.php index f1c640c87d..badd938c17 100644 --- a/src/Forms/Tags.php +++ b/src/Forms/Tags.php @@ -63,6 +63,7 @@ public function create() $jsDriver = $this->parseJsParamDriverAndOptions($this->params->get('js'), $form); + $data['sections'] = $this->getSections($this->sessionHandle(), $jsDriver); $data['fields'] = $this->getFields($this->sessionHandle(), $jsDriver); $data['honeypot'] = $form->honeypot(); @@ -209,16 +210,42 @@ protected function getForm() return $handle; } + /** + * Get sections of fields, using sections defined in blueprint. + * + * @param string $sessionHandle + * @param JsDriver $jsDriver + * @return array + */ + protected function getSections($sessionHandle, $jsDriver) + { + // TODO: Add blueprint helper method for this? + $sections = $this->form()->blueprint()->contents()['tabs']['main']['sections']; + + return collect($sections) + ->map(function ($section) use ($sessionHandle, $jsDriver) { + // TODO: Should this be done by blueprint helper method as well? + $fields = new \Statamic\Fields\Fields($section['fields']); + + return [ + 'display' => $section['display'], + 'fields' => $this->getFields($sessionHandle, $jsDriver, $fields->all()), + ]; + }) + ->all(); + } + /** * Get fields with extra data for looping over and rendering. * * @param string $sessionHandle * @param JsDriver $jsDriver + * @param array|null $fields * @return array */ - protected function getFields($sessionHandle, $jsDriver) + protected function getFields($sessionHandle, $jsDriver, $fields = null) { - return $this->form()->fields() + return collect($fields ?? $this->form()->fields()) ->map(function ($field) use ($sessionHandle, $jsDriver) { return $this->getRenderableField($field, $sessionHandle, function ($data, $field) use ($jsDriver) { return $jsDriver From 65b6dae278d94a4ed819834e2caca85a05a68dc7 Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Fri, 14 Apr 2023 15:30:47 -0400 Subject: [PATCH 3/8] Section `display` should be nullable. --- src/Forms/Tags.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Forms/Tags.php b/src/Forms/Tags.php index badd938c17..48e1cd8500 100644 --- a/src/Forms/Tags.php +++ b/src/Forms/Tags.php @@ -228,7 +228,7 @@ protected function getSections($sessionHandle, $jsDriver) $fields = new \Statamic\Fields\Fields($section['fields']); return [ - 'display' => $section['display'], + 'display' => Arr::get($section, 'display'), 'fields' => $this->getFields($sessionHandle, $jsDriver, $fields->all()), ]; }) From 85b46edba6f02e135a36532986c61af2404f3865 Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Fri, 14 Apr 2023 15:31:01 -0400 Subject: [PATCH 4/8] Support nullable section `instructions`. --- src/Forms/Tags.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Forms/Tags.php b/src/Forms/Tags.php index 48e1cd8500..66a51db173 100644 --- a/src/Forms/Tags.php +++ b/src/Forms/Tags.php @@ -229,6 +229,7 @@ protected function getSections($sessionHandle, $jsDriver) return [ 'display' => Arr::get($section, 'display'), + 'instructions' => Arr::get($section, 'instructions'), 'fields' => $this->getFields($sessionHandle, $jsDriver, $fields->all()), ]; }) From e97e611ddc49dbf2c27e053a24d82061dc68c32f Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Fri, 14 Apr 2023 15:46:10 -0400 Subject: [PATCH 5/8] We can get proper Tab, Section, and Fields objects off blueprint natively. --- src/Forms/Tags.php | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/Forms/Tags.php b/src/Forms/Tags.php index 66a51db173..dc876d4011 100644 --- a/src/Forms/Tags.php +++ b/src/Forms/Tags.php @@ -219,18 +219,12 @@ protected function getForm() */ protected function getSections($sessionHandle, $jsDriver) { - // TODO: Add blueprint helper method for this? - $sections = $this->form()->blueprint()->contents()['tabs']['main']['sections']; - - return collect($sections) + return $this->form()->blueprint()->tabs()->first()->sections() ->map(function ($section) use ($sessionHandle, $jsDriver) { - // TODO: Should this be done by blueprint helper method as well? - $fields = new \Statamic\Fields\Fields($section['fields']); - return [ - 'display' => Arr::get($section, 'display'), - 'instructions' => Arr::get($section, 'instructions'), - 'fields' => $this->getFields($sessionHandle, $jsDriver, $fields->all()), + 'display' => $section->display(), + 'instructions' => $section->instructions(), + 'fields' => $this->getFields($sessionHandle, $jsDriver, $section->fields()->all()), ]; }) ->all(); From 9047467ab454799f5d6d70044941e1183d9a82a0 Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Tue, 18 Apr 2023 10:56:28 -0400 Subject: [PATCH 6/8] Improve form creation helper. --- tests/Tags/Form/FormTestCase.php | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/Tags/Form/FormTestCase.php b/tests/Tags/Form/FormTestCase.php index 443851794e..7627a11228 100644 --- a/tests/Tags/Form/FormTestCase.php +++ b/tests/Tags/Form/FormTestCase.php @@ -49,7 +49,7 @@ public function setUp(): void { parent::setUp(); - $this->createContactForm(); + $this->createForm(); $this->clearSubmissions(); } @@ -72,13 +72,15 @@ protected function tag($tag) return Parse::template($tag, []); } - protected function createContactForm($fields = null) + protected function createForm($blueprintContents = null, $handle = null) { - $blueprint = Blueprint::make()->setContents([ - 'fields' => $fields ?? $this->defaultFields, - ]); + $defaultBlueprintContents = [ + 'fields' => $this->defaultFields, + ]; - $handle = $fields ? $this->customFieldBlueprintHandle : 'contact'; + $blueprint = Blueprint::make()->setContents($blueprintContents ?? $defaultBlueprintContents); + + $handle = $handle ?? 'contact'; Blueprint::shouldReceive('find')->with("forms.{$handle}")->andReturn($blueprint); Blueprint::makePartial(); @@ -93,13 +95,13 @@ protected function assertFieldRendersHtml($expectedHtmlParts, $fieldConfig, $old { $randomString = str_shuffle('nobodymesseswiththehoff'); - $this->customFieldBlueprintHandle = $handle = $fieldConfig['handle'].'_'.$randomString; + $handle = $fieldConfig['handle'].'_'.$randomString; $fields = $oldData ? array_merge([['handle' => 'failing_field', 'field' => ['type' => 'text', 'validate' => 'required']]], [$fieldConfig]) : [$fieldConfig]; - $this->createContactForm($fields); + $this->createForm(['fields' => $fields], $handle); if ($oldData) { $this->post('/!/forms/'.$handle, $oldData) From 4f43a925ad2f9b645650a4f96950fed3eda986f8 Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Tue, 18 Apr 2023 11:35:09 -0400 Subject: [PATCH 7/8] Add test for dynamically rendering new `sections` array. --- tests/Tags/Form/FormCreateTest.php | 55 ++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tests/Tags/Form/FormCreateTest.php b/tests/Tags/Form/FormCreateTest.php index d64adedbe4..1c308b6542 100644 --- a/tests/Tags/Form/FormCreateTest.php +++ b/tests/Tags/Form/FormCreateTest.php @@ -447,6 +447,61 @@ public function it_dynamically_renders_field_with_fallback_to_default_partial() ]); } + /** @test */ + public function it_dynamically_renders_sections_array() + { + $this->createForm([ + 'tabs' => [ + 'main' => [ + 'sections' => [ + [ + 'display' => 'One', + 'instructions' => 'One Instructions', + 'fields' => [ + ['handle' => 'alpha', 'field' => ['type' => 'text']], + ['handle' => 'bravo', 'field' => ['type' => 'text']], + ], + ], + [ + 'display' => 'Two', + 'instructions' => 'Two Instructions', + 'fields' => [ + ['handle' => 'charlie', 'field' => ['type' => 'text']], + ['handle' => 'delta', 'field' => ['type' => 'text']], + ], + ], + [ + 'display' => null, + 'instructions' => null, + 'fields' => [ + ['handle' => 'echo', 'field' => ['type' => 'text']], + ['handle' => 'fox', 'field' => ['type' => 'text']], + ], + ], + ], + ], + ], + ], 'survey'); + + $output = $this->normalizeHtml($this->tag(<<<'EOT' +{{ form:survey }} + {{ sections }} +
{{ if display}}{{ display }} - {{ /if }}{{ if instructions }}{{ instructions }} - {{ /if }}{{ fields | pluck('handle') | join(',') }}
+ {{ /sections }} +
{{ fields | pluck('handle') | join(',') }}
+{{ /form:survey }} +EOT + )); + + $this->assertStringContainsString('
One - One Instructions - alpha,bravo
', $output); + $this->assertStringContainsString('
Two - Two Instructions - charlie,delta
', $output); + $this->assertStringContainsString('
echo,fox
', $output); + + // Even though the fields are all nested within sections, + // we should still be able to get them via `{{ fields }}` array at top level... + $this->assertStringContainsString('
alpha,bravo,charlie,delta,echo,fox
', $output); + } + /** @test */ public function it_wont_submit_form_and_renders_errors() { From d1e75f6c5cce88db2d64763778189b1ddbb77d91 Mon Sep 17 00:00:00 2001 From: Jesse Leite Date: Tue, 18 Apr 2023 11:35:18 -0400 Subject: [PATCH 8/8] Rename for consistency. --- tests/Tags/Form/FormCreateTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Tags/Form/FormCreateTest.php b/tests/Tags/Form/FormCreateTest.php index 1c308b6542..018aab23d2 100644 --- a/tests/Tags/Form/FormCreateTest.php +++ b/tests/Tags/Form/FormCreateTest.php @@ -48,7 +48,7 @@ public function it_renders_form_with_redirects_to_anchor() } /** @test */ - public function it_renders_form_dynamically_with_fields_array() + public function it_dynamically_renders_fields_array() { $output = $this->normalizeHtml($this->tag(<<<'EOT' {{ form:contact }}