Skip to content

Commit

Permalink
EZP-30022: UDW widget for selecting user/groups when assigning roles (#…
Browse files Browse the repository at this point in the history
…969)

* EZP-30022: Add UDW picker in assign roles view - users/groups

* Add 2 translations

* EZP-30022: Adjust tests

* Fix tests - pass RoleName

* Adjust tests

* Fix CS
  • Loading branch information
tischsoic authored and Łukasz Serwatka committed Apr 18, 2019
1 parent 6336544 commit 8d3d74f
Show file tree
Hide file tree
Showing 17 changed files with 555 additions and 49 deletions.
32 changes: 19 additions & 13 deletions features/Roles.feature
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,13 @@ Feature: Roles management
Scenario: User assignation can be discarded
Given there's "Test Role edited" on "Roles" list
When I start assigning to "Test Role edited" from "Roles" page
And I select "Administrator User" from "User"
And I select options from "Group"
| option |
| Editors |
| Users |
And I assign users to role
| path |
| Users/Administrator users/Administrator User |
And I assign groups to role
| path |
| Users/Editors |
| Users |
And I select "Media" from Sections as role assignment limitation
And I click on the edit action bar button "Discard changes"
Then I should be on "Role" "Test Role edited" page
Expand All @@ -77,11 +79,13 @@ Feature: Roles management
Scenario: User can be assigned to role from the Roles list
Given there's "Test Role edited" on "Roles" list
When I start assigning to "Test Role edited" from "Roles" page
And I select options from "User"
| option |
| Administrator User |
| Anonymous User |
And I select "Editors" from "Group"
And I assign users to role
| path |
| Users/Anonymous Users/Anonymous User |
| Users/Administrator users/Administrator User |
And I assign groups to role
| path |
| Users/Editors |
And I select limitation "Media/Images" for assignment through UDW
And I click on the edit action bar button "Save"
Then I should be on "Role" "Test Role edited" page
Expand All @@ -97,8 +101,10 @@ Feature: Roles management
Given there's "Test Role edited" on "Roles" list
And I go to "Test Role edited" "Role" page
When I start assigning users and groups to "Test Role edited" from role page
And I select "Users" from "Group"
And I click on the edit action bar button "Save"
And I assign groups to role
| path |
| Users |
And I click on the edit action bar button "Save"
Then I should be on "Role" "Test Role edited" page
And "Policies" list in "Role" "Test Role edited" is empty
And there are assignments on the "Test Role edited" assignments list
Expand Down Expand Up @@ -196,4 +202,4 @@ Feature: Roles management
| item |
| Test Role edited |
Then notification that "Role" "Test Role edited" is removed appears
And there's no "Test Role edited" on "Roles" list
And there's no "Test Role edited" on "Roles" list
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ services:
EzSystems\EzPlatformAdminUi\UniversalDiscovery\ConfigResolver:
arguments:
$udwConfiguration: '$universal_discovery_widget_module.configuration$'

