Skip to content

Commit 463e93e

Browse files
author
Michael Yu
committed
Merge remote-tracking branch 'origin/MC-515-parent-container-for-content-types' into cms-team-2-sprint-12
2 parents 7993fa8 + 334026a commit 463e93e

File tree

74 files changed

+2637
-405
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+2637
-405
lines changed

app/code/Magento/PageBuilder/Model/Config/ContentType/Converter.php

Lines changed: 144 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ public function convert($source): array
5050
private function convertTypes(\DOMDocument $source): array
5151
{
5252
$typesData = [];
53+
$parentChildData = [];
5354
/** @var \DOMNodeList $contentTypes */
5455
$contentTypes = $source->getElementsByTagName('type');
5556
/** @var \DOMNode $contentType */
@@ -66,12 +67,16 @@ private function convertTypes(\DOMDocument $source): array
6667
$typesData[$name][$childNode->nodeName] = $this->convertAppearancesData($childNode);
6768
} elseif ('additional_data' === $childNode->nodeName) {
6869
$typesData[$name][$childNode->nodeName] = $this->convertAdditionalData($childNode);
69-
} elseif ('allowed_parents' === $childNode->nodeName) {
70-
$parents = [];
71-
foreach ($childNode->getElementsByTagName('parent') as $parentNode) {
72-
$parents[] = $parentNode->attributes->getNamedItem('name')->nodeValue;
73-
}
74-
$typesData[$name][$childNode->nodeName] = $parents;
70+
} elseif ('parents' === $childNode->nodeName) {
71+
$parentChildData[$name][$childNode->nodeName] = [
72+
'defaultPolicy' => $this->getAttributeValue($childNode, 'default_policy'),
73+
'types' => $this->convertParentChildData($childNode, 'parent')
74+
];
75+
} elseif ('children' === $childNode->nodeName) {
76+
$parentChildData[$name][$childNode->nodeName] = [
77+
'defaultPolicy' => $this->getAttributeValue($childNode, 'default_policy'),
78+
'types' => $this->convertParentChildData($childNode, 'child')
79+
];
7580
} else {
7681
$typesData[$name][$childNode->nodeName] = $childNode->nodeValue;
7782
}
@@ -83,7 +88,9 @@ private function convertTypes(\DOMDocument $source): array
8388
return (int)$firstElement['sortOrder'] <=> (int)$secondElement['sortOrder'];
8489
});
8590

86-
return $typesData;
91+
$allowedParents = $this->convertParentChildDataToAllowedParents(array_keys($typesData), $parentChildData);
92+
93+
return array_merge_recursive($typesData, $allowedParents);
8794
}
8895

