diff --git a/search_api.routing.yml b/search_api.routing.yml index 34c34480..4c8c4e35 100644 --- a/search_api.routing.yml +++ b/search_api.routing.yml @@ -124,7 +124,19 @@ entity.search_api_index.fields: _entity_access: 'search_api_index.fields' entity.search_api_index.add_fields: - path: '/admin/config/search/search-api/index/{search_api_index}/fields/add' + path: '/admin/config/search/search-api/index/{search_api_index}/fields/add/nojs' + options: + parameters: + search_api_index: + tempstore: TRUE + type: 'entity:search_api_index' + defaults: + _entity_form: 'search_api_index.add_fields' + requirements: + _entity_access: 'search_api_index.fields' + +entity.search_api_index.add_fields_ajax: + path: '/admin/config/search/search-api/index/{search_api_index}/fields/add/ajax' options: parameters: search_api_index: @@ -136,7 +148,7 @@ entity.search_api_index.add_fields: _entity_access: 'search_api_index.fields' entity.search_api_index.field_config: - path: '/admin/config/search/search-api/index/{search_api_index}/fields/{field_id}/edit' + path: '/admin/config/search/search-api/index/{search_api_index}/fields/edit/{field_id}' options: parameters: search_api_index: @@ -149,7 +161,7 @@ entity.search_api_index.field_config: _entity_access: 'search_api_index.fields' entity.search_api_index.remove_field: - path: '/admin/config/search/search-api/index/{search_api_index}/fields/{field_id}/remove' + path: '/admin/config/search/search-api/index/{search_api_index}/fields/remove/{field_id}' options: parameters: search_api_index: diff --git a/search_api.theme.inc b/search_api.theme.inc index ebb0bd7e..71c85585 100644 --- a/search_api.theme.inc +++ b/search_api.theme.inc @@ -35,15 +35,14 @@ function theme_search_api_admin_fields_table($variables) { $row[] = $cell; } } - if (empty($form['fields'][$name]['description']['#value'])) { - $rows[] = Utility::deepCopy($row); - } - else { - $rows[] = array( - 'data' => $row, - 'title' => strip_tags($form['fields'][$name]['description']['#value']), - ); + $row = array( + 'data' => $row, + 'data-field-row-id' => $name, + ); + if (!empty($form['fields'][$name]['description']['#value'])) { + $row['title'] = strip_tags($form['fields'][$name]['description']['#value']); } + $rows[] = $row; } } @@ -160,6 +159,9 @@ function theme_search_api_form_item_list(array $variables) { $build = array( '#theme' => 'item_list', ); + if (!empty($element['#title'])) { + $build['#title'] = $element['#title']; + } foreach (Element::children($element) as $key) { $build['#items'][$key] = $element[$key]; } diff --git a/src/Controller/IndexController.php b/src/Controller/IndexController.php index 07bdebdc..a1d9c487 100644 --- a/src/Controller/IndexController.php +++ b/src/Controller/IndexController.php @@ -3,9 +3,14 @@ namespace Drupal\search_api\Controller; use Drupal\Component\Render\FormattableMarkup; +use Drupal\Core\Ajax\AjaxResponse; +use Drupal\Core\Ajax\RemoveCommand; use Drupal\Core\Controller\ControllerBase; +use Drupal\Core\EventSubscriber\AjaxResponseSubscriber; use Drupal\search_api\IndexInterface; use Drupal\search_api\SearchApiException; +use Symfony\Component\DependencyInjection\ContainerInterface; +use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** @@ -14,6 +19,57 @@ class IndexController extends ControllerBase { /** + * The request stack. + * + * @var \Symfony\Component\HttpFoundation\RequestStack|null + */ + protected $requestStack; + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + /** @var static $controller */ + $controller = parent::create($container); + + $controller->setRequestStack($container->get('request_stack')); + + return $controller; + } + + /** + * Retrieves the request stack. + * + * @return \Symfony\Component\HttpFoundation\RequestStack + * The request stack. + */ + public function getRequestStack() { + return $this->requestStack ?: \Drupal::service('request_stack'); + } + + /** + * Retrieves the current request. + * + * @return \Symfony\Component\HttpFoundation\Request|null + */ + public function getRequest() { + return $this->getRequestStack()->getCurrentRequest(); + } + + /** + * Sets the request stack. + * + * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack + * The new request stack. + * + * @return $this + */ + public function setRequestStack(RequestStack $request_stack) { + $this->requestStack = $request_stack; + return $this; + } + + /** * Displays information about a search index. * * @param \Drupal\search_api\IndexInterface $search_api_index @@ -96,10 +152,12 @@ public function indexBypassEnable(IndexInterface $search_api_index) { */ public function removeField(IndexInterface $search_api_index, $field_id) { $fields = $search_api_index->getFields(); + $success = FALSE; if (isset($fields[$field_id])) { try { $search_api_index->removeField($field_id); $search_api_index->save(); + $success = TRUE; } catch (SearchApiException $e) { $args['%field'] = $fields[$field_id]->getLabel(); @@ -110,7 +168,13 @@ public function removeField(IndexInterface $search_api_index, $field_id) { throw new NotFoundHttpException(); } - // Redirect to the index's "View" page. + // If this is an AJAX request, just remove the row in question. + if ($success && $this->getRequest()->request->get(AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER)) { + $response = new AjaxResponse(); + $response->addCommand(new RemoveCommand("tr[data-field-row-id='$field_id']")); + return $response; + } + // Redirect to the index's "Fields" page. $url = $search_api_index->toUrl('fields'); return $this->redirect($url->getRouteName(), $url->getRouteParameters()); } diff --git a/src/Entity/Index.php b/src/Entity/Index.php index bbe53e78..69fe5192 100644 --- a/src/Entity/Index.php +++ b/src/Entity/Index.php @@ -78,7 +78,8 @@ * "add-form" = "/admin/config/search/search-api/add-index", * "edit-form" = "/admin/config/search/search-api/index/{search_api_index}/edit", * "fields" = "/admin/config/search/search-api/index/{search_api_index}/fields", - * "add-fields" = "/admin/config/search/search-api/index/{search_api_index}/fields/add", + * "add-fields" = "/admin/config/search/search-api/index/{search_api_index}/fields/add/nojs", + * "add-fields-ajax" = "/admin/config/search/search-api/index/{search_api_index}/fields/add/ajax", * "break-lock-form" = "/admin/config/search/search-api/index/{search_api_index}/fields/break-lock", * "processors" = "/admin/config/search/search-api/index/{search_api_index}/processors", * "delete-form" = "/admin/config/search/search-api/index/{search_api_index}/delete", diff --git a/src/Form/FieldConfigurationForm.php b/src/Form/FieldConfigurationForm.php index c81912f5..ccb12f41 100644 --- a/src/Form/FieldConfigurationForm.php +++ b/src/Form/FieldConfigurationForm.php @@ -2,9 +2,12 @@ namespace Drupal\search_api\Form; +use Drupal\Component\Render\FormattableMarkup; +use Drupal\Component\Utility\Html; use Drupal\Core\Datetime\DateFormatterInterface; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Entity\EntityTypeManagerInterface; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\RendererInterface; use Drupal\search_api\Processor\ConfigurablePropertyInterface; @@ -33,6 +36,13 @@ class FieldConfigurationForm extends EntityForm { protected $field; /** + * The "id" attribute of the generated form. + * + * @var string + */ + protected $formIdAttribute; + + /** * {@inheritdoc} */ public function getFormId() { @@ -76,9 +86,6 @@ public static function create(ContainerInterface $container) { public function buildForm(array $form, FormStateInterface $form_state) { $field = $this->getField(); - $args['%field'] = $field->getLabel(); - $form['#title'] = $this->t('Edit field %field', $args); - if (!$field) { $args['@id'] = $this->getRequest()->attributes->get('field_id'); $form['message'] = array( @@ -87,6 +94,21 @@ public function buildForm(array $form, FormStateInterface $form_state) { return $form; } + $args['%field'] = $field->getLabel(); + $form['#title'] = $this->t('Edit field %field', $args); + + if ($this->getRequest()->query->get('modal_redirect')) { + $form['title']['#markup'] = new FormattableMarkup('

@title

', ['@title' => $form['#title']]); + Html::setIsAjax(TRUE); + } + + $this->formIdAttribute = Html::getUniqueId($this->getFormId()); + $form['#id'] = $this->formIdAttribute; + + $form['messages'] = [ + '#type' => 'status_messages', + ]; + $property = $field->getDataDefinition(); if (!($property instanceof ConfigurablePropertyInterface)) { $args['%field'] = $field->getLabel(); @@ -123,11 +145,16 @@ protected function actions(array $form, FormStateInterface $form_state) { $actions = parent::actions($form, $form_state); unset($actions['delete']); - $actions['cancel'] = array( - '#type' => 'link', - '#title' => $this->t('Cancel'), - '#url' => $this->entity->toUrl('fields'), - ); + if ($this->getRequest()->query->get('modal_redirect')) { + $actions['submit']['#ajax']['wrapper'] = $this->formIdAttribute; + } + else { + $actions['cancel'] = array( + '#type' => 'link', + '#title' => $this->t('Cancel'), + '#url' => $this->entity->toUrl('fields'), + ); + } return $actions; } @@ -152,7 +179,16 @@ public function submitForm(array &$form, FormStateInterface $form_state) { $property->submitConfigurationForm($field, $form, $form_state); drupal_set_message($this->t('The field configuration was successfully saved.')); - $form_state->setRedirectUrl($this->entity->toUrl('fields')); + if ($this->getRequest()->query->get('modal_redirect')) { + $url = $this->entity->toUrl('add-fields-ajax') + ->setOption('query', [ + MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax', + ]); + $form_state->setRedirectUrl($url); + } + else { + $form_state->setRedirectUrl($this->entity->toUrl('fields')); + } } /** diff --git a/src/Form/IndexAddFieldsForm.php b/src/Form/IndexAddFieldsForm.php index 9d76f8bf..c4d5256d 100644 --- a/src/Form/IndexAddFieldsForm.php +++ b/src/Form/IndexAddFieldsForm.php @@ -2,19 +2,19 @@ namespace Drupal\search_api\Form; -use Drupal\Component\Render\PlainTextOutput; use Drupal\Component\Render\FormattableMarkup; use Drupal\Component\Utility\Html; use Drupal\Core\Datetime\DateFormatterInterface; -use Drupal\Component\Utility\NestedArray; use Drupal\Core\Entity\EntityForm; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Entity\TypedData\EntityDataDefinitionInterface; +use Drupal\Core\EventSubscriber\MainContentViewSubscriber; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\RendererInterface; use Drupal\Core\TypedData\ComplexDataDefinitionInterface; use Drupal\Core\TypedData\DataReferenceDefinitionInterface; use Drupal\Core\Url; +use Drupal\search_api\Datasource\DatasourceInterface; use Drupal\search_api\Processor\ConfigurablePropertyInterface; use Drupal\search_api\Processor\ProcessorPropertyInterface; use Drupal\search_api\Utility\FieldsHelperInterface; @@ -60,6 +60,13 @@ class IndexAddFieldsForm extends EntityForm { protected $unmappedFields = array(); /** + * The "id" attribute of the generated form. + * + * @var string + */ + protected $formIdAttribute; + + /** * {@inheritdoc} */ public function getFormId() { @@ -136,43 +143,26 @@ public function buildForm(array $form, FormStateInterface $form_state) { $this->checkEntityEditable($form, $index); - // Set title. Strip html to accommodate modal title. $args['%index'] = $index->label(); - $form['#title'] = PlainTextOutput::renderFromHtml($this->t('Add fields to index %index', $args)); + $form['#title'] = $this->t('Add fields to index %index', $args); - // Main container. - $form['index-fields'] = [ - '#type' => 'container', - '#attributes' => ['id' => 'index-fields'], + $this->formIdAttribute = Html::getUniqueId($this->getFormId()); + $form['#id'] = $this->formIdAttribute; + + $form['messages'] = [ + '#type' => 'status_messages', ]; - // We store the datasources we need to show in the form to accommodate the - // AJAX magic. - // Create hidden form field to store datasources. - $form['datasources'] = array( - '#type' => 'hidden', + $datasources = array( + '' => NULL, ); - - $datasources = $form_state->getValue('datasources'); - // First set some defaults when nothing is set. - if (empty($datasources)) { - // Get the datasources to add. - // Start with the general fields. - $datasources = ['general' => NULL]; - // Add entity datasource. - $entity_datasources = $this->entity->getDatasources(); - // For each datasource add id to form value. - foreach ($entity_datasources as $entity_datasource) { - $datasource_id = $entity_datasource->getPluginId(); - $datasources[$datasource_id] = NULL; + $datasources += $this->entity->getDatasources(); + foreach ($datasources as $datasource_id => $datasource) { + $item = $this->getDatasourceListItem($datasource); + if ($item) { + $form['datasources']['datasource_' . $datasource_id] = $item; } } - $form['datasources']['#value'] = $datasources; - - // Create form elements for each of the datasources we want to show. - // This is a recursive function, allowing to show the nested elements. - $containers = $this->createFieldContainers($form['datasources']['#value']); - $form['index-fields']['properties'] = $containers; $form['actions'] = $this->actionsElement($form, $form_state); @@ -203,95 +193,35 @@ public function buildForm(array $form, FormStateInterface $form_state) { } /** - * Creates form elements for each field. + * Creates a list item for one datasource. * - * @param array $fields - * A nested array which defines what fields to show. This info is - * stored in the form. + * @param \Drupal\search_api\Datasource\DatasourceInterface|null $datasource + * The datasource, or NULL for general properties. * * @return array - * Form elements for the given fields.. + * A render array representing the given datasource and, possibly, its + * attached properties. */ - protected function createFieldContainers(array $fields) { - $items = array(); - $url = $this->entity->toUrl('add-fields'); - - foreach (array_keys($fields) as $datasource_id) { - // Each element get' a container so we can add children for sub elements. - $item = [ - '#type' => 'container', - '#attributes' => [ - 'class' => ['container-inline'], - '#attributes' => ['id' => '' . $datasource_id], - ], - '#field-name' => $datasource_id, - ]; - - $item['test'] = [ - '#markup' => 'Show ' . $datasource_id . ' in ' . 'index-field-' . $datasource_id . ' container', - ]; - - $active = FALSE; + protected function getDatasourceListItem(DatasourceInterface $datasource = NULL) { + $datasource_id = $datasource ? $datasource->getPluginId() : NULL; + $datasource_id_param = $datasource_id ?: ''; + $properties = $this->entity->getPropertyDefinitions($datasource_id); + if ($properties) { + $active_property_path = ''; $active_datasource = $this->getParameter('datasource'); - if (isset($active_datasource)) { - $active = $active_datasource == $datasource_id; + if ($active_datasource !== NULL && $active_datasource == $datasource_id_param) { + $active_property_path = $this->getParameter('property_path', ''); } - $properties = $this->entity->getPropertyDefinitions($datasource_id == 'general' ? NULL : $datasource_id); - if ($properties) { - $active_property_path = NULL; - if ($active) { - $active_property_path = $this->getParameter('property_path', ''); - } - $base_url = clone $url; - $base_url->setOption('query', array('datasource' => $datasource_id)); - $item['properties'] = $this->getPropertiesList($properties, $active_property_path, $base_url); - } - $items[] = $item; + $base_url = $this->entity->toUrl('add-fields'); + $base_url->setOption('query', array('datasource' => $datasource_id_param)); - // Add child elements. - if (is_array($fields[$datasource_id])) { - $new_things = $this->createFieldContainers($fields[$datasource_id]); - foreach ($new_things as $new_thing) { - $items[] = $new_thing; - } - } + $item = $this->getPropertiesList($properties, $active_property_path, $base_url, $datasource_id); + $item['#title'] = $datasource ? $datasource->label() : $this->t('General'); + return $item; } - return $items; - } - - /** - * Handles form submissions for expanding a datasource. - */ - public function expandDatasourceFormSubmit(&$form, FormStateInterface &$form_state) { - // Find the triggering field. - $button = $form_state->getTriggeringElement(); - // Go one level up in the form, to the widgets container. - $element = NestedArray::getValue($form, array_slice($button['#array_parents'], 0, -1)); - $field_name = $element['#field-name']; - - // Add new items to form state. - $datasources = $form_state->getValue('datasources'); - - $properties = $this->entity->getPropertyDefinitions($field_name == 'general' ? NULL : $field_name); - - foreach (array_keys($properties) as $property) { - $datasources[$field_name][$property] = NULL; - } - - $form_state->setValue('datasources', $datasources); - $form_state->setRebuild(); - } - - /** - * Returns new datasource structure. - */ - public function expandDatasourceFormAjax(array $form, FormStateInterface &$form_state) { - $form['messages']['status'] = [ - '#type' => 'status_messages', - ]; - return $form; + return NULL; } /** @@ -304,6 +234,9 @@ public function expandDatasourceFormAjax(array $form, FormStateInterface &$form_ * @param \Drupal\Core\Url $base_url * The base URL to which property path parameters should be added for * the navigation links. + * @param string|null $datasource_id + * The datasource ID of the listed properties, or NULL for + * datasource-independent properties. * @param string $parent_path * (optional) The common property path prefix of the given properties. * @param string $label_prefix @@ -313,7 +246,7 @@ public function expandDatasourceFormAjax(array $form, FormStateInterface &$form_ * A render array representing the given properties and, possibly, nested * properties. */ - protected function getPropertiesList(array $properties, $active_property_path, Url $base_url, $parent_path = '', $label_prefix = '') { + protected function getPropertiesList(array $properties, $active_property_path, Url $base_url, $datasource_id, $parent_path = '', $label_prefix = '') { $list = array( '#theme' => 'search_api_form_item_list', ); @@ -386,65 +319,59 @@ protected function getPropertiesList(array $properties, $active_property_path, U continue; } - $nested_list = FALSE; - $expand_link = FALSE; + $item = array( + '#type' => 'container', + '#attributes' => array( + 'class' => array('container-inline'), + ), + ); + + $nested_list = array(); if ($nested_properties) { if ($key == $active_item) { $link_url = clone $base_url; $query_base['property_path'] = $parent_path; $link_url->setOption('query', $query_base); - $expand_link = array( + $item['expand_link'] = array( '#type' => 'link', '#title' => '(-) ', '#url' => $link_url, - '#attributes' => [ - 'class' => [ - 'use-ajax', - ], - ], + '#ajax' => array( + 'wrapper' => $this->formIdAttribute, + ), ); - $nested_list = $this->getPropertiesList($nested_properties, $active_property_path, $base_url, $this_path, $label_prefix . $label . ' » '); + $nested_list = $this->getPropertiesList($nested_properties, $active_property_path, $base_url, $datasource_id, $this_path, $label_prefix . $label . ' » '); } else { $link_url = clone $base_url; $query_base['property_path'] = $this_path; $link_url->setOption('query', $query_base); - $expand_link = array( + $item['expand_link'] = array( '#type' => 'link', '#title' => '(+) ', '#url' => $link_url, - '#attributes' => [ - 'class' => [ - 'use-ajax', - ], - ], + '#ajax' => array( + 'wrapper' => $this->formIdAttribute, + ), ); } } - $item = array( - '#type' => 'container', - '#attributes' => array( - 'class' => array('container-inline'), - ), - ); - - if ($expand_link) { - $item['expand_link'] = $expand_link; - } - $item['label']['#markup'] = Html::escape($label) . ' '; if ($can_be_indexed) { $item['add'] = array( '#type' => 'submit', - '#name' => Utility::createCombinedId($this->getParameter('datasource') ?: NULL, $this_path), + '#name' => Utility::createCombinedId($datasource_id, $this_path), '#value' => $this->t('Add'), '#submit' => array('::addField', '::save'), '#property' => $property, '#prefixed_label' => $label_prefix . $label, '#data_type' => $type_mapping[$type], + '#ajax' => array( + 'wrapper' => $this->formIdAttribute, + ), ); } @@ -452,13 +379,29 @@ protected function getPropertiesList(array $properties, $active_property_path, U $item['properties'] = $nested_list; } - $list[] = $item; + $list[$key] = $item; } return $list; } /** + * {@inheritdoc} + */ + protected function actions(array $form, FormStateInterface $form_state) { + return array( + 'done' => array( + '#type' => 'link', + '#title' => $this->t('Done'), + '#url' => $this->entity->toUrl('fields'), + '#attributes' => array( + 'class' => array('button'), + ), + ), + ); + } + + /** * Form submission handler for adding a new field to the index. * * @param array $form @@ -485,7 +428,15 @@ public function addField(array $form, FormStateInterface $form_state) { 'search_api_index' => $this->entity->id(), 'field_id' => $field->getFieldIdentifier(), ); - $form_state->setRedirect('entity.search_api_index.field_config', $parameters); + $options = array(); + $route = $this->getRequest()->attributes->get('_route'); + if ($route === 'entity.search_api_index.add_fields_ajax') { + $options['query'] = [ + MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax', + 'modal_redirect' => 1, + ]; + } + $form_state->setRedirect('entity.search_api_index.field_config', $parameters, $options); } $args['%label'] = $field->getLabel(); diff --git a/src/Form/IndexFieldsForm.php b/src/Form/IndexFieldsForm.php index 58e85455..26910b29 100644 --- a/src/Form/IndexFieldsForm.php +++ b/src/Form/IndexFieldsForm.php @@ -12,6 +12,7 @@ use Drupal\Core\Url; use Drupal\search_api\DataType\DataTypePluginManager; use Drupal\search_api\Processor\ConfigurablePropertyInterface; +use Drupal\search_api\SearchApiException; use Drupal\search_api\UnsavedConfigurationInterface; use Drupal\search_api\Utility\Utility; use Drupal\user\SharedTempStoreFactory; @@ -108,6 +109,8 @@ public function getDataTypePluginManager() { * {@inheritdoc} */ public function buildForm(array $form, FormStateInterface $form_state) { + $form['#attached']['library'][] = 'core/drupal.dialog.ajax'; + $index = $this->entity; // Do not allow the form to be cached. See @@ -123,7 +126,7 @@ public function buildForm(array $form, FormStateInterface $form_state) { $form['add-field'] = [ '#type' => 'link', '#title' => $this->t('Add fields'), - '#url' => Url::fromRoute('entity.search_api_index.add_fields', ['search_api_index' => $index->id()]), + '#url' => $this->entity->toUrl('add-fields'), '#attributes' => [ 'class' => [ 'use-ajax', @@ -205,11 +208,17 @@ protected function buildFieldsTable(array $fields) { } } - $fulltext_types = array('text'); + $fulltext_types = array( + array( + 'value' => 'text', + ), + ); // Add all data types with fallback "text" to fulltext types as well. - foreach ($data_type_plugin_manager->getInstances() as $id => $type) { + foreach ($data_type_plugin_manager->getInstances() as $type_id => $type) { if ($type->getFallbackType() == 'text') { - $fulltext_types[] = $id; + $fulltext_types[] = array( + 'value' => $type_id, + ); } } @@ -277,7 +286,6 @@ protected function buildFieldsTable(array $fields) { ); } - $css_key = '#edit-fields-' . Html::getId($key); $build['fields'][$key]['type'] = array( '#type' => 'select', '#options' => $types, @@ -291,10 +299,12 @@ protected function buildFieldsTable(array $fields) { '#type' => 'select', '#options' => $boosts, '#default_value' => sprintf('%.1f', $field->getBoost()), + '#states' => array( + 'visible' => array( + ':input[name="fields[' . $key . '][type]"]' => $fulltext_types, + ), + ), ); - foreach ($fulltext_types as $type) { - $build['fields'][$key]['boost']['#states']['visible'][$css_key . '-type'][] = array('value' => $type); - } $route_parameters = array( 'search_api_index' => $this->entity->id(), @@ -304,12 +314,26 @@ protected function buildFieldsTable(array $fields) { // don't break the table structure. (theme_search_api_admin_fields_table() // does not add empty cells.) $build['fields'][$key]['edit']['#markup'] = ''; - if ($field->getDataDefinition() instanceof ConfigurablePropertyInterface) { - $build['fields'][$key]['edit'] = array( - '#type' => 'link', - '#title' => $this->t('Edit'), - '#url' => Url::fromRoute('entity.search_api_index.field_config', $route_parameters), - ); + try { + if ($field->getDataDefinition() instanceof ConfigurablePropertyInterface) { + $build['fields'][$key]['edit'] = array( + '#type' => 'link', + '#title' => $this->t('Edit'), + '#url' => Url::fromRoute('entity.search_api_index.field_config', $route_parameters), + '#attributes' => [ + 'class' => [ + 'use-ajax', + ], + 'data-dialog-type' => 'modal', + 'data-dialog-options' => Json::encode([ + 'width' => 700, + ]), + ], + ); + } + } + catch (SearchApiException $e) { + // Could not retrieve data definition: ignore. } $build['fields'][$key]['remove']['#markup'] = ''; if (!$field->isIndexedLocked()) { @@ -317,6 +341,9 @@ protected function buildFieldsTable(array $fields) { '#type' => 'link', '#title' => $this->t('Remove'), '#url' => Url::fromRoute('entity.search_api_index.remove_field', $route_parameters), + '#attributes' => array( + 'class' => array('use-ajax'), + ), ); } } diff --git a/tests/src/Functional/IntegrationTest.php b/tests/src/Functional/IntegrationTest.php index 3bfbd64f..32cb1507 100644 --- a/tests/src/Functional/IntegrationTest.php +++ b/tests/src/Functional/IntegrationTest.php @@ -1035,7 +1035,7 @@ protected function checkUnsavedChanges() { $this->assertSession()->responseContains($message_parts[0]); $this->assertSession()->responseContains($message_parts[1]); $this->assertFalse($this->xpath('//input[not(@disabled)]')); - $this->drupalGet($this->getIndexPath('fields/rendered_item/edit')); + $this->drupalGet($this->getIndexPath('fields/edit/rendered_item')); $this->assertSession()->responseContains($message_parts[0]); $this->assertSession()->responseContains($message_parts[1]); $this->assertFalse($this->xpath('//input[not(@disabled)]')); diff --git a/tests/src/Functional/ProcessorIntegrationTest.php b/tests/src/Functional/ProcessorIntegrationTest.php index a8cdb021..1208b73e 100644 --- a/tests/src/Functional/ProcessorIntegrationTest.php +++ b/tests/src/Functional/ProcessorIntegrationTest.php @@ -307,7 +307,7 @@ public function checkAggregatedFieldsIntegration() { $this->submitForm([], 'aggregated_field'); $args['%label'] = 'Aggregated field'; $this->assertSession()->responseContains(new FormattableMarkup('Field %label was added to the index.', $args)); - $this->assertSession()->addressEquals($this->getIndexPath('fields/aggregated_field/edit')); + $this->assertSession()->addressEquals($this->getIndexPath('fields/edit/aggregated_field')); $edit = [ 'type' => 'first', 'fields[entity:node/title]' => 'title', @@ -500,7 +500,7 @@ public function checkRenderedItemIntegration() { $this->submitForm([], 'rendered_item'); $args['%label'] = 'Rendered HTML output'; $this->assertSession()->responseContains(new FormattableMarkup('Field %label was added to the index.', $args)); - $this->assertSession()->addressEquals($this->getIndexPath('fields/rendered_item/edit')); + $this->assertSession()->addressEquals($this->getIndexPath('fields/edit/rendered_item')); $edit = [ 'roles[]' => ['authenticated'], 'view_mode[entity:node][article]' => 'default',