EzSystems\EzPlatformAdminUi\UniversalDiscovery\Event\Subscriber\UserSelectionAllowedContentTypes:
arguments:
$userContentTypeIdentifier: '$user_content_type_identifier$'
tags:
- { name: kernel.event_subscriber }
10 changes: 10 additions & 0 deletions src/bundle/Resources/config/universal_discovery_widget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,13 @@ system:
image_asset:
multiple: false
visible_tabs: ['browse', 'search', 'bookmarks']
single_user:
multiple: false
multiple_user:
multiple: true
single_user_group:
allowed_content_types: ['user_group']
multiple: false
multiple_user_group:
allowed_content_types: ['user_group']
multiple: true
130 changes: 118 additions & 12 deletions src/bundle/Resources/public/js/scripts/admin.role_assignment.add.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
(function (global, doc) {
(function(global, doc, eZ, React, ReactDOM) {
const udwContainer = doc.getElementById('react-udw');
const limitationsRadio = [...doc.querySelectorAll('.ez-limitations__radio')];
const token = doc.querySelector('meta[name="CSRF-Token"]').content;
Expand All @@ -7,7 +7,7 @@
const selectSubtreeConfirm = (data) => {
const selectedItems = data.reduce((total, item) => total + `<li>${item.ContentInfo.Content.Name}</li>`, '');

doc.querySelector('#role_assignment_create_locations').value = data.map(item => item.id).join();
doc.querySelector('#role_assignment_create_locations').value = data.map((item) => item.id).join();
doc.querySelector('.ez-limitations__selected-subtree').innerHTML = selectedItems;

closeUDW();
Expand All @@ -17,16 +17,25 @@

const config = JSON.parse(event.currentTarget.dataset.udwConfig);

ReactDOM.render(React.createElement(eZ.modules.UniversalDiscovery, Object.assign({
onConfirm: selectSubtreeConfirm.bind(this),
onCancel: closeUDW,
multiple: true,
startingLocationId: window.eZ.adminUiConfig.universalDiscoveryWidget.startingLocationId,
restInfo: {token, siteaccess}
}, config)), udwContainer);
ReactDOM.render(
React.createElement(
eZ.modules.UniversalDiscovery,
Object.assign(
{
onConfirm: selectSubtreeConfirm.bind(this),
onCancel: closeUDW,
multiple: true,
startingLocationId: window.eZ.adminUiConfig.universalDiscoveryWidget.startingLocationId,
restInfo: { token, siteaccess },
},
config
)
),
udwContainer
);
};
const toggleDisabledState = () => {
limitationsRadio.forEach(radio => {
limitationsRadio.forEach((radio) => {
const disableNode = doc.querySelector(radio.dataset.disableSelector);
const methodName = radio.checked ? 'removeAttribute' : 'setAttribute';

Expand All @@ -37,5 +46,102 @@
};

doc.querySelector('.ez-btn--select-subtree').addEventListener('click', selectSubtree, false);
limitationsRadio.forEach(radio => radio.addEventListener('change', toggleDisabledState, false));
})(window, document);
limitationsRadio.forEach((radio) => radio.addEventListener('change', toggleDisabledState, false));

const addContentToInput = (selectBtn, newlySelectedItems) => {
const input = doc.querySelector(selectBtn.dataset.inputSelector);
const newlySelectedContentIds = newlySelectedItems.map((item) => item.ContentInfo.Content._id).join(',');

input.value = input.value ? `${input.value},${newlySelectedContentIds}` : newlySelectedContentIds;
};
const removeContentFromInput = (selectBtn, removedContentId) => {
const input = doc.querySelector(selectBtn.dataset.inputSelector);
const contentIdsWithoutRemoved = input.value.split(',').filter((contentId) => contentId !== removedContentId);

input.value = contentIdsWithoutRemoved.join(',');
};
const addContentTags = (selectBtn, newlySelectedItems) => {
const tagsList = doc.querySelector(selectBtn.dataset.selectedContentListSelector);
const tagTemplate = selectBtn.dataset.tagTemplate;
const fragment = doc.createDocumentFragment();

newlySelectedItems.forEach((location) => {
const { _id: contentId, Name: contentName } = location.ContentInfo.Content;
const container = doc.createElement('ul');
const renderedItem = tagTemplate.replace('{{ content_id }}', contentId).replace('{{ content_name }}', contentName);

container.insertAdjacentHTML('beforeend', renderedItem);

const listItemNode = container.querySelector('li');
const tagNode = listItemNode.querySelector('.ez-tag');

attachTagEventHandlers(selectBtn, tagNode);
fragment.append(listItemNode);
});

tagsList.append(fragment);
};
const handleTagRemove = (selectBtn, tag) => {
const removedContentId = tag.dataset.contentId;

removeContentFromInput(selectBtn, removedContentId);
tag.remove();
};
const attachTagEventHandlers = (selectBtn, tag) => {
const removeTagBtn = tag.querySelector('.ez-tag__remove-btn');

removeTagBtn.addEventListener('click', () => handleTagRemove(selectBtn, tag), false);
};
const handleUdwConfirm = (selectBtn, newlySelectedItems) => {
if (newlySelectedItems.length) {
addContentToInput(selectBtn, newlySelectedItems);
addContentTags(selectBtn, newlySelectedItems);
}

closeUDW();
};
const openUDW = (event) => {
event.preventDefault();

const selectBtn = event.currentTarget;
const input = doc.querySelector(selectBtn.dataset.inputSelector);
const selectedContentIds = input.value.split(',').map((idString) => parseInt(idString, 10));
const config = JSON.parse(selectBtn.dataset.udwConfig);

ReactDOM.render(
React.createElement(
eZ.modules.UniversalDiscovery,
Object.assign(
{
onConfirm: handleUdwConfirm.bind(this, selectBtn),
onCancel: () => ReactDOM.unmountComponentAtNode(udwContainer),
startingLocationId: eZ.adminUiConfig.universalDiscoveryWidget.startingLocationId,
title: selectBtn.dataset.universaldiscoveryTitle,
multiple: true,
restInfo: { token, siteaccess },
canSelectContent: ({ item }, callback) => {
const itemId = parseInt(item.ContentInfo.Content._id, 10);

callback(!selectedContentIds.includes(itemId));
},
},
config
)
),
udwContainer
);
};
const selectUsersBtn = doc.querySelector('#role_assignment_create_users__btn');
const selectGroupsBtn = doc.querySelector('#role_assignment_create_groups__btn');

[selectUsersBtn, selectGroupsBtn].forEach((selectBtn) => {
selectBtn.addEventListener('click', openUDW, false);

const tagsList = doc.querySelector(selectBtn.dataset.selectedContentListSelector);
const tags = tagsList.querySelectorAll('.ez-tag');

tags.forEach((tag) => {
attachTagEventHandlers(selectBtn, tag);
});
});
})(window, document, window.eZ, window.React, window.ReactDOM);
2 changes: 2 additions & 0 deletions src/bundle/Resources/public/scss/_tag.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

&__spinner {
height: calculateRem(22px);
line-height: 0;
}

&__remove-btn {
Expand All @@ -21,5 +22,6 @@
border: 0;
padding: 0;
outline: none;
line-height: 0;
}
}
20 changes: 20 additions & 0 deletions src/bundle/Resources/translations/role.en.xliff
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,31 @@
<target state="new">Limitations</target>
<note>key: role_assignment.view.add.panel.limitations.title</note>
</trans-unit>
<trans-unit id="049589ee01907c1397c6a43f2743b040573debad" resname="role_assignment.view.add.panel.users_and_groups.groups.udw_title">
<source>Select groups for role assignment</source>
<target state="new">Select groups for role assignment</target>
<note>key: role_assignment.view.add.panel.users_and_groups.groups.udw_title</note>
</trans-unit>
<trans-unit id="1ee375a8da2c2fe9b5b0a9c6b12bba981dfdb895" resname="role_assignment.view.add.panel.users_and_groups.select_groups_btn.label">
<source>Select groups</source>
<target state="new">Select groups</target>
<note>key: role_assignment.view.add.panel.users_and_groups.select_groups_btn.label</note>
</trans-unit>
<trans-unit id="f26210f27528dbbea87cf71c5479a0afd713bece" resname="role_assignment.view.add.panel.users_and_groups.select_users_btn.label">
<source>Select users</source>
<target state="new">Select users</target>
<note>key: role_assignment.view.add.panel.users_and_groups.select_users_btn.label</note>
</trans-unit>
<trans-unit id="f9465b09774c22747e887ffe9e6300fd02420546" resname="role_assignment.view.add.panel.users_and_groups.title">
<source>Users and Groups</source>
<target state="new">Users and Groups</target>
<note>key: role_assignment.view.add.panel.users_and_groups.title</note>
</trans-unit>
<trans-unit id="9328ffe3a5dcac34b985d43cf691f1c790d2ba28" resname="role_assignment.view.add.panel.users_and_groups.users.udw_title">
<source>Select users for role assignment</source>
<target state="new">Select users for role assignment</target>
<note>key: role_assignment.view.add.panel.users_and_groups.users.udw_title</note>
</trans-unit>
<trans-unit id="61a5ec154d3f0620ec619d196611b011996128ff" resname="role_assignment.view.add.title">
<source>Assigning to Users/Groups</source>
<target state="new">Assigning to Users/Groups</target>
Expand Down
62 changes: 60 additions & 2 deletions src/bundle/Resources/views/admin/role_assignment/create.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,66 @@
{{ 'role_assignment.view.add.panel.users_and_groups.title'|trans|desc('Users and Groups') }}
</div>
<div class="card-body">
{{ form_row(form.users) }}
{{ form_row(form.groups) }}
{{ form_label(form.users) }}
{{ form_errors(form.users) }}
{{ form_widget(form.users) }}

<button type="button" data-universaldiscovery-title="{{ "role_assignment.view.add.panel.users_and_groups.users.udw_title"
|trans({}, "role")
|desc("Select users for role assignment") }}"
data-tag-template="{{ include('@ezdesign/admin/role_assignment/create_tag_list_item.html.twig', {
'content_name': '{{ content_name }}',
'content_id': '{{ content_id }}'
})|e('html_attr') }}"
class="btn btn-secondary d-block"
id="{{ form.users.vars.id }}__btn"
data-input-selector="#{{ form.users.vars.id }}"
data-selected-content-list-selector="#{{ form.users.vars.id }}-selected-content"
data-udw-config="{{ ez_udw_config('multiple_user', {}) }}">
{{ 'role_assignment.view.add.panel.users_and_groups.select_users_btn.label'|trans|desc('Select users') }}
</button>

