silverstripe / silverstripe-framework

Silverstripe Framework, the MVC framework that powers Silverstripe CMS
https://www.silverstripe.org
BSD 3-Clause "New" or "Revised" License
723 stars 821 forks source link

Pagination with 1 item per page breaks breaks when using prev/next #11231

Open lekoala opened 4 months ago

lekoala commented 4 months ago

Module version(s) affected

5.x

Description

Stumbled upon this recently when doing some tests

When having a nested gridfield in a model admin, if you have setItemsPerPage = 1 for the nested grid field, when using the next arrow, it stops working after three clicks, as if there was no record anymore

Eg: i have 9 pages

image

It stops on record number 3

image

It works just fine with 2 items per page Refreshing the page doesn't help I guess something is wrong with the +1/-1 offset logic

How to reproduce

 public function getCMSFields()
    {
        $fields = parent::getCMSFields();

        $ManyRelation = $fields->dataFieldByName('ManyRelation');
        if ($ManyRelation) {
            $config = $ManyRelation->getConfig();
            $paginator = $config->getComponentByType(GridFieldPaginator::class);
            $paginator->setItemsPerPage(2);
        }

        return $fields;
    }

Possible Solution

No response

Additional Context

No response

Validations

GuySartorelli commented 4 months ago

Just to clarify, when you say "prev/next", is that the "previous page" and "next page" buttons in the paginator when you're viewing the GridField as a whole? Or is that the "previous record" and "next record" buttons when accessing the edit form for a record managed by the GridField?

GuySartorelli commented 4 months ago

Also your "how to reproduce" is just some code without context. Please give some steps along with the code, so it's easy to reproduce by just following some steps. Especially double check the code since you mention 1 item per page, but the code shows 2.

lekoala commented 4 months ago

Updated the how to reproduce. It's when using the detail form using the prev/next arrow next to the delete button

emteknetnz commented 4 months ago

I cannot replicate on 5.2.x-dev or 5.x-dev

Please let me know exact version and exact code used

Here's the code I failed to replicate with:

// app/src/MyModelAdmin.php

<?php

use SilverStripe\Admin\ModelAdmin;

class MyModelAdmin extends ModelAdmin
{
    private static $url_segment = 'MyModelAdmin';

    private static $menu_title = 'My model admin';

    private static $managed_models = [
        MyDataObject::class,
    ];
}

// app/src/MyDataObject.php

<?php

use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
use SilverStripe\ORM\DataObject;
use SilverStripe\Forms\GridField\GridFieldPaginator;

class MyDataObject extends DataObject
{
    private static $table_name = 'MyDataObject';

    private static $db = [
        'Title' => 'Varchar'
    ];

    private static $many_many = [
        'MySubDataObjects' => MySubDataObject::class
    ];

    public function getCMSFields()
    {
        $fields = parent::getCMSFields();
        $gridField = new GridField('MySubDataObjects', 'MySubDataObjecs', $this->MySubDataObjects());
        $config = GridFieldConfig_RecordEditor::create();
        $gridField->setConfig($config);
        $paginator = $config->getComponentByType(GridFieldPaginator::class);
        $paginator->setItemsPerPage(1);
        $fields->insertAfter('Title', $gridField);
        return $fields;
    }
}

// app/src/MySubDataObject.php

<?php

use SilverStripe\ORM\DataObject;

class MySubDataObject extends DataObject
{
    private static $table_name = 'MySubDataObject';

    private static $db = [
        'Title' => 'Varchar'
    ];

    private static $belongs_many_many = [
        'MyDataObjects' => MyDataObject::class
    ];
}
lekoala commented 4 months ago

here is a video maybe it's better:

https://github.com/silverstripe/silverstripe-framework/assets/250762/6868089c-8aca-4147-9710-f18fd0682b3e

it's on silverstripe/framework 5.2.6 using chrome/windows

emteknetnz commented 4 months ago

OK thanks that video helps a lot

I've done some debugging, looks like in the GridFieldDetailForm_ItemRequest the $this->gridField is the top level DataObject. Rather than the one being edited. This means that "gridstate" which is ?gridState-MySubDataObjects-1=%7B%22GridFieldPaginator%22%3A%7B%22currentPage%22%3A5%7D%7D thing in the URL will not match because it's using the wrong key, in the case of the code sample I had on this issue it $gridField->name should be 'MySubDataObjects' but it's mistakenly 'MyDataObject' instead

The full url of my request is /admin/MyModelAdmin/MyDataObject/EditForm/field/MyDataObject/item/1/ItemEditForm/field/MySubDataObjects/item/5?gridState-MySubDataObjects-1=%7B%22GridFieldPaginator%22%3A%7B%22currentPage%22%3A5%7D%7D

lekoala commented 4 months ago

yes, so while my issue (who would be using 1 item per page :) ) is pretty minor, i'm sure it leads to a larger issue that could cause tricky bugs

maybe related: https://github.com/silverstripe/silverstripe-framework/issues/9556

emteknetnz commented 4 months ago

Apparently we might look at a new way of managing the gridstate, so in the mean time I might just park this one for a wee while since it seems like it's very hard to fix