Merge branch 'feature-metafield-dropdown' into develop-unstable
commit
410c27aa35
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
use Migrations\AbstractMigration;
|
||||
use Phinx\Db\Adapter\MysqlAdapter;
|
||||
|
||||
|
||||
class MetaFieldSaneDefault extends AbstractMigration
|
||||
{
|
||||
|
||||
public $autoId = false; // turn off automatic `id` column create. We want it to be `int(10) unsigned`
|
||||
|
||||
|
||||
public function change()
|
||||
{
|
||||
$exists = $this->table('meta_template_fields')->hasColumn('sane_default');
|
||||
if (!$exists) {
|
||||
$this->table('meta_template_fields')
|
||||
->addColumn('sane_default', 'text', [
|
||||
'default' => null,
|
||||
'null' => true,
|
||||
'limit' => MysqlAdapter::TEXT_LONG,
|
||||
'comment' => 'List of sane default values to be proposed',
|
||||
])
|
||||
->addColumn('values_list', 'text', [
|
||||
'default' => null,
|
||||
'null' => true,
|
||||
'limit' => MysqlAdapter::TEXT_LONG,
|
||||
'comment' => 'List of values that have to be used',
|
||||
])
|
||||
->update();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -179,6 +179,7 @@ class IncomingConnectionRequestProcessor extends LocalToolInboxProcessor impleme
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->description = __('Handle Phase I of inter-connection when another cerebrate instance performs the request.');
|
||||
}
|
||||
|
||||
|
@ -291,6 +292,7 @@ class AcceptedRequestProcessor extends LocalToolInboxProcessor implements Generi
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->description = __('Handle Phase II of inter-connection when initial request has been accepted by the remote cerebrate.');
|
||||
}
|
||||
|
||||
|
@ -367,6 +369,7 @@ class DeclinedRequestProcessor extends LocalToolInboxProcessor implements Generi
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->description = __('Handle Phase II of MISP inter-connection when initial request has been declined by the remote cerebrate.');
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ class DataExchangeProcessor extends SynchronisationInboxProcessor implements Gen
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->description = __('Handle exchange of data between two cerebrate instances');
|
||||
$this->Users = TableRegistry::getTableLocator()->get('Users');
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ class RegistrationProcessor extends UserInboxProcessor implements GenericInboxPr
|
|||
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->description = __('Handle user account for this cerebrate instance');
|
||||
}
|
||||
|
||||
|
|
|
@ -70,6 +70,7 @@ class ResendFailedMessageProcessor extends BroodsOutboxProcessor implements Gene
|
|||
public function __construct() {
|
||||
parent::__construct();
|
||||
$this->description = __('Handle re-sending messages that failed to be received from other cerebrate instances.');
|
||||
$this->severity = $this->Inbox::SEVERITY_WARNING;
|
||||
$this->Broods = TableRegistry::getTableLocator()->get('Broods');
|
||||
$this->LocalTools = \Cake\ORM\TableRegistry::getTableLocator()->get('LocalTools');
|
||||
}
|
||||
|
|
|
@ -20,9 +20,14 @@ class GenericOutboxProcessor
|
|||
protected $validator;
|
||||
protected $processingTemplate = '/genericTemplates/confirm';
|
||||
protected $processingTemplatesDirectory = ROOT . '/libraries/default/OutboxProcessors/templates';
|
||||
protected $defaultSeverity;
|
||||
protected $severity;
|
||||
|
||||
|
||||
public function __construct($registerActions=false) {
|
||||
$this->Outbox = TableRegistry::getTableLocator()->get('Outbox');
|
||||
$this->Inbox = TableRegistry::getTableLocator()->get('Inbox');
|
||||
$this->defaultSeverity = $this->Inbox::SEVERITY_INFO;
|
||||
if ($registerActions) {
|
||||
$this->registerActionInProcessor();
|
||||
}
|
||||
|
@ -55,6 +60,10 @@ class GenericOutboxProcessor
|
|||
{
|
||||
return $this->description ?? '';
|
||||
}
|
||||
public function getSeverity()
|
||||
{
|
||||
return $this->severity ?? $this->defaultSeverity;
|
||||
}
|
||||
|
||||
protected function getProcessingTemplatePath()
|
||||
{
|
||||
|
@ -77,8 +86,9 @@ class GenericOutboxProcessor
|
|||
$builder = new ViewBuilder();
|
||||
$builder->disableAutoLayout()
|
||||
->setClassName('Monad')
|
||||
->setTemplate($processingTemplate);
|
||||
$view = $builder->build($viewVariables);
|
||||
->setTemplate($processingTemplate)
|
||||
->setVars($viewVariables);
|
||||
$view = $builder->build();
|
||||
$view->setRequest($serverRequest);
|
||||
return $view->render();
|
||||
}
|
||||
|
@ -193,6 +203,7 @@ class GenericOutboxProcessor
|
|||
$user_id = Router::getRequest()->getSession()->read('Auth.id');
|
||||
$requestData['scope'] = $this->scope;
|
||||
$requestData['action'] = $this->action;
|
||||
$requestData['severity'] = $this->getSeverity();
|
||||
$requestData['user_id'] = $user_id;
|
||||
$request = $this->generateRequest($requestData);
|
||||
$savedRequest = $this->Outbox->createEntry($request);
|
||||
|
|
|
@ -8,11 +8,10 @@ use Cake\ORM\TableRegistry;
|
|||
use \Cake\Database\Expression\QueryExpression;
|
||||
use Cake\Http\Exception\UnauthorizedException;
|
||||
use Cake\Core\Configure;
|
||||
use PhpParser\Node\Stmt\Echo_;
|
||||
|
||||
class AuditLogsController extends AppController
|
||||
{
|
||||
public $filterFields = ['model_id', 'model', 'request_action', 'user_id', 'model_title'];
|
||||
public $filterFields = ['model_id', 'model', 'request_action', 'user_id', 'model_title', 'AuditLogs.created'];
|
||||
public $quickFilterFields = ['model', 'request_action', 'model_title'];
|
||||
public $containFields = ['Users'];
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ class CRUDComponent extends Component
|
|||
if ($this->metaFieldsSupported()) {
|
||||
$query = $this->includeRequestedMetaFields($query);
|
||||
}
|
||||
$query = $this->setRequestedEntryAmount($query);
|
||||
$this->setRequestedEntryAmount();
|
||||
$data = $this->Controller->paginate($query, $this->Controller->paginate ?? []);
|
||||
if (isset($options['afterFind'])) {
|
||||
$function = $options['afterFind'];
|
||||
|
|
|
@ -16,7 +16,7 @@ use Cake\Http\Exception\ForbiddenException;
|
|||
|
||||
class InboxController extends AppController
|
||||
{
|
||||
public $filterFields = ['scope', 'action', 'Inbox.created', 'title', 'origin', 'message', 'Users.id', 'Users.username',];
|
||||
public $filterFields = ['scope', 'action', 'Inbox.created', 'severity', 'title', 'origin', 'message', 'Users.id', 'Users.username',];
|
||||
public $quickFilterFields = ['scope', 'action', ['title' => true], ['message' => true], 'origin'];
|
||||
public $containFields = ['Users'];
|
||||
|
||||
|
@ -43,9 +43,94 @@ class InboxController extends AppController
|
|||
[
|
||||
'default' => true,
|
||||
'label' => __('My Notifications'),
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where(function(QueryExpression $exp) {
|
||||
return $exp->or(['user_id' => $this->ACL->getUser()['id']])
|
||||
->isNull('user_id');
|
||||
});
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => __('User Registration'),
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'user_id' => $this->ACL->getUser()['id'],
|
||||
'scope' => 'User',
|
||||
'action' => 'Registration',
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => __('Inter-connection Requests'),
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'scope' => 'LocalTool',
|
||||
'action IN' => ['IncomingConnectionRequest', 'AcceptedRequest', 'DeclinedRequest'],
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => __('Data changed'),
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'user_id' => $this->ACL->getUser()['id'], // Each admin get a message about data changes
|
||||
'scope' => 'Notification',
|
||||
'action' => 'DataChange',
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => 'severity:primary',
|
||||
'viewElement' => 'bootstrapUI',
|
||||
'viewElementParams' => [
|
||||
'element' => 'badge',
|
||||
'text' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_PRIMARY],
|
||||
'variant' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_PRIMARY],
|
||||
],
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'severity' => $this->Inbox::SEVERITY_PRIMARY,
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => 'severity:info',
|
||||
'viewElement' => 'bootstrapUI',
|
||||
'viewElementParams' => [
|
||||
'element' => 'badge',
|
||||
'text' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_INFO],
|
||||
'variant' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_INFO],
|
||||
],
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'severity' => $this->Inbox::SEVERITY_INFO,
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => 'severity:warning',
|
||||
'viewElement' => 'bootstrapUI',
|
||||
'viewElementParams' => [
|
||||
'element' => 'badge',
|
||||
'text' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_WARNING],
|
||||
'variant' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_WARNING],
|
||||
],
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'severity' => $this->Inbox::SEVERITY_WARNING,
|
||||
]);
|
||||
}
|
||||
],
|
||||
[
|
||||
'label' => 'severity:danger',
|
||||
'viewElement' => 'bootstrapUI',
|
||||
'viewElementParams' => [
|
||||
'element' => 'badge',
|
||||
'text' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_DANGER],
|
||||
'variant' => $this->Inbox->severityVariant[$this->Inbox::SEVERITY_DANGER],
|
||||
],
|
||||
'filterConditionFunction' => function ($query) {
|
||||
return $query->where([
|
||||
'severity' => $this->Inbox::SEVERITY_DANGER,
|
||||
]);
|
||||
}
|
||||
],
|
||||
|
|
|
@ -7,5 +7,32 @@ use Cake\ORM\Entity;
|
|||
|
||||
class MetaTemplateField extends AppModel
|
||||
{
|
||||
protected $_virtual = ['form_type', 'form_options', ];
|
||||
|
||||
protected function _getFormType()
|
||||
{
|
||||
$formType = 'text';
|
||||
if (!empty($this->sane_default) || !empty($this->values_list)) {
|
||||
$formType = 'dropdown';
|
||||
} else if ($this->type === 'boolean') {
|
||||
$formType = 'checkbox';
|
||||
}
|
||||
return $formType;
|
||||
}
|
||||
|
||||
protected function _getFormOptions()
|
||||
{
|
||||
$formOptions = [];
|
||||
if ($this->formType === 'dropdown') {
|
||||
$selectOptions = !empty($this->sane_default) ? $this->sane_default : $this->values_list;
|
||||
$selectOptions = array_combine($selectOptions, $selectOptions);
|
||||
if (!empty($this->sane_default)) {
|
||||
$selectOptions[] = ['value' => '_custom', 'text' => __('-- custom value --'), 'class' => 'custom-value'];
|
||||
}
|
||||
$selectOptions[''] = __('-- no value --');
|
||||
$formOptions['options'] = $selectOptions;
|
||||
}
|
||||
return $formOptions;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ class MetaTemplateFieldsTable extends AppTable
|
|||
$this->hasMany('MetaFields');
|
||||
|
||||
$this->setDisplayField('field');
|
||||
$this->getSchema()->setColumnType('sane_default', 'json');
|
||||
$this->getSchema()->setColumnType('values_list', 'json');
|
||||
$this->loadTypeHandlers();
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,12 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
'sort' => 'request_ip',
|
||||
'data_path' => 'request_ip',
|
||||
],
|
||||
[
|
||||
'name' => 'created',
|
||||
'sort' => 'created',
|
||||
'data_path' => 'created',
|
||||
'element' => 'datetime'
|
||||
],
|
||||
[
|
||||
'name' => __('Username'),
|
||||
'sort' => 'user.username',
|
||||
|
|
|
@ -30,6 +30,14 @@ echo $this->element('genericElements/IndexTable/index_table', [
|
|||
'data_path' => 'multiple',
|
||||
'field' => 'textarea'
|
||||
],
|
||||
[
|
||||
'name' => __('Sane defaults'),
|
||||
'data_path' => 'sane_default'
|
||||
],
|
||||
[
|
||||
'name' => __('Values List'),
|
||||
'data_path' => 'values_list'
|
||||
],
|
||||
[
|
||||
'name' => __('Validation regex'),
|
||||
'sort' => 'regex',
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
if (!empty($element)) {
|
||||
echo $this->Bootstrap->{$element}([
|
||||
'text' => $text,
|
||||
'variant' => $variant,
|
||||
]);
|
||||
}
|
|
@ -1,14 +1,80 @@
|
|||
<?php
|
||||
$controlParams = [
|
||||
'options' => $fieldData['options'],
|
||||
'empty' => $fieldData['empty'] ?? false,
|
||||
'value' => $fieldData['value'] ?? null,
|
||||
'multiple' => $fieldData['multiple'] ?? false,
|
||||
'disabled' => $fieldData['disabled'] ?? false,
|
||||
'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select',
|
||||
'default' => ($fieldData['default'] ?? null)
|
||||
];
|
||||
if (!empty($fieldData['label'])) {
|
||||
$controlParams['label'] = $fieldData['label'];
|
||||
$seed = 's-' . mt_rand();
|
||||
$controlParams = [
|
||||
'type' => 'select',
|
||||
'options' => $fieldData['options'],
|
||||
'empty' => $fieldData['empty'] ?? false,
|
||||
'value' => $fieldData['value'] ?? null,
|
||||
'multiple' => $fieldData['multiple'] ?? false,
|
||||
'disabled' => $fieldData['disabled'] ?? false,
|
||||
'class' => ($fieldData['class'] ?? '') . ' formDropdown form-select',
|
||||
'default' => $fieldData['default'] ?? '',
|
||||
];
|
||||
if (!empty($fieldData['field'])) { // used for multi meta-field form
|
||||
$controlParams['field'] = $fieldData['field'];
|
||||
}
|
||||
if (!empty($fieldData['label'])) {
|
||||
$controlParams['label'] = $fieldData['label'];
|
||||
}
|
||||
if ($controlParams['options'] instanceof \Cake\ORM\Query) {
|
||||
$controlParams['options'] = $controlParams['options']->all()->toList();
|
||||
}
|
||||
if (in_array('_custom', array_keys($controlParams['options']))) {
|
||||
$customInputValue = $this->Form->getSourceValue($fieldData['field']);
|
||||
if (!in_array($customInputValue, $controlParams['options'])) {
|
||||
$controlParams['options'] = array_map(function ($option) {
|
||||
if (is_array($option) && $option['value'] == '_custom') {
|
||||
$option[] = 'selected';
|
||||
}
|
||||
return $option;
|
||||
}, $controlParams['options']);
|
||||
} else {
|
||||
$customInputValue = '';
|
||||
}
|
||||
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);
|
||||
$controlParams['class'] .= ' dropdown-custom-value' . "-$seed";
|
||||
$adaptedField = $fieldData['field'] . '_custom';
|
||||
$controlParams['templates']['formGroup'] = sprintf(
|
||||
'<label class="col-sm-2 col-form-label form-label" {{attrs}}>{{label}}</label><div class="col-sm-10 multi-metafield-input-container"><div class="d-flex form-dropdown-with-freetext input-group">{{input}}{{error}}%s</div></div>',
|
||||
sprintf('<input type="text" class="form-control custom-value" field="%s" value="%s">', h($adaptedField), h($customInputValue))
|
||||
);
|
||||
}
|
||||
echo $this->FormFieldMassage->prepareFormElement($this->Form, $controlParams, $fieldData);
|
||||
?>
|
||||
|
||||
<script>
|
||||
(function() {
|
||||
$(document).ready(function() {
|
||||
const $select = $('select.dropdown-custom-value-<?= $seed ?>')
|
||||
toggleFreetextSelectField($select[0]);
|
||||
$select.attr('onclick', 'toggleFreetextSelectField(this)')
|
||||
$select.parent().find('input.custom-value').attr('oninput', 'updateAssociatedSelect(this)')
|
||||
updateAssociatedSelect($select.parent().find('input.custom-value')[0])
|
||||
})
|
||||
|
||||
})()
|
||||
|
||||
function toggleFreetextSelectField(selectEl) {
|
||||
const $select = $(selectEl)
|
||||
const show = $select.find('option:selected').hasClass('custom-value')
|
||||
const $container = $(selectEl).parent()
|
||||
let $freetextInput = $container.find('input.custom-value')
|
||||
if (show) {
|
||||
$freetextInput.removeClass('d-none')
|
||||
} else {
|
||||
$freetextInput.addClass('d-none')
|
||||
}
|
||||
}
|
||||
|
||||
function updateAssociatedSelect(input) {
|
||||
const $input = $(input)
|
||||
const $select = $input.parent().find('select')
|
||||
const $customOption = $select.find('option.custom-value')
|
||||
$customOption.val($input.val())
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
form div.form-dropdown-with-freetext input.custom-value {
|
||||
flex-grow: 3;
|
||||
}
|
||||
</style>
|
|
@ -31,15 +31,16 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) {
|
|||
$metaField = reset($metaTemplateField->metaFields);
|
||||
$fieldData = [
|
||||
'label' => $metaTemplateField->label,
|
||||
'type' => $metaTemplateField->formType,
|
||||
];
|
||||
if (!empty($metaTemplateField->formOptions)) {
|
||||
$fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions);
|
||||
}
|
||||
if (isset($metaField->id)) {
|
||||
$fieldData['field'] = sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value', $metaField->meta_template_id, $metaField->meta_template_field_id, $metaField->id);
|
||||
} else {
|
||||
$fieldData['field'] = sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.%s.value', $metaField->meta_template_id, $metaField->meta_template_field_id, array_key_first($metaTemplateField->metaFields));
|
||||
}
|
||||
if ($metaTemplateField->type === 'boolean') {
|
||||
$fieldData['type'] = 'checkbox';
|
||||
}
|
||||
$this->Form->setTemplates($backupTemplates);
|
||||
$fieldsHtml .= $this->element(
|
||||
'genericElements/Form/fieldScaffold',
|
||||
|
@ -66,9 +67,10 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) {
|
|||
$fieldData = [
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
'label' => $metaTemplateField->label,
|
||||
'type' => $metaTemplateField->formType,
|
||||
];
|
||||
if ($metaTemplateField->type === 'boolean') {
|
||||
$fieldData['type'] = 'checkbox';
|
||||
if (!empty($metaTemplateField->formOptions)) {
|
||||
$fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions);
|
||||
}
|
||||
$fieldsHtml .= $this->element(
|
||||
'genericElements/Form/fieldScaffold',
|
||||
|
@ -80,4 +82,7 @@ foreach ($metaTemplate->meta_template_fields as $metaTemplateField) {
|
|||
}
|
||||
}
|
||||
}
|
||||
echo $fieldsHtml;
|
||||
$fieldContainer = $this->Bootstrap->genNode('div', [
|
||||
'class' => [],
|
||||
], $fieldsHtml);
|
||||
echo $fieldContainer;
|
|
@ -45,6 +45,8 @@ $seed = 'mfb-' . mt_rand();
|
|||
$clonedContainer
|
||||
.removeClass('has-error')
|
||||
.find('.error-message ').remove()
|
||||
$clonedContainer
|
||||
.find('label.form-label').text('')
|
||||
const $clonedInput = $clonedContainer.find('input, select')
|
||||
if ($clonedInput.length > 0) {
|
||||
const injectedTemplateId = $clicked.closest('.multi-metafields-container').find('.new-metafield').length
|
||||
|
@ -54,18 +56,25 @@ $seed = 'mfb-' . mt_rand();
|
|||
}
|
||||
}
|
||||
|
||||
function adjustClonedInputAttr($input, injectedTemplateId) {
|
||||
let explodedPath = $input.attr('field').split('.').splice(0, 5)
|
||||
explodedPath.push('new', injectedTemplateId)
|
||||
dottedPathStr = explodedPath.join('.')
|
||||
brackettedPathStr = explodedPath.map((elem, i) => {
|
||||
return i == 0 ? elem : `[${elem}]`
|
||||
}).join('')
|
||||
$input.attr('id', dottedPathStr)
|
||||
.attr('field', dottedPathStr)
|
||||
.attr('name', brackettedPathStr)
|
||||
.val('')
|
||||
.removeClass('is-invalid')
|
||||
function adjustClonedInputAttr($inputs, injectedTemplateId) {
|
||||
$inputs.each(function() {
|
||||
const $input = $(this)
|
||||
let explodedPath = $input.attr('field').split('.').splice(0, 5)
|
||||
explodedPath.push('new', injectedTemplateId)
|
||||
dottedPathStr = explodedPath.join('.')
|
||||
brackettedPathStr = explodedPath.map((elem, i) => {
|
||||
return i == 0 ? elem : `[${elem}]`
|
||||
}).join('')
|
||||
const attrs = ['id', 'field', 'name']
|
||||
attrs.forEach((attr) => {
|
||||
if ($input.attr(attr) !== undefined) {
|
||||
$input.attr(attr, attr === 'name' ? brackettedPathStr : dottedPathStr)
|
||||
}
|
||||
})
|
||||
$input
|
||||
.val('')
|
||||
.removeClass('is-invalid')
|
||||
})
|
||||
}
|
||||
})()
|
||||
</script>
|
|
@ -22,6 +22,7 @@ if (!empty($metaFieldsEntities)) {
|
|||
$metaFieldsEntity->meta_template_field_id,
|
||||
$metaFieldsEntity->id
|
||||
),
|
||||
'type' => $metaTemplateField->formType,
|
||||
];
|
||||
if($metaFieldsEntity->isNew()) {
|
||||
$fieldData['field'] = sprintf(
|
||||
|
@ -33,7 +34,10 @@ if (!empty($metaFieldsEntities)) {
|
|||
$fieldData['class'] = 'new-metafield';
|
||||
}
|
||||
if ($labelPrintedOnce) { // Only the first input can have a label
|
||||
$fieldData['label'] = false;
|
||||
$fieldData['label'] = ['text' => ''];
|
||||
}
|
||||
if ($metaTemplateField->formType === 'dropdown') {
|
||||
$fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions);
|
||||
}
|
||||
$labelPrintedOnce = true;
|
||||
$fieldsHtml .= $this->element(
|
||||
|
@ -49,14 +53,19 @@ if (!empty($metaTemplateField) && !empty($multiple)) { // Add multiple field but
|
|||
$metaTemplateField->label = Inflector::humanize($metaTemplateField->field);
|
||||
$emptyMetaFieldInput = '';
|
||||
if (empty($metaFieldsEntities)) { // Include editable field for meta-template not containing a meta-field
|
||||
$fieldData = [
|
||||
'label' => $metaTemplateField->label,
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
'class' => 'new-metafield',
|
||||
'type' => $metaTemplateField->formType,
|
||||
];
|
||||
if ($metaTemplateField->formType === 'dropdown') {
|
||||
$fieldData = array_merge_recursive($fieldData, $metaTemplateField->formOptions);
|
||||
}
|
||||
$emptyMetaFieldInput = $this->element(
|
||||
'genericElements/Form/fieldScaffold',
|
||||
[
|
||||
'fieldData' => [
|
||||
'label' => $metaTemplateField->label,
|
||||
'field' => sprintf('MetaTemplates.%s.meta_template_fields.%s.metaFields.new.0', $metaTemplateField->meta_template_id, $metaTemplateField->id),
|
||||
'class' => 'new-metafield',
|
||||
],
|
||||
'fieldData' => $fieldData,
|
||||
'form' => $form,
|
||||
]
|
||||
);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
} else {
|
||||
$currentFilteringContext = $filteringContext['filterCondition'];
|
||||
}
|
||||
$contextArray[] = [
|
||||
$contextItem = [
|
||||
'active' => (
|
||||
(
|
||||
$currentQuery == $currentFilteringContext && // query conditions match
|
||||
|
@ -42,9 +42,17 @@
|
|||
"#table-container-${tableRandomValue}",
|
||||
"#table-container-${tableRandomValue} table.table",
|
||||
],
|
||||
'text' => $filteringContext['label'],
|
||||
'class' => 'btn-sm'
|
||||
];
|
||||
if (!empty($filteringContext['viewElement'])) {
|
||||
$contextItem['html'] = $this->element(
|
||||
$filteringContext['viewElement'],
|
||||
$filteringContext['viewElementParams'] ?? []
|
||||
);
|
||||
} else {
|
||||
$contextItem['text'] = $filteringContext['label'];
|
||||
}
|
||||
$contextArray[] = $contextItem;
|
||||
}
|
||||
|
||||
$dataGroup = [
|
||||
|
|
|
@ -202,7 +202,7 @@ echo $this->Bootstrap->modal([
|
|||
rowData['operator'] = $row.find('select.fieldOperator').val()
|
||||
const $formElement = $row.find('.fieldValue');
|
||||
if ($formElement.attr('type') === 'datetime-local') {
|
||||
rowData['value'] = moment($formElement.val()).toISOString()
|
||||
rowData['value'] = $formElement.val().length > 0 ? moment($formElement.val()).toISOString() : $formElement.val()
|
||||
} else {
|
||||
rowData['value'] = $formElement.val()
|
||||
}
|
||||
|
|
|
@ -67,14 +67,21 @@ function saveAndUpdateSetting(statusNode, $input, settingName, settingValue) {
|
|||
settingValue = JSON.stringify(settingValue)
|
||||
}
|
||||
saveSetting(statusNode, settingName, settingValue).then((result) => {
|
||||
window.settingsFlattened[settingName] = result.data
|
||||
if ($input.attr('type') == 'checkbox') {
|
||||
$input.prop('checked', result.data.value == true)
|
||||
} else {
|
||||
$input.val(result.data.value)
|
||||
}
|
||||
updateSettingValue($input, settingName, result.data)
|
||||
}).catch((e) => {
|
||||
updateSettingValue($input, settingName, window.settingsFlattened[settingName])
|
||||
}).finally(() => {
|
||||
handleSettingValueChange($input)
|
||||
}).catch((e) => { })
|
||||
})
|
||||
}
|
||||
|
||||
function updateSettingValue($input, settingName, settingValue) {
|
||||
window.settingsFlattened[settingName] = settingValue
|
||||
if ($input.attr('type') == 'checkbox') {
|
||||
$input.prop('checked', settingValue.value == true)
|
||||
} else {
|
||||
$input.val(settingValue.value)
|
||||
}
|
||||
}
|
||||
|
||||
function handleSettingValueChange($input) {
|
||||
|
|
Loading…
Reference in New Issue