8996
/**
@@ -428,6 +435,120 @@ private function convertConvertersData(\DOMElement $childNode): array
428435
return $converters;
429436
}
430437

438+
/**
439+
* Convert parent and child data to correct format
440+
*
441+
* @param \DOMElement $elementNode
442+
* @param string $tagName
443+
* @return array
444+
*/
445+
private function convertParentChildData(\DOMElement $elementNode, string $tagName): array
446+
{
447+
$data = [];
448+
foreach ($elementNode->getElementsByTagName($tagName) as $node) {
449+
$name = $node->attributes->getNamedItem('name')->nodeValue;
450+
$data[$node->attributes->getNamedItem('policy')->nodeValue][] = $name;
451+
}
452+
return $data;
453+
}
454+
455+
/**
456+
* Convert parent and child data to allowed parents
457+
*
458+
* @param array $types
459+
* @param array $parentChildData
460+
* @return array
461+
*/
462+
private function convertParentChildDataToAllowedParents(array $types, array $parentChildData): array
463+
{
464+
$allowedParentsData = [];
465+
466+
// convert children
467+
$allowedParents = $this->convertChildrenToAllowedParents($parentChildData, $types);
468+
foreach ($types as $type) {
469+
$allowedParentsData[$type]['allowed_parents'] = $allowedParents[$type];
470+
}
471+
472+
// convert parents
473+
$allowedParentsData = $this->convertParentsToAllowedParents($parentChildData, $types, $allowedParentsData);
474+
475+
return $allowedParentsData;
476+
}
477+
478+
/**
479+
* Convert children data to allow parents
480+
*
481+
* @param array $parentChildData
482+
* @param array $types
483+
* @return array
484+
*/
485+
private function convertChildrenToAllowedParents(array $parentChildData, array $types): array
486+
{
487+
$allowedParents = [];
488+
489+
// setup allowed parents array
490+
foreach ($types as $type) {
491+
$allowedParents[$type] = [];
492+
}
493+
494+
foreach ($parentChildData as $key => $value) {
495+
$children = $value['children'] ?? [];
496+
497+
if (empty($children)) {
498+
continue;
499+
}
500+
501+
foreach ($allowedParents as $type => $parents) {
502+
$typeAllowed = in_array($type, $children['types']['allow'] ?? []);
503+
$typeDenied = in_array($type, $children['types']['deny'] ?? []);
504+
if (($children['defaultPolicy'] === 'deny' && !$typeAllowed) || $typeDenied) {
505+
$allowedParents[$type] = $this->removeDataInArray($key, $parents);
506+
} else {
507+
$allowedParents[$type][] = $key;
508+
}
509+
}
510+
}
511+
512+
return $allowedParents;
513+
}
514+
515+
/**
516+
* Convert parents data to allowed parents
517+
*
518+
* @param array $parentChildData
519+
* @param array $types
520+
* @param array $allowedParentsData
521+
* @return array
522+
*/
523+
private function convertParentsToAllowedParents(
524+
array $parentChildData,
525+
array $types,
526+
array $allowedParentsData
527+
): array {
528+
foreach ($parentChildData as $key => $value) {
529+
$parent = $value['parents'] ?? [];
530+
531+
if (empty($parent)) {
532+
continue;
533+
}
534+
535+
$allowedTypes = $parent['types']['allow'] ?? [];
536+
$deniedTypes = $parent['types']['deny'] ?? [];
537+
538+
if ($parent['defaultPolicy'] === 'deny') {
539+
$allowedParents = $allowedTypes;
540+
} else {
541+
$allowedParents = array_merge($types, $allowedTypes);
542+
foreach ($deniedTypes as $type) {
543+
$allowedParents = $this->removeDataInArray($type, $allowedParents);
544+
}
545+
}
546+
$allowedParentsData[$key]['allowed_parents'] = $allowedParents;
547+
}
548+
549+
return $allowedParentsData;
550+
}
551+
431552
/**
432553
* Check if node is configuration node
433554
*
@@ -467,4 +588,20 @@ private function extractVariableName(\DOMElement $node): string
467588
return $this->getAttributeValue($node, 'storage_key')
468589
?: $this->getAttributeValue($node, 'name');
469590
}
591+
592+
/**
593+
* Remove data from array
594+
*
595+
* @param $searchValue
596+
* @param $data
597+
* @return array
598+
*/
599+
private function removeDataInArray(string $searchValue, array $data): array
600+
{
601+
$removeKey = array_search($searchValue, $data);
602+
if ($removeKey !== false) {
603+
unset($data[$removeKey]);
604+
}
605+
return array_values($data);
606+
}
470607
}

