SortableGridField icon indicating copy to clipboard operation
SortableGridField copied to clipboard

Creating new DataObject results in database query with empty table and column names

Open leonixyz opened this issue 9 months ago • 1 comments

Affected Version

{
        "php": "^8.1",
        "silverstripe/recipe-plugin": "~2.0.0@stable",
        "silverstripe/vendor-plugin": "~2.0.0@stable",
        "silverstripe/recipe-cms": "~5.0.0@stable",
        "silverstripe/login-forms": "~5.0.0@stable",
        "silverstripe/display-logic": "^3.0",
        "undefinedoffset/sortablegridfield": "^2.2"
}

Description

A wrong query is issued to the database, having empty table name and empty column names.

UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3

If, after hitting the error, you examine the database, you'll find the many-to-many table has the new record correctly appended, but the SortOrder column is set at 0. Manually changing it to 1 solves the problem. But anytime you need to create a new one, the problem is back.

https://github.com/UndefinedOffset/SortableGridField/assets/4563795/5e79c425-d62d-4536-a301-8e7ef5fc0c92

Stack trace:

[Emergency] Uncaught SilverStripe\ORM\Connect\DatabaseException: Couldn't run query: UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3 Incorrect table name ''
GET /admin/views/View/EditForm/field/View/item/3/ItemEditForm/field/AttachmentsCategories/item/15

Line 64 in /var/www/html/vendor/silverstripe/framework/src/ORM/Connect/DBConnector.php
Source

