From c188ac72f30332e6239ce867248302c4ff546ad2 Mon Sep 17 00:00:00 2001 From: Sabina Talipova Date: Thu, 21 Dec 2023 08:56:02 +1300 Subject: [PATCH] ENH UI updated for versioned objects and all its relations --- src/Forms/GridField/GridField.php | 4 + .../GridFieldDetailForm_ItemRequest.php | 45 ++++- src/Forms/GridField/GridFieldVersionTag.php | 160 ++++++++++++++++++ .../GridFieldDetailForm_ItemRequestTest.php | 39 +++++ .../GridFieldDetailForm_ItemRequestTest.yml | 8 + tests/php/Forms/GridField/GridFieldTest.php | 3 + .../Forms/GridField/GridFieldTest/Team.php | 4 + .../GridField/GridFieldVersionTagTest.php | 77 +++++++++ .../GridField/GridFieldVersionTagTest.yml | 8 + 9 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 src/Forms/GridField/GridFieldVersionTag.php create mode 100644 tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.yml create mode 100644 tests/php/Forms/GridField/GridFieldVersionTagTest.php create mode 100644 tests/php/Forms/GridField/GridFieldVersionTagTest.yml diff --git a/src/Forms/GridField/GridField.php b/src/Forms/GridField/GridField.php index 2590aa758..9cbd42adb 100644 --- a/src/Forms/GridField/GridField.php +++ b/src/Forms/GridField/GridField.php @@ -319,6 +319,10 @@ class GridField extends FormField $this->config->addComponent(GridState_Component::create()); } + if (!$this->config->getComponentByType(GridFieldVersionTag::class)) { + $this->config->addComponent(GridFieldVersionTag::create()); + } + return $this; } diff --git a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php index 252b270bd..91d79433a 100644 --- a/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php +++ b/src/Forms/GridField/GridFieldDetailForm_ItemRequest.php @@ -10,6 +10,7 @@ use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\RequestHandler; use SilverStripe\Core\Convert; use SilverStripe\Core\ClassInfo; +use SilverStripe\Core\Injector\Injector; use SilverStripe\Forms\CompositeField; use SilverStripe\Forms\FieldList; use SilverStripe\Forms\Form; @@ -19,6 +20,7 @@ use SilverStripe\Forms\LiteralField; use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObjectInterface; +use SilverStripe\ORM\FieldType\DBField; use SilverStripe\ORM\FieldType\DBHTMLText; use SilverStripe\ORM\HasManyList; use SilverStripe\ORM\ManyManyList; @@ -27,6 +29,7 @@ use SilverStripe\ORM\RelationList; use SilverStripe\ORM\SS_List; use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\ValidationResult; +use SilverStripe\Versioned\RecursiveStagesInterface; use SilverStripe\View\ArrayData; use SilverStripe\View\HTML; use SilverStripe\View\SSViewer; @@ -417,7 +420,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler throw new LogicException(get_class($this->record) . ' must implement ' . DataObjectInterface::class); } - $noChangesClasses = 'btn-outline-primary font-icon-tick'; + $noChangesClasses = $this->stagesDifferRecursive() ? 'btn-primary font-icon-save' : 'btn-outline-primary font-icon-tick'; $majorActions->push(FormAction::create('doSave', _t('SilverStripe\\Forms\\GridField\\GridFieldDetailForm.Save', 'Save')) ->addExtraClass($noChangesClasses) ->setAttribute('data-btn-alternate-add', 'btn-primary font-icon-save') @@ -936,6 +939,25 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler } } + $status = $this->getRecordStatus(); + $badge = null; + if ($status) { + // Generate badge + $badge = DBField::create_field('HTMLFragment', sprintf( + '%s', + $status['class'], + $status['title'] + )); + } + + $this->extend('updateBadge', $badge); + + if ($badge) { + /** @var ArrayData $lastItem */ + $lastItem = $items->last(); + $lastItem->setField('Extra', $badge); + } + $this->extend('updateBreadcrumbs', $items); return $items; } @@ -947,4 +969,25 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler } return ClassInfo::shortName($this->record); } + + private function getRecordStatus(): ?array + { + if ($this->stagesDifferRecursive()) { + return [ + 'class' => 'modified', + 'title' => _t(__CLASS__ . '.MODIFIED', 'Modified') + ]; + } + + return null; + } + + + private function stagesDifferRecursive(): bool + { + /** @var RecursiveStagesInterface $service */ + $service = Injector::inst()->get(RecursiveStagesInterface::class); + + return $service->stagesDifferRecursive($this->record); + } } diff --git a/src/Forms/GridField/GridFieldVersionTag.php b/src/Forms/GridField/GridFieldVersionTag.php new file mode 100644 index 000000000..3381f5ea8 --- /dev/null +++ b/src/Forms/GridField/GridFieldVersionTag.php @@ -0,0 +1,160 @@ +setVersionedLabelFields($versionedLabelFields); + } + + public function getColumn(): ?string + { + return $this->column; + } + + public function setColumn(string $column): static + { + $this->column = $column; + return $this; + } + + public function getVersionedLabelFields(): array + { + return $this->versionedLabelFields; + } + + public function setVersionedLabelFields(array $versionedLabelFields): static + { + $this->versionedLabelFields = $versionedLabelFields; + return $this; + } + + /** + * Modify the list of columns displayed in the table. + * + * @see {@link GridFieldDataColumns->getDisplayFields()} + * @see {@link GridFieldDataColumns}. + * + * @param GridField $gridField + * @param array $columns List reference of all column names. + */ + public function augmentColumns($gridField, &$columns): void + { + // Skip if not versioned, or column already set + if ($this->getColumn()) { + return; + } + + $matchedVersionedFields = array_intersect( + $columns ?? [], + $this->versionedLabelFields + ); + + if (count($matchedVersionedFields ?? []) > 0) { + // Get first matched column + $this->setColumn(reset($matchedVersionedFields)); + } elseif ($columns) { + // Use first column if none of preferred matches + $this->setColumn(reset($columns)); + } + } + + /** + * Names of all columns which are affected by this component. + * + * @param GridField $gridField + * @return array + */ + public function getColumnsHandled($gridField): array + { + return $this->getColumn() ? [$this->getColumn()] : []; + } + + /** + * HTML for the column, content of the element. + * + * @param GridField $gridField + * @param DataObject $record Record displayed in this row + * @param string $columnName + * @return string HTML for the column. + */ + public function getColumnContent($gridField, $record, $columnName): string + { + $flagContent = ''; + $flags = $this->getStatusFlags($record); + foreach ($flags as $class => $data) { + $flagAttributes = [ + 'class' => "ss-gridfield-badge badge status-{$class}", + ]; + if (isset($data['title'])) { + $flagAttributes['title'] = $data['title']; + } + $flagContent .= ' ' . HTML::createTag('span', $flagAttributes, Convert::raw2xml($data['text'])); + } + return $flagContent; + } + + /** + * Attributes for the column + */ + public function getColumnAttributes($gridField, $record, $columnName): array + { + return []; + } + + /** + * Metadata for the column + */ + public function getColumnMetadata($gridField, $columnName): array + { + return []; + } + + /** + * Get status flags for a given record + */ + private function getStatusFlags(DataObject $record): array + { + if ($record->hasExtension(Versioned::class)) { + return []; + } + + if ($this->stagesDifferRecursive($record)) { + return [ + 'modified' => [ + 'text' => _t(__CLASS__ . '.MODIFIEDONDRAFTSHORT', 'Modified'), + 'title' => _t(__CLASS__ . '.MODIFIEDONDRAFTHELP', 'Item has unpublished changes'), + ] + ]; + } + + return []; + } + + /** + * Check if stages differ for a given record and all its relations + */ + private function stagesDifferRecursive(DataObject $record): bool + { + /** @var RecursiveStagesInterface $service */ + $service = Injector::inst()->get(RecursiveStagesInterface::class); + + return $service->stagesDifferRecursive($record); + } +} diff --git a/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.php b/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.php index 0a13a0749..f45a96aeb 100644 --- a/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.php +++ b/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.php @@ -4,18 +4,37 @@ namespace SilverStripe\Forms\Tests\GridField; use LogicException; use SilverStripe\Control\Controller; +use SilverStripe\Admin\LeftAndMain; use SilverStripe\Dev\SapphireTest; +use SilverStripe\Forms\FieldList; +use SilverStripe\Forms\Form; use SilverStripe\Forms\GridField\GridField; use SilverStripe\Forms\GridField\GridFieldConfig_Base; use SilverStripe\Forms\GridField\GridFieldDetailForm; use SilverStripe\Forms\GridField\GridFieldDetailForm_ItemRequest; +use SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader; +use SilverStripe\Forms\Tests\GridField\GridFieldTest\Team; use SilverStripe\ORM\ArrayList; use SilverStripe\View\ArrayData; +use SilverStripe\Versioned\Versioned; class GridFieldDetailForm_ItemRequestTest extends SapphireTest { protected $usesDatabase = false; + protected static $fixture_file = 'GridFieldDetailForm_ItemRequestTest.yml'; + + protected static $extra_dataobjects = [ + Cheerleader::class, + Team::class, + ]; + + protected static $required_extensions = [ + Cheerleader::class => [ + Versioned::class, + ], + ]; + public function testItemEditFormThrowsException() { $gridField = new GridField('dummy', 'dummy', new ArrayList(), new GridFieldConfig_Base()); @@ -31,4 +50,24 @@ class GridFieldDetailForm_ItemRequestTest extends SapphireTest $itemRequest->ItemEditForm(); } + + public function testBreadcrumbs() + { + $team = Team::get(); + $cheerleader = Cheerleader::get()->first(); + $form = new Form(null, 'Form', new FieldList(), new FieldList()); + $gridField = new GridField('TestGridField', 'TestGridFields', $team); + $gridField->setForm($form); + + $itemRequest = new GridFieldDetailForm_ItemRequest( + $gridField, + new GridFieldDetailForm(), + $team->first(), + new LeftandMain(), + '', + ); + + $item = $itemRequest->Breadcrumbs()->last()->toMap(); + $this->assertTrue(array_key_exists('Extra', $item)); + } } diff --git a/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.yml b/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.yml new file mode 100644 index 000000000..8899cf2af --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.yml @@ -0,0 +1,8 @@ +SilverStripe\Forms\Tests\GridField\GridFieldTest\Team: + team1: + Name: Team 1 + City: Cologne +SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader: + cheerleader1_team1: + Name: Heather + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1 diff --git a/tests/php/Forms/GridField/GridFieldTest.php b/tests/php/Forms/GridField/GridFieldTest.php index 642460aa5..521c48fb9 100644 --- a/tests/php/Forms/GridField/GridFieldTest.php +++ b/tests/php/Forms/GridField/GridFieldTest.php @@ -24,6 +24,7 @@ use SilverStripe\Forms\GridField\GridFieldToolbarHeader; use SilverStripe\Forms\GridField\GridState; use SilverStripe\Forms\GridField\GridState_Component; use SilverStripe\Forms\GridField\GridState_Data; +use SilverStripe\Forms\GridField\GridFieldVersionTag; use SilverStripe\Forms\RequiredFields; use SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader; use SilverStripe\Forms\Tests\GridField\GridFieldTest\Component; @@ -96,6 +97,7 @@ class GridFieldTest extends SapphireTest new GridFieldPageCount('toolbar-header-right'), $pagination = new GridFieldPaginator(), new GridState_Component(), + new GridFieldVersionTag(), ]); $sort->setThrowExceptionOnBadDataType(false); $filter->setThrowExceptionOnBadDataType(false); @@ -122,6 +124,7 @@ class GridFieldTest extends SapphireTest 0 => new GridFieldSortableHeader, 1 => new GridFieldDataColumns, 2 => new GridState_Component, + 3 => new GridFieldVersionTag, ] ); diff --git a/tests/php/Forms/GridField/GridFieldTest/Team.php b/tests/php/Forms/GridField/GridFieldTest/Team.php index 42e296653..b4e24d998 100644 --- a/tests/php/Forms/GridField/GridFieldTest/Team.php +++ b/tests/php/Forms/GridField/GridFieldTest/Team.php @@ -18,6 +18,10 @@ class Team extends DataObject implements TestOnly 'Players' => Player::class ]; + private static $owns = [ + 'Cheerleaders' + ]; + private static $has_many = [ 'Cheerleaders' => Cheerleader::class ]; diff --git a/tests/php/Forms/GridField/GridFieldVersionTagTest.php b/tests/php/Forms/GridField/GridFieldVersionTagTest.php new file mode 100644 index 000000000..a2d23b3a3 --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldVersionTagTest.php @@ -0,0 +1,77 @@ + [ + Versioned::class, + ], + ]; + + public function testGetColumnContent() + { + $team = Team::get(); + $cheerleader = Cheerleader::get()->first(); + $gridField = new GridField('TestGridField', 'TestGridFields', $team); + + $columns = $gridField->getConfig()->getComponentByType(GridFieldVersionTag::class); + $nameColumn = $columns->getColumnContent($gridField, $team->first(), 'Name'); + $this->assertEquals( + $nameColumn, + ' Modified' + ); + + $cheerleader->publishRecursive(); + $nameColumn = $columns->getColumnContent($gridField, $team->first(), 'Name'); + + $this->assertEquals($nameColumn, ''); + } + + public function testAugmentColumns() + { + $team = Team::get(); + $cheerleader = Cheerleader::get()->first(); + $gridField = new GridField('TestGridField', 'TestGridFields', $team); + + $columns = $gridField->getConfig()->getComponentByType(GridFieldVersionTag::class); + + $columns->setVersionedLabelFields(['Title']); + $column = $columns->getVersionedLabelFields(); + + $this->assertEquals($column, ['Title']); + + $augmentColumns = ['Name', 'Title', 'ID']; + + $columns->augmentColumns($gridField, $augmentColumns); + $nameColumn = $columns->getColumn(); + + $this->assertEquals($nameColumn, 'Title'); + + $columns->setVersionedLabelFields(['Non-Title']); + $column = $columns->getVersionedLabelFields(); + + $this->assertEquals($column, ['Non-Title']); + + $columns->augmentColumns($gridField, $augmentColumns); + $nameColumn = $columns->getColumn(); + + $this->assertNotEquals($nameColumn, 'Non-Title'); + $this->assertEquals($nameColumn, 'Title'); + } +} diff --git a/tests/php/Forms/GridField/GridFieldVersionTagTest.yml b/tests/php/Forms/GridField/GridFieldVersionTagTest.yml new file mode 100644 index 000000000..8899cf2af --- /dev/null +++ b/tests/php/Forms/GridField/GridFieldVersionTagTest.yml @@ -0,0 +1,8 @@ +SilverStripe\Forms\Tests\GridField\GridFieldTest\Team: + team1: + Name: Team 1 + City: Cologne +SilverStripe\Forms\Tests\GridField\GridFieldTest\Cheerleader: + cheerleader1_team1: + Name: Heather + Team: =>SilverStripe\Forms\Tests\GridField\GridFieldTest\Team.team1