Merge branch 'feature/configurable-datalist-field'

This commit is contained in:
Thomas Gelf 2019-05-06 21:30:03 +02:00
commit e148d2523b
5 changed files with 169 additions and 21 deletions

View File

@ -258,6 +258,22 @@ class SuggestController extends ActionController
]); ]);
} }
protected function suggestDataListValuesForListId($id)
{
$db = $this->db()->getDbAdapter();
$select = $db->select()
->from('director_datalist_entry', ['entry_name', 'entry_value'])
->where('list_id = ?', $id)
->order('entry_value ASC');
$result = $db->fetchPairs($select);
if ($result) {
return $result;
} else {
return [];
}
}
protected function suggestDataListValues($field = null) protected function suggestDataListValues($field = null)
{ {
if ($field === null) { if ($field === null) {

View File

@ -20,6 +20,7 @@ before switching to a new version.
* FIX: Auto-suggestion field was positioned wrongly once scrolled down * FIX: Auto-suggestion field was positioned wrongly once scrolled down
* FEATURE: It's now possible to clone a Service to a different Host (#1796) * FEATURE: It's now possible to clone a Service to a different Host (#1796)
* FEATURE: Scheduled Downtimes for "Hosts AND their services" (#1831) * FEATURE: Scheduled Downtimes for "Hosts AND their services" (#1831)
* FEATURE: auto-suggestion and more for Fields based on Data Lists (#1846)
### Import and Sync ### Import and Sync
* FIX: Avoid caching between multiple runs of sync (#1836) * FIX: Avoid caching between multiple runs of sync (#1836)

View File

@ -3,28 +3,87 @@
namespace Icinga\Module\Director\DataType; namespace Icinga\Module\Director\DataType;
use Icinga\Module\Director\Acl; use Icinga\Module\Director\Acl;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Hook\DataTypeHook; use Icinga\Module\Director\Hook\DataTypeHook;
use Icinga\Module\Director\Objects\DirectorDatalistEntry;
use Icinga\Module\Director\Web\Form\DirectorForm;
use Icinga\Module\Director\Web\Form\QuickForm; use Icinga\Module\Director\Web\Form\QuickForm;
use Icinga\Module\Director\Web\Form\DirectorObjectForm; use Icinga\Module\Director\Web\Form\DirectorObjectForm;
use Icinga\Module\Director\Web\Form\Validate\IsDataListEntry;
class DataTypeDatalist extends DataTypeHook class DataTypeDatalist extends DataTypeHook
{ {
/**
* @param $name
* @param QuickForm $form
* @return \Zend_Form_Element
* @throws \Zend_Form_Exception
*/
public function getFormElement($name, QuickForm $form) public function getFormElement($name, QuickForm $form)
{ {
$enum = $this->getEntries($form);
$params = []; $params = [];
if ($this->getSetting('data_type') === 'array') { $behavior = $this->getSetting('behavior', 'strict');
$type = 'extensibleSet'; $targetDataType = $this->getSetting('data_type');
$params['sorted'] = true; $listId = $this->getSetting('datalist_id');
$params = ['multiOptions' => $enum];
if ($behavior === 'strict') {
$enum = $this->getEntries($form);
if ($targetDataType === 'string') {
$params['sorted'] = true;
$params = ['multiOptions' => $enum];
$type = 'select';
} else {
$params = ['multiOptions' => $form->optionalEnum($enum)];
$type = 'extensibleSet';
}
} else { } else {
$params = ['multiOptions' => [ if ($targetDataType === 'string') {
null => $form->translate('- please choose -'), $type = 'text';
] + $enum]; } else {
$type = 'select'; $type = 'extensibleSet';
}
$params['class'] = 'director-suggest';
$params['data-suggestion-context'] = "dataListValuesForListId!$listId";
}
$element = $form->createElement($type, $name, $params);
if ($behavior === 'suggest_strict') {
$element->addValidator(new IsDataListEntry($listId, $form->getDb()));
} }
return $form->createElement($type, $name, $params); if ($behavior === 'suggest_extend') {
$form->callOnSucess(function (DirectorForm $form) use ($name, $listId) {
$value = (array) $form->getValue($name);
if ($value === null) {
return;
}
$db = $form->getDb();
foreach ($value as $entry) {
$this->createEntryIfNotExists($db, $listId, $entry);
}
});
}
return $element;
}
/**
* @param Db $db
* @param $listId
* @param $entry
*/
protected function createEntryIfNotExists(Db $db, $listId, $entry)
{
if (! DirectorDatalistEntry::exists([
'list_id' => $listId,
'entry_name' => $entry,
], $db)) {
DirectorDatalistEntry::create([
'list_id' => $listId,
'entry_name' => $entry,
'entry_value' => $entry,
])->store($db);
}
} }
protected function getEntries(QuickForm $form) protected function getEntries(QuickForm $form)
@ -34,7 +93,7 @@ class DataTypeDatalist extends DataTypeHook
$roles = array_map('json_encode', Acl::instance()->listRoleNames()); $roles = array_map('json_encode', Acl::instance()->listRoleNames());
$select = $db->select() $select = $db->select()
->from('director_datalist_entry', array('entry_name', 'entry_value')) ->from('director_datalist_entry', ['entry_name', 'entry_value'])
->where('list_id = ?', $this->getSetting('datalist_id')) ->where('list_id = ?', $this->getSetting('datalist_id'))
->order('entry_value ASC'); ->order('entry_value ASC');
@ -47,17 +106,20 @@ class DataTypeDatalist extends DataTypeHook
return $db->fetchPairs($select); return $db->fetchPairs($select);
} }
/**
* @param QuickForm $form
* @throws \Zend_Form_Exception
*/
public static function addSettingsFormFields(QuickForm $form) public static function addSettingsFormFields(QuickForm $form)
{ {
/** @var DirectorObjectForm $form */ /** @var DirectorObjectForm $form */
$db = $form->getDb(); $db = $form->getDb();
$form->addElement('select', 'datalist_id', array( $form->addElement('select', 'datalist_id', [
'label' => 'List name', 'label' => 'List name',
'required' => true, 'required' => true,
'multiOptions' => array(null => '- please choose -') + 'multiOptions' => $form->optionalEnum($db->enumDatalist()),
$db->enumDatalist(), ]);
));
$form->addElement('select', 'data_type', [ $form->addElement('select', 'data_type', [
'label' => $form->translate('Target data type'), 'label' => $form->translate('Target data type'),
@ -68,6 +130,20 @@ class DataTypeDatalist extends DataTypeHook
'required' => true, 'required' => true,
]); ]);
return $form; $form->addElement('select', 'behavior', [
'label' => $form->translate('Element behavior'),
'value' => 'strict',
'description' => $form->translate(
'This allows to show either a drop-down list or an auto-completion'
),
'multiOptions' => [
'strict' => $form->translate('Dropdown (list values only)'),
$form->translate('Autocomplete') => [
'suggest_strict' => $form->translate('Strict, list values only'),
'suggest_optional' => $form->translate('Allow for values not on the list'),
'suggest_extend' => $form->translate('Extend the list with new values'),
]
]
]);
} }
} }

View File

@ -2,7 +2,7 @@
namespace Icinga\Module\Director\Web\Form\Element; namespace Icinga\Module\Director\Web\Form\Element;
use Icinga\Exception\ProgrammingError; use InvalidArgumentException;
/** /**
* Input control for extensible sets * Input control for extensible sets
@ -21,12 +21,12 @@ class ExtensibleSet extends FormElement
{ {
$value = parent::getValue(); $value = parent::getValue();
if (is_string($value)) { if (is_string($value)) {
$value = array($value); $value = [$value];
} elseif ($value === null) { } elseif ($value === null) {
return $value; return $value;
} }
if (! is_array($value)) { if (! is_array($value)) {
throw new ProgrammingError( throw new InvalidArgumentException(
'ExtensibleSet expects to work with Arrays, got %s', 'ExtensibleSet expects to work with Arrays, got %s',
var_export($value, 1) var_export($value, 1)
); );
@ -69,7 +69,7 @@ class ExtensibleSet extends FormElement
public function isValid($value, $context = null) public function isValid($value, $context = null)
{ {
if ($value === null) { if ($value === null) {
$value = array(); $value = [];
} }
$value = array_filter($value, 'strlen'); $value = array_filter($value, 'strlen');
@ -84,6 +84,6 @@ class ExtensibleSet extends FormElement
return false; return false;
} }
return true; return parent::isValid($value, $context);
} }
} }

View File

@ -0,0 +1,55 @@
<?php
namespace Icinga\Module\Director\Web\Form\Validate;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Objects\DirectorDatalistEntry;
use Zend_Validate_Abstract;
class IsDataListEntry extends Zend_Validate_Abstract
{
const INVALID = 'intInvalid';
/** @var Db */
private $db;
/** @var int */
private $dataListId;
public function __construct($dataListId, Db $db)
{
$this->db = $db;
$this->dataListId = (int) $dataListId;
}
public function isValid($value)
{
if (is_array($value)) {
foreach ($value as $name) {
if (! $this->isListEntry($name)) {
$this->_error(self::INVALID, $value);
return false;
}
}
return true;
}
if ($this->isListEntry($value)) {
return true;
} else {
$this->_error(self::INVALID, $value);
return false;
}
}
protected function isListEntry($name)
{
return DirectorDatalistEntry::exists([
'list_id' => $this->dataListId,
'entry_name' => $name,
], $this->db);
}
}