diff --git a/CHANGELOG.md b/CHANGELOG.md index 7761553..da01117 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,27 +1,5 @@ ## [Unreleased] -### Added -* feat(repository): add RepositoryQuery::addCaseInsensitiveFilters() -* feat(repository): add RepositoryQuery::addForcedFilterHandler() - -### Fixed -* fix(crud/index): fix row attribute value render -* fix(crud/navigation_setting): fix form action -* fix(crud/template): use default route params - -## [v1.27.0] - 2025-12-22 -### Fixed -* fix(crud): use route params to redirect after a delation - -### Added -* add option `removeItemButton: true` when applying choices.js -* feat(builder): allow to define `allowed_widgets` in form options -* feat(collection): add delete_attr, add_attr options -* feat(builder): allow to add block between children -* feat(builder): improve UI to add new block -* feat(settings): allow to edit a setting in plain page -* feat(crud/index): allow to define row attributes - ## [v1.26.0] - 2025-03-17 ### Added * FileUploadHandler: allow to upload multiple files diff --git a/src/core/BuilderBlock/Block/Bootstrap/BootstrapBlock.php b/src/core/BuilderBlock/Block/Bootstrap/BootstrapBlock.php index 1f332ba..12fc12e 100644 --- a/src/core/BuilderBlock/Block/Bootstrap/BootstrapBlock.php +++ b/src/core/BuilderBlock/Block/Bootstrap/BootstrapBlock.php @@ -5,7 +5,7 @@ namespace App\Core\BuilderBlock\Block\Bootstrap; use App\Core\BuilderBlock\BuilderBlock; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; -abstract class BootstrapBlock extends BuilderBlock +class BootstrapBlock extends BuilderBlock { public function configure() { diff --git a/src/core/BuilderBlock/Block/Editor/EditorBlock.php b/src/core/BuilderBlock/Block/Editor/EditorBlock.php index 3172048..e89296a 100644 --- a/src/core/BuilderBlock/Block/Editor/EditorBlock.php +++ b/src/core/BuilderBlock/Block/Editor/EditorBlock.php @@ -5,7 +5,7 @@ namespace App\Core\BuilderBlock\Block\Editor; use App\Core\BuilderBlock\BuilderBlock; use Symfony\Component\DependencyInjection\Attribute\AutoconfigureTag; -abstract class EditorBlock extends BuilderBlock +class EditorBlock extends BuilderBlock { public function configure() { diff --git a/src/core/Controller/Admin/Crud/CrudController.php b/src/core/Controller/Admin/Crud/CrudController.php index 810087f..7d7092f 100644 --- a/src/core/Controller/Admin/Crud/CrudController.php +++ b/src/core/Controller/Admin/Crud/CrudController.php @@ -406,7 +406,7 @@ abstract class CrudController extends AdminController $this->addFlash('success', 'The data has been removed.'); } - return $this->redirectToRoute($configuration->getPageRoute($route), $configuration->getPageRouteParams($route)); + return $this->redirectToRoute($configuration->getPageRoute($route)); } protected function doFilter(Session $session, string $context = 'filter'): Response diff --git a/src/core/Controller/Setting/NavigationSettingAdminController.php b/src/core/Controller/Setting/NavigationSettingAdminController.php index 74bbb68..4a3be8f 100644 --- a/src/core/Controller/Setting/NavigationSettingAdminController.php +++ b/src/core/Controller/Setting/NavigationSettingAdminController.php @@ -35,8 +35,6 @@ class NavigationSettingAdminController extends AdminController $session = $request->getSession(); $lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId()); $lastRequest = $session->get($lastRequestId); - $options = $entity->getOptions(); - $optionView = $options['view'] ?? 'modal'; if (null !== $lastRequest && !$request->isMethod('POST')) { $fakeRequest = Request::create( @@ -66,19 +64,17 @@ class NavigationSettingAdminController extends AdminController $session->set($lastRequestId, $request->request->get('form')); $this->addFlash('warning', 'The form is not valid.'); - if ($optionView === 'modal') { - return $this->redirect(sprintf( - '%s?data-modal=%s', - $redirectTo, - urlencode($request->getUri()) - )); - } + return $this->redirect(sprintf( + '%s?data-modal=%s', + $redirectTo, + urlencode($request->getUri()) + )); } return $this->render('@Core/setting/navigation_setting_admin/edit.html.twig', [ 'form' => $form->createView(), 'entity' => $entity, - 'options' => $options, + 'options' => $event->getData()['options'], 'redirectTo' => $redirectTo, ]); } diff --git a/src/core/Controller/Setting/SettingAdminController.php b/src/core/Controller/Setting/SettingAdminController.php index 707a19e..317fe77 100644 --- a/src/core/Controller/Setting/SettingAdminController.php +++ b/src/core/Controller/Setting/SettingAdminController.php @@ -55,8 +55,6 @@ class SettingAdminController extends AdminController $session = $request->getSession(); $lastRequestId = sprintf('setting_request_%s_%s', get_class($entity), $entity->getId()); $lastRequest = $session->get($lastRequestId); - $options = $entity->getOptions(); - $optionView = $options['view'] ?? 'modal'; if (null !== $lastRequest && !$request->isMethod('POST')) { $fakeRequest = Request::create( @@ -84,13 +82,11 @@ class SettingAdminController extends AdminController $session->set($lastRequestId, $request->request->get('form')); $this->addFlash('warning', 'The form is not valid.'); - if ($optionView === 'modal') { - return $this->redirect(sprintf( - '%s?data-modal=%s', - $redirectTo, - urlencode($request->getUri()) - )); - } + return $this->redirect(sprintf( + '%s?data-modal=%s', + $redirectTo, + urlencode($request->getUri()) + )); } return $this->render('@Core/setting/setting_admin/edit.html.twig', [ diff --git a/src/core/Crud/CrudConfiguration.php b/src/core/Crud/CrudConfiguration.php index c083d9d..c8d8935 100644 --- a/src/core/Crud/CrudConfiguration.php +++ b/src/core/Crud/CrudConfiguration.php @@ -2,8 +2,6 @@ namespace App\Core\Crud; -use App\Core\Entity\EntityInterface; - /** * class CrudConfiguration. * @@ -30,7 +28,6 @@ class CrudConfiguration protected string $sortableCollectionProperty = 'sortOrder'; protected ?string $defaultLocale = null; protected array $showActions = []; - protected array $listRowAttributes = []; protected static $self; @@ -250,26 +247,6 @@ class CrudConfiguration return $this->viewDatas[$context][$name] ?? $defaultValue; } - public function setListRowAttributes(string $context, array $attributes): self - { - $this->listRowAttributes[$context] = $attributes; - - return $this; - } - - public function getListRowAttributes(string $context, EntityInterface $entity): array - { - $attributes = $this->listRowAttributes[$context] ?? []; - - foreach ($attributes as $key => $attribute) { - if (is_callable($attribute)) { - $attributes[$key] = $attribute($entity); - } - } - - return $attributes; - } - // -- public function setField(string $context, string $label, string $field, array $options): self diff --git a/src/core/Entity/NavigationSetting.php b/src/core/Entity/NavigationSetting.php index 8adfb36..bfaa2ac 100644 --- a/src/core/Entity/NavigationSetting.php +++ b/src/core/Entity/NavigationSetting.php @@ -26,9 +26,6 @@ class NavigationSetting implements EntityInterface #[ORM\Column(type: 'text', nullable: true)] protected $value; - #[ORM\Column(type: 'text', nullable: true)] - protected $options; - #[ORM\ManyToOne(targetEntity: Navigation::class, inversedBy: 'navigationSettings')] #[ORM\JoinColumn(nullable: false, onDelete: 'CASCADE')] protected $navigation; @@ -97,16 +94,4 @@ class NavigationSetting implements EntityInterface return $this; } - - public function getOptions() - { - return json_decode($this->options, true) ?? []; - } - - public function setOptions(?array $options): self - { - $this->options = json_encode($options ?? []); - - return $this; - } } diff --git a/src/core/Entity/Setting.php b/src/core/Entity/Setting.php index 032e74a..d4a1036 100644 --- a/src/core/Entity/Setting.php +++ b/src/core/Entity/Setting.php @@ -25,9 +25,6 @@ class Setting implements EntityInterface #[ORM\Column(type: 'text', nullable: true)] protected $value; - #[ORM\Column(type: 'text', nullable: true)] - protected $options; - public function getId(): ?int { return $this->id; @@ -80,16 +77,4 @@ class Setting implements EntityInterface return $this; } - - public function getOptions() - { - return json_decode($this->options, true) ?? []; - } - - public function setOptions(?array $options): self - { - $this->options = json_encode($options ?? []); - - return $this; - } } diff --git a/src/core/Form/Type/BuilderType.php b/src/core/Form/Type/BuilderType.php index 1f2fd09..d1f32d5 100644 --- a/src/core/Form/Type/BuilderType.php +++ b/src/core/Form/Type/BuilderType.php @@ -19,7 +19,6 @@ class BuilderType extends AbstractType parent::buildView($view, $form, $options); $view->vars = array_replace($view->vars, [ - 'allowed_widgets' => $options['allowed_widgets'], ]); } @@ -29,10 +28,7 @@ class BuilderType extends AbstractType $resolver->setDefaults([ 'compound' => false, - 'allowed_widgets' => [], ]); - - $resolver->setAllowedTypes('allowed_widgets', 'array'); } public function getBlockPrefix() diff --git a/src/core/Form/Type/CollectionType.php b/src/core/Form/Type/CollectionType.php index 5c91d90..3670c38 100644 --- a/src/core/Form/Type/CollectionType.php +++ b/src/core/Form/Type/CollectionType.php @@ -16,23 +16,12 @@ class CollectionType extends BaseCollectionType { parent::buildView($view, $form, $options); - $classes = [ - 'add_attr' => 'collection-add', - 'delete_attr' => 'text-right', - ]; - - foreach ($classes as $key => $class) { - $options[$key]['class'] = $class.' '.($options[$key]['class'] ?? ''); - } - $view->vars = array_replace($view->vars, [ 'collection_name' => $options['collection_name'], 'label_add' => $options['label_add'], 'label_delete' => $options['label_delete'], 'allow_add' => $options['allow_add'], 'allow_delete' => $options['allow_delete'], - 'add_attr' => $options['add_attr'], - 'delete_attr' => $options['delete_attr'], 'template_before_item' => $options['template_before_item'], 'template_after_item' => $options['template_after_item'], ]); @@ -48,8 +37,6 @@ class CollectionType extends BaseCollectionType 'label_delete' => 'Delete', 'template_before_item' => null, 'template_after_item' => null, - 'add_attr' => [], - 'delete_attr' => [], ]); } diff --git a/src/core/Murph.php b/src/core/Murph.php index e46eda8..621f419 100644 --- a/src/core/Murph.php +++ b/src/core/Murph.php @@ -3,7 +3,7 @@ namespace App\Core; if (!defined('MURPH_VERSION')) { - define('MURPH_VERSION', 'v1.27.0'); + define('MURPH_VERSION', 'v1.26.0'); } /** diff --git a/src/core/Repository/RepositoryQuery.php b/src/core/Repository/RepositoryQuery.php index e2943b0..904c965 100644 --- a/src/core/Repository/RepositoryQuery.php +++ b/src/core/Repository/RepositoryQuery.php @@ -18,7 +18,6 @@ abstract class RepositoryQuery protected PaginatorInterface $paginator; protected string $id; protected array $forcedFilterHandlers = []; - protected array $caseInsensitiveFilters = []; public function __construct(ServiceEntityRepository $repository, string $id, PaginatorInterface $paginator = null) { @@ -89,11 +88,7 @@ abstract class RepositoryQuery $this->andWhere('.'.$name.' = :'.$name); $this->setParameter(':'.$name, $value); } elseif (is_string($value)) { - if (in_array($name, $this->caseInsensitiveFilters)) { - $this->andWhere(sprintf('LOWER ( .%1$s) LIKE LOWER(:%1$s)', $name)); - } else { - $this->andWhere('.'.$name.' LIKE :'.$name); - } + $this->andWhere('.'.$name.' LIKE :'.$name); $this->setParameter(':'.$name, '%'.$value.'%'); } else { $this->filterHandler($name, $value); @@ -147,18 +142,4 @@ abstract class RepositoryQuery protected function filterHandler(string $name, $value) { } - - protected function addCaseInsensitiveFilters(string $name): self - { - $this->caseInsensitiveFilters[] = $name; - - return $this; - } - - protected function addForcedFilterHandlers(string $name): self - { - $this->forcedFilterHandlers[] = $name; - - return $this; - } } diff --git a/src/core/Resources/assets/css/admin.scss b/src/core/Resources/assets/css/admin.scss index b11c614..a38fb98 100644 --- a/src/core/Resources/assets/css/admin.scss +++ b/src/core/Resources/assets/css/admin.scss @@ -761,19 +761,16 @@ label.required::after { } .builder-widget { - .container { - max-width: 100%; - } - .block { - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; - padding: 15px; + border: 1px solid rgba(map-get($theme-colors, 'dark-blue'), 0.3); + padding: 10px; border-radius: 4px; + margin-bottom: 10px; background: rgba(map-get($theme-colors, 'dark-blue'), 0.02); } > .block { - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + border: 1px solid map-get($theme-colors, 'dark-blue'); } .block-header { @@ -787,6 +784,9 @@ label.required::after { } } + $block-colors: #E183F5 #E3F7C6 #82DDF5 #F5BA82 #A088A6; + $block-colors-length: length($block-colors); + .block .block-icon { > * { display: inline-block; @@ -794,34 +794,36 @@ label.required::after { } } - .builder-add { - &-top { - margin-top: 7px; - } + @for $i from 1 through 100 { + $block-color-index: ($block-colors-length + $i) % $block-colors-length + 1; - &-button { - cursor: pointer; - background: rgba(map-get($theme-colors, 'dark-blue'), 0.1); - text-align: center; - padding-bottom: 5px; - margin: 8px 0; - border-radius: 4px; - - &:hover { - background: rgba(map-get($theme-colors, 'dark-blue'), 0.2); + .block-depth-#{$i} { + .block-label { + background: nth($block-colors, $block-color-index); + border: 1px solid darken(nth($block-colors, $block-color-index), 50%); + color: darken(nth($block-colors, $block-color-index), 50%); } - .btn { - font-size: 12px; - line-height: 14px; - padding: 3px 5px; + .builder-add .btn { + background: nth($block-colors, $block-color-index); + border: 1px solid darken(nth($block-colors, $block-color-index), 50%); + color: darken(nth($block-colors, $block-color-index), 50%); } } } - .block-root { - border: 1px solid map-get($theme-colors, 'dark-blue'); - box-shadow: none; + .builder-add { + width: 100%; + + &-top { + margin-top: 7px; + } + + .btn { + font-size: 12px; + line-height: 14px; + padding: 3px 5px; + } } .block-root > .container .builder-add { @@ -838,6 +840,10 @@ label.required::after { } } + .block .block { + margin-top: 10px; + } + .block-id { font-size: 12px; margin-right: 5px; @@ -868,32 +874,4 @@ label.required::after { min-height: 50vh; } } - - .dragger { - cursor: pointer; - color: #6c757d; - border-color: #6c757d; - text-align: center; - vertical-align: middle; - } - - $block-colors: #E183F5 #E3F7C6 #82DDF5 #F5BA82 #A088A6; - $block-colors-length: length($block-colors); - - @for $i from 1 through 100 { - $block-color-index: ($block-colors-length + $i) % $block-colors-length + 1; - - .block-depth-#{$i} { - .block-label { - background: nth($block-colors, $block-color-index); - border: 1px solid darken(nth($block-colors, $block-color-index), 50%); - color: darken(nth($block-colors, $block-color-index), 50%); - } - - .builder-add-button:hover { - background: nth($block-colors, $block-color-index); - color: darken(nth($block-colors, $block-color-index), 50%); - } - } - } } diff --git a/src/core/Resources/assets/js/components/builder-block/BuilderBlock.vue b/src/core/Resources/assets/js/components/builder-block/BuilderBlock.vue index b13233c..88a7f6f 100644 --- a/src/core/Resources/assets/js/components/builder-block/BuilderBlock.vue +++ b/src/core/Resources/assets/js/components/builder-block/BuilderBlock.vue @@ -8,7 +8,7 @@ :container="value" :widgets="widgets" :openedBlocks="openedBlocks" - :allowedWidgets="allowedWidgets" + :allowedWidgets="[]" v-if="value.length > 0" position="top" /> @@ -34,26 +34,16 @@ @remove-item="removeBlock(key)" @drag-start="dragStart" @drag-end="dragEnd" - > - - -
- -
-
- + -
+
@@ -116,7 +116,7 @@ export default { required: true }, position: { - type: [String, Number], + type: String, required: true }, }, @@ -142,14 +142,10 @@ export default { children: [], } - if (this.position === 'bottom') { this.container.push(block) - this.$emit('updateContainer', this.container) - } else if (this.position === 'top') { - this.container.unshift(block) } else { - this.container.splice(this.position+1, 0, block) + this.container.unshift(block) } this.$emit('updateContainer', this.container) diff --git a/src/core/Resources/assets/js/components/builder-block/BuilderBlockItem.vue b/src/core/Resources/assets/js/components/builder-block/BuilderBlockItem.vue index 854eaee..8e4cc29 100644 --- a/src/core/Resources/assets/js/components/builder-block/BuilderBlockItem.vue +++ b/src/core/Resources/assets/js/components/builder-block/BuilderBlockItem.vue @@ -1,122 +1,116 @@ @@ -168,7 +159,7 @@ export default { depth: { type: Number, required: true - }, + } }, data() { return { diff --git a/src/core/Resources/assets/js/components/builder-block/BuilderBlockSetting.vue b/src/core/Resources/assets/js/components/builder-block/BuilderBlockSetting.vue index 0090545..5738f5d 100644 --- a/src/core/Resources/assets/js/components/builder-block/BuilderBlockSetting.vue +++ b/src/core/Resources/assets/js/components/builder-block/BuilderBlockSetting.vue @@ -3,7 +3,7 @@ { el: component, template: ``, data() { return { - value: JSON.parse(component.getAttribute('data-value')), - allowedWidgets: JSON.parse(component.getAttribute('data-allowedwidgets')), + value: JSON.parse(component.getAttribute('data-value')) } }, components: { diff --git a/src/core/Resources/assets/js/modules/choices.js b/src/core/Resources/assets/js/modules/choices.js index 4e86b16..74b179b 100644 --- a/src/core/Resources/assets/js/modules/choices.js +++ b/src/core/Resources/assets/js/modules/choices.js @@ -4,7 +4,6 @@ module.exports = () => { document.querySelectorAll('*[data-jschoice]').forEach((item) => { return new Choices(item, { searchFields: ['label'], - removeItemButton: true, }) }) } diff --git a/src/core/Resources/views/admin/crud/index.html.twig b/src/core/Resources/views/admin/crud/index.html.twig index ae40134..a76c9b7 100644 --- a/src/core/Resources/views/admin/crud/index.html.twig +++ b/src/core/Resources/views/admin/crud/index.html.twig @@ -183,20 +183,17 @@ {% endif %} {% block list_item %} - {%- set dbClick -%} - {%- if configuration.doubleClick(context) -%} - {%- if configuration.action(context, 'show', true, [item]) -%} - {{- path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) -}} - {%- elseif configuration.action(context, 'edit', true, [item]) -%} - {{- path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) -}} - {%- endif -%} - {%- endif -%} - {%- endset -%} + {%- set dbClick %} + {% if configuration.doubleClick(context) %} + {% if configuration.action(context, 'show', true, [item]) %} + {{ path(configuration.pageRoute('show'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }} + {% elseif configuration.action(context, 'edit', true, [item]) %} + {{ path(configuration.pageRoute('edit'), {entity: item.id}|merge(configuration.pageRouteParams('show'))) }} + {% endif %} + {% endif %} + {% endset -%} - {% set rowAttributes = configuration.listRowAttributes(context, item) %} - {% set rowClasses = rowAttributes['class']|default('') %} - - + {% if configuration.hasBatchAction(context) %} diff --git a/src/core/Resources/views/admin/crud/show.html.twig b/src/core/Resources/views/admin/crud/show.html.twig index d98dd22..2cefa56 100644 --- a/src/core/Resources/views/admin/crud/show.html.twig +++ b/src/core/Resources/views/admin/crud/show.html.twig @@ -18,7 +18,7 @@ {% block header_actions_before %}{% endblock %} {% if configuration.action(context, 'back', true) %} - + {{ configuration.actionTitle(context, 'back', 'Back to the list')|trans }} @@ -27,7 +27,7 @@ {% endif %} {% if configuration.action(context, 'edit', true, [entity]) %} - + diff --git a/src/core/Resources/views/admin/layout.html.twig b/src/core/Resources/views/admin/layout.html.twig index fd97838..f6195ed 100644 --- a/src/core/Resources/views/admin/layout.html.twig +++ b/src/core/Resources/views/admin/layout.html.twig @@ -1,5 +1,4 @@ {% apply spaceless %} -{% block html %} @@ -63,5 +62,4 @@ {% endblock %} -{% endblock %} {% endapply %} diff --git a/src/core/Resources/views/form/bootstrap_4_form_theme.html.twig b/src/core/Resources/views/form/bootstrap_4_form_theme.html.twig index 735bad5..d937d6d 100644 --- a/src/core/Resources/views/form/bootstrap_4_form_theme.html.twig +++ b/src/core/Resources/views/form/bootstrap_4_form_theme.html.twig @@ -3,14 +3,13 @@ {% block builder_widget %} {% set row_attr = row_attr|merge({class: 'builder-widget ' ~ (row_attr.class ?? '')}) %} {% set value = value is iterable ? value|json_encode : value %} - {% set allowed_widgets = allowed_widgets is iterable ? allowed_widgets|json_encode : allowed_widgets %} {% if value == '' %} {% set value = '[]' %} {% endif %}
-
+
{% endblock %} @@ -79,8 +78,6 @@ {% block collection_block_widget %} {% set allow_delete = allow_delete|default(false) %} {% set allow_add = allow_add|default(false) %} - {% set add_attr = add_attr|default({}) %} - {% set delete_attr = delete_attr|default({}) %}
{% for item in form.value %} @@ -90,7 +87,7 @@ {% endfor %} {% if allow_delete %} -
+
@@ -104,7 +101,7 @@
{% if allow_add %} -
+
{{ label_add|trans }} @@ -116,7 +113,7 @@ {{ form_rest(form.value.vars.prototype) }} {% if allow_delete %} -
+
{{ label_delete|trans }} @@ -131,8 +128,6 @@ {% set attrs = attr|merge({class: 'mb-1 ' ~ (attr.class ?? '')}) %} {% set allow_delete = allow_delete|default(false) %} {% set allow_add = allow_add|default(false) %} - {% set add_attr = add_attr|default({}) %} - {% set delete_attr = delete_attr|default({}) %}
{% for item in form %} @@ -150,7 +145,7 @@ {% endif %} {% if allow_delete %} -
+
@@ -164,7 +159,7 @@
{% if allow_add %} -
+
{{ label_add|trans }} @@ -176,7 +171,7 @@ {{ form_rest(form.vars.prototype) }} {% if allow_delete %} -
+
{{ label_delete|trans }} diff --git a/src/core/Resources/views/setting/navigation_setting_admin/edit.html.twig b/src/core/Resources/views/setting/navigation_setting_admin/edit.html.twig index e1488ef..6e7c2a3 100644 --- a/src/core/Resources/views/setting/navigation_setting_admin/edit.html.twig +++ b/src/core/Resources/views/setting/navigation_setting_admin/edit.html.twig @@ -1,77 +1,20 @@ -{% extends '@Core/admin/layout.html.twig' %} - -{% set view = entity.options['view']|default('modal') %} - -{% block html %} - {% if view == 'modal' %} -