Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature : Add new types of Action #88

Open
alexandre-castelain opened this issue May 14, 2024 · 6 comments
Open

Feature : Add new types of Action #88

alexandre-castelain opened this issue May 14, 2024 · 6 comments
Labels
feature New feature that would fit the core bundle

Comments

@alexandre-castelain
Copy link
Contributor

Hello,

Currently, the following action types can be added directly to a data table:

  • LinkActionType
  • ButtonActionType
  • FormActionType

It would benefit the bundle to have additional action types such as:

  • DropDownActionType
    An action displayed as a select/option, containing a set of other actions. This allows for managing a large number of actions on a row without taking up too much space.

  • FrontActionType
    An action that triggers a JavaScript event. This event should be handled by the developer's code to perform specific tasks.

  • CallbackActionType
    An action that manages the callback directly within the data table, enabling the developer to handle a click as desired.

  • SwitchActionType
    An extension of CallbackActionType that allows for a "Yes/No" action directly in the data table. If the action is set on a row, it modifies the current row. If set on the header, it can, for example, modify the SQL query.

  • ChoiceActionType
    An extension of CallbackActionType that allows the user to select from a predefined set of values. Similar to SwitchActionType in terms of utility.

Have a great day,

Alexandre

@Kreyu
Copy link
Owner

Kreyu commented May 17, 2024

Hey @alexandre-castelain, thanks for the suggestion!

Let me add some comments from my perspective:

  • DropDownActionType
    This seems really helpful, but we will have to come up with some easy configuration via action options to make it happen. I'm up for it (and maybe named DropdownActionType? 😉)

  • FrontActionType
    In my opinion, actions of such type seems very specific, and in most cases could be handled by simply adding the HTML attribute to the button, that the JavaScript will attach listeners to. Cool idea, but I would skip this one.

  • CallbackActionType
    I think this would require DataTableBundle to add some routes to handle given logic, for example, using AJAX. This makes it very hard to properly handle such actions, because the whole context can be lost (the whole data table and other variables from the original request). I think manually creating a route for some action and using currently built-in actions is more intuitive, and can be re-used with ease outside of the data table.

  • SwitchActionType and ChoiceActionType
    Those two seems really complicated, can you provide an example of such feature in some real-world scenario? I've never seen those, and I'm interested, but handling this logic may be really difficult.

TLDR: your suggestions are great, but personally, I'm up for the dropdown action type alone - this one seems really helpful, and I think it would fit in the core bundle nicely.

Cheers.

@Kreyu Kreyu added the feature New feature that would fit the core bundle label May 17, 2024
@bdecarne
Copy link
Contributor

bdecarne commented Jul 2, 2024

I have a naive implementation of DropdownActionType in my current project :

image
image

class DropdownActionType extends AbstractActionType
{
    public function buildView(ActionView $view, ActionInterface $action, array $options): void
    {
        $view->vars['dropdown'] = true;
    }

    public function getParent(): ?string
    {
        return LinkActionType::class;
    }

    public function configureOptions(OptionsResolver $resolver): void
    {
        // @todo : use group options to handle multiple dropdown
        $resolver->setDefault('group', null);
    }
}

And the template :

{% block actions %}
    {% set dropdown_actions = actions | filter(a => a.vars.dropdown|default) %}
    <div class="d-flex align-items-center gap-2">

        {% for action in actions | filter(a => a not in dropdown_actions) %}
            {{ data_table_action(action) }}
        {% endfor %}

        {% if dropdown_actions|length %}
            <div class="dropdown">
                <twig:Button type="button" size="sm" ghost data-bs-toggle="dropdown"
                                 data-bs-popper-config="{{ { strategy: "fixed" }|json_encode|escape }}">
                        <twig:Icon icon="dots" class="m-0" />
                    </twig:Button>
                <div class=" dropdown-menu">
                    {% for action in dropdown_actions %}
                        {% set class = ('dropdown-item ' ~ action.vars.attr.class|default('')) | trim %}
                        {% set attr = action.vars.attr|default([])|merge({ class }) %}
                        {{ data_table_action(action, { attr }) }}
                    {% endfor %}
                </div>
            </div>
        {% endif %}
    </div>
{% endblock %}

@alexandre-castelain
Copy link
Contributor Author

This is exactly the kind of thing I have in mind. We could add options:

  • Choice of text
  • Choice of icon
  • Choice of class
  • The same for sub-actions
  • ...

I don't have any implementation with this bundle yet.
I see you have a twig:Button element, is this yours ? Do you use another Twig Component ?

@Kreyu
Copy link
Owner

Kreyu commented Jul 3, 2024

This is exactly the kind of thing I have in mind. We could add options:

  • Choice of text
  • Choice of icon
  • Choice of class
  • The same for sub-actions
  • ...

I think the point is to define actions like we can define them currently, but optionally grouping them using the group option. Therefore, we don't need to add options you've described, because that is already possible.

Thanks for suggestion @bdecarne!

@Kreyu
Copy link
Owner