<ul class="list-unstyled" id="{{ form.users.vars.id }}-selected-content">
{% for user in form.users.vars.data %}
{% if user is not empty %}
{% set content_name = user.content.versionInfo.contentInfo.name %}
{{ include('@ezdesign/admin/role_assignment/create_tag_list_item.html.twig', {
'content_name': content_name,
'content_id': user.content.versionInfo.contentInfo.id
}) }}
{% endif %}
{% endfor %}
</ul>
{{ form_label(form.groups) }}
{{ form_errors(form.groups) }}
{{ form_widget(form.groups) }}

<button type="button" data-universaldiscovery-title="{{ "role_assignment.view.add.panel.users_and_groups.groups.udw_title"
|trans({}, "role")
|desc("Select groups for role assignment") }}"
data-tag-template="{{ include('@ezdesign/admin/role_assignment/create_tag_list_item.html.twig', {
'content_name': '{{ content_name }}',
'content_id': '{{ content_id }}'
})|e('html_attr') }}"
class="btn btn-secondary d-block"
id="{{ form.groups.vars.id }}__btn"
data-input-selector="#{{ form.groups.vars.id }}"
data-selected-content-list-selector="#{{ form.groups.vars.id }}-selected-content"
data-udw-config="{{ ez_udw_config('multiple_user_group', {}) }}">
{{ 'role_assignment.view.add.panel.users_and_groups.select_groups_btn.label'|trans|desc('Select groups') }}
</button>