55         if (!empty($sql)) {
56             $formatter = new SQLFormatter();
57             $formattedSQL = $formatter->formatPlain($sql);
58             $msg = "Couldn't run query:\n\n{$formattedSQL}\n\n{$msg}";
59         }
60 
61         if ($errorLevel === E_USER_ERROR) {
62             // Treating errors as exceptions better allows for responding to errors
63             // in code, such as credential checking during installation
64             throw new DatabaseException($msg, 0, null, $sql, $parameters);
65         } else {
66             user_error($msg ?? '', $errorLevel ?? 0);
67         }
68     }
69 
70     /**

Trace

    SilverStripe\ORM\Connect\DBConnector->databaseError(Couldn't run query: UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3 Incorrect table name '', 256, UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3)
    MySQLiConnector.php:194
    SilverStripe\ORM\Connect\MySQLiConnector->query(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3, 256)
    Database.php:159
    SilverStripe\ORM\Connect\Database->SilverStripe\ORM\Connect\{closure}(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3)
    Database.php:258
    SilverStripe\ORM\Connect\Database->benchmarkQuery(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3, Closure)
    Database.php:160
    SilverStripe\ORM\Connect\Database->query(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3, 256)
    MySQLDatabase.php:381
    SilverStripe\ORM\Connect\MySQLDatabase->query(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3, 256)
    DB.php:341
    SilverStripe\ORM\DB::query(UPDATE "" SET "SortOrder" = 1 WHERE "" = 15 AND "" = 3)
    GridFieldSortableRows.php:329
    UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows->fixSortColumn(SilverStripe\Forms\GridField\GridField, SilverStripe\ORM\ManyManyList)
    GridFieldSortableRows.php:151
    UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows->getManipulatedData(SilverStripe\Forms\GridField\GridField, SilverStripe\ORM\ManyManyList)
    GridField.php:411
    SilverStripe\Forms\GridField\GridField->getManipulatedList()
    GridFieldDetailForm_ItemRequest.php:573
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->getGridFieldItemAdjacencies()
    GridFieldDetailForm_ItemRequest.php:654
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->getAdjacentRecordID(-1)
    GridFieldDetailForm_ItemRequest.php:682
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->getPreviousRecordID()
    GridFieldDetailForm_ItemRequest.php:334
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->getRightGroupField()
    GridFieldDetailForm_ItemRequest.php:420
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->getFormActions()
    VersionedGridFieldItemRequest.php:90
    SilverStripe\Versioned\VersionedGridFieldItemRequest->getFormActions()
    GridFieldDetailForm_ItemRequest.php:242
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->ItemEditForm()
    GridFieldDetailForm_ItemRequest.php:160
    SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest->edit(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:323
    SilverStripe\Control\RequestHandler->handleAction(SilverStripe\Control\HTTPRequest, edit)
    RequestHandler.php:202
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    GridFieldDetailForm.php:149
    SilverStripe\Forms\GridField\GridFieldDetailForm->handleItem(SilverStripe\Forms\GridField\GridField, SilverStripe\Control\HTTPRequest)
    GridField.php:1237
    SilverStripe\Forms\GridField\GridField->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    GridFieldDetailForm.php:149
    SilverStripe\Forms\GridField\GridFieldDetailForm->handleItem(SilverStripe\Forms\GridField\GridField, SilverStripe\Control\HTTPRequest)
    GridField.php:1237
    SilverStripe\Forms\GridField\GridField->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    RequestHandler.php:226
    SilverStripe\Control\RequestHandler->handleRequest(SilverStripe\Control\HTTPRequest)
    Controller.php:202
    SilverStripe\Control\Controller->handleRequest(SilverStripe\Control\HTTPRequest)
    LeftAndMain.php:799
    SilverStripe\Admin\LeftAndMain->handleRequest(SilverStripe\Control\HTTPRequest)
    AdminRootController.php:124
    SilverStripe\Admin\AdminRootController->handleRequest(SilverStripe\Control\HTTPRequest)
    Director.php:349
    SilverStripe\Control\Director->SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    VersionedHTTPMiddleware.php:41
    SilverStripe\Versioned\VersionedHTTPMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    LoginSessionMiddleware.php:53
    SilverStripe\SessionManager\Middleware\LoginSessionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ExecMetricMiddleware.php:20
    SilverStripe\Control\Middleware\ExecMetricMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ConfirmationMiddleware.php:254
    SilverStripe\Control\Middleware\ConfirmationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ConfirmationMiddleware.php:254
    SilverStripe\Control\Middleware\ConfirmationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    PasswordExpirationMiddleware.php:84
    SilverStripe\Security\PasswordExpirationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    BasicAuthMiddleware.php:68
    SilverStripe\Security\BasicAuthMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    AuthenticationMiddleware.php:61
    SilverStripe\Security\AuthenticationMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    CanonicalURLMiddleware.php:245
    SilverStripe\Control\Middleware\CanonicalURLMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPCacheControlMiddleware.php:41
    SilverStripe\Control\Middleware\HTTPCacheControlMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    ChangeDetectionMiddleware.php:28
    SilverStripe\Control\Middleware\ChangeDetectionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    FlushMiddleware.php:31
    SilverStripe\Control\Middleware\FlushMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    SessionMiddleware.php:20
    SilverStripe\Control\Middleware\SessionMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    AllowedHostsMiddleware.php:60
    SilverStripe\Control\Middleware\AllowedHostsMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    TrustedProxyMiddleware.php:176
    SilverStripe\Control\Middleware\TrustedProxyMiddleware->process(SilverStripe\Control\HTTPRequest, Closure)
    HTTPMiddlewareAware.php:62
    SilverStripe\Control\Director->SilverStripe\Control\Middleware\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPMiddlewareAware.php:65
    SilverStripe\Control\Director->callMiddleware(SilverStripe\Control\HTTPRequest, Closure)
    Director.php:358
    SilverStripe\Control\Director->handleRequest(SilverStripe\Control\HTTPRequest)
    HTTPApplication.php:114
    SilverStripe\Control\HTTPApplication::SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    call_user_func(Closure, SilverStripe\Control\HTTPRequest)
    HTTPApplication.php:137
    SilverStripe\Control\HTTPApplication->SilverStripe\Control\{closure}(SilverStripe\Control\HTTPRequest)
    HTTPMiddlewareAware.php:65
    SilverStripe\Control\HTTPApplication->callMiddleware(SilverStripe\Control\HTTPRequest, Closure)
    HTTPApplication.php:138
    SilverStripe\Control\HTTPApplication->execute(SilverStripe\Control\HTTPRequest, Closure, )
    HTTPApplication.php:113
    SilverStripe\Control\HTTPApplication->handle(SilverStripe\Control\HTTPRequest)
    index.php:24

Steps to Reproduce

Given the following relations, whenever you try to create a new Button, disregarding whether you do it from the View gridfield, or from the MetricGroup gridfield, you get a 500 and the above error.

┌─────────────┐                                                                       
│             │                                                                       
│     View    ├───────┐*                                                              
│             │*      ├─────────┐       ┌─────────────────────┐      ┌───────────────┐
└─────────────┘       │         │       │                     │      │               │
                      │  Button ├───────┤ AttachmentsCategory ├──────┤  Attachments  │
┌──────────────┐      │         │1     *│                     │*    *│               │
│              │      ├─────────┘       └─────────────────────┘      └───────────────┘
│ MetricGroup  │      │*                                                              
│              ├──────┘                                                               
└──────────────┘*                                                                     

Please forgive me if the code is redundant.

GridFieldConfig.php

<?php

use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;


class SortableGridFieldConfig extends GridFieldConfig_RelationEditor {
    public static function create(mixed ...$args) {
        $config = GridFieldConfig_RelationEditor::create(50);
        $config->addComponent(GridFieldSortableRows::create('SortOrder'));
        return $config;
    }
}

Attachments.php

<?php

use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\File;
use Silverstripe\Forms\CheckboxField;
use Silverstripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\TabSet;
use Silverstripe\Forms\TextField;
use Silverstripe\ORM\DataObject;


class Button extends DataObject {
    private static $db = [
        'AdminOnly' => 'Boolean(0)',
        'Description' => 'Text',
        'Name' => 'Text',
    ];

    private static $has_many = [
        'AttachmentsCategories' => AttachmentsCategory::class,
    ];

    private static $belongs_many_many = [
        'Views' => View::class,
        'MetricGroups' => MetricGroup::class,
    ];

    private static $searchable_fields = [
        'Name',
        'Description',
    ];

    private static $summary_fields = [
        'Name' => 'Name',
        'Description' => 'Description',
        'IsAdminOnly' => 'Admin Only',
    ];

    private static $casting = [
        'IsAdminOnly' => 'Text',
    ];

    private function boolToText($input) {
        if($input) {
            return 'yes';
        } else {
            return 'no';
        }
    }

    public function getIsAdminOnly() {
        return $this->boolToText($this->AdminOnly);
    }

    public function AttachmentsCategories() {
        return $this->getComponents('AttachmentsCategories')->sort('SortOrder');
    }

    public function getCMSfields() {
        $fields = FieldList::create(TabSet::create('Root'));
        $fields->addFieldsToTab('Root.Main', [
            CheckboxField::create('AdminOnly', 'Visible only to Administrators'),
            TextField::create('Name'),
            TextField::create('Description'),
        ]);
        $fields->addFieldsToTab('Root.Main', [
            GridField::create(
                'AttachmentsCategories',
                'Attachments Categories',
                $this->AttachmentsCategories(),
                $gridConfig = SortableGridFieldConfig::create(),
            ),
        ]);
        return $fields;
    }
}


class AttachmentsCategory extends DataObject {
    private static $db = [
        'Name' => 'Text',
        'SortOrder' => 'Int',
    ];

    private static $has_one = [
        'Button' => Button::class,
    ];

    private static $many_many = [
        'Attachments' => Attachment::class,
    ];

    private static $many_many_extraFields = [
        'Attachments' => [
            'SortOrder' => 'Int',
        ],
    ];

    public function Attachments() {
        return $this->getManyManyComponents('Attachments')->sort('SortOrder');
    }

    public function getCMSfields() {
        $fields = FieldList::create(TabSet::create('Root'));
        $fields->addFieldsToTab('Root.Main', [
            TextField::create('Name'),
        ]);
        $fields->addFieldsToTab('Root.Main', [
            GridField::create(
                'Attachments',
                'Attachments',
                $this->Attachments(),
                SortableGridFieldConfig::create(),
            ),
        ]);
        return $fields;
    }
}

class Attachment extends DataObject {
    private static $db = [
        'Name' => 'Text',
    ];

    private static $has_one = [
        'File' => File::class,
    ];

    private static $belongs_many_many = [
        'Category' => AttachmentsCategory::class,
    ];

    public function getCMSfields() {
        $fields = FieldList::create(TabSet::create('Root'));
        $fields->addFieldsToTab('Root.Main', [
            TextField::create('Name'),
            UploadField::create('File'),
        ]);

        return $fields;
    }
}

MetricGroup.php

<?php

use Silverstripe\Forms\CheckboxField;
use Silverstripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
use Silverstripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\TabSet;
use Silverstripe\Forms\TextField;
use Silverstripe\ORM\DataObject;
use SilverStripe\Security\Security;


class MetricGroup extends DataObject {
    private static $db = [
        'AdminOnly' => 'Boolean(0)',
        'Description' => 'HTMLText',
        'Enabled' => 'Boolean(1)',
        'Subtitle' => 'Text',
        'Title' => 'Text',
    ];

    private static $defaults = [
        'Enabled' => true,
    ];

    private static $belongs_many_many = [
        'View' => View::class,
    ];

    private static $many_many = [
        'Buttons' => Button::class,
        'Metrics' => Metric::class,
    ];

	private static $many_many_extraFields = [
		'Metrics' => [
			'SortOrder' => 'Int',
        ],
        'Buttons' => [
            'SortOrder' => 'Int',
        ],
	];

    private static $summary_fields = [
        'Title' => 'Title',
        'Subtitle' => 'Subtitle',
        'IsEnabled' => 'Enabled',
        'IsAdminOnly' => 'Admin Only',
        'MetricsCount' => 'Metrics',
    ];

    private static $casting = [
        'IsEnabled' => 'Text',
        'IsAdminOnly' => 'Text',
        'MetricsCount' => 'Text',
    ];

    private function boolToText($input) {
        if($input) {
            return 'yes';
        } else {
            return 'no';
        }
    }

    public function getIsEnabled() {
        return $this->boolToText($this->Enabled);
    }

    public function getIsAdminOnly() {
        return $this->boolToText($this->AdminOnly);
    }

    public function getMetricsCount() {
        return count($this->Metrics());
    }

    public function Metrics() {
        $member = Security::getCurrentUser();
        $metrics = $this->getManyManyComponents('Metrics')->sort('SortOrder');
        if (!$member->inGroup('administrators')) {
            $metrics = $metrics->filter(['AdminOnly' => false]);
        }
        return $metrics;
	}

    public function Buttons() {
        $member = Security::getCurrentUser();
        $buttons = $this->owner->getManyManyComponents('Buttons')->sort('SortOrder');
        if (!$member->inGroup('administrators')) {
            $buttons = $buttons->filter(['AdminOnly' => false]);
        }
        return $buttons;
    }

    public function getCMSfields() {
        $fields = FieldList::create(TabSet::create('Root'));
        $fields->addFieldsToTab('Root.Main', [
            CheckboxField::create('Enabled'),
            CheckboxField::create('AdminOnly', 'Visible only to Administrators'),
            TextField::create('Title'),
            TextField::create('Subtitle'),
            HTMLEditorField::create('Description'),
            GridField::create(
                'Metrics',
                'Metrics',
                $this->Metrics(),
                SortableGridFieldConfig::create()
                    ->removeComponentsByType(SilverStripe\Forms\GridField\GridFieldAddNewButton::class),
            ),
        ]);
        $fields->addFieldsToTab('Root.Buttons', [
            GridField::create(
                'AttachmentsCategories',
                'Attachments Categories',
                $this->Buttons(),
                $gridConfig = SortableGridFieldConfig::create(),
            ),
        ]);
        $gridConfig->getComponentByType(GridFieldAddExistingAutocompleter::class)->setResultsFormat('$Name ($Description)');
        return $fields;
    }
}

View.php

<?php

use SilverStripe\AssetAdmin\Forms\UploadField;
use SilverStripe\Assets\File;
use Silverstripe\Forms\CheckboxField;
use Silverstripe\Forms\FieldList;
use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldAddExistingAutocompleter;
use Silverstripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\TabSet;
use Silverstripe\Forms\TextField;
use Silverstripe\ORM\DataObject;
use SilverStripe\Security\Member;
use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\Security\Security;


class View extends DataObject {

    private static $db = [
        'Enabled' => 'Boolean(1)',
        'Name' => 'Text',
        'Code' => 'Text',
        'Factory' => 'Text',
        'Description' => 'HTMLText',
    ];

    private static $defaults = [
        'Enabled' => true,
    ];

    private static $has_one = [
        'Picture' => File::class,
        'Graphic' => File::class,
    ];

    private static $belongs_many_many = [
        'Owners' => Member::class,
    ];

    private static $many_many = [
        'Buttons' => Button::class,
        'MetricGroups' => MetricGroup::class,
    ];

    private static $many_many_extraFields = [
        'MetricGroups' => [
            'SortOrder' => 'Int',
        ],
        'Buttons' => [
            'SortOrder' => 'Int',
        ],
    ];

    private static $summary_fields = [
        'Name' => 'Name',
        'Code' => 'Code',
        'IsEnabled' => 'Enabled',
    ];

    private static $casting = [
        'IsEnabled' => 'Text',
    ];

    private function boolToText($input) {
        if($input) {
            return 'yes';
        } else {
            return 'no';
        }
    }

    public function getIsEnabled() {
        return $this->boolToText($this->Enabled);
    }

    public function MetricGroups() {
        $member = Security::getCurrentUser();
        $metric_groups = $this->getManyManyComponents('MetricGroups')->sort('SortOrder');
        if (!$member->inGroup('administrators')) {
            $metric_groups = $metric_groups->filter(['AdminOnly' => false]);
        }
        return $metric_groups;
	}

    public function Buttons() {
        $member = Security::getCurrentUser();
        $buttons = $this->owner->getManyManyComponents('Buttons')->sort('SortOrder');
        if (!$member->inGroup('administrators')) {
            $buttons = $buttons->filter(['AdminOnly' => false]);
        }
        return $buttons;
    }

    public function getCMSfields() {
        $fields = FieldList::create(TabSet::create('Root'));
        $fields->addFieldsToTab('Root.Main', [
            CheckboxField::create('Enabled'),
            TextField::create('Name'),
            TextField::create('Code'),
            TextField::create('Factory'),
            HTMLEditorField::create('Description'),
            UploadField::create('Graphic', 'Graphic for main menu'),
            UploadField::create('Picture', 'Synoptic'),
        ]);
        $fields->addFieldsToTab('Root.MetricGroups', [    
            GridField::create(
                'MetricGroups',
                'Metric Groups',
                $this->MetricGroups(),
                SortableGridFieldConfig::create(),
            ),
        ]);
        $fields->addFieldsToTab('Root.Buttons', [
            GridField::create(
                'AttachmentsCategories',
                'Attachments Categories',
                $this->Buttons(),
                $gridConfig = SortableGridFieldConfig::create(),
            ),
        ]);
        $gridConfig->getComponentByType(GridFieldAddExistingAutocompleter::class)->setResultsFormat('$Name ($Description)');
        return $fields;
    }
}

leonixyz avatar May 11 '24 22:05 leonixyz