diff --git a/UPGRADE-1.9.md b/UPGRADE-1.9.md index 6dd26054a16..0d051ef0127 100644 --- a/UPGRADE-1.9.md +++ b/UPGRADE-1.9.md @@ -13,6 +13,7 @@ UPGRADE FROM 1.8 to 1.9 ####AddressBundle - `oro_address.address.manager` service was marked as private +- Validation `AbstractAddress::isRegionValid` was moved to `Oro\Bundle\AddressBundle\Validator\Constraints\ValidRegion` constraint ####CalendarBundle - `oro_calendar.calendar_provider.user` service was marked as private @@ -29,11 +30,92 @@ UPGRADE FROM 1.8 to 1.9 ####DataAuditBundle - `Oro\Bundle\DataAuditBundle\EventListener\KernelListener` added to the class cache and constructor have container as performance improvement +- `Oro\Bundle\DataAuditBundle\Entity\AbstractAudit` has `@InheritanceType("SINGLE_TABLE")` +- `audit-grid` and `audit-history-grid` based on `Oro\Bundle\DataAuditBundle\Entity\AbstractAudit` now. Make join to get your entity on grid ####DataGridBundle +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::DATASOURCE_PATH` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::DATASOURCE_PATH`. +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::DATASOURCE_TYPE_PATH` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::getAclResource`. +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::DATASOURCE_ACL_PATH` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::getAclResource`. +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::BASE_DATAGRID_CLASS_PATH` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::BASE_DATAGRID_CLASS_PATH`. +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::DATASOURCE_SKIP_ACL_CHECK` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::isDatasourceSkipAclApply`. +- `Oro\Bundle\DataGridBundle\Datagrid\Builder::DATASOURCE_SKIP_COUNT_WALKER_PATH` marked as deprecated. Use `Oro\Bundle\DataGridBundle\Datagrid\Common\DatagridConfiguration::DATASOURCE_SKIP_COUNT_WALKER_PATH`. +- Option "acl_resource" moved from option "source" to root node of datagrid configuration: + +Before + +``` +datagrid: + acme-demo-grid: + ... # some configuration + source: + acl_resource: 'acme_demo_entity_view' + ... # some configuration +``` + +Now + +``` +datagrid: + acme-demo-grid: + acl_resource: 'acme_demo_entity_view' + ... # some configuration +``` + +- Option of datagrid "skip_acl_check" is deprecated, use option "skip_acl_apply" instead. Logic of this option was also changed. Before this option caused ignorance of option "acl_resource". Now it is responsible only for indication whether or not ACL should be applied to source query of the grid. See [advanced_grid_configuration.md](.src/Oro/Bundle/DataGridBundle/Resources/doc/backend/advanced_grid_configuration.md) for use cases. + +Before + +``` +datagrid: + acme-demo-grid: + ... # some configuration + options: + skip_acl_check: true +``` + +Now + +``` +datagrid: + acme-demo-grid: + ... # some configuration + source: + skip_acl_apply: true + ... # some configuration +``` + - Services with tag `oro_datagrid.extension.formatter.property` was marked as private - JS collection models format changed to maintain compatibility with Backbone collections: now it is always list of models, and additional parameters are passed through the options - +- Grid merge uses distinct policy + +``` +grid-name: + source: + value: 1 +grid-name: + source: + value: 2 +``` + +will result + +``` +grid-name: + source: + value: 2 +``` + +instead of + +``` +grid-name: + source: + value: + - 1 + - 2 +``` + ####DistributionBundle: - Fix `priority` attribute handling for `routing.options_resolver` tag to be conform Symfony standards. New behaviour: the higher the priority, the sooner the resolver gets executed. @@ -54,6 +136,7 @@ UPGRADE FROM 1.8 to 1.9 - `oro_entity.entity_hierarchy_provider` service was marked as private. - `oro_entity.entity_hierarchy_provider.class` parameter was removed. - `oro_entity.entity_hierarchy_provider.all` service was added. It can be used if you need a hierarchy of all entities but not only configurable ones. +- Class `Oro\Bundle\EntityBundle\Provider\EntityContextProvider` was moved to `Oro\Bundle\ActivityBundle\Provider\ContextGridProvider` and `oro_entity.entity_context_provider` service was moved to `oro_activity.provider.context_grid`. ####EntityConfigBundle - Removed `optionSet` field type deprecated since v1.4. Existing options sets are converted to `Select` or `Multi-Select` automatically during the Platform update. @@ -133,12 +216,16 @@ after: - Added `Oro\Bundle\ImportExportBundle\Formatter\ExcelDateTimeTypeFormatter` as default formatter for the date, time and datetime types in `Oro\Bundle\ImportExportBundle\Serializer\Normalizer\DateTimeNormalizer`. This types exported/imported depends on the application locale and timezone and recognized as dates in Microsoft Excel. - `Oro\Bundle\ImportExportBundle\Field\DatabaseHelper::getRegistry` is deprecated. Use class methods instead of disposed registry - Services with tag `oro_importexport.normalizer` was marked as private +- Allow to omit empty identity fields. To use this feature set `Use As Identity Field` option to `Only when not empty +` (-1 or `Oro\Bundle\ImportExportBundle\Field\FieldHelper::IDENTITY_ONLY_WHEN_NOT_EMPTY` in a code) ####InstallerBundle - `Oro\Bundle\InstallerBundle\EventListener\RequestListener` added to the class cache as performance improvement ####LayoutBundle - `Oro\Bundle\LayoutBundle\EventListener\ThemeListener` added to the class cache as performance improvement +- The theme definition should be placed at theme folder and named `theme.yml`, for example `DemoBundle/Resources/views/layouts/first_theme/theme.yml` +- Deprecated method: placed at `Resources/config/oro/` and named `layout.yml`, for example `DemoBundle/Resources/config/oro/layout.yml` ####LocaleBundle - `Oro\Bundle\LocaleBundle\EventListener\LocaleListener` added to the class cache and constructor have container as performance improvement @@ -150,6 +237,9 @@ after: - `Oro\Bundle\NavigationBundle\Event\AddMasterRequestRouteListener` added to the class cache as performance improvement - `Oro\Bundle\NavigationBundle\Event\RequestTitleListener` added to the class cache as performance improvement +####NoteBundle + - Added parameter `DoctrineHelper $doctrineHelper` to constructor of `\Oro\Bundle\NoteBundle\Placeholder\PlaceholderFilter` + ####PlatformBundle - Bundle now has priority `-200` and it is loaded right after main Symfony bundles - Services with tag `doctrine.event_listener` was marked as private @@ -161,10 +251,15 @@ after: - `Oro\Bundle\SecurityBundle\Owner\OwnerTreeInterface` is changed. New method `buildTree` added (due to performance issues). It should be called once after all `addDeepEntity` calls. See [OwnerTreeProvider](./src/Oro/Bundle/SecurityBundle/Owner/OwnerTreeProvider.php) method `fillTree`. Implementation example [OwnerTree](./src/Oro/Bundle/SecurityBundle/Owner/OwnerTree.php). - Bundle now contains part of Symfony security configuration (ACL configuration and access decision manager strategy) - `Oro\Bundle\SecurityBundle\Http\Firewall\ContextListener` added to the class cache and constructor have container as performance improvement +- `Oro\Bundle\SecurityBundle\Authentication\Token\UsernamePasswordOrganizationTokenFactoryInterface` and its implementation `Oro\Bundle\SecurityBundle\Authentication\Token\UsernamePasswordOrganizationTokenFactory` were introduced to encapsulate creation of `UsernamePasswordOrganizationToken` in `Oro\Bundle\SecurityBundle\Authentication\Provider\UsernamePasswordOrganizationAuthenticationProvider` and `Oro\Bundle\SecurityBundle\Http\Firewall\OrganizationBasicAuthenticationListener` +- `Oro\Bundle\SecurityBundle\Authentication\Token\OrganizationRememberMeTokenFactoryInterface` and its implementation `Oro\Bundle\SecurityBundle\Authentication\Token\OrganizationRememberMeTokenFactory` were introduced to encapsulate creation of `OrganizationRememberMeToken` in `Oro\Bundle\SecurityBundle\Authentication\Provider\UsernamePasswordOrganizationAuthenticationProvider` ####SidebarBundle - `Oro\Bundle\SidebarBundle\EventListener\RequestHandler` added to the class cache as performance improvement +####SSOBundle +- `Oro\Bundle\SSOBundle\Security\OAuthTokenFactoryInterface` and its implementation `Oro\Bundle\SSOBundle\Security\OAuthTokenFactory` were introduced to encapsulate creation of `OAuthToken` in `Oro\Bundle\SSOBundle\Security\OAuthProvider` + ####SoapBundle - Bundle now contains configuration of security firewall `wsse_secured` - `Oro\Bundle\SoapBundle\EventListener\LocaleListener` added to the class cache and constructor have container as performance improvement @@ -176,15 +271,22 @@ after: - `/Resources/translations/tooltips.*.yml` deprecated since 1.9.0. Will be removed in 1.11.0. Use `/Resources/translations/messages.*.yml` instead ####UiBundle +- Added `assets_version_strategy` parameter which can be used to automatically update `assets_version` parameter. Possible values are: + - null - the assets version stays unchanged + - time_hash - a hash of the current time (default strategy) + - incremental - the next assets version is the previous version is incremented by one (e.g. 'ver1' -> 'ver2' or '1' -> '2') +- Removed `assets_version` global variable from TWIG. Use `asset_version` or `asset` TWIG functions instead - Added possibility to group tabs in dropdown for tabs panel. Added options to tabPanel function. Example: `{{ tabPanel(tabs, {useDropdown: true}) }}` - Added possibility to set content for specific tab. Example: `{{ tabPanel([{label: 'Tab', content: 'Tab content'}]) }}` - `Oro\Bundle\UIBundle\EventListener\ContentProviderListener` added to the class cache and constructor have container as performance improvement - Services with tag `oro_ui.content_provider` was marked as private - Services with tag `oro_formatter` was marked as private +- Class `Oro\Bundle\UIBundle\Tools\ArrayUtils` marked as deprecated. Use `Oro\Component\PhpUtils\ArrayUtil` instead. ####UserBundle - Bundle now contains configuration of security providers (`chain_provider`, `oro_user`, `in_memory`), encoders and security firewalls (`login`, `reset_password`, `main`) - Bundle DI extension `OroUserExtension` has been updated to make sure that `main` security firewall is always the last in list +- `Oro\Bundle\UserBundle\Security\WsseTokenFactoryInterface` and its implementation `Oro\Bundle\UserBundle\Security\WsseTokenFactory` were introduced to encapsulate creation of `WsseToken` in `Oro\Bundle\UserBundle\Security\WsseAuthProvider` ####WorkflowBundle - Constructor of `Oro\Bundle\WorkflowBundle\Model\Process` changed. New argument: `ConditionFactory $conditionFactory` diff --git a/composer.json b/composer.json index 6045b5d6073..4a7c481469e 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "symfony/icu": "~1.1", "symfony/swiftmailer-bundle": "2.3.*", "symfony/monolog-bundle": "2.7.*", - "sensio/distribution-bundle": "2.3.14", + "sensio/distribution-bundle": "4.0.3", "sensio/framework-extra-bundle": "2.3.4", "incenteev/composer-parameter-handler": "2.1.0", "jms/job-queue-bundle": "1.2.*", @@ -75,7 +75,8 @@ "components/font-awesome": "~4.3.0", "piwik/device-detector": "~3.0", "oro/jsplumb": "~1.7", - "oro/moment-timezone": "0.3.*" + "oro/moment-timezone": "0.3.*", + "vakata/jstree": "^3.2" }, "require-dev": { "sensio/generator-bundle": "2.5.3" diff --git a/src/Oro/Bundle/ActivityBundle/Autocomplete/ContextSearchHandler.php b/src/Oro/Bundle/ActivityBundle/Autocomplete/ContextSearchHandler.php index 6eacb7c800b..7f5dfb00f0b 100644 --- a/src/Oro/Bundle/ActivityBundle/Autocomplete/ContextSearchHandler.php +++ b/src/Oro/Bundle/ActivityBundle/Autocomplete/ContextSearchHandler.php @@ -19,6 +19,7 @@ use Oro\Bundle\EntityBundle\Tools\EntityClassNameHelper; use Oro\Bundle\EntityConfigBundle\Config\ConfigManager; use Oro\Bundle\ActivityBundle\Manager\ActivityManager; +use Oro\Bundle\ActivityBundle\Event\SearchAliasesEvent; use Oro\Bundle\FormBundle\Autocomplete\ConverterInterface; use Oro\Bundle\SearchBundle\Engine\Indexer; use Oro\Bundle\SearchBundle\Query\Result\Item; @@ -183,17 +184,14 @@ protected function searchById($targetsString) */ public function convertItem($item) { + $this->dispatcher->dispatch(PrepareResultItemEvent::EVENT_NAME, new PrepareResultItemEvent($item)); + /** @var Item $item */ $text = $item->getRecordTitle(); $className = $item->getEntityName(); $entityMapParameter = $this->mapper->getEntityMapParameter($className, 'title_fields'); - if ($text === null && $entityMapParameter) { - $this->dispatcher->dispatch(PrepareResultItemEvent::EVENT_NAME, new PrepareResultItemEvent($item)); - $text = $item->getRecordTitle(); - } - if (strlen($text) === 0 && !$entityMapParameter) { $text = $this->translator->trans('oro.entity.item', ['%id%' => $item->getRecordId()]); } @@ -406,6 +404,10 @@ protected function getSearchAliases() $aliases[] = $alias; } } + /** dispatch oro_activity.search_aliases event */ + $event = new SearchAliasesEvent($aliases, $targetEntityClasses); + $this->dispatcher->dispatch(SearchAliasesEvent::EVENT_NAME, $event); + $aliases = $event->getAliases(); return $aliases; } diff --git a/src/Oro/Bundle/ActivityBundle/Controller/ActivityController.php b/src/Oro/Bundle/ActivityBundle/Controller/ActivityController.php index 6b4f8dbfe73..b188061a1d5 100644 --- a/src/Oro/Bundle/ActivityBundle/Controller/ActivityController.php +++ b/src/Oro/Bundle/ActivityBundle/Controller/ActivityController.php @@ -63,7 +63,7 @@ public function contextAction($activity, $id) throw new AccessDeniedException(); } - $entityTargets = $this->get('oro_entity.entity_context_provider')->getSupportedTargets($entity); + $entityTargets = $this->get('oro_activity.provider.context_grid')->getSupportedTargets($entity); $entityClassAlias = $this->get('oro_entity.entity_alias_resolver')->getPluralAlias($entityClass); return [ @@ -93,12 +93,14 @@ public function contextAction($activity, $id) */ public function contextGridAction($activity, $id, $entityClass = null) { - $gridName = $this->get('oro_entity.entity_context_provider')->getContextGridByEntity($entityClass); + $entityClass = $this->get('oro_entity.routing_helper')->resolveEntityClass($entityClass); + $gridName = $this->get('oro_activity.provider.context_grid')->getContextGridByEntity($entityClass); // Need to specify parameters for Oro\Bundle\ActivityBundle\EventListener\Datagrid\ContextGridListener $params = [ 'activityClass' => $activity, - 'activityId' => $id + 'activityId' => $id, + 'class_name' => $entityClass, ]; return [ diff --git a/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityContextApiEntityManager.php b/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityContextApiEntityManager.php index 5712efe1246..c2704256e8f 100644 --- a/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityContextApiEntityManager.php +++ b/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityContextApiEntityManager.php @@ -5,11 +5,12 @@ use Doctrine\Common\Util\ClassUtils; use Doctrine\Common\Persistence\ObjectManager; -use Oro\Bundle\ActivityBundle\Model\ActivityInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Oro\Bundle\ActivityBundle\Model\ActivityInterface; use Oro\Bundle\ActivityBundle\Manager\ActivityManager; use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; use Oro\Bundle\EntityBundle\ORM\EntityAliasResolver; @@ -17,6 +18,7 @@ use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper; use Oro\Bundle\SearchBundle\Engine\ObjectMapper; use Oro\Bundle\SoapBundle\Entity\Manager\ApiEntityManager; +use Oro\Bundle\ActivityBundle\Event\PrepareContextTitleEvent; class ActivityContextApiEntityManager extends ApiEntityManager { @@ -44,6 +46,9 @@ class ActivityContextApiEntityManager extends ApiEntityManager /** @var DoctrineHelper */ protected $doctrineHelper; + /** @var EventDispatcherInterface */ + protected $dispatcher; + /** * @param ObjectManager $om * @param ActivityManager $activityManager @@ -54,6 +59,7 @@ class ActivityContextApiEntityManager extends ApiEntityManager * @param ObjectMapper $objectMapper * @param TranslatorInterface $translator * @param DoctrineHelper $doctrineHelper + * @param EventDispatcherInterface $dispatcher */ public function __construct( ObjectManager $om, @@ -64,7 +70,8 @@ public function __construct( EntityAliasResolver $entityAliasResolver, ObjectMapper $objectMapper, TranslatorInterface $translator, - DoctrineHelper $doctrineHelper + DoctrineHelper $doctrineHelper, + EventDispatcherInterface $dispatcher ) { parent::__construct(null, $om); @@ -76,6 +83,7 @@ public function __construct( $this->mapper = $objectMapper; $this->translator = $translator; $this->doctrineHelper = $doctrineHelper; + $this->dispatcher = $dispatcher; } /** @@ -110,32 +118,18 @@ public function getActivityContext($class, $id) $item = []; $config = $entityProvider->getConfig($targetClass); - $metadata = $this->configManager->getEntityMetadata($targetClass); $safeClassName = $this->entityClassNameHelper->getUrlSafeClassName($targetClass); - $link = null; - if ($metadata) { - $link = $this->router->generate($metadata->getRoute(), ['id' => $targetId]); - } elseif ($link === null && ExtendHelper::isCustomEntity($targetClass)) { - // Generate view link for the custom entity - $link = $this->router->generate( - 'oro_entity_view', - [ - 'id' => $targetId, - 'entityName' => $safeClassName - - ] - ); - } - - if ($fields = $this->mapper->getEntityMapParameter($targetClass, 'title_fields')) { - $text = []; - foreach ($fields as $field) { - $text[] = $this->mapper->getFieldValue($target, $field); + if (!array_key_exists('title', $item) || !$item['title']) { + if ($fields = $this->mapper->getEntityMapParameter($targetClass, 'title_fields')) { + $text = []; + foreach ($fields as $field) { + $text[] = $this->mapper->getFieldValue($target, $field); + } + $item['title'] = implode(' ', $text); + } else { + $item['title'] = $this->translator->trans('oro.entity.item', ['%id%' => $targetId]); } - $item['title'] = implode(' ', $text); - } else { - $item['title'] = $this->translator->trans('oro.entity.item', ['%id%' => $targetId]); } $item['activityClassAlias'] = $this->entityAliasResolver->getPluralAlias($class); @@ -145,11 +139,49 @@ public function getActivityContext($class, $id) $item['targetClassName'] = $safeClassName; $item['icon'] = $config->get('icon'); - $item['link'] = $link; + $item['link'] = $this->getContextLink($targetClass, $targetId); + + $event = new PrepareContextTitleEvent($item, $targetClass); + $this->dispatcher->dispatch(PrepareContextTitleEvent::EVENT_NAME, $event); + $item = $event->getItem(); $result[] = $item; } return $result; } + + /** + * @param string $targetClass The FQCN of the activity target entity + * @param int $targetId The identifier of the activity target entity + * + * @return string|null + */ + protected function getContextLink($targetClass, $targetId) + { + $metadata = $this->configManager->getEntityMetadata($targetClass); + $link = null; + if ($metadata) { + try { + $route = $metadata->getRoute('view', true); + } catch (\LogicException $exception) { + // Need for cases when entity does not have route. + return null; + } + $link = $this->router->generate($route, ['id' => $targetId]); + } elseif (ExtendHelper::isCustomEntity($targetClass)) { + $safeClassName = $this->entityClassNameHelper->getUrlSafeClassName($targetClass); + // Generate view link for the custom entity + $link = $this->router->generate( + 'oro_entity_view', + [ + 'id' => $targetId, + 'entityName' => $safeClassName + + ] + ); + } + + return $link; + } } diff --git a/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityEntityDeleteHandler.php b/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityEntityDeleteHandler.php index 67e4c648540..b6fa0385a09 100644 --- a/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityEntityDeleteHandler.php +++ b/src/Oro/Bundle/ActivityBundle/Entity/Manager/ActivityEntityDeleteHandler.php @@ -4,6 +4,7 @@ use Doctrine\ORM\EntityNotFoundException; +use Oro\Bundle\ActivityBundle\Manager\ActivityManager; use Oro\Bundle\ActivityBundle\Model\ActivityInterface; use Oro\Bundle\SecurityBundle\Exception\ForbiddenException; use Oro\Bundle\SecurityBundle\SecurityFacade; @@ -16,6 +17,9 @@ class ActivityEntityDeleteHandler extends DeleteHandler /** @var SecurityFacade */ protected $securityFacade; + /** @var ActivityManager */ + protected $activityManager; + /** * @param SecurityFacade $securityFacade */ @@ -24,6 +28,14 @@ public function setSecurityFacade(SecurityFacade $securityFacade) $this->securityFacade = $securityFacade; } + /** + * @param ActivityManager $activityManager + */ + public function setActivityManager(ActivityManager $activityManager) + { + $this->activityManager = $activityManager; + } + /** * Handle delete entity object. * @@ -54,7 +66,7 @@ public function handleDelete($id, ApiEntityManager $manager) throw new ForbiddenException('has no view permissions for related entity'); } - $entity->removeActivityTarget($targetEntity); + $this->activityManager->removeActivityTarget($entity, $targetEntity); $em->flush(); } diff --git a/src/Oro/Bundle/ActivityBundle/Event/PrepareContextTitleEvent.php b/src/Oro/Bundle/ActivityBundle/Event/PrepareContextTitleEvent.php new file mode 100644 index 00000000000..c259e92adc4 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Event/PrepareContextTitleEvent.php @@ -0,0 +1,59 @@ +item = $item; + $this->targetClass = $targetClass; + } + + /** + * Return item array + * + * @return array + */ + public function getItem() + { + return $this->item; + } + + /** + * Set the item array + * + * @param array $item + */ + public function setItem($item) + { + $this->item = $item; + } + + /** + * Return target class + * + * @return string + */ + public function getTargetClass() + { + return $this->targetClass; + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Event/SearchAliasesEvent.php b/src/Oro/Bundle/ActivityBundle/Event/SearchAliasesEvent.php new file mode 100644 index 00000000000..cd1c2e78314 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Event/SearchAliasesEvent.php @@ -0,0 +1,59 @@ +aliases = $aliases; + $this->targetClasses = $targetClasses; + } + + /** + * Return aliases config array + * + * @return array + */ + public function getAliases() + { + return $this->aliases; + } + + /** + * Set the aliases config array + * + * @param array $aliases + */ + public function setAliases($aliases) + { + $this->aliases = $aliases; + } + + /** + * Return target classes array + * + * @return array + */ + public function getTargetClasses() + { + return $this->targetClasses; + } +} diff --git a/src/Oro/Bundle/ActivityBundle/EventListener/Datagrid/ContextGridListener.php b/src/Oro/Bundle/ActivityBundle/EventListener/Datagrid/ContextGridListener.php index 0281dbd1cd8..a4e404c0b34 100644 --- a/src/Oro/Bundle/ActivityBundle/EventListener/Datagrid/ContextGridListener.php +++ b/src/Oro/Bundle/ActivityBundle/EventListener/Datagrid/ContextGridListener.php @@ -60,10 +60,9 @@ public function onBuildAfter(BuildAfter $event) $class = $parameters->get('activityClass'); $entityClass = $this->entityClassNameHelper->resolveEntityClass($class, true); - /** @var ActivityInterface $entity */ $entity = $this->doctrineHelper->getEntity($entityClass, $id); - if ($entity) { + if ($entity && $entity instanceof ActivityInterface) { $targetsArray = $entity->getActivityTargets($targetClass); $targetIds = []; @@ -72,7 +71,7 @@ public function onBuildAfter(BuildAfter $event) } if ($targetIds) { - $queryBuilder->andWhere($queryBuilder->expr()->notIn("$alias.id", $targetIds)); + $queryBuilder->andWhere($queryBuilder->expr()->notIn(sprintf('%s.id', $alias), $targetIds)); } } } diff --git a/src/Oro/Bundle/ActivityBundle/Form/DataTransformer/ContextsToViewTransformer.php b/src/Oro/Bundle/ActivityBundle/Form/DataTransformer/ContextsToViewTransformer.php index bf74880d7ad..f534bb32f77 100644 --- a/src/Oro/Bundle/ActivityBundle/Form/DataTransformer/ContextsToViewTransformer.php +++ b/src/Oro/Bundle/ActivityBundle/Form/DataTransformer/ContextsToViewTransformer.php @@ -5,10 +5,12 @@ use Doctrine\Common\Util\ClassUtils; use Doctrine\ORM\EntityManager; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\DataTransformerInterface; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Oro\Bundle\ActivityBundle\Event\PrepareContextTitleEvent; use Oro\Bundle\EntityConfigBundle\Config\ConfigManager; use Oro\Bundle\SearchBundle\Engine\ObjectMapper; @@ -29,25 +31,31 @@ class ContextsToViewTransformer implements DataTransformerInterface /* @var TokenStorageInterface */ protected $securityTokenStorage; + /** @var EventDispatcherInterface */ + protected $dispatcher; + /** * @param EntityManager $entityManager * @param ConfigManager $configManager * @param TranslatorInterface $translator * @param ObjectMapper $mapper * @param TokenStorageInterface $securityTokenStorage + * @param EventDispatcherInterface $dispatcher */ public function __construct( EntityManager $entityManager, ConfigManager $configManager, TranslatorInterface $translator, ObjectMapper $mapper, - TokenStorageInterface $securityTokenStorage + TokenStorageInterface $securityTokenStorage, + EventDispatcherInterface $dispatcher ) { $this->entityManager = $entityManager; $this->configManager = $configManager; $this->translator = $translator; $this->mapper = $mapper; $this->securityTokenStorage = $securityTokenStorage; + $this->dispatcher = $dispatcher; } /** @@ -64,13 +72,14 @@ public function transform($value) $user = $this->securityTokenStorage->getToken()->getUser(); foreach ($value as $target) { // Exclude current user - if (ClassUtils::getClass($user) === ClassUtils::getClass($target) && + $targetClass = ClassUtils::getClass($target); + if (ClassUtils::getClass($user) === $targetClass && $user->getId() === $target->getId() ) { continue; } - if ($fields = $this->mapper->getEntityMapParameter(ClassUtils::getClass($target), 'title_fields')) { + if ($fields = $this->mapper->getEntityMapParameter($targetClass, 'title_fields')) { $text = []; foreach ($fields as $field) { $text[] = $this->mapper->getFieldValue($target, $field); @@ -79,10 +88,17 @@ public function transform($value) $text = [$this->translator->trans('oro.entity.item', ['%id%' => $target->getId()])]; } $text = implode(' ', $text); - if ($label = $this->getClassLabel(ClassUtils::getClass($target))) { + if ($label = $this->getClassLabel($targetClass)) { $text .= ' (' . $label . ')'; } + $item['title'] = $text; + $item['targetId'] = $target->getId(); + $event = new PrepareContextTitleEvent($item, $targetClass); + $this->dispatcher->dispatch(PrepareContextTitleEvent::EVENT_NAME, $event); + $item = $event->getItem(); + $text = $item['title']; + $result[] = json_encode( [ 'text' => $text, diff --git a/src/Oro/Bundle/ActivityBundle/Form/Type/ContextsSelectType.php b/src/Oro/Bundle/ActivityBundle/Form/Type/ContextsSelectType.php index 4bbc7deee86..0522b96a998 100644 --- a/src/Oro/Bundle/ActivityBundle/Form/Type/ContextsSelectType.php +++ b/src/Oro/Bundle/ActivityBundle/Form/Type/ContextsSelectType.php @@ -12,6 +12,7 @@ use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Translation\TranslatorInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Oro\Bundle\ActivityBundle\Form\DataTransformer\ContextsToViewTransformer; use Oro\Bundle\EntityConfigBundle\Config\ConfigManager; @@ -36,25 +37,31 @@ class ContextsSelectType extends AbstractType /* @var TokenStorageInterface */ protected $securityTokenStorage; + /** @var EventDispatcherInterface */ + protected $dispatcher; + /** * @param EntityManager $entityManager * @param ConfigManager $configManager * @param TranslatorInterface $translator * @param ObjectMapper $mapper * @param TokenStorageInterface $securityTokenStorage + * @param EventDispatcherInterface $dispatcher */ public function __construct( EntityManager $entityManager, ConfigManager $configManager, TranslatorInterface $translator, ObjectMapper $mapper, - TokenStorageInterface $securityTokenStorage + TokenStorageInterface $securityTokenStorage, + EventDispatcherInterface $dispatcher ) { $this->entityManager = $entityManager; $this->configManager = $configManager; $this->translator = $translator; $this->mapper = $mapper; $this->securityTokenStorage = $securityTokenStorage; + $this->dispatcher = $dispatcher; } /** @@ -69,7 +76,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) $this->configManager, $this->translator, $this->mapper, - $this->securityTokenStorage + $this->securityTokenStorage, + $this->dispatcher ) ); } diff --git a/src/Oro/Bundle/ActivityBundle/Form/Type/MultipleAssociationChoiceType.php b/src/Oro/Bundle/ActivityBundle/Form/Type/MultipleAssociationChoiceType.php new file mode 100644 index 00000000000..346ac062b9c --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Form/Type/MultipleAssociationChoiceType.php @@ -0,0 +1,51 @@ +getClassName(); + + /** @var FormView $choiceView */ + foreach ($view->children as $choiceView) { + // disable activity with same class as target entity + if ((isset($view->vars['disabled']) && $view->vars['disabled']) + || ($choiceView->vars['value'] === $targetClassName) + ) { + $choiceView->vars['disabled'] = true; + } + } + + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'oro_activity_multiple_association_choice'; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'oro_entity_extend_multiple_association_choice'; + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/OroActivityBundleInstaller.php b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/OroActivityBundleInstaller.php index d12ffde18a3..6512e5c8899 100644 --- a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/OroActivityBundleInstaller.php +++ b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/OroActivityBundleInstaller.php @@ -29,7 +29,7 @@ public function setContainer(ContainerInterface $container = null) */ public function getMigrationVersion() { - return 'v1_0'; + return 'v1_1'; } /** diff --git a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/OroActivityBundle.php b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/OroActivityBundle.php index 003e4115dc0..5eb16e5c06f 100644 --- a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/OroActivityBundle.php +++ b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/OroActivityBundle.php @@ -7,9 +7,6 @@ use Oro\Bundle\MigrationBundle\Migration\Migration; use Oro\Bundle\MigrationBundle\Migration\QueryBag; -/** - * - */ class OroActivityBundle implements Migration { /** diff --git a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/UpdateActivityButtonConfigQuery.php b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/UpdateActivityButtonConfigQuery.php index 1731aec1fb3..a93150a204a 100644 --- a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/UpdateActivityButtonConfigQuery.php +++ b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_0/UpdateActivityButtonConfigQuery.php @@ -10,7 +10,7 @@ class UpdateActivityButtonConfigQuery extends ParametrizedMigrationQuery { /** - * {inheritdoc} + * {@inheritdoc} */ public function getDescription() { @@ -21,7 +21,7 @@ public function getDescription() } /** - * {inheritdoc} + * {@inheritdoc} */ public function execute(LoggerInterface $logger) { diff --git a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/OroActivityBundle.php b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/OroActivityBundle.php new file mode 100644 index 00000000000..cb0ebc1c1d9 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/OroActivityBundle.php @@ -0,0 +1,19 @@ +addQuery(new RemoveUnusedContextConfigQuery()); + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/RemoveUnusedContextConfigQuery.php b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/RemoveUnusedContextConfigQuery.php new file mode 100644 index 00000000000..2840c2c2a20 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Migrations/Schema/v1_1/RemoveUnusedContextConfigQuery.php @@ -0,0 +1,73 @@ +removeContextConfigs($logger, true); + + return $logger->getMessages(); + } + + /** + * {@inheritdoc} + */ + public function execute(LoggerInterface $logger) + { + $this->removeContextConfigs($logger); + } + + /** + * @param LoggerInterface $logger + * @param bool $dryRun + */ + protected function removeContextConfigs(LoggerInterface $logger, $dryRun = false) + { + $configs = $this->loadConfigs($logger); + foreach ($configs as $id => $data) { + if (!isset($data['entity']['context-grid'])) { + continue; + } + unset($data['entity']['context-grid']); + + $query = 'UPDATE oro_entity_config SET data = :data WHERE id = :id'; + $params = ['data' => $data, 'id' => $id]; + $types = ['data' => 'array', 'id' => 'integer']; + $this->logQuery($logger, $query, $params, $types); + if (!$dryRun) { + $this->connection->executeUpdate($query, $params, $types); + } + } + } + + /** + * @param LoggerInterface $logger + * + * @return array key = {config id}, value = data + */ + protected function loadConfigs(LoggerInterface $logger) + { + $sql = 'SELECT id, data FROM oro_entity_config'; + $this->logQuery($logger, $sql); + + $result = []; + + $rows = $this->connection->fetchAll($sql); + foreach ($rows as $row) { + $result[$row['id']] = $this->connection->convertToPHPValue($row['data'], 'array'); + } + + return $result; + } +} diff --git a/src/Oro/Bundle/EntityBundle/Provider/EntityContextProvider.php b/src/Oro/Bundle/ActivityBundle/Provider/ContextGridProvider.php similarity index 60% rename from src/Oro/Bundle/EntityBundle/Provider/EntityContextProvider.php rename to src/Oro/Bundle/ActivityBundle/Provider/ContextGridProvider.php index 9a7a8ae5c39..234ff536310 100644 --- a/src/Oro/Bundle/EntityBundle/Provider/EntityContextProvider.php +++ b/src/Oro/Bundle/ActivityBundle/Provider/ContextGridProvider.php @@ -1,67 +1,63 @@ routingHelper = $routingHelper; - $this->entityProvider = $entityProvider; + $this->routingHelper = $routingHelper; + $this->entityProvider = $entityProvider; $this->entityConfigProvider = $entityConfigProvider; } /** * @param object $entity + * * @return array */ public function getSupportedTargets($entity) { $targetEntities = $this->entityProvider->getEntities(); - $entityTargets = []; + $entityTargets = []; if (!is_object($entity) || !method_exists($entity, 'supportActivityTarget')) { return $entityTargets; } $count = count($targetEntities); - for ($i=0; $i < $count; $i++) { + for ($i = 0; $i < $count; $i++) { $targetEntity = $targetEntities[$i]; - $className = $targetEntity['name']; - $gridName = $this->getContextGridByEntity($className); + $className = $targetEntity['name']; + $gridName = $this->getContextGridByEntity($className); if ($gridName && !empty($className) && $entity->supportActivityTarget($className)) { $entityTargets[] = [ - 'label' => $targetEntity['label'], + 'label' => $targetEntity['label'], 'className' => $this->routingHelper->getUrlSafeClassName($targetEntity['name']), - 'first' => count($entityTargets) === 0, - 'gridName' => $gridName + 'first' => count($entityTargets) === 0, + 'gridName' => $gridName ]; $i++; @@ -73,16 +69,22 @@ public function getSupportedTargets($entity) /** * @param string $entityClass + * * @return string|null */ public function getContextGridByEntity($entityClass) { if (!empty($entityClass)) { $entityClass = $this->routingHelper->resolveEntityClass($entityClass); + if (ExtendHelper::isCustomEntity($entityClass)) { + return 'custom-entity-grid'; + } $config = $this->entityConfigProvider->getConfig($entityClass); - $gridName = $config->get('context-grid'); - if ($gridName) { - return $gridName; + if ($config->has('context')) { + return $config->get('context'); + } + if ($config->has('default')) { + return $config->get('default'); } } diff --git a/src/Oro/Bundle/ActivityBundle/README.md b/src/Oro/Bundle/ActivityBundle/README.md index a574f392756..be7e5b1d776 100644 --- a/src/Oro/Bundle/ActivityBundle/README.md +++ b/src/Oro/Bundle/ActivityBundle/README.md @@ -273,3 +273,26 @@ Bind items declared in *placeholders.yml* to the activity entity using `action_b */ class Email extends ExtendEmail ``` + +How to configure custom grid for activity context dialog +-------------------------------------------------------- + +If you want to define context grid for entity(e.g User) in the activity context dialog you need to add the +`context` option in entity class `@Config` annotation, e.g: + +``` php +/** + * @Config( + * defaultValues={ + * "grid"={ + * default="default-grid", + * context="default-context-grid" + * } + * } + * ) + */ +class User extends ExtendUser +``` + +This option is used to recognize grid for entity with higher priority than `default` option. +In cases if these options (`context` or `default`) are not defined for entity, it won`t appear in the context dialog. diff --git a/src/Oro/Bundle/ActivityBundle/Resources/config/assets.yml b/src/Oro/Bundle/ActivityBundle/Resources/config/assets.yml index fca15891bf9..1882abb6b81 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/config/assets.yml +++ b/src/Oro/Bundle/ActivityBundle/Resources/config/assets.yml @@ -1,3 +1,3 @@ css: 'oroactivity': - - 'bundles/oroactivity/css/less/style.less' + - 'bundles/oroactivity/css/less/main.less' diff --git a/src/Oro/Bundle/ActivityBundle/Resources/config/entity_config.yml b/src/Oro/Bundle/ActivityBundle/Resources/config/entity_config.yml index 84ba0b116c3..a9270e25b5c 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/config/entity_config.yml +++ b/src/Oro/Bundle/ActivityBundle/Resources/config/entity_config.yml @@ -8,7 +8,7 @@ oro_entity_config: require_schema_update: true priority: 250 form: - type: oro_entity_extend_multiple_association_choice + type: oro_activity_multiple_association_choice options: block: associations required: false @@ -74,3 +74,11 @@ oro_entity_config: action_link_widget: # string options: auditable: false + + grid: + entity: + items: + # grid name that used for rendering entity context + context: # string + options: + auditable: false diff --git a/src/Oro/Bundle/ActivityBundle/Resources/config/form.yml b/src/Oro/Bundle/ActivityBundle/Resources/config/form.yml index 2c45598d918..02ae491ca4d 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/config/form.yml +++ b/src/Oro/Bundle/ActivityBundle/Resources/config/form.yml @@ -1,3 +1,6 @@ +parameters: + oro_activity.type.multiple_association_choice.class: Oro\Bundle\ActivityBundle\Form\Type\MultipleAssociationChoiceType + services: oro_activity.form.type.contexts_select: class: Oro\Bundle\ActivityBundle\Form\Type\ContextsSelectType @@ -7,6 +10,7 @@ services: - @translator - @oro_search.mapper - @security.token_storage + - @event_dispatcher tags: - { name: form.type, alias: oro_activity_contexts_select } @@ -21,3 +25,11 @@ services: - [setRequest, [@?request=]] tags: - { name: form.type_extension, alias: form } + + oro_activity.type.multiple_association_choice: + class: %oro_activity.type.multiple_association_choice.class% + arguments: + - @oro_entity_extend.association_type_helper + - @oro_entity_config.config_manager + tags: + - { name: form.type, alias: oro_activity_multiple_association_choice } diff --git a/src/Oro/Bundle/ActivityBundle/Resources/config/services.yml b/src/Oro/Bundle/ActivityBundle/Resources/config/services.yml index a621ac871c2..7b40325dc1c 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/ActivityBundle/Resources/config/services.yml @@ -13,7 +13,7 @@ parameters: oro_activity.handler.delete.activity_entity.class: Oro\Bundle\ActivityBundle\Entity\Manager\ActivityEntityDeleteHandler oro_activity.form.handler.activity_entity.api.class: Oro\Bundle\ActivityBundle\Form\Handler\ActivityEntityApiHandler oro_activity.manager.activity_target.api.class: Oro\Bundle\ActivityBundle\Entity\Manager\ActivityTargetApiEntityManager - oro_activity.listener.datagrid.context.class: Oro\Bundle\ActivityBundle\EventListener\Datagrid\ContextGridListener + services: oro_activity.manager: class: %oro_activity.manager.class% @@ -60,6 +60,21 @@ services: tags: - { name: oro_activity.activity_widget_provider } + oro_activity.provider.context_grid: + class: Oro\Bundle\ActivityBundle\Provider\ContextGridProvider + arguments: + - @oro_entity.routing_helper + - @oro_entity.entity_provider + - @oro_entity_config.provider.grid + + oro_activity.listener.context_grid: + class: Oro\Bundle\ActivityBundle\EventListener\Datagrid\ContextGridListener + arguments: + - @oro_entity.doctrine_helper + - @oro_entity.entity_class_name_helper + tags: + - { name: kernel.event_listener, event: oro_datagrid.datagrid.build.after, method: onBuildAfter } + oro_activity.widget_provider.actions: class: %oro_activity.widget_provider.actions.class% arguments: @@ -113,6 +128,7 @@ services: parent: oro_soap.handler.delete.abstract calls: - [setSecurityFacade, [@oro_security.security_facade]] + - [setActivityManager, [@oro_activity.manager]] oro_activity.form.handler.autocomplete: class: Oro\Bundle\ActivityBundle\Autocomplete\ContextSearchHandler @@ -169,3 +185,4 @@ services: - @oro_search.mapper - @translator - @oro_entity.doctrine_helper + - @event_dispatcher diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/style.less b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/activity-context.less similarity index 71% rename from src/Oro/Bundle/ActivityBundle/Resources/public/css/less/style.less rename to src/Oro/Bundle/ActivityBundle/Resources/public/css/less/activity-context.less index 506f6ce89eb..6acf5ec67be 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/style.less +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/activity-context.less @@ -1,11 +1,13 @@ -@import "oroui/css/less/mixins"; - .activity-list-widget { .activity-context-activity-list { padding: 0 @horizontalPadding; } } +.activity-context-activity { + display: none; +} + .activity-context-activity-list { margin-bottom: 5px; } @@ -19,11 +21,10 @@ .context-item { list-style: none; cursor: pointer; - padding: 0 7px 0 7px; white-space: nowrap; } -.context-item:hover, .context-item.active { +.context-item.active { background-color: #ebebeb; } @@ -52,8 +53,13 @@ } .context-items-dropdown { - top: 35px; - left: 15px; + top: 38px; + left: 14px; + border-color: #d3d3d3; + .context-item { + padding: 2px 8px; + font-size: 13px; + } } .activity-context-current-block { @@ -63,6 +69,9 @@ outline: none; margin: 10px 10px 15px 10px; box-shadow: none; + .btn-group.open & { + box-shadow: none; + } } .activity-context-current-item { @@ -70,3 +79,14 @@ font-weight: bold; color: #666666; } + +.control-group .controls .activity-context-activity-items { + padding-top: 5px; + margin-left: 0; + .context-item { + color: #777; + font-size: 13px; + line-height: 20px; + padding: 0 2px; + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/main.less b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/main.less new file mode 100644 index 00000000000..d46d55814c3 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/main.less @@ -0,0 +1,3 @@ +@import "oroui/css/less/mixins"; +@import "./activity-context"; +@import "./mobile/main"; diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/activity-context.less b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/activity-context.less new file mode 100644 index 00000000000..e7a7cd2cd41 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/activity-context.less @@ -0,0 +1,49 @@ +// e.g. inside a page header +.activity-context-activity-block { + .activity-context-activity { + width: 100%; + .activity-context-activity-label, + .activity-context-activity-items { + font-size: inherit; + line-height: inherit; + } + .activity-context-activity-items .context-item { + font-size: inherit; + } + } +} + +// e.g. inside activity list widget +.activity-context-activity-list { + margin-bottom: 7px; + .activity-context-activity-label, + .activity-context-activity-items { + font-size: 12px; + line-height: 1.2em; + } + .activity-context-activity-label { + margin-bottom: 5px; + color: #777; + float: none; + text-align: left; + } + .activity-context-activity-items { + margin-left: 0; + padding-left: 0; + .context-item { + font-size: inherit; + line-height: inherit; + } + } +} + +.activity-list-widget { + .activity-context-activity-list { + padding: 0 @contentPadding; + } + .responsive-cell { + .activity-context-activity-list { + padding: 0; + } + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/main.less b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/main.less new file mode 100644 index 00000000000..83096550294 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/css/less/mobile/main.less @@ -0,0 +1,4 @@ +.mobile-version { + @import "oroui/css/less/mobile/variables"; + @import "./activity-context"; +} diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/components/activity-context-activity-component.js b/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/components/activity-context-activity-component.js index 910436f147c..babd5d660b0 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/components/activity-context-activity-component.js +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/components/activity-context-activity-component.js @@ -12,12 +12,7 @@ define(function(require) { initialize: function(options) { this.options = options; - this.init(); - }, - - init: function() { this.initView(); - this.contextsView.render(); }, initView: function() { diff --git a/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/views/activity-context-activity-view.js b/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/views/activity-context-activity-view.js index a2f3161e7f3..e9b3eec5fb8 100644 --- a/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/views/activity-context-activity-view.js +++ b/src/Oro/Bundle/ActivityBundle/Resources/public/js/app/views/activity-context-activity-view.js @@ -24,7 +24,7 @@ define([ this.template = _.template($('#activity-context-activity-list').html()); this.$containerContextTargets = $(options.el).find('.activity-context-activity-items'); - this.collection = new ActivityContextActivityCollection('oro_api_delete_activity_relation'); + this.collection = new ActivityContextActivityCollection(); this.editable = options.editable; this.initEvents(); @@ -74,11 +74,7 @@ define([ }, render: function() { - if (this.collection.length === 0) { - this.$el.hide(); - } else { - this.$el.show(); - } + this.$el.toggle(this.collection.length > 0); }, initEvents: function() { @@ -99,6 +95,7 @@ define([ self.$containerContextTargets.append($view); $view.find('i.icon-remove').click(function() { + $view.fadeOut(); model.destroy({ success: function(model, response) { messenger.notificationFlashMessage('success', __('oro.activity.contexts.removed')); @@ -112,6 +109,7 @@ define([ } }, error: function(model, response) { + $view.show(); messenger.showErrorMessage(__('oro.ui.item_delete_error'), response.responseJSON || {}); } }); diff --git a/src/Oro/Bundle/ActivityBundle/Tests/Unit/Event/SearchAliasesEventTest.php b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Event/SearchAliasesEventTest.php new file mode 100644 index 00000000000..a73fa873400 --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Event/SearchAliasesEventTest.php @@ -0,0 +1,18 @@ +assertSame($aliases, $event->getAliases()); + $updatedAliases = array_merge($aliases, ['customEntity']); + $event->setAliases($updatedAliases); + $this->assertSame($updatedAliases, $event->getAliases()); + } +} diff --git a/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/ContextsSelectTypeTest.php b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/ContextsSelectTypeTest.php index 60b9720aaf7..42b3fff444b 100644 --- a/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/ContextsSelectTypeTest.php +++ b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/ContextsSelectTypeTest.php @@ -26,6 +26,9 @@ class ContextsSelectTypeTest extends TypeTestCase /* @var \PHPUnit_Framework_MockObject_MockObject */ protected $securityTokenStorage; + /* @var \PHPUnit_Framework_MockObject_MockObject */ + protected $dispatcher; + protected function setUp() { parent::setUp(); @@ -45,6 +48,10 @@ protected function setUp() ->disableOriginalConstructor() ->getMock(); + $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->securityTokenStorage = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface') ->disableOriginalConstructor() @@ -73,7 +80,8 @@ public function testBuildForm() $this->configManager, $this->translator, $this->mapper, - $this->securityTokenStorage + $this->securityTokenStorage, + $this->dispatcher ); $type->buildForm($builder, []); } @@ -102,7 +110,8 @@ public function testSetDefaultOptions() $this->configManager, $this->translator, $this->mapper, - $this->securityTokenStorage + $this->securityTokenStorage, + $this->dispatcher ); $type->setDefaultOptions($resolver); } @@ -114,7 +123,8 @@ public function testGetParent() $this->configManager, $this->translator, $this->mapper, - $this->securityTokenStorage + $this->securityTokenStorage, + $this->dispatcher ); $this->assertEquals('genemu_jqueryselect2_hidden', $type->getParent()); @@ -127,7 +137,8 @@ public function testGetName() $this->configManager, $this->translator, $this->mapper, - $this->securityTokenStorage + $this->securityTokenStorage, + $this->dispatcher ); $this->assertEquals('oro_activity_contexts_select', $type->getName()); } diff --git a/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/MultipleAssociationChoiceTypeTest.php b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/MultipleAssociationChoiceTypeTest.php new file mode 100644 index 00000000000..07ffcae8ccc --- /dev/null +++ b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Form/Type/MultipleAssociationChoiceTypeTest.php @@ -0,0 +1,97 @@ +getMockBuilder('Oro\Bundle\EntityBundle\ORM\EntityClassResolver') + ->disableOriginalConstructor() + ->getMock(); + + $this->type = new MultipleAssociationChoiceType( + new AssociationTypeHelper($this->configManager, $entityClassResolver), + $this->configManager + ); + } + + public function testFinishViewForDisabled() + { + $this->configManager->expects($this->any()) + ->method('getProvider') + ->will( + $this->returnValueMap( + [ + ['test', $this->testConfigProvider], + ] + ) + ); + + $this->testConfigProvider->expects($this->once()) + ->method('hasConfig') + ->with('Test\Entity2') + ->will($this->returnValue(false)); + $this->testConfigProvider->expects($this->never()) + ->method('getConfig'); + + $view = new FormView(); + $form = new Form($this->getMock('Symfony\Component\Form\FormConfigInterface')); + $options = [ + 'config_id' => new EntityConfigId('test', 'Test\Entity2'), + 'association_class' => 'test' + ]; + + $view->vars['disabled'] = false; + + $view->children[0] = new FormView($view); + $view->children[1] = new FormView($view); + + $view->children[0]->vars['value'] = 'Test\Entity1'; + $view->children[1]->vars['value'] = 'Test\Entity2'; + + $this->type->finishView($view, $form, $options); + + $this->assertEquals( + [ + 'attr' => [], + 'value' => 'Test\Entity1' + ], + $view->children[0]->vars + ); + $this->assertEquals( + [ + 'attr' => [], + 'disabled' => true, + 'value' => 'Test\Entity2' + ], + $view->children[1]->vars + ); + } + + public function testGetName() + { + $this->assertEquals('oro_activity_multiple_association_choice', $this->type->getName()); + } + + public function testGetParent() + { + $this->assertEquals('oro_entity_extend_multiple_association_choice', $this->type->getParent()); + } +} diff --git a/src/Oro/Bundle/EntityBundle/Tests/Unit/Provider/EntityContextProviderTest.php b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Provider/ContextGridProviderTest.php similarity index 85% rename from src/Oro/Bundle/EntityBundle/Tests/Unit/Provider/EntityContextProviderTest.php rename to src/Oro/Bundle/ActivityBundle/Tests/Unit/Provider/ContextGridProviderTest.php index c5da4ce6fb7..628d50538a5 100644 --- a/src/Oro/Bundle/EntityBundle/Tests/Unit/Provider/EntityContextProviderTest.php +++ b/src/Oro/Bundle/ActivityBundle/Tests/Unit/Provider/ContextGridProviderTest.php @@ -1,10 +1,10 @@ configProvider = $this ->getMockBuilder('Oro\Bundle\EntityConfigBundle\Provider\ConfigProvider') ->disableOriginalConstructor() - ->setMethods(['getConfig', 'get']) + ->setMethods(['getConfig', 'has', 'get']) ->getMock(); $this->configProvider->expects($this->any()) @@ -86,12 +86,17 @@ protected function setUp() ->with($this->routingHelper->getUrlSafeClassName($this->entityClass)) ->will($this->returnValue($this->configProvider)); + $this->configProvider->expects($this->any()) + ->method('has') + ->with('context') + ->willReturn(true); + $this->configProvider->expects($this->any()) ->method('get') - ->with('context-grid') + ->with('context') ->will($this->returnValue($this->expectedGridName)); - $this->provider = new EntityContextProvider( + $this->provider = new ContextGridProvider( $this->routingHelper, $this->entityProvider, $this->configProvider diff --git a/src/Oro/Bundle/ActivityListBundle/Entity/Manager/ActivityListManager.php b/src/Oro/Bundle/ActivityListBundle/Entity/Manager/ActivityListManager.php index 48feaa073c1..8a9c276663f 100644 --- a/src/Oro/Bundle/ActivityListBundle/Entity/Manager/ActivityListManager.php +++ b/src/Oro/Bundle/ActivityListBundle/Entity/Manager/ActivityListManager.php @@ -2,12 +2,12 @@ namespace Oro\Bundle\ActivityListBundle\Entity\Manager; -use Doctrine\Bundle\DoctrineBundle\Registry; -use Doctrine\ORM\EntityManager; use Doctrine\ORM\QueryBuilder; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Security\Core\Util\ClassUtils; +use Oro\Bundle\ActivityListBundle\Event\ActivityListPreQueryBuildEvent; use Oro\Bundle\ActivityListBundle\Helper\ActivityInheritanceTargetsHelper; use Oro\Bundle\ActivityBundle\EntityConfig\ActivityScope; use Oro\Bundle\ActivityListBundle\Model\ActivityListGroupProviderInterface; @@ -55,6 +55,9 @@ class ActivityListManager /** @var ActivityInheritanceTargetsHelper */ protected $activityInheritanceTargetsHelper; + /** @var EventDispatcherInterface */ + protected $eventDispatcher; + /** * @param SecurityFacade $securityFacade * @param EntityNameResolver $entityNameResolver @@ -66,6 +69,7 @@ class ActivityListManager * @param DoctrineHelper $doctrineHelper * @param ActivityListAclCriteriaHelper $aclHelper * @param ActivityInheritanceTargetsHelper $activityInheritanceTargetsHelper + * @param EventDispatcherInterface $eventDispatcher * * @SuppressWarnings(PHPMD.ExcessiveParameterList) */ @@ -79,7 +83,8 @@ public function __construct( CommentApiManager $commentManager, DoctrineHelper $doctrineHelper, ActivityListAclCriteriaHelper $aclHelper, - ActivityInheritanceTargetsHelper $activityInheritanceTargetsHelper + ActivityInheritanceTargetsHelper $activityInheritanceTargetsHelper, + EventDispatcherInterface $eventDispatcher ) { $this->securityFacade = $securityFacade; $this->entityNameResolver = $entityNameResolver; @@ -91,6 +96,7 @@ public function __construct( $this->doctrineHelper = $doctrineHelper; $this->activityListAclHelper = $aclHelper; $this->activityInheritanceTargetsHelper = $activityInheritanceTargetsHelper; + $this->eventDispatcher = $eventDispatcher; } /** @@ -260,15 +266,18 @@ public function getEntityViewModel(ActivityList $entity, $targetEntityData = []) /** * @param string $entityClass - * @param string $entityId + * @param int $entityId * * @return QueryBuilder */ protected function getBaseQB($entityClass, $entityId) { + $event = new ActivityListPreQueryBuildEvent($entityClass, $entityId); + $this->eventDispatcher->dispatch(ActivityListPreQueryBuildEvent::EVENT_NAME, $event); + $entityIds = $event->getTargetIds(); return $this->getRepository()->getBaseActivityListQueryBuilder( $entityClass, - $entityId, + $entityIds, $this->config->get('oro_activity_list.sorting_field'), $this->config->get('oro_activity_list.sorting_direction'), $this->config->get('oro_activity_list.grouping') diff --git a/src/Oro/Bundle/ActivityListBundle/Entity/Repository/ActivityListRepository.php b/src/Oro/Bundle/ActivityListBundle/Entity/Repository/ActivityListRepository.php index 9732ad34c46..7b1100d6208 100644 --- a/src/Oro/Bundle/ActivityListBundle/Entity/Repository/ActivityListRepository.php +++ b/src/Oro/Bundle/ActivityListBundle/Entity/Repository/ActivityListRepository.php @@ -54,7 +54,7 @@ public function getActivityListQueryBuilder( /** * @param string $entityClass - * @param integer $entityId + * @param integer|integer[] $entityIds * @param string $orderField * @param string $orderDirection * @param boolean $grouping @@ -63,16 +63,27 @@ public function getActivityListQueryBuilder( */ public function getBaseActivityListQueryBuilder( $entityClass, - $entityId, + $entityIds, $orderField = 'updatedAt', $orderDirection = 'DESC', $grouping = false ) { + if (is_scalar($entityIds)) { + $entityIds = [$entityIds]; + } $queryBuilder = $this->createQueryBuilder('activity') ->leftJoin('activity.' . $this->getAssociationName($entityClass), 'r') - ->leftJoin('activity.activityOwners', 'ao') - ->where('r.id = :entityId') - ->setParameter('entityId', $entityId) + ->leftJoin('activity.activityOwners', 'ao'); + if (count($entityIds) > 1) { + $queryBuilder + ->where('r.id IN (:entityIds)') + ->setParameter('entityIds', $entityIds); + } else { + $queryBuilder + ->where('r.id = :entityId') + ->setParameter('entityId', reset($entityIds)); + } + $queryBuilder ->orderBy('activity.' . $orderField, $orderDirection) ->groupBy('activity.id'); diff --git a/src/Oro/Bundle/ActivityListBundle/Event/ActivityListPreQueryBuildEvent.php b/src/Oro/Bundle/ActivityListBundle/Event/ActivityListPreQueryBuildEvent.php new file mode 100644 index 00000000000..ea1ed789a5d --- /dev/null +++ b/src/Oro/Bundle/ActivityListBundle/Event/ActivityListPreQueryBuildEvent.php @@ -0,0 +1,68 @@ +targetClass = $targetClass; + $this->targetId = $targetId; + } + + /** + * @return string + */ + public function getTargetClass() + { + return $this->targetClass; + } + + /** + * @return integer[] + */ + public function getTargetIds() + { + if (!$this->targetIds) { + $this->targetIds = [$this->targetId]; + } + + return $this->targetIds; + } + + /** + * @return integer + */ + public function getTargetId() + { + return $this->targetId; + } + + /** + * @param integer[] $targetIds + */ + public function setTargetIds(array $targetIds) + { + $this->targetIds = $targetIds; + } +} diff --git a/src/Oro/Bundle/ActivityListBundle/Model/Strategy/ReplaceStrategy.php b/src/Oro/Bundle/ActivityListBundle/Model/Strategy/ReplaceStrategy.php index 31104106d0c..dd96f740ae4 100644 --- a/src/Oro/Bundle/ActivityListBundle/Model/Strategy/ReplaceStrategy.php +++ b/src/Oro/Bundle/ActivityListBundle/Model/Strategy/ReplaceStrategy.php @@ -3,6 +3,9 @@ namespace Oro\Bundle\ActivityListBundle\Model\Strategy; use Symfony\Component\Security\Core\Util\ClassUtils; + +use Oro\Component\PhpUtils\ArrayUtil; + use Oro\Bundle\ActivityBundle\Manager\ActivityManager; use Oro\Bundle\ActivityListBundle\Entity\Manager\ActivityListManager; use Oro\Bundle\ActivityListBundle\Entity\ActivityList; @@ -10,12 +13,7 @@ use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; use Oro\Bundle\EntityMergeBundle\Data\FieldData; use Oro\Bundle\EntityMergeBundle\Model\Strategy\StrategyInterface; -use Oro\Bundle\UIBundle\Tools\ArrayUtils; -/** - * Class ReplaceStrategy - * @package Oro\Bundle\ActivityListBundle\Model\Strategy - */ class ReplaceStrategy implements StrategyInterface { /** @var ActivityListManager */ @@ -56,7 +54,7 @@ public function merge(FieldData $fieldData) $activityClass = $fieldMetadata->get('type'); $activityListItems = $this->getActivitiesByEntity($masterEntity, $activityClass); - $activityIds = ArrayUtils::arrayColumn($activityListItems, 'relatedActivityId'); + $activityIds = ArrayUtil::arrayColumn($activityListItems, 'relatedActivityId'); $activities = $this->doctrineHelper->getEntityRepository($activityClass)->findBy(['id' => $activityIds]); foreach ($activities as $activity) { @@ -65,7 +63,7 @@ public function merge(FieldData $fieldData) $activityListItems = $this->getActivitiesByEntity($sourceEntity, $activityClass); - $activityIds = ArrayUtils::arrayColumn($activityListItems, 'id'); + $activityIds = ArrayUtil::arrayColumn($activityListItems, 'id'); $entityClass = ClassUtils::getRealClass($masterEntity); $this->activityListManager ->replaceActivityTargetWithPlainQuery( @@ -75,7 +73,7 @@ public function merge(FieldData $fieldData) $masterEntity->getId() ); - $activityIds = ArrayUtils::arrayColumn($activityListItems, 'relatedActivityId'); + $activityIds = ArrayUtil::arrayColumn($activityListItems, 'relatedActivityId'); $this->activityListManager ->replaceActivityTargetWithPlainQuery( $activityIds, diff --git a/src/Oro/Bundle/ActivityListBundle/Model/Strategy/UniteStrategy.php b/src/Oro/Bundle/ActivityListBundle/Model/Strategy/UniteStrategy.php index 44621d1dc0f..24ee39db5b7 100644 --- a/src/Oro/Bundle/ActivityListBundle/Model/Strategy/UniteStrategy.php +++ b/src/Oro/Bundle/ActivityListBundle/Model/Strategy/UniteStrategy.php @@ -3,18 +3,16 @@ namespace Oro\Bundle\ActivityListBundle\Model\Strategy; use Symfony\Component\Security\Core\Util\ClassUtils; + +use Oro\Component\PhpUtils\ArrayUtil; + use Oro\Bundle\ActivityListBundle\Entity\Manager\ActivityListManager; use Oro\Bundle\ActivityListBundle\Entity\ActivityList; use Oro\Bundle\ActivityListBundle\Model\MergeModes; use Oro\Bundle\EntityBundle\ORM\DoctrineHelper; use Oro\Bundle\EntityMergeBundle\Model\Strategy\StrategyInterface; use Oro\Bundle\EntityMergeBundle\Data\FieldData; -use Oro\Bundle\UIBundle\Tools\ArrayUtils; -/** - * Class UniteStrategy - * @package Oro\Bundle\ActivityListBundle\Model\Strategy - */ class UniteStrategy implements StrategyInterface { /** @var ActivityListManager */ @@ -53,7 +51,7 @@ public function merge(FieldData $fieldData) $activityListItems = $queryBuilder->getQuery()->getResult(); - $activityIds = ArrayUtils::arrayColumn($activityListItems, 'id'); + $activityIds = ArrayUtil::arrayColumn($activityListItems, 'id'); $this->activityListManager ->replaceActivityTargetWithPlainQuery( $activityIds, @@ -62,7 +60,7 @@ public function merge(FieldData $fieldData) $masterEntity->getId() ); - $activityIds = ArrayUtils::arrayColumn($activityListItems, 'relatedActivityId'); + $activityIds = ArrayUtil::arrayColumn($activityListItems, 'relatedActivityId'); $this->activityListManager ->replaceActivityTargetWithPlainQuery( $activityIds, diff --git a/src/Oro/Bundle/ActivityListBundle/Placeholder/PlaceholderFilter.php b/src/Oro/Bundle/ActivityListBundle/Placeholder/PlaceholderFilter.php index c7b2931ecca..9e4b8c3a5fa 100644 --- a/src/Oro/Bundle/ActivityListBundle/Placeholder/PlaceholderFilter.php +++ b/src/Oro/Bundle/ActivityListBundle/Placeholder/PlaceholderFilter.php @@ -66,29 +66,11 @@ public function isApplicable($entity = null, $pageType = null) } $entityClass = $this->doctrineHelper->getEntityClass($entity); - if (!$this->configProvider->hasConfig($entityClass)) { - return false; - } - - $hasAppliedActivityAssociation = false; - $activityAssociations = $this->activityManager->getActivityAssociations($entityClass); - foreach ($activityAssociations as $activityAssociation) { - $isAssociationAccessible = ExtendHelper::isFieldAccessible( - $this->configProvider->getConfig( - $activityAssociation['className'], - $activityAssociation['associationName'] - ) - ); - if ($isAssociationAccessible) { - $hasAppliedActivityAssociation = true; - break; - } - } /** * If at least one activity is accessible we can continue otherwise no. */ - if (!$hasAppliedActivityAssociation) { + if (!$this->hasApplicableActivityAssociations($entityClass)) { return false; } @@ -102,6 +84,36 @@ public function isApplicable($entity = null, $pageType = null) ); } + /** + * @param string $entityClass + * @return bool + */ + protected function hasApplicableActivityAssociations($entityClass) + { + if (!$this->configProvider->hasConfig($entityClass)) { + return false; + } + $supportedActivities = $this->activityListProvider->getSupportedActivities(); + foreach ($supportedActivities as $supportedActivity) { + if ($this->activityListProvider->isApplicableTarget($entityClass, $supportedActivity)) { + return true; + } + } + $activityAssociations = $this->activityManager->getActivityAssociations($entityClass); + foreach ($activityAssociations as $activityAssociation) { + $isAssociationAccessible = ExtendHelper::isFieldAccessible( + $this->configProvider->getConfig( + $activityAssociation['className'], + $activityAssociation['associationName'] + ) + ); + if ($isAssociationAccessible) { + return true; + } + } + return false; + } + /** * @param string $entityClass * @param int $pageType diff --git a/src/Oro/Bundle/ActivityListBundle/Provider/ActivityListChainProvider.php b/src/Oro/Bundle/ActivityListBundle/Provider/ActivityListChainProvider.php index 2cf79f7df5f..8847ede7b4b 100644 --- a/src/Oro/Bundle/ActivityListBundle/Provider/ActivityListChainProvider.php +++ b/src/Oro/Bundle/ActivityListBundle/Provider/ActivityListChainProvider.php @@ -20,8 +20,6 @@ use Oro\Bundle\UIBundle\Tools\HtmlTagHelper; /** - * Class ActivityListChainProvider - * @package Oro\Bundle\ActivityListBundle\Provider * @SuppressWarnings(PHPMD.CouplingBetweenObjects) * @SuppressWarnings(PHPMD.ExcessiveClassComplexity) */ @@ -90,9 +88,9 @@ public function addProvider(ActivityListProviderInterface $provider) } /** - * Get array providers + * Get all registered providers * - * @return \Oro\Bundle\ActivityListBundle\Model\ActivityListProviderInterface[] + * @return ActivityListProviderInterface[] [activity class => provider, ...] */ public function getProviders() { @@ -133,19 +131,16 @@ public function getTargetEntityClasses() */ public function isApplicableTarget($targetClassName, $activityClassName) { - /** @var ConfigIdInterface[] $configIds */ - $configIds = $this->configManager->getIds('entity', null, false); - foreach ($configIds as $configId) { - if (array_key_exists($activityClassName, $this->providers)) { - $provider = $this->getProviderByClass($activityClassName); - if ($provider->isApplicableTarget($configId, $this->configManager) - && $configId->getClassName() === $targetClassName) { - return true; - } - } + if (!isset($this->providers[$activityClassName]) + || !$this->configManager->hasConfig($targetClassName) + ) { + return false; } - return false; + return $this->providers[$activityClassName]->isApplicableTarget( + $this->configManager->getId('entity', $targetClassName), + $this->configManager + ); } /** diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/config/assets.yml b/src/Oro/Bundle/ActivityListBundle/Resources/config/assets.yml index 7831d3d2c3b..a3cc25040ef 100644 --- a/src/Oro/Bundle/ActivityListBundle/Resources/config/assets.yml +++ b/src/Oro/Bundle/ActivityListBundle/Resources/config/assets.yml @@ -1,3 +1,3 @@ css: oroactivitylist: - - 'bundles/oroactivitylist/css/less/activity-list.less' + - 'bundles/oroactivitylist/css/less/main.less' diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/config/services.yml b/src/Oro/Bundle/ActivityListBundle/Resources/config/services.yml index e6b445e63dc..8e46369cb82 100644 --- a/src/Oro/Bundle/ActivityListBundle/Resources/config/services.yml +++ b/src/Oro/Bundle/ActivityListBundle/Resources/config/services.yml @@ -50,6 +50,7 @@ services: - @oro_entity.doctrine_helper - @oro_activity_list.helper.acl_criteria - @oro_activity_list.helper.activity_inheritance_targets + - @event_dispatcher oro_activity_list.collect_manager: class: %oro_activity_list.collect_manager.class% diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/activity-list.less b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/activity-list.less index b8329d31588..749770af82f 100644 --- a/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/activity-list.less +++ b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/activity-list.less @@ -131,7 +131,7 @@ width: 27px; font-size: 18px; color: #999; - margin: 8px 0 0 10px; + margin: 8px 6px 0 8px; } > .actions{ @@ -141,7 +141,7 @@ .horizontal-icon-menu; } > .details { - margin: 7px 7px 0 0; + margin: 9px 7px 0 0; max-width: 247px; min-width: 247px; padding-bottom: 1px; @@ -154,7 +154,7 @@ } > .created-at { float: right; - margin: 7px 0 -1px 8px; + margin: 8px 0 -1px 8px; color: #888; } > .comment-count { @@ -162,7 +162,7 @@ margin-top: 8px; } > .message-item { - margin: 7px 0 0 0; + margin: 9px 0 0 0; float: left; width: calc(~"100% - 510px"); color: #888; @@ -220,7 +220,7 @@ .accordion > .items { .message-item { clear: left; - margin-left: 4px; + margin: 7px 0 7px 4px; width: calc(~"100% - 186px"); } .details { diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/main.less b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/main.less new file mode 100644 index 00000000000..e70f1ca72b7 --- /dev/null +++ b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/main.less @@ -0,0 +1,4 @@ +@import "./activity-list"; + +// mobile +@import "./mobile/main"; diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/activity-list.less b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/activity-list.less new file mode 100644 index 00000000000..326f32a09eb --- /dev/null +++ b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/activity-list.less @@ -0,0 +1,18 @@ +.activity-list-widget { + .activity-list { + .info { + margin-bottom: @contentPadding; + } + } + .grid-toolbar { + padding: 0; + margin-bottom: @contentPadding; + .filter-container { + padding: 0; + margin-bottom: @contentPadding; + } + } + .comments-view-footer { + margin-bottom: 0; + } +} diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/main.less b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/main.less new file mode 100644 index 00000000000..4e3b4d898b3 --- /dev/null +++ b/src/Oro/Bundle/ActivityListBundle/Resources/public/css/less/mobile/main.less @@ -0,0 +1,4 @@ +.mobile-version { + @import "oroui/css/less/mobile/variables"; + @import "./activity-list"; +} diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/public/js/app/views/activity-view.js b/src/Oro/Bundle/ActivityListBundle/Resources/public/js/app/views/activity-view.js index 851bbfd02ed..04443c681aa 100644 --- a/src/Oro/Bundle/ActivityListBundle/Resources/public/js/app/views/activity-view.js +++ b/src/Oro/Bundle/ActivityListBundle/Resources/public/js/app/views/activity-view.js @@ -68,7 +68,8 @@ define(function(require) { data.collapsed = this.collapsed; data.createdAt = dateTimeFormatter.formatSmartDateTime(data.createdAt); data.updatedAt = dateTimeFormatter.formatSmartDateTime(data.updatedAt); - data.relatedActivityClass = _.escape(data.relatedActivityClass); + // use special model's method to get activity class name with replaced slashes + data.relatedActivityClass = _.escape(this.model.getRelatedActivityClass()); if (data.owner_id) { data.owner_url = routing.generate('oro_user_view', {'id': data.owner_id}); } else { diff --git a/src/Oro/Bundle/ActivityListBundle/Resources/views/ActivityList/widget/activities.html.twig b/src/Oro/Bundle/ActivityListBundle/Resources/views/ActivityList/widget/activities.html.twig index 85d81461b60..cf0bfa1cee3 100644 --- a/src/Oro/Bundle/ActivityListBundle/Resources/views/ActivityList/widget/activities.html.twig +++ b/src/Oro/Bundle/ActivityListBundle/Resources/views/ActivityList/widget/activities.html.twig @@ -20,7 +20,7 @@
- {{ 'oro.navigation.help.save'|trans }}
-
- {{ 'oro.navigation.help.restore'|trans }}
+ {{ 'oro.navigation.help.message'|trans }}
+
+