fix: dynamic admin group choices (#741)
This commit is contained in:
parent
eea58804cd
commit
9167e81da2
6 changed files with 145 additions and 14 deletions
|
|
@ -2,7 +2,7 @@ import { Controller} from '@hotwired/stimulus'
|
||||||
|
|
||||||
/* stimulusFetch: 'lazy' */
|
/* stimulusFetch: 'lazy' */
|
||||||
export default class extends Controller {
|
export default class extends Controller {
|
||||||
static targets = ['servicesEnabledField', 'parentField', 'idField']
|
static targets = ['servicesEnabledField', 'parentField', 'idField', 'ownerField']
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
const parentFields = document.querySelectorAll('[data-label="Parent"]')
|
const parentFields = document.querySelectorAll('[data-label="Parent"]')
|
||||||
|
|
@ -16,6 +16,17 @@ export default class extends Controller {
|
||||||
}
|
}
|
||||||
|
|
||||||
parentFieldTargetConnected(element) {
|
parentFieldTargetConnected(element) {
|
||||||
|
// edit page
|
||||||
|
const parentGroupId = element.value
|
||||||
|
const servicesEnabledToggle = document.getElementById('Group_servicesEnabled')
|
||||||
|
this.checkGroupEditDisableServices(parentGroupId, servicesEnabledToggle)
|
||||||
|
|
||||||
|
element.addEventListener('change', () => {
|
||||||
|
const newParentGroupId = element.value
|
||||||
|
this.checkGroupEditDisableServices(newParentGroupId, servicesEnabledToggle)
|
||||||
|
})
|
||||||
|
|
||||||
|
// list page
|
||||||
const observer = new MutationObserver( ( ) => {
|
const observer = new MutationObserver( ( ) => {
|
||||||
if (element.tomselect) {
|
if (element.tomselect) {
|
||||||
observer.disconnect()
|
observer.disconnect()
|
||||||
|
|
@ -65,6 +76,17 @@ export default class extends Controller {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ownerFieldTargetConnected() {
|
||||||
|
const initialUserId = this.ownerFieldTarget.value
|
||||||
|
const groupsField = document.getElementById('Product_groups')
|
||||||
|
this.replaceGroups(initialUserId, groupsField)
|
||||||
|
this.ownerFieldTarget.addEventListener('change', () => {
|
||||||
|
const userId = this.ownerFieldTarget.value
|
||||||
|
|
||||||
|
this.replaceGroups(userId, groupsField)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async checkDisabledServices(tr) {
|
async checkDisabledServices(tr) {
|
||||||
const id = tr.getAttribute('data-id')
|
const id = tr.getAttribute('data-id')
|
||||||
const url = `/api/groups/${id}`
|
const url = `/api/groups/${id}`
|
||||||
|
|
@ -122,4 +144,98 @@ export default class extends Controller {
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async replaceGroups(userId, groupsField) {
|
||||||
|
const url = `/api/groups?user=${userId}&services_enabled=true&admin=0`
|
||||||
|
const response = await fetch(url, {method: 'GET'})
|
||||||
|
if (!response.ok) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const data = await response.json()
|
||||||
|
const groups = data['hydra:member']
|
||||||
|
|
||||||
|
const parentDiv = groupsField.parentElement
|
||||||
|
const smallElement = parentDiv.querySelector('small')
|
||||||
|
|
||||||
|
const saveContinue = document.getElementsByClassName('action-saveAndContinue')[0]
|
||||||
|
const saveReturn = document.getElementsByClassName('action-saveAndReturn')[0]
|
||||||
|
const saveAdd = document.getElementsByClassName('action-saveAndAddAnother')[0]
|
||||||
|
|
||||||
|
|
||||||
|
groupsField.tomselect.clear()
|
||||||
|
groupsField.tomselect.clearOptions()
|
||||||
|
if (groups.length === 0) {
|
||||||
|
groupsField.tomselect.disable()
|
||||||
|
groupsField.tomselect.lock()
|
||||||
|
// show helper
|
||||||
|
if (null !== smallElement) {
|
||||||
|
smallElement.style.visibility = 'visible'
|
||||||
|
}
|
||||||
|
if (undefined !== saveContinue) {
|
||||||
|
saveContinue.disabled = true
|
||||||
|
}
|
||||||
|
if (undefined !== saveAdd) {
|
||||||
|
saveAdd.disabled = true
|
||||||
|
}
|
||||||
|
saveReturn.disabled = true
|
||||||
|
} else {
|
||||||
|
groups.map(group => {
|
||||||
|
groupsField.tomselect.addOption(new Option(group.name, group.id))
|
||||||
|
})
|
||||||
|
groupsField.tomselect.enable()
|
||||||
|
groupsField.tomselect.unlock()
|
||||||
|
|
||||||
|
// remove helper
|
||||||
|
if (null !== smallElement) {
|
||||||
|
smallElement.style.visibility = 'hidden'
|
||||||
|
}
|
||||||
|
if (undefined !== saveContinue) {
|
||||||
|
saveContinue.disabled = false
|
||||||
|
}
|
||||||
|
if (undefined !== saveAdd) {
|
||||||
|
saveAdd.disabled = false
|
||||||
|
}
|
||||||
|
saveReturn.disabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkGroupEditDisableServices(parentGroupId, servicesEnabledToggle) {
|
||||||
|
const url = `/api/groups/${parentGroupId}`
|
||||||
|
|
||||||
|
const response = await fetch(url, {method: 'GET'})
|
||||||
|
if (!response.ok) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parentGroup = await response.json()
|
||||||
|
let parentAll = parentGroup.parentsRecursively
|
||||||
|
parentAll.push(parentGroup['@id'])
|
||||||
|
|
||||||
|
const parentDiv = servicesEnabledToggle.parentElement.parentElement
|
||||||
|
const smallElement = parentDiv.querySelector('small')
|
||||||
|
|
||||||
|
let disabled = false
|
||||||
|
for (const parentUrl of parentAll) {
|
||||||
|
const parentResponse = await fetch(parentUrl, { method: 'GET' })
|
||||||
|
if (!response.ok) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const parent = await parentResponse.json()
|
||||||
|
if (!parent.servicesEnabled) {
|
||||||
|
servicesEnabledToggle.checked = false
|
||||||
|
servicesEnabledToggle.disabled = true
|
||||||
|
if (null !== smallElement) {
|
||||||
|
smallElement.style.visibility = 'visible'
|
||||||
|
}
|
||||||
|
disabled = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!disabled) {
|
||||||
|
servicesEnabledToggle.disabled = false
|
||||||
|
if (null !== smallElement) {
|
||||||
|
smallElement.style.visibility = 'hidden'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -252,7 +252,12 @@ abstract class AbstractProductCrudController extends AbstractCrudController impl
|
||||||
$groupsField = AssociationField::new('groups')->onlyOnForms();
|
$groupsField = AssociationField::new('groups')->onlyOnForms();
|
||||||
$groupsFieldList = CollectionField::new('groups')->hideOnForm();
|
$groupsFieldList = CollectionField::new('groups')->hideOnForm();
|
||||||
|
|
||||||
$ownerField = AssociationField::new('owner');
|
$ownerField = AssociationField::new('owner')
|
||||||
|
->setFormTypeOption('attr', [
|
||||||
|
'data-controller' => 'admin-parentgroup',
|
||||||
|
'data-admin-parentgroup-target' => 'ownerField',
|
||||||
|
])
|
||||||
|
->addWebpackEncoreEntries('admin');
|
||||||
$categoryField = AssociationField::new('category')
|
$categoryField = AssociationField::new('category')
|
||||||
->setQueryBuilder(function (QueryBuilder $queryBuilder) {
|
->setQueryBuilder(function (QueryBuilder $queryBuilder) {
|
||||||
return $this->categoryRepository->addTypeFilter($queryBuilder, $this->getProductType());
|
return $this->categoryRepository->addTypeFilter($queryBuilder, $this->getProductType());
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ final class GroupCrudController extends AbstractCrudController implements GroupA
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
array_splice($fields, 3, 0, [$servicesEnabledField]);
|
array_splice($fields, 4, 0, [$servicesEnabledField]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
|
|
@ -328,7 +328,7 @@ final class GroupCrudController extends AbstractCrudController implements GroupA
|
||||||
];
|
];
|
||||||
|
|
||||||
if ($this->configurationRepository->getInstanceConfigurationOrCreate()->getServicesEnabled()) {
|
if ($this->configurationRepository->getInstanceConfigurationOrCreate()->getServicesEnabled()) {
|
||||||
array_splice($fields, 2, 0, [$servicesEnabledField]);
|
array_splice($fields, 3, 0, [$servicesEnabledField]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $fields;
|
return $fields;
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,11 @@ final class ServiceCrudController extends AbstractProductCrudController
|
||||||
/** @var ChoiceField $statusField */
|
/** @var ChoiceField $statusField */
|
||||||
$statusField->setChoices(ProductStatus::cases());
|
$statusField->setChoices(ProductStatus::cases());
|
||||||
|
|
||||||
|
$i18prefix = $this->getI18nPrefix(self::class);
|
||||||
|
|
||||||
|
/** @var AssociationField $groupsField */
|
||||||
|
$groupsField->setHelp($i18prefix.'.field.groups.help');
|
||||||
|
|
||||||
if ($pageName === Crud::PAGE_NEW) {
|
if ($pageName === Crud::PAGE_NEW) {
|
||||||
return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField];
|
return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField];
|
||||||
}
|
}
|
||||||
|
|
@ -85,7 +90,6 @@ final class ServiceCrudController extends AbstractProductCrudController
|
||||||
$product = $this->getContext()?->getEntity()?->getInstance();
|
$product = $this->getContext()?->getEntity()?->getInstance();
|
||||||
$owner = $product?->getOwner();
|
$owner = $product?->getOwner();
|
||||||
if (null !== $owner && !$owner->getUserGroupsConfirmedWithServices()->isEmpty()) {
|
if (null !== $owner && !$owner->getUserGroupsConfirmedWithServices()->isEmpty()) {
|
||||||
/** @var AssociationField $groupsField */
|
|
||||||
$groupsField->setQueryBuilder(function (QueryBuilder $queryBuilder) use ($owner) {
|
$groupsField->setQueryBuilder(function (QueryBuilder $queryBuilder) use ($owner) {
|
||||||
return $queryBuilder
|
return $queryBuilder
|
||||||
->join('entity.userGroups', 'ug')
|
->join('entity.userGroups', 'ug')
|
||||||
|
|
@ -98,9 +102,7 @@ final class ServiceCrudController extends AbstractProductCrudController
|
||||||
;
|
;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$i18prefix = $this->getI18nPrefix(self::class);
|
$groupsField->setDisabled();
|
||||||
/** @var AssociationField $groupsField */
|
|
||||||
$groupsField->setHelp($i18prefix.'.field.groups.help')->setDisabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField];
|
return [$nameField, $ownerField, $categoryField, $statusField, $groupsField, $descriptionField, $imageField, $durationField];
|
||||||
|
|
@ -114,6 +116,7 @@ final class ServiceCrudController extends AbstractProductCrudController
|
||||||
$categoryField,
|
$categoryField,
|
||||||
$statusField,
|
$statusField,
|
||||||
$visibilityField,
|
$visibilityField,
|
||||||
|
$groupsFieldList,
|
||||||
$nameField,
|
$nameField,
|
||||||
$descriptionField,
|
$descriptionField,
|
||||||
$durationField,
|
$durationField,
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ final class GroupRepository extends ServiceEntityRepository
|
||||||
/**
|
/**
|
||||||
* @return Group[]
|
* @return Group[]
|
||||||
*/
|
*/
|
||||||
public function getGroupsByEnabledServices(bool $servicesEnabled, ?User $user = null): array
|
public function getGroupsByEnabledServices(bool $servicesEnabled, ?User $user = null, bool $admin = true): array
|
||||||
{
|
{
|
||||||
$qb = $this->createQueryBuilder('g')
|
$qb = $this->createQueryBuilder('g')
|
||||||
->andWhere('g.servicesEnabled = :servicesEnabled')
|
->andWhere('g.servicesEnabled = :servicesEnabled')
|
||||||
|
|
@ -100,10 +100,15 @@ final class GroupRepository extends ServiceEntityRepository
|
||||||
$qb
|
$qb
|
||||||
->leftJoin('g.userGroups', 'gu')
|
->leftJoin('g.userGroups', 'gu')
|
||||||
->andWhere('gu.user = :user')
|
->andWhere('gu.user = :user')
|
||||||
->andWhere('gu.mainAdminAccount = :mainAdminAccount OR gu.membership = :membership')
|
->setParameter('user', $user);
|
||||||
->setParameter('user', $user)
|
|
||||||
->setParameter('mainAdminAccount', true)
|
if ($admin) {
|
||||||
->setParameter('membership', UserMembership::ADMIN);
|
$qb
|
||||||
|
->andWhere('gu.mainAdminAccount = :mainAdminAccount OR gu.membership = :membership')
|
||||||
|
->setParameter('mainAdminAccount', true)
|
||||||
|
->setParameter('membership', UserMembership::ADMIN)
|
||||||
|
;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var Group[] */
|
/** @var Group[] */
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,9 @@ class GroupsProvider implements ProviderInterface
|
||||||
if (isset($context['filters']['user'])) { // @phpstan-ignore-line
|
if (isset($context['filters']['user'])) { // @phpstan-ignore-line
|
||||||
$user = $this->userRepository->find($context['filters']['user']);
|
$user = $this->userRepository->find($context['filters']['user']);
|
||||||
|
|
||||||
return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true', $user); // @phpstan-ignore-line
|
$admin = (bool) ($context['filters']['admin'] ?? true); // @phpstan-ignore-line
|
||||||
|
|
||||||
|
return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true', $user, $admin); // @phpstan-ignore-line
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true'); // @phpstan-ignore-line
|
return $this->groupRepository->getGroupsByEnabledServices($context['filters']['services_enabled'] === 'true'); // @phpstan-ignore-line
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue