diff --git a/app/Grid/Renderer/TwigBulkActionGridRenderer.php b/app/Grid/Renderer/TwigBulkActionGridRenderer.php new file mode 100644 index 000000000..256a425b0 --- /dev/null +++ b/app/Grid/Renderer/TwigBulkActionGridRenderer.php @@ -0,0 +1,58 @@ +getType(); + if (!isset($this->bulkActionTemplates[$type])) { + throw new \InvalidArgumentException(sprintf('Missing template for bulk action type "%s".', $type)); + } + + $options = $this->optionsParser->parseOptions( + $bulkAction->getOptions(), + $this->requestStack?->getCurrentRequest() ?? new Request(), + $data, + ); + + return $this->twig->render($this->bulkActionTemplates[$type], [ + 'grid' => $gridView, + 'action' => $bulkAction, + 'data' => $data, + 'options' => $options, + ]); + } +} diff --git a/app/Grid/Renderer/TwigGridRenderer.php b/app/Grid/Renderer/TwigGridRenderer.php new file mode 100644 index 000000000..51a3a4f3c --- /dev/null +++ b/app/Grid/Renderer/TwigGridRenderer.php @@ -0,0 +1,79 @@ +gridRenderer->render($gridView, $template); + } + + public function renderField(GridViewInterface $gridView, Field $field, $data): string + { + return $this->gridRenderer->renderField($gridView, $field, $data); + } + + public function renderAction(GridViewInterface $gridView, Action $action, $data = null): string + { + $type = $action->getType(); + + $template = $action->getOptions()['template'] ?? $this->actionTemplates[$type] ?? null; + + if (null === $template) { + throw new \InvalidArgumentException(sprintf('Missing template for action type "%s".', $type)); + } + + $options = $this->optionsParser->parseOptions( + $action->getOptions(), + $this->requestStack?->getCurrentRequest() ?? new Request(), + $data, + ); + + return $this->twig->render($template, [ + 'grid' => $gridView, + 'action' => $action, + 'data' => $data, + 'options' => $options, + ]); + } + + public function renderFilter(GridViewInterface $gridView, Filter $filter): string + { + return $this->gridRenderer->renderFilter($gridView, $filter); + } +} diff --git a/app/Grid/SpeakerGrid.php b/app/Grid/SpeakerGrid.php index 6384256bf..b4e7d7943 100644 --- a/app/Grid/SpeakerGrid.php +++ b/app/Grid/SpeakerGrid.php @@ -38,6 +38,7 @@ public static function getName(): string public function buildGrid(GridBuilderInterface $gridBuilder): void { $gridBuilder + ->setLimits([10, 25, 50]) ->addFilter( StringFilter::create('search', ['firstName', 'lastName', 'companyName']) ->setLabel('sylius.ui.search'), @@ -82,8 +83,23 @@ public function buildGrid(GridBuilderInterface $gridBuilder): void ], ], ]), - UpdateAction::create(), - DeleteAction::create(), + UpdateAction::create() + ->setOptions([ + 'link' => [ + 'route' => 'app_admin_speaker_update', + 'parameters' => [ + 'id' => 'resource.id', + ], + ], + ]), + DeleteAction::create()->setOptions([ + 'link' => [ + 'route' => 'app_admin_speaker_delete', + 'parameters' => [ + 'id' => 'resource.id', + ], + ], + ]), ), ) ->addActionGroup( diff --git a/app/Twig/Component/SpeakerDataTableComponent.php b/app/Twig/Component/SpeakerDataTableComponent.php new file mode 100644 index 000000000..44c42ea00 --- /dev/null +++ b/app/Twig/Component/SpeakerDataTableComponent.php @@ -0,0 +1,37 @@ + ['all' => true], Sylius\UiTranslations\Symfony\SyliusUiTranslationsBundle::class => ['all' => true], Sylius\BootstrapAdminUi\Symfony\SyliusBootstrapAdminUiBundle::class => ['all' => true], + Sylius\TwigComponentGrid\Symfony\SyliusTwigComponentGridBundle::class => ['all' => true], Symfony\Bundle\WebProfilerBundle\WebProfilerBundle::class => ['dev' => true, 'test' => true], Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], Symfony\UX\LiveComponent\LiveComponentBundle::class => ['all' => true], diff --git a/config/sylius/twig_hooks/speaker/index.php b/config/sylius/twig_hooks/speaker/index.php index 55bb5f6a4..a81b2d48b 100644 --- a/config/sylius/twig_hooks/speaker/index.php +++ b/config/sylius/twig_hooks/speaker/index.php @@ -13,6 +13,9 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use App\Twig\Component\SpeakerDataTableComponent; +use App\Twig\Component\SpeakerGridComponent; + return static function (ContainerConfigurator $container): void { $container->extension('sylius_twig_hooks', [ 'hooks' => [ @@ -26,6 +29,18 @@ ], ], ], + + 'sylius_admin.speaker.index.content.grid' => [ + 'data_table' => [ + 'component' => SpeakerDataTableComponent::class, + 'props' => [ + 'page' => '@=_context.page', + 'limit' => '@=_context.limit', + 'criteria' => '@=_context.criteria', + 'sorting' => '@=_context.sorting', + ], + ], + ], ], ]); }; diff --git a/importmap.php b/importmap.php index 3b49af095..ea1cce89e 100644 --- a/importmap.php +++ b/importmap.php @@ -45,4 +45,12 @@ '@symfony/ux-live-component' => [ 'path' => './vendor/symfony/ux-live-component/assets/dist/live_controller.js', ], + 'tom-select/dist/css/tom-select.bootstrap4.css' => [ + 'version' => '2.4.3', + 'type' => 'css', + ], + 'tom-select/dist/css/tom-select.bootstrap5.css' => [ + 'version' => '2.4.3', + 'type' => 'css', + ], ]; diff --git a/src/AdminUi/config/routes.php b/src/AdminUi/config/routes.php index 18f91d455..761142f24 100644 --- a/src/AdminUi/config/routes.php +++ b/src/AdminUi/config/routes.php @@ -32,4 +32,10 @@ 'template' => '@SyliusAdminUi/dashboard/index.html.twig', ]) ; + + $routes->add('sylius_admin_ui_live_component', '/_components/{_live_component}/{_live_action}') + ->defaults([ + '_live_action' => 'get', + ]) + ; }; diff --git a/src/BootstrapAdminUi/assets/styles/_body.scss b/src/BootstrapAdminUi/assets/styles/_body.scss index ecce06584..c34fefe00 100644 --- a/src/BootstrapAdminUi/assets/styles/_body.scss +++ b/src/BootstrapAdminUi/assets/styles/_body.scss @@ -40,6 +40,13 @@ a.link-reset { text-decoration: none; } +button.link-reset { + border: none; + background-color: transparent; + text-transform: inherit; + font-weight: inherit; +} + .btn-collapse { &.collapsed { .icon-chevron-right { diff --git a/src/BootstrapAdminUi/public/app.css b/src/BootstrapAdminUi/public/app.css index 773ef909b..2232117b3 100644 --- a/src/BootstrapAdminUi/public/app.css +++ b/src/BootstrapAdminUi/public/app.css @@ -20,7 +20,7 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. - */*{--tblr-breadcrumb-item-active-color:var(--tblr-gray-500);--tblr-breadcrumb-divider-color:var(--tblr-gray-300);--tblr-code-color:#36393b;--tblr-blue-rgb:17,81,141;--tblr-green-rgb:0,97,16}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-bg-surface:#1e2433}@font-face{font-family:Inter;font-weight:1 999;src:url(fonts/Inter-VariableFont_slnt,wght.853e0197.ttf) format("truetype-variations")}body{--bs-body-bg:#f6f8fb;--bs-tertiary-bg:#f6f8fb;--bs-body-color:#212529;font-feature-settings:"cv03","cv04","cv11"}a{text-underline-offset:.25em}a.link-reset{text-decoration:none}.btn-collapse.collapsed .icon-chevron-right{display:inline-flex}.btn-collapse.collapsed .icon-chevron-down,.btn-collapse:not(.collapsed) .icon-chevron-right{display:none}.btn-collapse:not(.collapsed) .icon-chevron-down{display:inline-flex}.breadcrumb-item a{text-decoration:none}.breadcrumb-item a:hover{color:#22b99a}.switch-collapse,body[data-bs-theme=dark] html[data-bs-theme=light] [data-theme-switch=dark],html[data-bs-theme=dark] [data-theme-switch=dark],html[data-bs-theme=light] [data-theme-switch=light]{display:none}label:has(input:checked)~.switch-collapse{display:block}.btn:not(.btn-sm){min-height:44px;min-width:44px}/*! + */*{--tblr-breadcrumb-item-active-color:var(--tblr-gray-500);--tblr-breadcrumb-divider-color:var(--tblr-gray-300);--tblr-code-color:#36393b;--tblr-blue-rgb:17,81,141;--tblr-green-rgb:0,97,16}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-bg-surface:#1e2433}@font-face{font-family:Inter;font-weight:1 999;src:url(fonts/Inter-VariableFont_slnt,wght.853e0197.ttf) format("truetype-variations")}body{--bs-body-bg:#f6f8fb;--bs-tertiary-bg:#f6f8fb;--bs-body-color:#212529;font-feature-settings:"cv03","cv04","cv11"}a{text-underline-offset:.25em}a.link-reset{text-decoration:none}button.link-reset{background-color:transparent;border:none;font-weight:inherit;text-transform:inherit}.btn-collapse.collapsed .icon-chevron-right{display:inline-flex}.btn-collapse.collapsed .icon-chevron-down,.btn-collapse:not(.collapsed) .icon-chevron-right{display:none}.btn-collapse:not(.collapsed) .icon-chevron-down{display:inline-flex}.breadcrumb-item a{text-decoration:none}.breadcrumb-item a:hover{color:#22b99a}.switch-collapse,body[data-bs-theme=dark] html[data-bs-theme=light] [data-theme-switch=dark],html[data-bs-theme=dark] [data-theme-switch=dark],html[data-bs-theme=light] [data-theme-switch=light]{display:none}label:has(input:checked)~.switch-collapse{display:block}.btn:not(.btn-sm){min-height:44px;min-width:44px}/*! * This file is part of the Sylius package. * * (c) Sylius Sp. z o.o. diff --git a/src/BootstrapAdminUi/public/app.rtl.css b/src/BootstrapAdminUi/public/app.rtl.css index cbd0b8f57..2ee9c8c87 100644 --- a/src/BootstrapAdminUi/public/app.rtl.css +++ b/src/BootstrapAdminUi/public/app.rtl.css @@ -20,7 +20,7 @@ * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. - */*{--tblr-breadcrumb-item-active-color:var(--tblr-gray-500);--tblr-breadcrumb-divider-color:var(--tblr-gray-300);--tblr-code-color:#36393b;--tblr-blue-rgb:17,81,141;--tblr-green-rgb:0,97,16}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-bg-surface:#1e2433}@font-face{font-family:Inter;font-weight:1 999;src:url(fonts/Inter-VariableFont_slnt,wght.853e0197.ttf) format("truetype-variations")}body{--bs-body-bg:#f6f8fb;--bs-tertiary-bg:#f6f8fb;--bs-body-color:#212529;font-feature-settings:"cv03","cv04","cv11"}a{text-underline-offset:.25em}a.link-reset{text-decoration:none}.btn-collapse.collapsed .icon-chevron-right{display:inline-flex}.btn-collapse.collapsed .icon-chevron-down,.btn-collapse:not(.collapsed) .icon-chevron-right{display:none}.btn-collapse:not(.collapsed) .icon-chevron-down{display:inline-flex}.breadcrumb-item a{text-decoration:none}.breadcrumb-item a:hover{color:#22b99a}.switch-collapse,body[data-bs-theme=dark] html[data-bs-theme=light] [data-theme-switch=dark],html[data-bs-theme=dark] [data-theme-switch=dark],html[data-bs-theme=light] [data-theme-switch=light]{display:none}label:has(input:checked)~.switch-collapse{display:block}.btn:not(.btn-sm){min-height:44px;min-width:44px}/*! + */*{--tblr-breadcrumb-item-active-color:var(--tblr-gray-500);--tblr-breadcrumb-divider-color:var(--tblr-gray-300);--tblr-code-color:#36393b;--tblr-blue-rgb:17,81,141;--tblr-green-rgb:0,97,16}[data-bs-theme=dark],body[data-bs-theme=dark] [data-bs-theme=light]{--tblr-bg-surface:#1e2433}@font-face{font-family:Inter;font-weight:1 999;src:url(fonts/Inter-VariableFont_slnt,wght.853e0197.ttf) format("truetype-variations")}body{--bs-body-bg:#f6f8fb;--bs-tertiary-bg:#f6f8fb;--bs-body-color:#212529;font-feature-settings:"cv03","cv04","cv11"}a{text-underline-offset:.25em}a.link-reset{text-decoration:none}button.link-reset{background-color:transparent;border:none;font-weight:inherit;text-transform:inherit}.btn-collapse.collapsed .icon-chevron-right{display:inline-flex}.btn-collapse.collapsed .icon-chevron-down,.btn-collapse:not(.collapsed) .icon-chevron-right{display:none}.btn-collapse:not(.collapsed) .icon-chevron-down{display:inline-flex}.breadcrumb-item a{text-decoration:none}.breadcrumb-item a:hover{color:#22b99a}.switch-collapse,body[data-bs-theme=dark] html[data-bs-theme=light] [data-theme-switch=dark],html[data-bs-theme=dark] [data-theme-switch=dark],html[data-bs-theme=light] [data-theme-switch=light]{display:none}label:has(input:checked)~.switch-collapse{display:block}.btn:not(.btn-sm){min-height:44px;min-width:44px}/*! * This file is part of the Sylius package. * * (c) Sylius Sp. z o.o. diff --git a/src/BootstrapAdminUi/templates/shared/components/grid/data_table.html.twig b/src/BootstrapAdminUi/templates/shared/components/grid/data_table.html.twig new file mode 100644 index 000000000..4d6b3f455 --- /dev/null +++ b/src/BootstrapAdminUi/templates/shared/components/grid/data_table.html.twig @@ -0,0 +1,55 @@ +{% import '@SyliusBootstrapAdminUi/shared/helper/table.html.twig' as table %} +{% import '@SyliusBootstrapAdminUi/shared/helper/pagination.html.twig' as pagination %} + +{% set resources = hookable_metadata.context.resources|default(this.resources|default(null)) %} +{% set data = resources.data|default([]) %} +{% set definition = resources.definition|default(null) %} +{% set live = attributes is defined %} + +