app/code/Magento/PageBuilder/Model/Config/ContentType/Reader.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ class Reader extends \Magento\Framework\Config\Reader\Filesystem
1919
*/
2020
protected $_idAttributes = [
2121
self::TYPE_PATH => 'name',
22-
self::TYPE_PATH . '/allowed_parents/parent' => 'name',
22+
self::TYPE_PATH . '/parents/parent' => 'name',
23+
self::TYPE_PATH . '/children/child' => 'name',
2324
self::TYPE_PATH . '/appearances/appearance' => 'name',
2425
self::TYPE_PATH . '/appearances/appearance/data' => 'name',
2526
self::TYPE_PATH . '/appearances/appearance/data_mapping/elements/element' => 'name',

app/code/Magento/PageBuilder/Test/Mftf/ActionGroup/DragAndDropActionGroup.xml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,22 @@
9898
<waitForPageLoad time="30" stepKey="waitForAnimation"/>
9999
<waitForElementVisible time="30" selector="{{PageBuilderStage.contentTypeInStageByIndex(contentType.role, contentTypeIndex)}}" stepKey="waitForContentTypeInStage"/>
100100
</actionGroup>
101+
<actionGroup name="cannotDragContentTypeToTarget">
102+
<arguments>
103+
<argument name="contentType"/>
104+
<argument name="contentTypeIndex" defaultValue="1" type="string"/>
105+
<argument name="containerTargetType"/>
106+
<argument name="containerTargetIndex" defaultValue="1" type="string"/>
107+
<argument name="dropZoneIndex" defaultValue="1" type="string"/>
108+
<argument name="offsetXCoordinate" defaultValue="null" type="string"/>
109+
<argument name="offsetYCoordinate" defaultValue="null" type="string"/>
110+
</arguments>
111+
<scrollTo selector="{{CmsNewPagePageActionsSection.contentSectionName}}" stepKey="scrollToTopOfStage"/>
112+
<waitForElement time="30" selector="{{PageBuilderStage.dropZone(containerTargetType.role, containerTargetIndex, dropZoneIndex)}}" stepKey="waitForTargetActive"/>
113+
<dragAndDrop selector1="{{PageBuilderPanel.draggableContentTypeInPanel(contentType.name)}}" selector2="{{PageBuilderStage.dropZone(containerTargetType.role, containerTargetIndex, dropZoneIndex)}}" x="{{offsetXCoordinate}}" y="{{offsetYCoordinate}}" stepKey="dragContentTypeIntoTarget"/>
114+
<waitForPageLoad time="30" stepKey="waitForAnimation"/>
115+
<dontSeeElementInDOM selector="{{PageBuilderStage.contentTypeInStageByIndex(contentType.role, contentTypeIndex)}}" stepKey="dontSeeElement"/>
116+
</actionGroup>
101117
<actionGroup name="moveContentTypeToContainer">
102118
<arguments>
103119
<argument name="contentType"/>

app/code/Magento/PageBuilder/Test/Mftf/ActionGroup/StageActionGroup.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,15 @@
4646
</arguments>
4747
<waitForElementVisible time="30" selector="{{PageBuilderStage.contentTypeInsideContainerStage(containerTargetType.role, containerTargetIndex, positionInContainer, contentType.role, contentTypeIndex)}}" stepKey="waitForContentTypeStage"/>
4848
</actionGroup>
49+
<actionGroup name="validateContentTypeNotInsideContainerStage">
50+
<arguments>
51+
<argument name="contentType"/>
52+
<argument name="contentTypeIndex" defaultValue="1" type="string"/>
53+
<argument name="containerTargetType"/>
54+
<argument name="containerTargetIndex" defaultValue="1" type="string"/>
55+
<argument name="positionInContainer" defaultValue="1" type="string"/>
56+
</arguments>
57+
<waitForElementVisible time="30" selector="{{PageBuilderStage.contentTypeInStageByIndex(containerTargetType.role, containerTargetIndex)}}" stepKey="waitForContentTypeStage"/>
58+
<dontSeeElementInDOM selector="{{PageBuilderStage.contentTypeInsideContainerStage(containerTargetType.role, containerTargetIndex, positionInContainer, contentType.role, contentTypeIndex)}}" stepKey="dontSeeContentTypeInContainer"/>
59+
</actionGroup>
4960
</actionGroups>

app/code/Magento/PageBuilder/Test/Mftf/ActionGroup/StorefrontActionGroup.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,13 @@
2424
</arguments>
2525
<waitForElementVisible time="30" selector="{{PageBuilderStoreFront.contentTypeInsideContainerStorefront(containerTargetType.role, containerTargetIndex, contentType.role, contentTypeIndex)}}" stepKey="waitForContentTypeStorefront"/>
2626
</actionGroup>
27+
<actionGroup name="validateContentTypeInsideContainerStorefrontInDOM">
28+
<arguments>
29+
<argument name="contentType"/>
30+
<argument name="contentTypeIndex" defaultValue="1" type="string"/>
31+
<argument name="containerTargetType"/>
32+
<argument name="containerTargetIndex" defaultValue="1" type="string"/>
33+
</arguments>
34+
<waitForElement time="30" selector="{{PageBuilderStoreFront.contentTypeInsideContainerStorefront(containerTargetType.role, containerTargetIndex, contentType.role, contentTypeIndex)}}" stepKey="waitForContentTypeStorefront"/>
35+
</actionGroup>
2736
</actionGroups>

app/code/Magento/PageBuilder/Test/Mftf/Section/PageBuilderAccordionSection.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<element name="itemOpenOnLoadState" type="input" selector="//input[@name='items[{{arg1}}][open_on_load]'][@value='{{arg2}}']" parameterized="true"/>
1616
</section>
1717
<section name="AccordionOnStage">
18+
<element name="all" type="button" selector="//div[@class='pagebuilder-accordion']"/>
1819
<element name="default" type="button" selector="(//div[@class='pagebuilder-accordion'])[{{arg1}}][@style='border-width: {{arg2}}px; border-radius: {{arg3}}px; margin: {{arg4}}px; padding: {{arg5}}px;']" parameterized="true"/>
1920
</section>
2021
<section name="AccordionFrontendSection">

app/code/Magento/PageBuilder/Test/Mftf/Section/PageBuilderHeadingSection.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1010
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
1111
<section name="HeadingOnStage">
12+
<element name="all" type="button" selector="//div[contains(@class,'pagebuilder-heading')]"/>
1213
<element name="base" type="text" selector="(//{{arg1}})[{{arg2}}]" parameterized="true"/>
1314
<element name="allHeadingsInContainer" type="button" selector="(//div[contains(@class, '{{arg1}}-container')])[{{arg2}}]//div[contains(@class,'pagebuilder-heading')]" parameterized="true"/>
1415
<element name="headingText" type="button" selector="(//{{arg1}}[.= '{{arg2}}'])[{{arg3}}]" parameterized="true"/>

app/code/Magento/PageBuilder/Test/Mftf/Section/PageBuilderStorefrontSection.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<sections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
1010
xsi:noNamespaceSchemaLocation="../../../../../../../dev/tests/acceptance/vendor/magento/magento2-functional-testing-framework/src/Magento/FunctionalTestingFramework/Page/etc/SectionObject.xsd">
1111
<section name="PageBuilderStoreFront">
12-
<element name="contentTypeInsideContainerStorefront" type="button" selector='(//div[@data-role="{{arg1}}"])[{{arg2}}]//div[@data-role="{{arg3}}"][{{arg4}}]' parameterized="true"/>
12+
<element name="contentTypeInsideContainerStorefront" type="button" selector='(//div[@data-role="{{arg1}}"])[{{arg2}}]//div|figure[@data-role="{{arg3}}"][{{arg4}}]' parameterized="true"/>
1313
<element name="imageSourceOnFrontEnd" type="button" selector="//div[not(contains(@class, 'pagebuilder-mobile-hidden')) and contains(@style, '{{var1}}')]" parameterized="true" />
1414
</section>
1515
</sections>

app/code/Magento/PageBuilder/Test/Mftf/Test/AdminPageBuilderAccordionTest.xml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,102 @@
137137
<comment userInput="Validate Style On Stage" stepKey="CommentValidateStage"/>
138138
<waitForElementVisible selector="{{AccordionOnStage.default('1', PageBuilderAdvancedBorderWidthPropertyDefault.value, PageBuilderAdvancedBorderRadiusDefaultProperty.value, PageBuilderMarginsPropertyDefault.value, PageBuilderPaddingProperty40.value)}}" stepKey="waitForStyle"/>
139139
</test>
140+
<test name="AccordionCannotAddToStage">
141+
<annotations>
142+
<features value="PageBuilder"/>
143+
<stories value="Accordion"/>
144+
<title value="Cannot add Accordion to Stage"/>
145+
<description value="If user drags Accordion to Stage, it should have no effect"/>
146+
<severity value="CRITICAL"/>
147+
<useCaseId value="MC-515"/>
148+
<testCaseId value="MC-3111"/>
149+
<group value="pagebuilder"/>
150+
<group value="pagebuilder-accordion"/>
151+
<group value="pagebuilder-cannotAddToStage"/>
152+
</annotations>
153+
<before>
154+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
155+
<actionGroup ref="navigateToAPageWithPageBuilder" stepKey="navigateToAPageWithPageBuilder"/>
156+
<actionGroup ref="switchToPageBuilderStage" stepKey="switchToPageBuilderStage"/>
157+
</before>
158+
<after>
159+
<actionGroup ref="logout" stepKey="logout"/>
160+
</after>
161+
<actionGroup ref="expandPageBuilderPanelGroup" stepKey="expandGroupInteractive">
162+
<argument name="group" value="PageBuilderAccordionContentType"/>
163+
</actionGroup>
164+
<actionGroup ref="cannotDragContentTypeToTarget" stepKey="dragAccordionIntoStage">
165+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
166+
<argument name="containerTargetType" value="PageBuilderStage"/>
167+
</actionGroup>
168+
<dontSeeElementInDOM selector="{{AccordionOnStage.all}}" stepKey="dontSeeAccordion"/>
169+
</test>
170+
<test name="AccordionCanAddToColumn">
171+
<annotations>
172+
<features value="PageBuilder"/>
173+
<stories value="Accordion"/>
174+
<title value="Add Accordion to Column container and view on Admin and Storefront"/>
175+
<description value="As a Content Manager I want column to be a container so that I can add Accordion inside"/>
176+
<severity value="CRITICAL"/>
177+
<useCaseId value="MC-515"/>
178+
<testCaseId value="MC-3112"/>
179+
<group value="pagebuilder"/>
180+
<group value="pagebuilder-column"/>
181+
<group value="pagebuilder-accordion"/>
182+
<group value="pagebuilder-addToColumn"/>
183+
</annotations>
184+
<before>
185+
<actionGroup ref="LoginAsAdmin" stepKey="loginAsAdmin"/>
186+
<actionGroup ref="navigateToAPageWithPageBuilder" stepKey="navigateToAPageWithPageBuilder"/>
187+
<actionGroup ref="switchToPageBuilderStage" stepKey="switchToPageBuilderStage"/>
188+
</before>
189+
<after>
190+
<actionGroup ref="logout" stepKey="logout"/>
191+
</after>
192+
<actionGroup ref="addPageBuilderPageTitle" stepKey="enterPageTitle">
193+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
194+
</actionGroup>
195+
<actionGroup ref="dragContentTypeToStage" stepKey="dragColumnIntoStage">
196+
<argument name="contentType" value="PageBuilderColumnContentType"/>
197+
</actionGroup>
198+
<!-- Add Accordion to Stage -->
199+
<comment userInput="Add Accordion to Stage" stepKey="addAccordionToStage"/>
200+
<actionGroup ref="expandPageBuilderPanelGroup" stepKey="expandGroupInteractive">
201+
<argument name="group" value="PageBuilderAccordionContentType"/>
202+
</actionGroup>
203+
<actionGroup ref="dragContentTypeToContainer" stepKey="dragAccordionOntoColumn">
204+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
205+
<argument name="containerTargetType" value="PageBuilderColumnContentType"/>
206+
<argument name="containerTargetIndex" value="2" />
207+
</actionGroup>
208+
<!-- Validate Stage -->
209+
<comment userInput="User sees Accordion displayed in column on Stage" stepKey="confirmAccordionOnStage"/>
210+
<actionGroup ref="validateContentTypeInsideContainerStage" stepKey="checkContentTypeInContainerStage">
211+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
212+
<argument name="containerTargetType" value="PageBuilderColumnContentType"/>
213+
<argument name="contentTypeIndex" value="1"/>
214+
<argument name="containerTargetIndex" value="2"/>
215+
</actionGroup>
216+
<actionGroup ref="saveAndContinueEditCmsPage" stepKey="saveAndContinueEditCmsPage"/>
217+
<actionGroup ref="switchToPageBuilderStage" stepKey="switchToPageBuilderStage2"/>
218+
<!-- Validate Stage After Save -->
219+
<comment userInput="Validate stage after save" stepKey="validateAccordionOnStage"/>
220+
<actionGroup ref="validateContentTypeInsideContainerStage" stepKey="checkContentTypeInContainerStage2">
221+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
222+
<argument name="containerTargetType" value="PageBuilderColumnContentType"/>
223+
<argument name="contentTypeIndex" value="1"/>
224+
<argument name="containerTargetIndex" value="2"/>
225+
</actionGroup>
226+
<!-- Validate Storefront -->
227+
<comment userInput="View Accordion inside column on storefront" stepKey="viewAccordionOnStorefront"/>
228+
<actionGroup ref="navigateToStoreFront" stepKey="navigateToStoreFront">
229+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
230+
</actionGroup>
231+
<actionGroup ref="validateContentTypeInsideContainerStorefront" stepKey="checkContentTypeInContainerStorefront">
232+
<argument name="contentType" value="PageBuilderAccordionContentType"/>
233+
<argument name="containerTargetType" value="PageBuilderColumnContentType"/>
234+
<argument name="contentTypeIndex" value="1"/>
235+
<argument name="containerTargetIndex" value="2"/>
236+
</actionGroup>
237+
</test>
140238
</tests>

0 commit comments

Comments
 (0)