<ul class="list-unstyled" id="{{ form.groups.vars.id }}-selected-content">
{% for group in form.groups.vars.data %}
{% if group is not empty %}
{% set content_name = group.content.versionInfo.contentInfo.name %}
{{ include('@ezdesign/admin/role_assignment/create_tag_list_item.html.twig', {
'content_name': content_name,
'content_id': group.content.versionInfo.contentInfo.id
}) }}
{% endif %}
{% endfor %}
</ul>
</div>
</div>
</section>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<li class="mt-2">
{{ include('@ezdesign/parts/tag.html.twig', {
'content': content_name,
'is_loading_state': false,
'tag_attributes': {
'data-content-id': content_id,
}
}) }}
</li>
23 changes: 23 additions & 0 deletions src/lib/Behat/BusinessContext/RolesContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class RolesContext extends BusinessContext
'assignment' => 'Assignments',
];

private $itemTypeToLabelMapping = [
'users' => 'Select users',
'groups' => 'Select groups',
];

private $fields = [
'newPolicySelectList' => 'policy_create_policy',
'newPolicyAssignmentLimitation' => 'role_assignment_create_sections',
Expand Down Expand Up @@ -167,4 +172,22 @@ public function iSelectSectionLimitation(string $limitationName): void
->adminUpdateForm->fillFieldWithValue('Sections', 'true');
$this->utilityContext->selectOption($this->fields['newPolicyAssignmentLimitation'], $limitationName);
}

/**
* @When I assign :itemType to role
*/
public function iAssignToRole(string $itemType, TableNode $items): void
{
$pageObject = PageObjectFactory::createPage($this->utilityContext, AdminUpdateItemPage::PAGE_NAME);
$pageObject->adminUpdateForm->clickButton($this->itemTypeToLabelMapping[$itemType]);

$udw = ElementFactory::createElement($this->utilityContext, UniversalDiscoveryWidget::ELEMENT_NAME);
$udw->verifyVisibility();

foreach ($items->getHash() as $item) {
$udw->selectContent($item['path']);
}

$udw->confirm();
}
}
Loading

0 comments on commit 8d3d74f

Please sign in to comment.