Kreyu commented Jul 3, 2024

Oh, sorry @alexandre-castelain, I think I misunderstood what you meant at first - setting a label/icon/attributes for the dropdown itself? In that case I am not sure how we should handle following scenario:

$builder
    ->addAction('red', DropdownActionType::class, [
        'group' => 'colors',
        'group_label' => 'Foo',
    ])
    ->addAction('blue', DropdownActionType::class, [
        'group' => 'colors',
        'group_label' => 'Bar',
    ])
;

Single group, but two different labels (or icon, or attributes...) 😞 Maybe something like this:

$builder
    ->addAction('colors', DropdownActionType::class, [
        'actions' => [
            $builder->createAction('red', LinkActionType::class),
            $builder->createAction('blue', LinkActionType::class),
        ],
    ])
;

Then, I'm not sure which action types would be allowed in the dropdown to be able to render them properly.

@alexandre-castelain
Copy link
Contributor Author

alexandre-castelain commented Jul 4, 2024

Hi @Kreyu ,

Indeed, the second option was what I had in mind. We currently have this kind of action in our data-table implementation, and it is very convenient to use.

Note, I'm not suggesting to adopt this functionality as it is, but rather to give you an idea.

->addColumn('action', ActionColumn::class, [
                'label' => 'list.columns.actions.label',
                'field' => 'id',
                'actions' => function (int $idOfMyEntity, MyEntityDisplayed $myEntity) {
                    $actions = [
                        (new DropDownMenuAction())
                            ->setLabel('list.columns.actions.menu.label')
                            ->setActions([
                                (new DropDownItemAction('my_route'))
                                    ->setLabel('list.columns.actions.menu.customers_map.label')
                                    ->setActionType(AbstractAction::ACTION_TYPE_ROUTE)
                                    ->setActionParams(['id' => $idOfMyEntity])
                                    ->setDisplayRights([
                                        //Add a way to pass some ROLES that must be matched to display this specific action.
                                    ]),
                            ]),
                        (new ButtonAction('another_route'))
                            ->setActionType(AbstractAction::ACTION_TYPE_ROUTE)
                            ->setActionParams(['id' => $idOfMyEntity])
                            ->setPictogram((new Icon())->setCssClass('fa-solid fa-eye')) //We could use Twig:Icon on the frontend side
                    ];

                    if ('KO' === $myEntity->getStatus()) {
                        $actions[] = (new ButtonAction($this->router->generate('another_another_route')))
                            ->setActionType(AbstractAction::ACTION_TYPE_AJAX_CALL) //This is usefull, you can make an ajax call and then refresh the data-table
                            ->setActionParams(['id' => $idOfMyEntity])
                            ->setDisplayRights([
                                ['right' => MY_ENTITY::ROLE 'subject' => $myEntity], // This is the way we check the right in our lib.
                            ])
                            ->setPictogram((new Icon())->setCssClass('fa-solid fa-trash-arrow-up'))
                            ->setCssClass('button-secondary');
                    }
                    return $actions;
                },
            ]);

I know there is a lot of information in this code snippet. I will try to review the elements that seem important to me.

->addColumn('action', ActionColumn::class, [
A type of column that accepts multiple actions. In our implementation, a data-table accepts only one ActionColumn. This should be changed.
'field' => 'id',
This is useful as it allows sending directly into the callback the entity field we want to use.
(new DropDownMenuAction())
This is our way of handling select/options. I'm not convinced by the name and I think it would be appropriate to redesign this part. But I find the idea interesting.
(new DropDownItemAction('my_route'))
Again, the class name should probably be reconsidered. But the idea is there: adding a child to the select/options. It would be nicer to be able to use the actions you have already defined.
->setActionType(AbstractAction::ACTION_TYPE_ROUTE)
We have added several action types: route (a redirect to this route), link (an external link), ajax_call (an ajax call + data-table refresh, which is extremely useful), dt-reload (refresh the data-table), js_function (a call to a JS function, to open a modal for example).
->setDisplayRights([
To manage display rights by button, in the background, we use Symfony's voter system.
->setPictogram((new Icon())->setCssClass('fa-solid fa-eye'))
This is a way to add icons throughout our application. We can manage the color, icon, and size directly on the backend.

I think I have covered the interesting options in this code snippet. We have implemented other things as well, but if we can add this to the bundle, it would already be very good!

Again, I don't want to add this as it is; I think there is room for improvement.

What do you think?

alexandre-castelain added a commit to alexandre-castelain/data-table-bundle that referenced this issue Jul 11, 2024
alexandre-castelain added a commit to alexandre-castelain/data-table-bundle that referenced this issue Jul 11, 2024
alexandre-castelain added a commit to alexandre-castelain/data-table-bundle that referenced this issue Jul 11, 2024
alexandre-castelain added a commit to alexandre-castelain/data-table-bundle that referenced this issue Jul 11, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature that would fit the core bundle
Projects
None yet
Development

No branches or pull requests

3 participants