mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ADD New search component for GridFields (#1777)
This commit is contained in:
parent
e4c1ceae59
commit
cc22024e9a
@ -83,6 +83,10 @@ en:
|
|||||||
Print: Print
|
Print: Print
|
||||||
RelationSearch: 'Relation search'
|
RelationSearch: 'Relation search'
|
||||||
ResetFilter: Reset
|
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:
|
SilverStripe\Forms\GridField\GridFieldDeleteAction:
|
||||||
Delete: Delete
|
Delete: Delete
|
||||||
DeletePermissionsFailure: 'No delete permissions'
|
DeletePermissionsFailure: 'No delete permissions'
|
||||||
|
@ -16,6 +16,7 @@ class GridFieldConfig_Base extends GridFieldConfig
|
|||||||
{
|
{
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->addComponent(new GridFieldToolbarHeader());
|
$this->addComponent(new GridFieldToolbarHeader());
|
||||||
|
$this->addComponent(new GridFieldButtonRow('before'));
|
||||||
$this->addComponent($sort = new GridFieldSortableHeader());
|
$this->addComponent($sort = new GridFieldSortableHeader());
|
||||||
$this->addComponent($filter = new GridFieldFilterHeader());
|
$this->addComponent($filter = new GridFieldFilterHeader());
|
||||||
$this->addComponent(new GridFieldDataColumns());
|
$this->addComponent(new GridFieldDataColumns());
|
||||||
|
@ -2,14 +2,22 @@
|
|||||||
|
|
||||||
namespace SilverStripe\Forms\GridField;
|
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\FieldGroup;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
|
use SilverStripe\Forms\Form;
|
||||||
|
use SilverStripe\Forms\Schema\FormSchema;
|
||||||
use SilverStripe\Forms\TextField;
|
use SilverStripe\Forms\TextField;
|
||||||
|
use SilverStripe\ORM\ArrayList;
|
||||||
use SilverStripe\ORM\Filterable;
|
use SilverStripe\ORM\Filterable;
|
||||||
use SilverStripe\ORM\SS_List;
|
use SilverStripe\ORM\SS_List;
|
||||||
use SilverStripe\ORM\ArrayList;
|
|
||||||
use SilverStripe\View\ArrayData;
|
use SilverStripe\View\ArrayData;
|
||||||
use SilverStripe\View\SSViewer;
|
use SilverStripe\View\SSViewer;
|
||||||
use LogicException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GridFieldFilterHeader alters the {@link GridField} with some filtering
|
* GridFieldFilterHeader alters the {@link GridField} with some filtering
|
||||||
@ -17,9 +25,8 @@ use LogicException;
|
|||||||
*
|
*
|
||||||
* @see GridField
|
* @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()}
|
* See {@link setThrowExceptionOnBadDataType()}
|
||||||
*
|
*
|
||||||
@ -27,6 +34,33 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
*/
|
*/
|
||||||
protected $throwExceptionOnBadDataType = true;
|
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}.
|
* 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
|
* @param GridField $gridField
|
||||||
* @return array
|
* @return array
|
||||||
@ -83,9 +118,15 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
return [];
|
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)
|
public function handleAction(GridField $gridField, $actionName, $arguments, $data)
|
||||||
{
|
{
|
||||||
if (!$this->checkDataType($gridField->getList())) {
|
if (!$this->checkDataType($gridField->getList())) {
|
||||||
@ -106,10 +147,7 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* @inheritDoc
|
||||||
* @param GridField $gridField
|
|
||||||
* @param SS_List $dataList
|
|
||||||
* @return SS_List
|
|
||||||
*/
|
*/
|
||||||
public function getManipulatedData(GridField $gridField, SS_List $dataList)
|
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
|
* @param GridField $gridField
|
||||||
* @return boolean
|
* @return boolean
|
||||||
*/
|
*/
|
||||||
public function canFilterAnyColumns($gridField)
|
public function canFilterAnyColumns(GridField $gridField)
|
||||||
{
|
{
|
||||||
$list = $gridField->getList();
|
$list = $gridField->getList();
|
||||||
|
|
||||||
@ -161,21 +199,133 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
return false;
|
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();
|
$list = $gridField->getList();
|
||||||
if (!$this->checkDataType($list)) {
|
if (!$this->checkDataType($list)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var Filterable $list */
|
|
||||||
$forTemplate = new ArrayData(array());
|
|
||||||
$forTemplate->Fields = new ArrayList();
|
|
||||||
|
|
||||||
$columns = $gridField->getColumns();
|
$columns = $gridField->getColumns();
|
||||||
$filterArguments = $gridField->State->GridFieldFilterHeader->Columns->toArray();
|
$filterArguments = $gridField->State->GridFieldFilterHeader->Columns->toArray();
|
||||||
$currentColumn = 0;
|
$currentColumn = 0;
|
||||||
$canFilter = false;
|
$canFilter = false;
|
||||||
|
$fieldsList = new ArrayList();
|
||||||
|
|
||||||
foreach ($columns as $columnField) {
|
foreach ($columns as $columnField) {
|
||||||
$currentColumn++;
|
$currentColumn++;
|
||||||
@ -225,16 +375,44 @@ class GridFieldFilterHeader implements GridField_HTMLProvider, GridField_DataMan
|
|||||||
$fields->addExtraClass('no-change-track');
|
$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;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$templates = SSViewer::get_templates_by_class($this, '_Row', __CLASS__);
|
if ($this->useLegacyFilterHeader) {
|
||||||
return array(
|
$fieldsList = $this->getLegacyFilterHeader($gridField);
|
||||||
'header' => $forTemplate->renderWith($templates),
|
$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(
|
||||||
|
'<button type="button" name="showFilter" aria-label="%s" title="%s"' .
|
||||||
|
' class="btn btn-secondary font-icon-search btn--no-text btn--icon-large grid-field__filter-open"></button>',
|
||||||
|
_t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter"),
|
||||||
|
_t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter")
|
||||||
|
)
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,10 +190,15 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
|
|||||||
if ($currentColumn == count($columns)) {
|
if ($currentColumn == count($columns)) {
|
||||||
$filter = $gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class);
|
$filter = $gridField->getConfig()->getComponentByType(GridFieldFilterHeader::class);
|
||||||
|
|
||||||
if ($filter && $filter->canFilterAnyColumns($gridField)) {
|
if ($filter && $filter->useLegacyFilterHeader && $filter->canFilterAnyColumns($gridField)) {
|
||||||
$field = new LiteralField(
|
$field = new LiteralField(
|
||||||
$fieldName,
|
$fieldName,
|
||||||
'<button type="button" name="showFilter" title="Open search and filter" class="btn btn-secondary font-icon-search btn--no-text btn--icon-large grid-field__filter-open"></button>'
|
sprintf(
|
||||||
|
'<button type="button" name="showFilter" aria-label="%s" title="%s"' .
|
||||||
|
' class="btn btn-secondary font-icon-search btn--no-text btn--icon-large grid-field__filter-open"></button>',
|
||||||
|
_t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter"),
|
||||||
|
_t('SilverStripe\\Forms\\GridField\\GridField.OpenFilter', "Open search and filter")
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$field = new LiteralField($fieldName, '<span class="non-sortable">' . $title . '</span>');
|
$field = new LiteralField($fieldName, '<span class="non-sortable">' . $title . '</span>');
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<% if $Fields %>
|
<% if $Fields %>
|
||||||
<tr class="grid-field__filter-header" style="display:none;">
|
<tr class="grid-field__filter-header grid-field__search-holder--hidden">
|
||||||
<% loop $Fields %>
|
<% loop $Fields %>
|
||||||
<th class="extra">$Field</th>
|
<th class="extra">$Field</th>
|
||||||
<% end_loop %>
|
<% end_loop %>
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
<div class="search-holder grid-field__search-holder grid-field__search-holder--hidden" data-schema="$SearchFieldSchema"></div>
|
@ -321,17 +321,17 @@ class CmsUiContext implements Context
|
|||||||
public function iExpandTheContentFilters($action)
|
public function iExpandTheContentFilters($action)
|
||||||
{
|
{
|
||||||
$page = $this->getSession()->getPage();
|
$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'));
|
assertNotNull($filterButton, sprintf('Filter button link not found'));
|
||||||
|
|
||||||
$filterButtonCssClass = $filterButton->getAttribute('class');
|
$filterButtonExpanded = $filterButton->getAttribute('aria-expanded');
|
||||||
|
|
||||||
if ($action === 'expand') {
|
if ($action === 'expand') {
|
||||||
if (strpos($filterButtonCssClass, 'active') === false) {
|
if ($filterButtonExpanded === false) {
|
||||||
$filterButton->click();
|
$filterButton->click();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (strpos($filterButtonCssClass, 'active') !== false) {
|
if ($filterButtonExpanded === true) {
|
||||||
$filterButton->click();
|
$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$/
|
* @When /^I (expand|collapse) "([^"]*)" in the tree$/
|
||||||
*/
|
*/
|
||||||
|
121
tests/php/Forms/GridField/GridFieldFilterHeaderTest.php
Normal file
121
tests/php/Forms/GridField/GridFieldFilterHeaderTest.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField;
|
||||||
|
|
||||||
|
use SilverStripe\Control\HTTPRequest;
|
||||||
|
use SilverStripe\Dev\SapphireTest;
|
||||||
|
use SilverStripe\Forms\FieldList;
|
||||||
|
use SilverStripe\Forms\Form;
|
||||||
|
use SilverStripe\Forms\GridField\GridField;
|
||||||
|
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
|
||||||
|
use SilverStripe\Forms\GridField\GridFieldFilterHeader;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Cheerleader;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\CheerleaderHat;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Mom;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\Team;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\TeamGroup;
|
||||||
|
use SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest\TestController;
|
||||||
|
use SilverStripe\ORM\DataList;
|
||||||
|
|
||||||
|
class GridFieldFilterHeaderTest extends SapphireTest
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var ArrayList
|
||||||
|
*/
|
||||||
|
protected $list;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var GridField
|
||||||
|
*/
|
||||||
|
protected $gridField;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var Form
|
||||||
|
*/
|
||||||
|
protected $form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var GridFieldFilterHeader
|
||||||
|
*/
|
||||||
|
protected $component;
|
||||||
|
|
||||||
|
protected static $fixture_file = 'GridFieldFilterHeaderTest.yml';
|
||||||
|
|
||||||
|
protected static $extra_dataobjects = array(
|
||||||
|
Team::class,
|
||||||
|
TeamGroup::class,
|
||||||
|
Cheerleader::class,
|
||||||
|
CheerleaderHat::class,
|
||||||
|
Mom::class,
|
||||||
|
);
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->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('<div class="search-holder grid-field__search-holder grid-field__search-holder--hidden"', $htmlFragment['before']);
|
||||||
|
$this->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(
|
||||||
|
'<tr class="grid-field__filter-header grid-field__search-holder--hidden">',
|
||||||
|
$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);
|
||||||
|
}
|
||||||
|
}
|
76
tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml
Normal file
76
tests/php/Forms/GridField/GridFieldFilterHeaderTest.yml
Normal file
@ -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
|
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Cheerleader extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
|
||||||
|
private static $table_name = 'GridFieldFilterHeaderTest_Cheerleader';
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'Name' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $has_one = array(
|
||||||
|
'Team' => Team::class,
|
||||||
|
'Hat' => CheerleaderHat::class
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class CheerleaderHat extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'GridFieldFilterHeaderTest_CheerleaderHat';
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'Colour' => 'Varchar'
|
||||||
|
);
|
||||||
|
|
||||||
|
private static $has_one = array(
|
||||||
|
'Cheerleader' => Cheerleader::class
|
||||||
|
);
|
||||||
|
}
|
18
tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php
Normal file
18
tests/php/Forms/GridField/GridFieldFilterHeaderTest/Mom.php
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should have access to same properties as cheerleader
|
||||||
|
*/
|
||||||
|
class Mom extends Cheerleader implements TestOnly
|
||||||
|
{
|
||||||
|
|
||||||
|
private static $table_name = 'GridFieldFilterHeaderTest_Mom';
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'NumberOfCookiesBaked' => 'Int'
|
||||||
|
);
|
||||||
|
}
|
27
tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php
Normal file
27
tests/php/Forms/GridField/GridFieldFilterHeaderTest/Team.php
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
use SilverStripe\ORM\DataObject;
|
||||||
|
|
||||||
|
class Team extends DataObject implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'GridFieldFilterHeaderTest_Team';
|
||||||
|
|
||||||
|
private static $summary_fields = array(
|
||||||
|
'Name' => '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
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace SilverStripe\Forms\Tests\GridField\GridFieldFilterHeaderTest;
|
||||||
|
|
||||||
|
use SilverStripe\Dev\TestOnly;
|
||||||
|
|
||||||
|
class TeamGroup extends Team implements TestOnly
|
||||||
|
{
|
||||||
|
private static $table_name = 'GridFieldFilterHeaderTest_TeamGroup';
|
||||||
|
|
||||||
|
private static $db = array(
|
||||||
|
'GroupName' => 'Varchar'
|
||||||
|
);
|
||||||
|
}
|
@ -7,6 +7,7 @@ use SilverStripe\Dev\SapphireTest;
|
|||||||
use SilverStripe\Forms\FieldList;
|
use SilverStripe\Forms\FieldList;
|
||||||
use SilverStripe\Forms\Form;
|
use SilverStripe\Forms\Form;
|
||||||
use SilverStripe\Forms\GridField\GridField;
|
use SilverStripe\Forms\GridField\GridField;
|
||||||
|
use SilverStripe\Forms\GridField\GridFieldButtonRow;
|
||||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||||
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
|
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
|
||||||
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
|
use SilverStripe\Forms\GridField\GridFieldConfig_RecordEditor;
|
||||||
@ -81,6 +82,7 @@ class GridFieldTest extends SapphireTest
|
|||||||
|
|
||||||
$expectedComponents = new ArrayList([
|
$expectedComponents = new ArrayList([
|
||||||
new GridFieldToolbarHeader(),
|
new GridFieldToolbarHeader(),
|
||||||
|
new GridFieldButtonRow(),
|
||||||
$sort = new GridFieldSortableHeader(),
|
$sort = new GridFieldSortableHeader(),
|
||||||
$filter = new GridFieldFilterHeader(),
|
$filter = new GridFieldFilterHeader(),
|
||||||
new GridFieldDataColumns(),
|
new GridFieldDataColumns(),
|
||||||
|
Loading…
Reference in New Issue
Block a user