diff --git a/.travis.yml b/.travis.yml index 151e0daf5..76189246c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ stages: env: global: - - THUNDER_ADMIN_BRANCH=8.x-2.x + - THUNDER_ADMIN_BRANCH=feature/3041804-layout_thunder_editorial_search_with_search_api jobs: include: diff --git a/composer.json b/composer.json index e4bf8241c..6b6f58e8d 100644 --- a/composer.json +++ b/composer.json @@ -77,6 +77,12 @@ "drupal/password_policy": { "Policies should declare a config dependency on the plugin modules": "https://www.drupal.org/files/issues/2018-10-09/2918974-2.patch", "Importing configuration on site without password_policy activated": "https://www.drupal.org/files/issues/2018-07-30/password_policy-config_import_field_error-2771129-57.patch" + }, + "drupal/search_api": { + "SearchApiQuery does not implement getCacheTags()": "https://www.drupal.org/files/issues/2019-03-13/3034996-7.patch" + }, + "drupal/select2": { + "Support for AJAX Facets": "https://patch-diff.githubusercontent.com/raw/thunder/select2/pull/54.patch" } } }, @@ -109,6 +115,7 @@ "drupal/entity_browser": "1.7", "drupal/entity_reference_revisions": "^1.0", "drupal/fb_instant_articles": "^1.0", + "drupal/facets": "^1.0", "drupal/field_group": "^1.0", "drupal/focal_point": "^1.0", "drupal/google_analytics": "^2.0", @@ -135,6 +142,7 @@ "drupal/redirect": "^1.0", "drupal/riddle_marketplace": "^2.0", "drupal/scheduler": "1.0", + "drupal/search_api": "dev-1.x", "drupal/scheduler_content_moderation_integration": "~1.0", "drupal/select2": "^1.0", "drupal/simple_sitemap": "^2.0", @@ -145,6 +153,7 @@ "drupal/token": "^1.0", "drupal/update_helper": "^1.0", "drupal/video_embed_field": "^1.0", + "drupal/views_bulk_operations": "^2.4", "drupal/views_load_more": "dev-1.x", "valiton/harbourmaster": "~8.1", "bower-asset/dropzone": "^5.5", diff --git a/config/install/config_selector.feature.thunder_content_view.yml b/config/install/config_selector.feature.thunder_content_view.yml new file mode 100644 index 000000000..40f0acb74 --- /dev/null +++ b/config/install/config_selector.feature.thunder_content_view.yml @@ -0,0 +1,9 @@ +langcode: en +status: true +dependencies: + enforced: + module: + - config_selector +id: thunder_content_view +label: 'Content view' +description: 'The main view for editing content' diff --git a/config/optional/core.entity_view_display.node.article.search_index.yml b/config/optional/core.entity_view_display.node.article.search_index.yml new file mode 100644 index 000000000..2ddcba92e --- /dev/null +++ b/config/optional/core.entity_view_display.node.article.search_index.yml @@ -0,0 +1,54 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.search_index + - field.field.node.article.field_channel + - field.field.node.article.field_meta_tags + - field.field.node.article.field_paragraphs + - field.field.node.article.field_seo_title + - field.field.node.article.field_tags + - field.field.node.article.field_teaser_media + - field.field.node.article.field_teaser_text + - node.type.article + module: + - entity_reference_revisions + - user +id: node.article.search_index +targetEntityType: node +bundle: article +mode: search_index +content: + field_paragraphs: + type: entity_reference_revisions_entity_view + weight: 0 + label: hidden + settings: + view_mode: default + link: '' + third_party_settings: { } + region: content + field_tags: + type: entity_reference_label + weight: 2 + label: hidden + settings: + link: true + third_party_settings: { } + region: content + field_teaser_text: + type: basic_string + weight: 1 + region: content + label: hidden + settings: { } + third_party_settings: { } +hidden: + content_moderation_control: true + field_channel: true + field_meta_tags: true + field_seo_title: true + field_teaser_media: true + langcode: true + links: true + shariff_field: true diff --git a/config/optional/core.entity_view_display.node.page.search_index.yml b/config/optional/core.entity_view_display.node.page.search_index.yml new file mode 100644 index 000000000..21b553626 --- /dev/null +++ b/config/optional/core.entity_view_display.node.page.search_index.yml @@ -0,0 +1,28 @@ +langcode: en +status: true +dependencies: + config: + - core.entity_view_mode.node.search_index + - field.field.node.page.body + - node.type.page + module: + - text + - user +id: node.page.search_index +targetEntityType: node +bundle: page +mode: search_index +content: + body: + label: hidden + type: text_default + weight: 100 + settings: { } + third_party_settings: { } + region: content + links: + weight: 101 + region: content +hidden: + langcode: true + shariff_field: true diff --git a/config/optional/facets.facet.author.yml b/config/optional/facets.facet.author.yml new file mode 100644 index 000000000..1cab7abc1 --- /dev/null +++ b/config/optional/facets.facet.author.yml @@ -0,0 +1,68 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: author +name: Author +url_alias: author +weight: -2 +min_count: 1 +show_only_one_result: true +field_identifier: uid +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: or +use_hierarchy: false +expand_hierarchy: false +enable_parent_when_child_gets_disabled: true +hard_limit: 20 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + active_widget_order: + processor_id: active_widget_order + weights: + sort: -10 + settings: + sort: DESC + count_widget_order: + processor_id: count_widget_order + weights: + sort: -10 + settings: + sort: DESC + display_value_widget_order: + processor_id: display_value_widget_order + weights: + sort: -10 + settings: + sort: ASC + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + uid_to_username_callback: + processor_id: uid_to_username_callback + weights: + build: 5 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.channel.yml b/config/optional/facets.facet.channel.yml new file mode 100644 index 000000000..5695f9e64 --- /dev/null +++ b/config/optional/facets.facet.channel.yml @@ -0,0 +1,73 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: channel +name: Channel +url_alias: channel +weight: -4 +min_count: 0 +show_only_one_result: true +field_identifier: field_channel +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: and +use_hierarchy: true +expand_hierarchy: true +enable_parent_when_child_gets_disabled: true +hard_limit: 250 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + active_widget_order: + processor_id: active_widget_order + weights: + sort: -10 + settings: + sort: DESC + count_widget_order: + processor_id: count_widget_order + weights: + sort: -10 + settings: + sort: DESC + display_value_widget_order: + processor_id: display_value_widget_order + weights: + sort: -10 + settings: + sort: ASC + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + hide_non_narrowing_result_processor: + processor_id: hide_non_narrowing_result_processor + weights: + build: 40 + settings: { } + translate_entity: + processor_id: translate_entity + weights: + build: 5 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.promoted_to_front_page.yml b/config/optional/facets.facet.promoted_to_front_page.yml new file mode 100644 index 000000000..1c4d32882 --- /dev/null +++ b/config/optional/facets.facet.promoted_to_front_page.yml @@ -0,0 +1,52 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: promoted_to_front_page +name: Promoted +url_alias: promoted_to_front_page +weight: 1 +min_count: 1 +show_only_one_result: true +field_identifier: promote +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: or +use_hierarchy: false +expand_hierarchy: false +enable_parent_when_child_gets_disabled: true +hard_limit: 3 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + boolean_item: + processor_id: boolean_item + weights: + build: -10 + settings: + on_value: 'Yes' + off_value: 'No' + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.status.yml b/config/optional/facets.facet.status.yml new file mode 100644 index 000000000..18a63623f --- /dev/null +++ b/config/optional/facets.facet.status.yml @@ -0,0 +1,57 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: status +name: Status +url_alias: status +weight: 0 +min_count: 1 +show_only_one_result: true +field_identifier: status +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: or +use_hierarchy: false +expand_hierarchy: false +enable_parent_when_child_gets_disabled: true +hard_limit: 3 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + boolean_item: + processor_id: boolean_item + weights: + build: -10 + settings: + on_value: Published + off_value: Unpublished + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + hide_non_narrowing_result_processor: + processor_id: hide_non_narrowing_result_processor + weights: + build: 40 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.sticky_at_top_of_lists.yml b/config/optional/facets.facet.sticky_at_top_of_lists.yml new file mode 100644 index 000000000..a3365f399 --- /dev/null +++ b/config/optional/facets.facet.sticky_at_top_of_lists.yml @@ -0,0 +1,52 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: sticky_at_top_of_lists +name: Sticky +url_alias: sticky_at_top_of_lists +weight: 2 +min_count: 1 +show_only_one_result: true +field_identifier: sticky +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: or +use_hierarchy: false +expand_hierarchy: false +enable_parent_when_child_gets_disabled: true +hard_limit: 3 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + boolean_item: + processor_id: boolean_item + weights: + build: -10 + settings: + on_value: 'Yes' + off_value: 'No' + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.tags.yml b/config/optional/facets.facet.tags.yml new file mode 100644 index 000000000..36c0ccc59 --- /dev/null +++ b/config/optional/facets.facet.tags.yml @@ -0,0 +1,68 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: tags +name: Tags +url_alias: tags +weight: -3 +min_count: 1 +show_only_one_result: false +field_identifier: field_tags +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: true + match_operator: CONTAINS +query_operator: and +use_hierarchy: false +expand_hierarchy: true +enable_parent_when_child_gets_disabled: true +hard_limit: 50 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + active_widget_order: + processor_id: active_widget_order + weights: + sort: 20 + settings: + sort: DESC + count_widget_order: + processor_id: count_widget_order + weights: + sort: 30 + settings: + sort: DESC + display_value_widget_order: + processor_id: display_value_widget_order + weights: + sort: 40 + settings: + sort: ASC + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: 50 + settings: { } + translate_entity: + processor_id: translate_entity + weights: + build: 5 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: 50 + build: 15 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet.type.yml b/config/optional/facets.facet.type.yml new file mode 100644 index 000000000..1c488deee --- /dev/null +++ b/config/optional/facets.facet.type.yml @@ -0,0 +1,63 @@ +langcode: en +status: true +dependencies: + config: + - search_api.index.content + - views.view.content_search_api + module: + - search_api +id: type +name: Type +url_alias: type +weight: -1 +min_count: 1 +show_only_one_result: true +field_identifier: type +facet_source_id: 'search_api:views_page__content_search_api__page_1' +widget: + type: select2 + config: + show_numbers: true + width: resolve + autocomplete: false + match_operator: CONTAINS +query_operator: or +use_hierarchy: false +expand_hierarchy: false +enable_parent_when_child_gets_disabled: true +hard_limit: 50 +exclude: false +only_visible_when_facet_source_is_visible: true +processor_configs: + active_widget_order: + processor_id: active_widget_order + weights: + sort: -10 + settings: + sort: DESC + count_widget_order: + processor_id: count_widget_order + weights: + sort: -10 + settings: + sort: DESC + display_value_widget_order: + processor_id: display_value_widget_order + weights: + sort: -10 + settings: + sort: ASC + hide_1_result_facet: + processor_id: hide_1_result_facet + weights: + build: -10 + settings: { } + url_processor_handler: + processor_id: url_processor_handler + weights: + pre_query: -10 + build: -10 + settings: { } +empty_behavior: + behavior: none +show_title: true diff --git a/config/optional/facets.facet_source.search_api__views_page__content_search_api__page_1.yml b/config/optional/facets.facet_source.search_api__views_page__content_search_api__page_1.yml new file mode 100644 index 000000000..b6661548a --- /dev/null +++ b/config/optional/facets.facet_source.search_api__views_page__content_search_api__page_1.yml @@ -0,0 +1,10 @@ +langcode: en +status: true +dependencies: { } +id: search_api__views_page__content_search_api__page_1 +name: 'search_api:views_page__content_search_api__page_1' +filter_key: '' +url_processor: query_string +breadcrumb: + active: false + group: false diff --git a/config/optional/search_api.index.content.yml b/config/optional/search_api.index.content.yml new file mode 100644 index 000000000..30fd6232d --- /dev/null +++ b/config/optional/search_api.index.content.yml @@ -0,0 +1,193 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_channel + - field.storage.node.field_tags + - search_api.server.database + - core.entity_view_mode.node.search_index + module: + - node + - user + - search_api +id: content +name: Content +description: '' +read_only: false +field_settings: + field_channel: + label: Channel + datasource_id: 'entity:node' + property_path: field_channel + type: integer + dependencies: + config: + - field.storage.node.field_channel + field_tags: + label: Tags + datasource_id: 'entity:node' + property_path: field_tags + type: integer + dependencies: + config: + - field.storage.node.field_tags + name: + label: 'Authored by » User » Name' + datasource_id: 'entity:node' + property_path: 'uid:entity:name' + type: string + dependencies: + module: + - node + - user + - user + node_changed: + label: Changed + datasource_id: 'entity:node' + property_path: changed + type: date + dependencies: + module: + - node + node_grants: + label: 'Node access information' + property_path: search_api_node_grants + type: string + indexed_locked: true + type_locked: true + hidden: true + promote: + label: 'Promoted to front page' + datasource_id: 'entity:node' + property_path: promote + type: boolean + dependencies: + module: + - node + rendered_item: + label: 'Rendered HTML output' + property_path: rendered_item + type: text + configuration: + roles: + anonymous: anonymous + view_mode: + 'entity:media': + gallery: default + image: default + instagram: default + pinterest: default + twitter: default + video: default + 'entity:node': + article: search_index + page: search_index + status: + label: status + datasource_id: 'entity:node' + property_path: status + type: boolean + indexed_locked: true + type_locked: true + dependencies: + module: + - node + sticky: + label: 'Sticky at top of lists' + datasource_id: 'entity:node' + property_path: sticky + type: boolean + dependencies: + module: + - node + title: + label: Title + datasource_id: 'entity:node' + property_path: title + type: string + dependencies: + module: + - node + type: + label: 'Content type' + datasource_id: 'entity:node' + property_path: type + type: string + dependencies: + module: + - node + uid: + label: uid + datasource_id: 'entity:node' + property_path: uid + type: integer + indexed_locked: true + type_locked: true + dependencies: + module: + - node +datasource_settings: + 'entity:node': + bundles: + default: true + selected: { } + languages: + default: true + selected: { } +processor_settings: + add_url: { } + aggregated_field: { } + content_access: + weights: + preprocess_query: -30 + hierarchy: + fields: + field_channel: taxonomy_term-parent + weights: + preprocess_index: -45 + html_filter: + all_fields: true + fields: + - name + - rendered_item + - title + - type + title: true + alt: true + tags: + b: 2 + h1: 5 + h2: 3 + h3: 2 + strong: 2 + weights: + preprocess_index: -15 + preprocess_query: -15 + ignorecase: + all_fields: true + fields: + - name + - rendered_item + - title + - type + weights: + preprocess_index: -20 + preprocess_query: -20 + rendered_item: { } + tokenizer: + all_fields: true + fields: + - rendered_item + spaces: '' + overlap_cjk: 1 + minimum_word_size: '3' + weights: + preprocess_index: -6 + preprocess_query: -6 +tracker_settings: + default: + indexing_order: fifo +options: + index_directly: true + cron_limit: 50 +server: database diff --git a/config/optional/search_api.server.database.yml b/config/optional/search_api.server.database.yml new file mode 100644 index 000000000..4aa0f8351 --- /dev/null +++ b/config/optional/search_api.server.database.yml @@ -0,0 +1,16 @@ +langcode: en +status: true +dependencies: + module: + - search_api_db +id: database +name: Database +description: '' +backend: search_api_db +backend_config: + database: 'default:default' + min_chars: 3 + matching: words + autocomplete: + suggest_suffix: true + suggest_words: true diff --git a/config/optional/views.view.content.yml b/config/optional/views.view.content.yml index 58c3c944c..1a9b59c75 100644 --- a/config/optional/views.view.content.yml +++ b/config/optional/views.view.content.yml @@ -6,9 +6,14 @@ dependencies: - field.storage.node.field_teaser_media - image.style.thumbnail module: + - config_selector - media_entity - node - user +third_party_settings: + config_selector: + feature: thunder_content_view + priority: 0 id: content label: Content module: node diff --git a/config/optional/views.view.content_search_api.yml b/config/optional/views.view.content_search_api.yml new file mode 100644 index 000000000..0a14dcd30 --- /dev/null +++ b/config/optional/views.view.content_search_api.yml @@ -0,0 +1,1036 @@ +langcode: en +status: true +dependencies: + config: + - field.storage.node.field_channel + - field.storage.node.field_teaser_media + - image.style.thumbnail + - search_api.index.content + module: + - config_selector + - media_entity + - search_api + - user + - views_bulk_operations +third_party_settings: + config_selector: + feature: thunder_content_view + priority: 1 +id: content_search_api +label: 'Content - Search API' +module: views +description: 'Find and manage content with an advanced search technology.' +tag: '' +base_table: search_api_index_content +base_field: search_api_id +core: 8.x +display: + default: + display_plugin: default + id: default + display_title: Master + position: 0 + display_options: + access: + type: perm + options: + perm: 'access content overview' + cache: + type: search_api_tag + options: { } + query: + type: search_api_query + options: + skip_access: false + bypass_access: false + preserve_facet_query_args: true + exposed_form: + type: basic + options: + submit_button: Apply + reset_button: false + reset_button_label: Reset + exposed_sorts_label: 'Sort by' + expose_sort_order: true + sort_asc_label: Asc + sort_desc_label: Desc + pager: + type: full + options: + items_per_page: 50 + offset: 0 + id: 0 + total_pages: null + tags: + previous: ‹‹ + next: ›› + first: '« First' + last: 'Last »' + expose: + items_per_page: false + items_per_page_label: 'Items per page' + items_per_page_options: '5, 10, 25, 50' + items_per_page_options_all: false + items_per_page_options_all_label: '- All -' + offset: false + offset_label: Offset + quantity: 9 + style: + type: table + options: + grouping: { } + row_class: '' + default_row_class: true + override: true + sticky: false + caption: '' + summary: '' + description: '' + columns: + search_api_id: search_api_id + views_bulk_operations_bulk_form: views_bulk_operations_bulk_form + field_teaser_media: field_teaser_media + title: title + type: type + field_channel: field_channel + status: status + node_changed: node_changed + search_api_operations: search_api_operations + info: + search_api_id: + sortable: false + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + views_bulk_operations_bulk_form: + align: '' + separator: '' + empty_column: false + responsive: '' + field_teaser_media: + align: '' + separator: '' + empty_column: false + responsive: priority-low + title: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: '' + type: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + field_channel: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-low + status: + sortable: true + default_sort_order: asc + align: '' + separator: '' + empty_column: false + responsive: priority-medium + node_changed: + sortable: true + default_sort_order: desc + align: '' + separator: '' + empty_column: false + responsive: priority-low + search_api_operations: + align: '' + separator: '' + empty_column: false + responsive: '' + default: '-1' + empty_table: false + row: + type: fields + fields: + search_api_id: + id: search_api_id + table: search_api_index_content + field: search_api_id + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: true + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: false + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + plugin_id: standard + views_bulk_operations_bulk_form: + id: views_bulk_operations_bulk_form + table: views + field: views_bulk_operations_bulk_form + relationship: none + group_type: group + admin_label: '' + label: 'Views bulk operations' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + batch: true + batch_size: 10 + form_step: true + action_title: Action + selected_actions: + media_delete_action: 0 + media_publish_action: 0 + media_save_action: 0 + media_unpublish_action: 0 + node_assign_owner_action: node_assign_owner_action + node_unpromote_action: node_unpromote_action + node_promote_action: node_promote_action + node_publish_action: node_publish_action + node_save_action: node_save_action + node_make_sticky_action: node_make_sticky_action + node_unpublish_by_keyword_action: node_unpublish_by_keyword_action + node_unpublish_action: node_unpublish_action + node_make_unsticky_action: node_make_unsticky_action + views_bulk_operations_delete_entity: views_bulk_operations_delete_entity + pathauto_update_alias: 0 + preconfiguration: + node_assign_owner_action: + label_override: '' + node_unpromote_action: + label_override: '' + node_promote_action: + label_override: '' + node_publish_action: + label_override: '' + node_save_action: + label_override: '' + node_make_sticky_action: + label_override: '' + node_unpublish_by_keyword_action: + label_override: '' + node_unpublish_action: + label_override: '' + node_make_unsticky_action: + label_override: '' + views_bulk_operations_delete_entity: + label_override: '' + plugin_id: views_bulk_operations_bulk_form + field_teaser_media: + id: field_teaser_media + table: search_api_datasource_content_entity_node + field: field_teaser_media + relationship: none + group_type: group + admin_label: '' + label: '' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: media_thumbnail + settings: + image_style: thumbnail + image_link: '' + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api_entity + fallback_options: + link_to_item: false + multi_type: separator + multi_separator: ', ' + display_methods: + gallery: + display_method: label + view_mode: default + image: + display_method: label + view_mode: default + instagram: + display_method: label + view_mode: default + pinterest: + display_method: label + view_mode: default + twitter: + display_method: label + view_mode: default + video: + display_method: label + view_mode: default + entity_type: node + plugin_id: search_api_field + title: + id: title + table: search_api_index_content + field: title + relationship: none + group_type: group + admin_label: '' + label: Title + exclude: false + alter: + alter_text: true + text: '{{ title }}' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: string + settings: + link_to_entity: true + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api + fallback_options: + link_to_item: false + use_highlighting: false + multi_type: separator + multi_separator: ', ' + plugin_id: search_api_field + type: + id: type + table: search_api_index_content + field: type + relationship: none + group_type: group + admin_label: '' + label: Type + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: false + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api_entity + fallback_options: + link_to_item: false + use_highlighting: false + multi_type: separator + multi_separator: ', ' + display_methods: + node_type: + display_method: label + plugin_id: search_api_field + field_channel: + id: field_channel + table: search_api_index_content + field: field_channel + relationship: none + group_type: group + admin_label: '' + label: Channel + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: target_id + type: entity_reference_label + settings: + link: true + group_column: target_id + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api_entity + fallback_options: + link_to_item: false + multi_type: separator + multi_separator: ', ' + display_methods: + channel: + display_method: label + view_mode: default + tags: + display_method: label + view_mode: default + plugin_id: search_api_field + status: + id: status + table: search_api_index_content + field: status + relationship: none + group_type: group + admin_label: '' + label: Status + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: boolean + settings: + format: custom + format_custom_true: Published + format_custom_false: Unpublished + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api_boolean + fallback_options: + type: yes-no + type_custom_true: '' + type_custom_false: '' + not: false + link_to_item: false + multi_type: separator + multi_separator: ', ' + plugin_id: search_api_field + node_changed: + id: node_changed + table: search_api_index_content + field: node_changed + relationship: none + group_type: group + admin_label: '' + label: 'Changed ' + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: true + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + click_sort_column: value + type: timestamp + settings: + date_format: short + custom_date_format: '' + timezone: '' + group_column: value + group_columns: { } + group_rows: true + delta_limit: 0 + delta_offset: 0 + delta_reversed: false + delta_first_last: false + multi_type: separator + separator: ', ' + field_api_classes: false + field_rendering: true + fallback_handler: search_api_date + fallback_options: + date_format: fallback + custom_date_format: '' + timezone: '' + link_to_item: false + multi_type: separator + multi_separator: ', ' + plugin_id: search_api_field + search_api_operations: + id: search_api_operations + table: search_api_index_content + field: search_api_operations + relationship: none + group_type: group + admin_label: '' + label: Operations + exclude: false + alter: + alter_text: false + text: '' + make_link: false + path: '' + absolute: false + external: false + replace_spaces: false + path_case: none + trim_whitespace: false + alt: '' + rel: '' + link_class: '' + prefix: '' + suffix: '' + target: '' + nl2br: false + max_length: 0 + word_boundary: true + ellipsis: true + more_link: false + more_link_text: '' + more_link_path: '' + strip_tags: false + trim: false + preserve_tags: '' + html: false + element_type: '' + element_class: '' + element_label_type: '' + element_label_class: '' + element_label_colon: false + element_wrapper_type: '' + element_wrapper_class: '' + element_default_classes: true + empty: '' + hide_empty: false + empty_zero: false + hide_alter_empty: true + destination: true + plugin_id: search_api_entity_operations + filters: + search_api_fulltext: + id: search_api_fulltext + table: search_api_index_content + field: search_api_fulltext + relationship: none + group_type: group + admin_label: '' + operator: and + value: '' + group: 1 + exposed: true + expose: + operator_id: search_api_fulltext_op + label: 'Fulltext search' + description: '' + use_operator: false + operator: search_api_fulltext_op + identifier: search_api_fulltext + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + editor: '0' + seo: '0' + administrator: '0' + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + parse_mode: terms + min_length: 3 + fields: { } + plugin_id: search_api_fulltext + search_api_language: + id: search_api_language + table: search_api_index_content + field: search_api_language + relationship: none + group_type: group + admin_label: '' + operator: in + value: + '***LANGUAGE_language_interface***': '***LANGUAGE_language_interface***' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + reduce: false + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + plugin_id: search_api_language + search_api_datasource: + id: search_api_datasource + table: search_api_index_content + field: search_api_datasource + relationship: none + group_type: group + admin_label: '' + operator: or + value: + 'entity:node': 'entity:node' + group: 1 + exposed: false + expose: + operator_id: '' + label: '' + description: '' + use_operator: false + operator: '' + identifier: '' + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + reduce: false + is_grouped: false + group_info: + label: '' + description: '' + identifier: '' + optional: true + widget: select + multiple: false + remember: false + default_group: All + default_group_multiple: { } + group_items: { } + reduce_duplicates: false + plugin_id: search_api_datasource + sorts: + search_api_relevance: + id: search_api_relevance + table: search_api_index_content + field: search_api_relevance + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: false + expose: + label: '' + plugin_id: search_api + node_changed: + id: node_changed + table: search_api_index_content + field: node_changed + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: false + expose: + label: '' + plugin_id: search_api + search_api_id: + id: search_api_id + table: search_api_index_content + field: search_api_id + relationship: none + group_type: group + admin_label: '' + order: DESC + exposed: false + expose: + label: '' + plugin_id: search_api + title: Content + header: + result: + id: result + table: views + field: result + relationship: none + group_type: group + admin_label: '' + empty: false + content: 'Displaying @start - @end of @total' + plugin_id: result + footer: { } + empty: { } + relationships: { } + arguments: { } + display_extenders: { } + use_ajax: true + filter_groups: + operator: AND + groups: + 1: AND + css_class: thunder-search-api + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: + - 'config:field.storage.node.field_channel' + - 'config:field.storage.node.field_teaser_media' + page_1: + display_options: + path: admin/content + menu: + type: tab + title: Content + description: '' + expanded: false + parent: '' + weight: 1 + context: '0' + menu_name: admin + tab_options: + type: normal + title: Content + description: 'Find and manage content' + weight: -10 + display_extenders: { } + defaults: + cache: true + exposed_block: true + display_plugin: page + display_title: Page + id: page_1 + position: 1 + cache_metadata: + max-age: 0 + contexts: + - 'languages:language_content' + - 'languages:language_interface' + - url + - url.query_args + - user.permissions + tags: + - 'config:field.storage.node.field_channel' + - 'config:field.storage.node.field_teaser_media' diff --git a/config/optional/views.view.thunder_media.yml b/config/optional/views.view.thunder_media.yml index 2dc2b22bc..6e780b27a 100644 --- a/config/optional/views.view.thunder_media.yml +++ b/config/optional/views.view.thunder_media.yml @@ -12,7 +12,7 @@ dependencies: id: thunder_media label: Media module: views -description: '' +description: 'Find and manage media.' tag: '' base_table: media_field_data base_field: mid diff --git a/config/update/thunder_update_8136.yml b/config/update/thunder_update_8136.yml new file mode 100644 index 000000000..c88f01c94 --- /dev/null +++ b/config/update/thunder_update_8136.yml @@ -0,0 +1,11 @@ +__global_actions: + import_configs: + - config_selector.feature.thunder_content_view +views.view.content: + expected_config: { } + update_actions: + add: + third_party_settings: + config_selector: + feature: thunder_content_view + priority: 0 diff --git a/drupal-org.make b/drupal-org.make index d28074dc1..a7a7c0dac 100644 --- a/drupal-org.make +++ b/drupal-org.make @@ -45,6 +45,8 @@ projects[entity_browser][version] = 1.7 projects[entity_browser][patch][] = https://www.drupal.org/files/issues/2858438_6.patch projects[entity_reference_revisions][type] = module projects[entity_reference_revisions][version] = 1 +projects[facets][type] = module +projects[facets][version] = 1 projects[fb_instant_articles][type] = module projects[fb_instant_articles][version] = 1 projects[field_group][type] = module @@ -101,6 +103,9 @@ projects[riddle_marketplace][type] = module projects[riddle_marketplace][version] = 2 projects[redirect][type] = module projects[redirect][version] = 1 +projects[search_api][type] = module +projects[search_api][download][branch] = 8.x-1.x +projects[search_api][patch][] = https://www.drupal.org/files/issues/2019-03-13/3034996-7.patch projects[scheduler][type] = module projects[scheduler][version] = 1.0 projects[scheduler][patch][] = https://www.drupal.org/files/issues/2019-01-23/2798689-170-alternative-approach.patch @@ -134,6 +139,8 @@ projects[infinite_module][download][tag] = 8.x-1.0-beta6 projects[infinite][type] = theme projects[infinite][download][url] = https://git.drupal.org/sandbox/gos77-2677750.git projects[infinite][download][tag] = 8.x-1.0-beta7 +projects[views_bulk_operations][type] = module +projects[views_bulk_operations][version] = 2 projects[video_embed_field][type] = module projects[video_embed_field][version] = 1 projects[views_load_more][type] = module diff --git a/modules/thunder_search_api/js/thunder_search_api.js b/modules/thunder_search_api/js/thunder_search_api.js new file mode 100644 index 000000000..43599d492 --- /dev/null +++ b/modules/thunder_search_api/js/thunder_search_api.js @@ -0,0 +1,31 @@ +/** + * @file thunder_search_api.js + */ + +(function ($, Drupal) { + + 'use strict'; + + /** + * Visually mark outdaed rows and disable vbo checkbox + * + * @type {Object} + */ + Drupal.behaviors.thunderSearchApiFlagOutdatedContent = { + attach: function (context, settings) { + var outdated = settings.thunderSearchApi || []; + + if (outdated.length) { + $('[data-thunder-search-api-id]', context) + .filter(function () { + return outdated.indexOf($(this).data('thunder-search-api-id')) !== -1; + }) + .closest('tr').css('background-color', '#fff4f4') + .find('.views-field-views-bulk-operations-bulk-form input[type="checkbox"]') + .prop('disabled', true); + } + } + }; + + +}(jQuery, Drupal)); diff --git a/modules/thunder_search_api/src/SearchApiManager.php b/modules/thunder_search_api/src/SearchApiManager.php new file mode 100644 index 000000000..c3b8fbbe0 --- /dev/null +++ b/modules/thunder_search_api/src/SearchApiManager.php @@ -0,0 +1,166 @@ +entityTypeManager = $entity_type_manager; + $this->state = $state; + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('entity_type.manager'), + $container->get('state') + ); + } + + /** + * Act on entity update. + * + * @param array $indexes + * List of Search API Indexes. + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity that was just saved. + * + * @see hook_entity_update() + */ + public function entityUpdate(array $indexes, EntityInterface $entity) { + $ids = []; + foreach (array_keys($entity->getTranslationLanguages()) as $langcode) { + $ids[] = $this->createCombinedId($entity, $langcode); + } + foreach ($indexes as $index) { + $this->setOutdated($index, $ids); + } + } + + /** + * Act on recently indexed items. + * + * @param \Drupal\search_api\IndexInterface $index + * Search API Index. + * @param string[] $item_ids + * Indexed entity ids. + * + * @see hook_search_api_items_indexed() + */ + public function itemsIndexed(IndexInterface $index, array $item_ids) { + $outdated_ids = $this->state->get('thunder_search_api_outdated_' . $index->id(), []); + $outdated_ids = array_diff($outdated_ids, $item_ids); + $this->state->set('thunder_search_api_outdated_' . $index->id(), $outdated_ids); + } + + /** + * Stores search_api combinedIds for outdated entities. + * + * @param \Drupal\search_api\IndexInterface $index + * Search API Index. + * @param string[] $ids + * List of ids. + */ + public function setOutdated(IndexInterface $index, array $ids) { + + $ids = $this->state->get('thunder_search_api_outdated_' . $index->id(), []) + $ids; + $this->state->set('thunder_search_api_outdated_' . $index->id(), $ids); + } + + /** + * Check if entity is outdated. + * + * @param \Drupal\search_api\IndexInterface $index + * Search API Index. + * @param string $id + * Entity combined id. + * + * @return bool + * Entity is outdated. + */ + public function isOutdated(IndexInterface $index, $id) { + $outdated = array_flip($this->state->get('thunder_search_api_outdated_' . $index->id(), [])); + + return isset($outdated[$id]); + } + + /** + * Return search_api combinedId for given entity. + * + * @param \Drupal\Core\Entity\EntityInterface $entity + * The entity. + * @param string $langcode + * The language code of the translation to get or + * LanguageInterface::LANGCODE_DEFAULT + * to get the data in default language. + * + * @return string + * The combinedId. + */ + public function createCombinedId(EntityInterface $entity, $langcode = NULL) { + $datasource_id = 'entity:' . $entity->getEntityTypeId(); + if (!$langcode) { + $langcode = $entity->language()->getId(); + } + + return Utility::createCombinedId($datasource_id, $entity->id() . ':' . $langcode); + } + + /** + * Add library and data to view. + * + * @param \Drupal\views\ViewExecutable $view + * The current view object. + */ + public function preprocessView(ViewExecutable $view) { + $index = $view->query->getIndex(); + + foreach ($view->result as $row) { + if (isset($row->search_api_id) && $this->isOutdated($index, $row->search_api_id)) { + $data[] = $row->search_api_id; + } + } + + if (!empty($data)) { + $view->element['#attached']['library'][] = 'thunder_search_api/thunder_search_api'; + $view->element['#attached']['drupalSettings']['thunderSearchApi'] = $data; + } + } + +} diff --git a/modules/thunder_search_api/thunder_search_api.info.yml b/modules/thunder_search_api/thunder_search_api.info.yml new file mode 100644 index 000000000..69945774e --- /dev/null +++ b/modules/thunder_search_api/thunder_search_api.info.yml @@ -0,0 +1,7 @@ +name: 'Thunder Search Api' +description: 'Provide search_api integration for thunder.' +type: module +core: 8.x +dependencies: + - search_api:search_api +package: Thunder diff --git a/modules/thunder_search_api/thunder_search_api.libraries.yml b/modules/thunder_search_api/thunder_search_api.libraries.yml new file mode 100644 index 000000000..ef4113fbe --- /dev/null +++ b/modules/thunder_search_api/thunder_search_api.libraries.yml @@ -0,0 +1,6 @@ +thunder_search_api: + js: + js/thunder_search_api.js: {} + dependencies: + - core/jquery + - core/drupal diff --git a/modules/thunder_search_api/thunder_search_api.module b/modules/thunder_search_api/thunder_search_api.module new file mode 100644 index 000000000..cf256a41c --- /dev/null +++ b/modules/thunder_search_api/thunder_search_api.module @@ -0,0 +1,55 @@ +search_api_skip_tracking) { + return; + } + + $indexes = ContentEntity::getIndexesForEntity($entity); + if (!$indexes) { + return; + } + + \Drupal::service('class_resolver') + ->getInstanceFromDefinition(SearchApiManager::class) + ->entityUpdate($indexes, $entity); +} + +/** + * Implements hook_views_pre_render(). + */ +function thunder_search_api_preprocess_views_view(&$variables) { + /* @var Drupal\views\ViewExecutable $view */ + $view = $variables['view']; + if (!$view->result || !$view->query instanceof SearchApiQuery) { + return; + } + Drupal::service('class_resolver') + ->getInstanceFromDefinition(SearchApiManager::class) + ->preprocessView($view); +} + +/** + * Implements function hook_search_api_items_indexed(). + */ +function thunder_search_api_search_api_items_indexed(IndexInterface $index, array $item_ids) { + \Drupal::service('class_resolver') + ->getInstanceFromDefinition(SearchApiManager::class) + ->itemsIndexed($index, $item_ids); +} diff --git a/src/Plugin/Thunder/OptionalModule/ThunderDemo.php b/src/Plugin/Thunder/OptionalModule/ThunderDemo.php index 11df18fef..559357566 100644 --- a/src/Plugin/Thunder/OptionalModule/ThunderDemo.php +++ b/src/Plugin/Thunder/OptionalModule/ThunderDemo.php @@ -11,7 +11,7 @@ * description = @Translation("Installs demo content to show how Thunder works."), * type = "module", * standardlyEnabled = 1, - * weight = -1 + * weight = -2 * ) */ class ThunderDemo extends AbstractOptionalModule {} diff --git a/src/Plugin/Thunder/OptionalModule/ThunderSearch.php b/src/Plugin/Thunder/OptionalModule/ThunderSearch.php new file mode 100644 index 000000000..b1676230b --- /dev/null +++ b/src/Plugin/Thunder/OptionalModule/ThunderSearch.php @@ -0,0 +1,16 @@ + [ + 'status' => TRUE, + ], 'views.view.glossary' => [ 'dependencies' => [ 'config' => TRUE, diff --git a/tests/src/Functional/ModuleUninstallTest.php b/tests/src/Functional/ModuleUninstallTest.php index 32ed87b98..31d9aac08 100644 --- a/tests/src/Functional/ModuleUninstallTest.php +++ b/tests/src/Functional/ModuleUninstallTest.php @@ -34,6 +34,13 @@ class ModuleUninstallTest extends ThunderTestBase { ['length_indicator'], ['redirect'], ['simple_sitemap'], + [ + 'search_api_db', + 'search_api', + 'facets', + 'views_bulk_operations', + 'select2_facets', + ], // ['amp'], // Patch provided: https://www.drupal.org/files/issues/2901581_3.patch. diff --git a/tests/src/FunctionalJavascript/Integration/ConfigSelectorTest.php b/tests/src/FunctionalJavascript/Integration/ConfigSelectorTest.php new file mode 100644 index 000000000..fd9ed9655 --- /dev/null +++ b/tests/src/FunctionalJavascript/Integration/ConfigSelectorTest.php @@ -0,0 +1,53 @@ +assertSession(); + + // Content lock fields are there by default. + $this->drupalGet('admin/content'); + $assert_session->elementExists('xpath', '//*[@id="view-title-table-column"]/a'); + $assert_session->elementExists('css', '#block-thunder-admin-content > div > div.view-content'); + + // Install search_api. + $module_installer = \Drupal::service('module_installer'); + $module_installer->install(['search_api']); + + // Now we have a search_api based view. + $this->drupalGet('admin/config/search/search-api/index/content'); + $this->getSession()->getPage()->pressButton('Index now'); + $assert_session->waitForId('edit-index-now'); + + $this->drupalGet('admin/content'); + $assert_session->elementExists('xpath', '//*[@id="view-title-table-column"]/a'); + $assert_session->elementExists('css', '#block-thunder-admin-content > div > div.view-content-search-api'); + + // Uninstall search_api. + $module_installer->uninstall(['search_api']); + drupal_flush_all_caches(); + + // The normal view is back. + $this->drupalGet('admin/content'); + $assert_session->elementExists('xpath', '//*[@id="view-title-table-column"]/a'); + $assert_session->elementExists('css', '#block-thunder-admin-content > div > div.view-content'); + } + +} diff --git a/thunder.install b/thunder.install index cad0bece0..b5b269078 100644 --- a/thunder.install +++ b/thunder.install @@ -1138,3 +1138,15 @@ function thunder_update_8135() { // Output logged messages to related channel of update execution. return $updateHelper->logger()->output(); } + +/** + * Add config_selector settings to content view. + */ +function thunder_update_8136() { + /** @var \Drupal\update_helper\Updater $updateHelper */ + $updater = \Drupal::service('update_helper.updater'); + $updater->executeUpdate('thunder', 'thunder_update_8136'); + + // Output logged messages to related channel of update execution. + return $updater->logger()->output(); +} diff --git a/thunder.profile b/thunder.profile index 55878a781..7fb297b44 100644 --- a/thunder.profile +++ b/thunder.profile @@ -9,8 +9,10 @@ use Drupal\Core\Entity\EntityStorageException; use Drupal\Core\Entity\EntityTypeInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\block\Entity\Block; +use Drupal\search_api\Plugin\views\query\SearchApiQuery; use Drupal\user\Entity\User; use Drupal\user\Entity\Role; +use Drupal\views\ViewExecutable; /** * Implements hook_form_FORM_ID_alter() for install_configure_form(). @@ -383,6 +385,15 @@ function thunder_modules_installed($modules) { $field->save(); } + + // When enabling search_api, enable facets and VBO. + if (_thunder_check_triggering_modules($modules, ['search_api'])) { + \Drupal::service('module_installer')->install(['search_api_db']); + \Drupal::service('module_installer')->install(['facets']); + \Drupal::service('module_installer')->install(['select2_facets']); + \Drupal::service('module_installer')->install(['views_bulk_operations']); + \Drupal::messenger()->addStatus(t("It's needed to index the search index in order to have all content searchable.")); + } } /** @@ -460,3 +471,35 @@ function thunder_field_widget_info_alter(array &$info) { unset($info['thunder_moderation_state_default']); } } + +/** + * Implements hook_views_data(). + */ +function thunder_views_data() { + $data['views']['facet_block'] = [ + 'title' => t('Facet block'), + 'help' => t('.'), + 'area' => [ + 'id' => 'facet_block', + ], + ]; + return $data; +} + +/** + * Implements hook_views_pre_render(). + */ +function thunder_views_pre_render(ViewExecutable $view) { + if ($view->result || !$view->query instanceof SearchApiQuery) { + return; + } + + /** @var \Drupal\search_api\Task\IndexTaskManagerInterface $index_task_manager */ + $index_task_manager = \Drupal::service('search_api.index_task_manager'); + + $index = $view->query->getIndex(); + if (!$index_task_manager->isTrackingComplete($index) || $index->getTrackerInstance()->getRemainingItemsCount()) { + \Drupal::messenger()->addError(t("It's needed to index the search index in order to have all content searchable.")); + } + +} diff --git a/updates_checklist.yml b/updates_checklist.yml index 182aca3d3..554d9dcc3 100644 --- a/updates_checklist.yml +++ b/updates_checklist.yml @@ -322,3 +322,8 @@ v2.36: '#description_successful': '
Configuration is successfully updated.
' '#description_failed': 'Adjust the order to your needs and save the page. If the order is already correct displayed, move one item for and back before saving.
' filter_page: { '#text': 'Text formats and editors', '#url': 'internal:/admin/config/content/formats' } +thunder_update_8136: + '#title': 'Add config_selector settings to content view' + '#description': '
Config selector settings have to be added to the content view, to ensure that view switching by the config selector works properly.
' + '#description_successful': 'Settings successfully added.
' + '#description_failed': 'Update of configuration has failed.
'