From cc22024e9ab0de865e5cf88f1f087f3242415a74 Mon Sep 17 00:00:00 2001 From: Maxime Rainville Date: Tue, 4 Sep 2018 11:35:17 +1200 Subject: [PATCH] ADD New search component for GridFields (#1777) --- lang/en.yml | 4 + src/Forms/GridField/GridFieldConfig_Base.php | 1 + src/Forms/GridField/GridFieldFilterHeader.php | 222 ++++++++++++++++-- .../GridField/GridFieldSortableHeader.php | 9 +- .../GridField/GridFieldFilterHeader_Row.ss | 2 +- .../GridField/GridFieldFilterHeader_Search.ss | 1 + tests/behat/src/CmsUiContext.php | 23 +- .../GridField/GridFieldFilterHeaderTest.php | 121 ++++++++++ .../GridField/GridFieldFilterHeaderTest.yml | 76 ++++++ .../GridFieldFilterHeaderTest/Cheerleader.php | 21 ++ .../CheerleaderHat.php | 19 ++ .../GridFieldFilterHeaderTest/Mom.php | 18 ++ .../GridFieldFilterHeaderTest/Team.php | 27 +++ .../GridFieldFilterHeaderTest/TeamGroup.php | 14 ++ tests/php/Forms/GridField/GridFieldTest.php | 2 + 15 files changed, 531 insertions(+), 29 deletions(-) create mode 100644 templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Search.ss create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest.php create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest/Cheerleader.php create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest/CheerleaderHat.php create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php create mode 100644 tests/php/Forms/GridField/GridFieldFilterHeaderTest/TeamGroup.php diff --git a/lang/en.yml b/lang/en.yml index 8c1756543..35be6b4b9 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -83,6 +83,10 @@ en: Print: Print RelationSearch: 'Relation search' ResetFilter: Reset + OpenFilter: 'Open search and filter' + SilverStripe\Forms\GridField\GridFieldFilterHeader: + Search: 'Search "{name}"' + SearchFormFaliure: 'No search form could be generated' SilverStripe\Forms\GridField\GridFieldDeleteAction: Delete: Delete DeletePermissionsFailure: 'No delete permissions' diff --git a/src/Forms/GridField/GridFieldConfig_Base.php b/src/Forms/GridField/GridFieldConfig_Base.php index 8ed4f70ad..026bab57a 100644 --- a/src/Forms/GridField/GridFieldConfig_Base.php +++ b/src/Forms/GridField/GridFieldConfig_Base.php @@ -16,6 +16,7 @@ class GridFieldConfig_Base extends GridFieldConfig { parent::__construct(); $this->addComponent(new GridFieldToolbarHeader()); + $this->addComponent(new GridFieldButtonRow('before')); $this->addComponent($sort = new GridFieldSortableHeader()); $this->addComponent($filter = new GridFieldFilterHeader()); $this->addComponent(new GridFieldDataColumns()); diff --git a/src/Forms/GridField/GridFieldFilterHeader.php b/src/Forms/GridField/GridFieldFilterHeader.php index b44ec9df6..bd38f2104 100755 --- a/src/Forms/GridField/GridFieldFilterHeader.php +++ b/src/Forms/GridField/GridFieldFilterHeader.php @@ -2,14 +2,22 @@ namespace SilverStripe\Forms\GridField; +use LogicException; +use SilverStripe\Admin\LeftAndMain; +use SilverStripe\Control\Controller; +use SilverStripe\Control\HTTPResponse; +use SilverStripe\Core\Convert; +use SilverStripe\Dev\Deprecation; use SilverStripe\Forms\FieldGroup; +use SilverStripe\Forms\FieldList; +use SilverStripe\Forms\Form; +use SilverStripe\Forms\Schema\FormSchema; use SilverStripe\Forms\TextField; +use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\Filterable; use SilverStripe\ORM\SS_List; -use SilverStripe\ORM\ArrayList; use SilverStripe\View\ArrayData; use SilverStripe\View\SSViewer; -use LogicException; /** * GridFieldFilterHeader alters the {@link GridField} with some filtering @@ -17,9 +25,8 @@ use LogicException; * * @see GridField */ -class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider +class GridFieldFilterHeader implements GridField_URLHandler, GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider { - /** * See {@link setThrowExceptionOnBadDataType()} * @@ -27,6 +34,33 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan */ protected $throwExceptionOnBadDataType = true; + /** + * Indicates that this component should revert to displaying it's legacy + * table header style rather than the react driven search box + * + * @deprecated 5.0 + * @var bool + */ + public $useLegacyFilterHeader = false; + + /** + * @inheritDoc + */ + public function getURLHandlers($gridField) + { + return [ + 'GET schema/SearchForm' => 'getSearchFormSchema' + ]; + } + + /** + * @param bool $useLegacy + */ + public function __construct($useLegacy = false) + { + $this->useLegacyFilterHeader = $useLegacy; + } + /** * Determine what happens when this component is used with a list that isn't {@link SS_Filterable}. * @@ -73,6 +107,7 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan } /** + * If the GridField has a filterable datalist, return an array of actions * * @param GridField $gridField * @return array @@ -83,9 +118,15 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan return []; } - return array('filter', 'reset'); + return ['filter', 'reset']; } + /** + * If the GridField has a filterable datalist, return an array of actions + * + * @param GridField $gridField + * @return array + */ public function handleAction(GridField $gridField, $actionName, $arguments, $data) { if (!$this->checkDataType($gridField->getList())) { @@ -106,10 +147,7 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan /** - * - * @param GridField $gridField - * @param SS_List $dataList - * @return SS_List + * @inheritDoc */ public function getManipulatedData(GridField $gridField, SS_List $dataList) { @@ -135,12 +173,12 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan } /** - * Returns whether this {@link GridField} has any columns to sort on at all. + * Returns whether this {@link GridField} has any columns to filter on at all * * @param GridField $gridField * @return boolean */ - public function canFilterAnyColumns($gridField) + public function canFilterAnyColumns(GridField $gridField) { $list = $gridField->getList(); @@ -161,21 +199,133 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan return false; } - public function getHTMLFragments($gridField) + + /** + * Generate a search context based on the model class of the of the GridField + * + * @param GridField $gridfield + * @return \SilverStripe\ORM\Search\SearchContext + */ + public function getSearchContext(GridField $gridField) { + $context = singleton($gridField->getModelClass())->getDefaultSearchContext(); + + return $context; + } + + /** + * Returns the search field schema for the component + * + * @param GridField $gridfield + * @return string + */ + public function getSearchFieldSchema(GridField $gridField) + { + $schemaUrl = Controller::join_links($gridField->Link(), 'schema/SearchForm'); + + $context = $this->getSearchContext($gridField); + $params = $gridField->getRequest()->postVar('filter') ?: []; + if (array_key_exists($gridField->getName(), $params)) { + $params = $params[$gridField->getName()]; + } + $context->setSearchParams($params); + + $searchField = $context->getSearchFields()->first(); + $searchField = $searchField && property_exists($searchField, 'name') ? $searchField->name : null; + + $name = $gridField->Title ?: singleton($gridField->getModelClass())->i18n_plural_name(); + + $schema = [ + 'formSchemaUrl' => $schemaUrl, + 'name' => $searchField, + 'placeholder' => _t(__CLASS__ . '.Search', 'Search "{name}"', ['name' => $name]), + 'filters' => $context->getSearchParams() ?: new \stdClass, // stdClass maps to empty json object '{}' + 'gridfield' => $gridField->getName(), + 'searchAction' => GridField_FormAction::create($gridField, 'filter', false, 'filter', null)->getAttribute('name'), + 'clearAction' => GridField_FormAction::create($gridField, 'reset', false, 'reset', null)->getAttribute('name') + ]; + + return Convert::raw2json($schema); + } + + /** + * Returns the search form schema for the component + * + * @param GridField $gridfield + * @return HTTPResponse + */ + public function getSearchFormSchema(GridField $gridField) + { + $searchContext = $this->getSearchContext($gridField); + $searchFields = $searchContext->getSearchFields(); + + // If there are no filterable fields, return a 400 response + if ($searchFields->count() === 0) { + return new HTTPResponse(_t(__CLASS__ . '.SearchFormFaliure', 'No search form could be generated'), 400); + } + + $columns = $gridField->getColumns(); + + // Update field titles to match column titles + foreach ($columns as $columnField) { + $metadata = $gridField->getColumnMetadata($columnField); + // Get the field name, without any modifications + $name = explode('.', $columnField); + $title = $metadata['title']; + $field = $searchFields->fieldByName($name[0]); + + if ($field) { + $field->setTitle($title); + } + } + + foreach ($searchFields->getIterator() as $field) { + $field->addExtraClass('stacked'); + } + + $form = new Form( + $gridField, + "SearchForm", + $searchFields, + new FieldList() + ); + $form->setFormMethod('get'); + $form->setFormAction($gridField->Link()); + $form->addExtraClass('cms-search-form form--no-dividers'); + $form->disableSecurityToken(); // This form is not tied to session so we disable this + $form->loadDataFrom($gridField->getRequest()->getVars()); + + $parts = $gridField->getRequest()->getHeader(LeftAndMain::SCHEMA_HEADER); + $schemaID = $gridField->getRequest()->getURL(); + $data = FormSchema::singleton() + ->getMultipartSchema($parts, $schemaID, $form); + + $response = new HTTPResponse(Convert::raw2json($data)); + $response->addHeader('Content-Type', 'application/json'); + return $response; + } + + /** + * Generate fields for the legacy filter header row + * + * @deprecated 5.0 + * @param GridField $gridfield + * @return ArrayList|null + */ + public function getLegacyFilterHeader(GridField $gridField) + { + Deprecation::notice('5.0', 'Table row based filter header will be removed in favor of search field in 5.0'); + $list = $gridField->getList(); if (!$this->checkDataType($list)) { return null; } - /** @var Filterable $list */ - $forTemplate = new ArrayData(array()); - $forTemplate->Fields = new ArrayList(); - $columns = $gridField->getColumns(); $filterArguments = $gridField->State->GridFieldFilterHeader->Columns->toArray(); $currentColumn = 0; $canFilter = false; + $fieldsList = new ArrayList(); foreach ($columns as $columnField) { $currentColumn++; @@ -225,16 +375,44 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan $fields->addExtraClass('no-change-track'); } - $forTemplate->Fields->push($fields); + $fieldsList->push($fields); } - if (!$canFilter) { + return $canFilter ? $fieldsList : null; + } + + /** + * Either returns the legacy filter header or the search button and field + * + * @param GridField $gridField + * @return array|null + */ + public function getHTMLFragments($gridField) + { + $forTemplate = new ArrayData([]); + + if (!$this->canFilterAnyColumns($gridField)) { return null; } - $templates = SSViewer::get_templates_by_class($this, '_Row', __CLASS__); - return array( - 'header' => $forTemplate->renderWith($templates), - ); + if ($this->useLegacyFilterHeader) { + $fieldsList = $this->getLegacyFilterHeader($gridField); + $forTemplate->Fields = $fieldsList; + $filterTemplates = SSViewer::get_templates_by_class($this, '_Row', __CLASS__); + return ['header' => $forTemplate->renderWith($filterTemplates)]; + } else { + $fieldSchema = $this->getSearchFieldSchema($gridField); + $forTemplate->SearchFieldSchema = $fieldSchema; + $searchTemplates = SSViewer::get_templates_by_class($this, '_Search', __CLASS__); + return [ + 'before' => $forTemplate->renderWith($searchTemplates), + 'buttons-before-right' => sprintf( + '', + _t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter"), + _t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter") + ) + ]; + } } } diff --git a/src/Forms/GridField/GridFieldSortableHeader.php b/src/Forms/GridField/GridFieldSortableHeader.php index 6d84784d2..b26dab2c9 100644 --- a/src/Forms/GridField/GridFieldSortableHeader.php +++ b/src/Forms/GridField/GridFieldSortableHeader.php @@ -190,10 +190,15 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM if ($currentColumn == count($columns)) { $filter = $gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class); - if ($filter && $filter->canFilterAnyColumns($gridField)) { + if ($filter && $filter->useLegacyFilterHeader && $filter->canFilterAnyColumns($gridField)) { $field = new LiteralField( $fieldName, - '' + sprintf( + '', + _t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter"), + _t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter") + ) ); } else { $field = new LiteralField($fieldName, '' . $title . ''); diff --git a/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Row.ss b/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Row.ss index 7bd392d20..bed1ebf5d 100644 --- a/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Row.ss +++ b/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Row.ss @@ -1,5 +1,5 @@ <% if $Fields %> - + <% loop $Fields %> $Field <% end_loop %> diff --git a/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Search.ss b/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Search.ss new file mode 100644 index 000000000..f6dbaf31c --- /dev/null +++ b/templates/SilverStripe/Forms/GridField/GridFieldFilterHeader_Search.ss @@ -0,0 +1 @@ +
diff --git a/tests/behat/src/CmsUiContext.php b/tests/behat/src/CmsUiContext.php index 502a20932..209835615 100644 --- a/tests/behat/src/CmsUiContext.php +++ b/tests/behat/src/CmsUiContext.php @@ -321,17 +321,17 @@ class CmsUiContext implements Context public function iExpandTheContentFilters($action) { $page = $this->getSession()->getPage(); - $filterButton = $page->find('css', '#filters-button'); + $filterButton = $page->find('css', '.search-box__filter-trigger'); assertNotNull($filterButton, sprintf('Filter button link not found')); - $filterButtonCssClass = $filterButton->getAttribute('class'); + $filterButtonExpanded = $filterButton->getAttribute('aria-expanded'); if ($action === 'expand') { - if (strpos($filterButtonCssClass, 'active') === false) { + if ($filterButtonExpanded === false) { $filterButton->click(); } } else { - if (strpos($filterButtonCssClass, 'active') !== false) { + if ($filterButtonExpanded === true) { $filterButton->click(); } } @@ -350,6 +350,21 @@ SCRIPT } } + /** + * @Given /^I press the "([^"]*)" key in the "([^"]*)" field$/ + */ + public function iPressTheKeyInTheField($key, $field) + { + $this->getSession()->evaluateScript(sprintf( + "jQuery('[name=\"%s\"]')[0].dispatchEvent(new KeyboardEvent('keydown', { bubbles: true, key: \"%s\" })); + jQuery('[name=\"%s\"]')[0].dispatchEvent(new KeyboardEvent('keyup', { bubbles: true, key: \"%s\" }));", + $field, + $key, + $field, + $key + )); + } + /** * @When /^I (expand|collapse) "([^"]*)" in the tree$/ */ diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest.php new file mode 100644 index 000000000..293ff2299 --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest.php @@ -0,0 +1,121 @@ +list = new DataList(Team::class); + $config = GridFieldConfig_RecordEditor::create()->addComponent(new GridFieldFilterHeader()); + $this->gridField = new GridField('testfield', 'testfield', $this->list, $config); + $this->form = new Form(null, 'Form', new FieldList([$this->gridField]), new FieldList()); + $this->component = $this->gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class); + } + + /** + * Tests that the appropriate filter headers are generated + * + * @skipUpgrade + */ + public function testRenderHeaders() + { + $htmlFragment = $this->component->getHTMLFragments($this->gridField); + + // Check that the output is the new search field + $this->assertContains('
assertContains('Open search and filter', $htmlFragment['buttons-before-right']); + + $this->gridField->getConfig()->removeComponentsByType(GridFieldFilterHeader::class); + $this->gridField->getConfig()->addComponent(new GridFieldFilterHeader(true)); + $this->component = $this->gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class); + $htmlFragment = $this->component->getHTMLFragments($this->gridField); + + // Check that the output is the legacy filter header + $this->assertContains( + '', + $htmlFragment['header'] + ); + $this->assertFalse(array_key_exists('buttons-before-right', $htmlFragment)); + } + + public function testSearchFieldSchema() + { + $searchSchema = json_decode($this->component->getSearchFieldSchema($this->gridField)); + + $this->assertEquals('field/testfield/schema/SearchForm', $searchSchema->formSchemaUrl); + $this->assertEquals('Name', $searchSchema->name); + $this->assertEquals('Search "Teams"', $searchSchema->placeholder); + $this->assertEquals(new \stdClass, $searchSchema->filters); + + $request = new HTTPRequest( + 'POST', + 'field/testfield', + [], + [ + 'filter' => [ + 'testfield' => [ + 'Name' => 'test', + 'City' => 'place' + ] + ], + ] + ); + $this->gridField->setRequest($request); + $searchSchema = json_decode($this->component->getSearchFieldSchema($this->gridField)); + + $this->assertEquals('field/testfield/schema/SearchForm', $searchSchema->formSchemaUrl); + $this->assertEquals('Name', $searchSchema->name); + $this->assertEquals('Search "Teams"', $searchSchema->placeholder); + $this->assertEquals('test', $searchSchema->filters->Name); + $this->assertEquals('place', $searchSchema->filters->City); + $this->assertEquals('testfield', $searchSchema->gridfield); + } +} diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml b/tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml new file mode 100644 index 000000000..47eeeb765 --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml @@ -0,0 +1,76 @@ +SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat: + hat1: + Colour: Blue + hat2: + Colour: Red + hat3: + Colour: Green + hat4: + Colour: Pink +SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader: + cheerleader1: + Name: Heather + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat2 + cheerleader2: + Name: Bob + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat4 + cheerleader3: + Name: Jenny + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat1 + cheerleader4: + Name: Sam + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat3 + +SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom: + mom1: + Name: Ethel + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat2 + mom2: + Name: Eileene + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat4 + mom3: + Name: Gertrude + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat1 + mom4: + Name: Andrew + Hat: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat.hat3 + +SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Team: + team1: + Name: Team 1 + City: Cologne + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader3 + team2: + Name: Team 2 + City: Wellington + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader2 + team3: + Name: Team 3 + City: Auckland + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader4 + team4: + Name: Team 4 + City: Melbourne + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader1 + +SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\TeamGroup: + group1: + Name: Group 1 + City: Cologne + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader3 + CheerleadersMom: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom.mom3 + group2: + Name: Group 2 + City: Wellington + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader2 + CheerleadersMom: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom.mom2 + group3: + Name: Group 3 + City: Auckland + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader4 + CheerleadersMom: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom.mom4 + group4: + Name: Group 4 + City: Melbourne + Cheerleader: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader.cheerleader1 + CheerleadersMom: =>SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom.mom1 diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Cheerleader.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Cheerleader.php new file mode 100644 index 000000000..1a56979ce --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Cheerleader.php @@ -0,0 +1,21 @@ + 'Varchar' + ); + + private static $has_one = array( + 'Team' => Team::class, + 'Hat' => CheerleaderHat::class + ); +} diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest/CheerleaderHat.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/CheerleaderHat.php new file mode 100644 index 000000000..1fe95282e --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/CheerleaderHat.php @@ -0,0 +1,19 @@ + 'Varchar' + ); + + private static $has_one = array( + 'Cheerleader' => Cheerleader::class + ); +} diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php new file mode 100644 index 000000000..b5f7d6edc --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php @@ -0,0 +1,18 @@ + 'Int' + ); +} diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php new file mode 100644 index 000000000..24db304ff --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php @@ -0,0 +1,27 @@ + 'Name', + 'City.Initial' => 'City', + 'Cheerleader.Hat.Colour' => 'Cheerleader Hat' + ); + + private static $db = array( + 'Name' => 'Varchar', + 'City' => 'Varchar' + ); + + private static $has_one = array( + 'Cheerleader' => Cheerleader::class, + 'CheerleadersMom' => Mom::class + ); +} diff --git a/tests/php/Forms/GridField/GridFieldFilterHeaderTest/TeamGroup.php b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/TeamGroup.php new file mode 100644 index 000000000..eb01339af --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldFilterHeaderTest/TeamGroup.php @@ -0,0 +1,14 @@ + 'Varchar' + ); +} diff --git a/tests/php/Forms/GridField/GridFieldTest.php b/tests/php/Forms/GridField/GridFieldTest.php index be39f2fa2..ce68a429c 100644 --- a/tests/php/Forms/GridField/GridFieldTest.php +++ b/tests/php/Forms/GridField/GridFieldTest.php @@ -7,6 +7,7 @@ use SilverStripe\Dev\SapphireTest; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; use SilverStripe\Forms\GridField\GridField; +use SilverStripe\Forms\GridField\GridFieldButtonRow; use SilverStripe\Forms\GridField\GridFieldConfig; use SilverStripe\Forms\GridField\GridFieldConfig_Base; use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor; @@ -81,6 +82,7 @@ class GridFieldTest extends SapphireTest $expectedComponents = new ArrayList([ new GridFieldToolbarHeader(), + new GridFieldButtonRow(), $sort = new GridFieldSortableHeader(), $filter = new GridFieldFilterHeader(), new GridFieldDataColumns(),