Skip to content

Commit

Permalink
ENH UI updated for versioned objects and all its relations
Browse files Browse the repository at this point in the history
  • Loading branch information
sabina-talipova committed Dec 21, 2023
1 parent 6c69d32 commit f79ecfa
Show file tree
Hide file tree
Showing 10 changed files with 374 additions and 2 deletions.
2 changes: 1 addition & 1 deletion src/Forms/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -1483,7 +1483,7 @@ public function loadDataFrom($data, $mergeStrategy = 0, $fieldList = null)
* @param FieldList $fieldList An optional list of fields to process. This can be useful when you have a
* form that has some fields that save to one object, and some that save to another.
*/
public function saveInto(DataObjectInterface $dataObject, $fieldList = null)
public function saveInto(ViewableData|DataObjectInterface $dataObject, $fieldList = null)
{
$form = $this;
$dataObject->invokeWithExtensions('onBeforeFormSaveInto', $form, $fieldList);
Expand Down
4 changes: 4 additions & 0 deletions src/Forms/GridField/GridField.php
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,10 @@ public function setConfig(GridFieldConfig $config)
$this->config->addComponent(GridState_Component::create());
}

if (!$this->config->getComponentByType(GridFieldVersionTag::class)) {
$this->config->addComponent(GridFieldVersionTag::create());
}

return $this;
}

Expand Down
45 changes: 44 additions & 1 deletion src/Forms/GridField/GridFieldDetailForm_ItemRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
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;
Expand All @@ -19,6 +20,7 @@
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;
Expand All @@ -27,6 +29,7 @@
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;
Expand Down Expand Up @@ -417,7 +420,7 @@ protected function getFormActions()
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')
Expand Down Expand Up @@ -936,6 +939,25 @@ public function Breadcrumbs($unlinked = false)
}
}

$status = $this->getRecordStatus();
$badge = null;
if ($status) {
// Generate badge
$badge = DBField::create_field('HTMLFragment', sprintf(
'<span class="badge version-status version-status--%s">%s</span>',
$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;
}
Expand All @@ -947,4 +969,25 @@ private function getModelName(): string
}
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);
}
}
186 changes: 186 additions & 0 deletions src/Forms/GridField/GridFieldVersionTag.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
<?php

namespace SilverStripe\Forms\GridField;

use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridField_ColumnProvider;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Core\Convert;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Versioned\RecursiveStagesInterface;
use SilverStripe\View\HTML;

class GridFieldVersionTag extends AbstractGridFieldComponent implements GridField_ColumnProvider
{
/**
* @var string
*/
protected $column = null;

/**
* Fields/columns to display version states. We can specifies more than one
* field but states only show in the first column found.
*
* @array
*/
protected $versionedLabelFields = [];

public function __construct($versionedLabelFields = ['Name', 'Title'])
{
$this->setVersionedLabelFields($versionedLabelFields);
}

/**
* Column to decorate with version state
*
* @return string
*/
public function getColumn()
{
return $this->column;
}

/**
* @param string $column
* @return VersionedGridFieldState
*/
public function setColumn($column)
{
$this->column = $column;
return $this;
}

/**
* Search list for default column
*
* @return array
*/
public function getVersionedLabelFields()
{
return $this->versionedLabelFields;
}

/**
* @param array $versionedLabelFields
* @return VersionedGridFieldState
*/
public function setVersionedLabelFields($versionedLabelFields)
{
$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)
{
// 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)
{
return $this->getColumn() ? [$this->getColumn()] : [];
}

/**
* HTML for the column, content of the <td> element.
*
* @param GridField $gridField
* @param DataObject $record Record displayed in this row
* @param string $columnName
* @return string HTML for the column. Return NULL to skip.
*/
public function getColumnContent($gridField, $record, $columnName)
{
$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)
{
return [];
}

/**
* Metadata for the column
*/
public function getColumnMetadata($gridField, $columnName)
{
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);
}
}
39 changes: 39 additions & 0 deletions tests/php/Forms/GridField/GridFieldDetailForm_ItemRequestTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,37 @@

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());
Expand All @@ -31,4 +50,24 @@ public function testItemEditFormThrowsException()

$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));
}
}
Original file line number Diff line number Diff line change
@@ -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
3 changes: 3 additions & 0 deletions tests/php/Forms/GridField/GridFieldTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
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;
Expand Down Expand Up @@ -96,6 +97,7 @@ public function testGridFieldDefaultConfig()
new GridFieldPageCount('toolbar-header-right'),
$pagination = new GridFieldPaginator(),
new GridState_Component(),
new GridFieldVersionTag(),
]);
$sort->setThrowExceptionOnBadDataType(false);
$filter->setThrowExceptionOnBadDataType(false);
Expand All @@ -122,6 +124,7 @@ public function testGridFieldSetCustomConfig()
0 => new GridFieldSortableHeader,
1 => new GridFieldDataColumns,
2 => new GridState_Component,
3 => new GridFieldVersionTag,
]
);

Expand Down
4 changes: 4 additions & 0 deletions tests/php/Forms/GridField/GridFieldTest/Team.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class Team extends DataObject implements TestOnly
'Players' => Player::class
];

private static $owns = [
'Cheerleaders'
];

private static $has_many = [
'Cheerleaders' => Cheerleader::class
];
Expand Down

0 comments on commit f79ecfa

Please sign in to comment.