From bf45cacb183188d2fe4751f10c3769b2fc710864 Mon Sep 17 00:00:00 2001 From: berliner Date: Fri, 6 Dec 2024 10:54:49 +0100 Subject: [PATCH] HPC-9936: Use entity browser widget for article selection in sub articles paragraph --- ..._display.paragraph.sub_article.default.yml | 20 +++- config/entity_browser.browser.article.yml | 31 +++++ ...ld.paragraph.sub_article.field_article.yml | 11 +- config/user.role.administrator.yml | 2 + config/user.role.editor.yml | 2 + config/views.view.article_selection.yml | 113 ++++++------------ .../css/edit-form/content_edit_form.css | 4 + .../custom/ncms_ui/css/gin_entity_browser.css | 22 +++- html/modules/custom/ncms_ui/ncms_ui.module | 39 +++++- .../EntityReferenceBrowserTableWidgetNcms.php | 26 +++- 10 files changed, 173 insertions(+), 97 deletions(-) create mode 100644 config/entity_browser.browser.article.yml diff --git a/config/core.entity_form_display.paragraph.sub_article.default.yml b/config/core.entity_form_display.paragraph.sub_article.default.yml index bdad364d..937adc8e 100755 --- a/config/core.entity_form_display.paragraph.sub_article.default.yml +++ b/config/core.entity_form_display.paragraph.sub_article.default.yml @@ -3,23 +3,33 @@ langcode: en status: true dependencies: config: + - entity_browser.browser.article - field.field.paragraph.sub_article.field_article - field.field.paragraph.sub_article.field_collapsible - paragraphs.paragraphs_type.sub_article + module: + - ncms_ui id: paragraph.sub_article.default targetEntityType: paragraph bundle: sub_article mode: default content: field_article: - type: entity_reference_autocomplete + type: entity_reference_browser_table_widget_ncms weight: 0 region: content settings: - match_operator: CONTAINS - match_limit: 10 - size: 60 - placeholder: '' + open: true + entity_browser: article + field_widget_display: label + field_widget_edit: '1' + field_widget_remove: '1' + selection_mode: selection_append + additional_fields: + options: + status: status + field_widget_replace: 0 + field_widget_display_settings: { } third_party_settings: { } field_collapsible: type: boolean_checkbox diff --git a/config/entity_browser.browser.article.yml b/config/entity_browser.browser.article.yml new file mode 100644 index 00000000..b79e6d7d --- /dev/null +++ b/config/entity_browser.browser.article.yml @@ -0,0 +1,31 @@ +uuid: eace0cc6-384b-40ae-9727-8c581f7d61b3 +langcode: en +status: true +dependencies: + config: + - views.view.article_selection + module: + - views +name: article +label: Article +display: modal +display_configuration: + width: '1300' + height: '' + link_text: 'Add article' + auto_open: false +selection_display: no_display +selection_display_configuration: { } +widget_selector: single +widget_selector_configuration: { } +widgets: + f5d14464-491c-413c-9b95-763f2285fa42: + id: view + uuid: f5d14464-491c-413c-9b95-763f2285fa42 + label: 'Articles table' + weight: 1 + settings: + submit_text: 'Add selected article' + auto_select: false + view: article_selection + view_display: entity_browser_table diff --git a/config/field.field.paragraph.sub_article.field_article.yml b/config/field.field.paragraph.sub_article.field_article.yml index a2436c1e..1dd31d09 100755 --- a/config/field.field.paragraph.sub_article.field_article.yml +++ b/config/field.field.paragraph.sub_article.field_article.yml @@ -6,12 +6,21 @@ dependencies: - field.storage.paragraph.field_article - node.type.article - paragraphs.paragraphs_type.sub_article + module: + - field_config_cardinality +third_party_settings: + field_config_cardinality: + cardinality_config: '1' + cardinality_label_config: false + unlimited_not_required: '' + limited_not_required: '' + limited_required: '' id: paragraph.sub_article.field_article field_name: field_article entity_type: paragraph bundle: sub_article label: Article -description: 'Enter the title of the Article.' +description: '' required: true translatable: true default_value: { } diff --git a/config/user.role.administrator.yml b/config/user.role.administrator.yml index 42dfe0fc..298242a4 100755 --- a/config/user.role.administrator.yml +++ b/config/user.role.administrator.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: config: + - entity_browser.browser.article - entity_browser.browser.articles - filter.format.filtered_html - filter.format.footnotes @@ -44,6 +45,7 @@ weight: -8 is_admin: null permissions: - 'access administration pages' + - 'access article entity browser pages' - 'access articles entity browser pages' - 'access content overview' - 'access media overview' diff --git a/config/user.role.editor.yml b/config/user.role.editor.yml index 0e84a608..5c3ed2ee 100755 --- a/config/user.role.editor.yml +++ b/config/user.role.editor.yml @@ -3,6 +3,7 @@ langcode: en status: true dependencies: config: + - entity_browser.browser.article - entity_browser.browser.articles - filter.format.filtered_html - media.type.author @@ -31,6 +32,7 @@ weight: -6 is_admin: null permissions: - 'access administration pages' + - 'access article entity browser pages' - 'access articles entity browser pages' - 'access content overview' - 'access media overview' diff --git a/config/views.view.article_selection.yml b/config/views.view.article_selection.yml index 316def86..aeeb853a 100644 --- a/config/views.view.article_selection.yml +++ b/config/views.view.article_selection.yml @@ -8,10 +8,10 @@ dependencies: - field.storage.node.field_tags - image.style.thumbnail_medium_x1 - node.type.article - - taxonomy.vocabulary.major_tags module: - entity_browser - media + - ncms_tags - node - taxonomy - user @@ -505,36 +505,35 @@ display: default_group: All default_group_multiple: { } group_items: { } - field_tags_target_id: - id: field_tags_target_id - table: node__field_tags - field: field_tags_target_id + computed_tags_active_tags: + id: computed_tags_active_tags + table: node__field_computed_tags + field: computed_tags_active_tags relationship: none group_type: group admin_label: '' - plugin_id: taxonomy_index_tid - operator: and - value: { } + plugin_id: computed_tags_active_tags + operator: '=' + value: '' group: 1 exposed: true expose: - operator_id: field_tags_target_id_op + operator_id: '' label: Tags description: '' use_operator: false - operator: field_tags_target_id_op + operator: computed_tags_active_tags_op operator_limit_selection: false operator_list: { } identifier: tags required: false remember: false - multiple: true + multiple: false remember_roles: authenticated: authenticated anonymous: '0' - editor: '0' administrator: '0' - reduce: false + editor: '0' is_grouped: false group_info: label: '' @@ -547,12 +546,6 @@ display: default_group: All default_group_multiple: { } group_items: { } - reduce_duplicates: true - vid: major_tags - type: textfield - hierarchy: false - limit: true - error_message: true filter_groups: operator: AND groups: @@ -601,27 +594,9 @@ display: - 'languages:language_interface' - url - url.query_args - - user - 'user.node_grants:view' - user.permissions tags: - - 'config:core.entity_view_display.node.article.default' - - 'config:core.entity_view_display.node.article.full' - - 'config:core.entity_view_display.node.article.home_page' - - 'config:core.entity_view_display.node.article.layout_paragraphs_preview_table' - - 'config:core.entity_view_display.node.article.preview' - - 'config:core.entity_view_display.node.article.related_article' - - 'config:core.entity_view_display.node.article.sub_article' - - 'config:core.entity_view_display.node.article.teaser' - - 'config:core.entity_view_display.node.article.teaser_card' - - 'config:core.entity_view_display.node.document.default' - - 'config:core.entity_view_display.node.document.full' - - 'config:core.entity_view_display.node.document.teaser' - - 'config:core.entity_view_display.node.story.default' - - 'config:core.entity_view_display.node.story.full' - - 'config:core.entity_view_display.node.story.home_page' - - 'config:core.entity_view_display.node.story.preview' - - 'config:core.entity_view_display.node.story.teaser' - 'config:field.storage.node.field_hero_image' - 'config:field.storage.node.field_tags' entity_browser_grid: @@ -1007,27 +982,9 @@ display: - 'languages:language_interface' - url - url.query_args - - user - 'user.node_grants:view' - user.permissions tags: - - 'config:core.entity_view_display.node.article.default' - - 'config:core.entity_view_display.node.article.full' - - 'config:core.entity_view_display.node.article.home_page' - - 'config:core.entity_view_display.node.article.layout_paragraphs_preview_table' - - 'config:core.entity_view_display.node.article.preview' - - 'config:core.entity_view_display.node.article.related_article' - - 'config:core.entity_view_display.node.article.sub_article' - - 'config:core.entity_view_display.node.article.teaser' - - 'config:core.entity_view_display.node.article.teaser_card' - - 'config:core.entity_view_display.node.document.default' - - 'config:core.entity_view_display.node.document.full' - - 'config:core.entity_view_display.node.document.teaser' - - 'config:core.entity_view_display.node.story.default' - - 'config:core.entity_view_display.node.story.full' - - 'config:core.entity_view_display.node.story.home_page' - - 'config:core.entity_view_display.node.story.preview' - - 'config:core.entity_view_display.node.story.teaser' - 'config:field.storage.node.field_hero_image' - 'config:field.storage.node.field_tags' entity_browser_table: @@ -1087,7 +1044,7 @@ display: hide_empty: false empty_zero: false hide_alter_empty: true - use_field_cardinality: false + use_field_cardinality: true title: id: title table: node_field_data @@ -1153,14 +1110,15 @@ display: multi_type: separator separator: ', ' field_api_classes: false - field_tags: - id: field_tags - table: node__field_tags - field: field_tags + term_node_tid: + id: term_node_tid + table: node_field_data + field: term_node_tid relationship: none group_type: group admin_label: '' - plugin_id: field + entity_type: node + plugin_id: taxonomy_index_tid label: Tags exclude: false alter: @@ -1194,7 +1152,7 @@ display: element_class: '' element_label_type: '' element_label_class: '' - element_label_colon: false + element_label_colon: true element_wrapper_type: '' element_wrapper_class: '' element_default_classes: true @@ -1202,20 +1160,21 @@ display: 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 + type: separator separator: ', ' - field_api_classes: false + link_to_taxonomy: true + limit: true + vids: + country: country + document_type: document_type + month: month + theme: theme + year: year + appeals: '0' + content_space: '0' + interactive_content_type: '0' + major_tags: '0' + story_type: '0' style: type: table options: @@ -1271,8 +1230,6 @@ display: - 'languages:language_interface' - url - url.query_args - - user - 'user.node_grants:view' - user.permissions - tags: - - 'config:field.storage.node.field_tags' + tags: { } diff --git a/html/modules/custom/ncms_ui/css/edit-form/content_edit_form.css b/html/modules/custom/ncms_ui/css/edit-form/content_edit_form.css index 9ac32bd1..264f527b 100644 --- a/html/modules/custom/ncms_ui/css/edit-form/content_edit_form.css +++ b/html/modules/custom/ncms_ui/css/edit-form/content_edit_form.css @@ -4,3 +4,7 @@ .node-content-base.gin--edit-form .submit-trash.button { position: inherit; } +.ui-dialog [data-drupal-selector="edit-layout-paragraphs-component-form-sub-article"] { + width: 80vw; + max-width: 1200px; +} diff --git a/html/modules/custom/ncms_ui/css/gin_entity_browser.css b/html/modules/custom/ncms_ui/css/gin_entity_browser.css index 80e8943a..1b44d540 100644 --- a/html/modules/custom/ncms_ui/css/gin_entity_browser.css +++ b/html/modules/custom/ncms_ui/css/gin_entity_browser.css @@ -8,19 +8,23 @@ .ui-dialog form.layout-paragraphs-component-form div[data-drupal-selector="edit-group-tabs"] { max-height: 65vh; } -#entity-browser-articles-form > .view { +#entity-browser-articles-form > .view, +#entity-browser-article-form > .view { padding: var(--gin-spacing-l) var(--gin-spacing-l); margin-bottom: 1rem; } -#entity-browser-articles-form > .form-actions { +#entity-browser-articles-form > .form-actions, +#entity-browser-article-form > .form-actions { padding: 0 var(--gin-spacing-l); border-top: 1px solid var(--gin-border-color-layer); background: var(--gin-bg-app); } -#entity-browser-articles-form .entities-list { +#entity-browser-articles-form .entities-list, +#entity-browser-article-form .entities-list { display: none; } -#entity-browser-articles-form .view-content .gin-table-scroll-wrapper { +#entity-browser-articles-form .view-content .gin-table-scroll-wrapper, +#entity-browser-article-form .view-content .gin-table-scroll-wrapper { margin: 0; padding: 0; } @@ -58,8 +62,14 @@ .field--widget-entity-reference-browser-table-widget-ncms > details > .details-wrapper > .form-wrapper > input.button { margin: var(--gin-spacing-s) 0; } -.field--widget-entity-reference-browser-table-widget-ncms table th { - padding-left: var(--gin-spacing-m); +table.table--widget-entity_reference_browser_table_widget th, +table.table--widget-entity_reference_browser_table_widget td { + padding-left: var(--gin-spacing-m) !important; + white-space: nowrap; +} +.table--widget-entity_reference_browser_table_widget--sortable th:first-child, +.table--widget-entity_reference_browser_table_widget--sortable td:first-child { + padding: 0; } .field--widget-entity-reference-browser-table-widget-ncms table th.th__title { width: 100%; diff --git a/html/modules/custom/ncms_ui/ncms_ui.module b/html/modules/custom/ncms_ui/ncms_ui.module index 3f0fbb23..077e1573 100644 --- a/html/modules/custom/ncms_ui/ncms_ui.module +++ b/html/modules/custom/ncms_ui/ncms_ui.module @@ -6,11 +6,14 @@ */ use Drupal\Component\Serialization\Json; +use Drupal\content_moderation\Entity\ContentModerationStateInterface; use Drupal\Core\Access\AccessResult; use Drupal\Core\Database\Query\AlterableInterface; use Drupal\Core\Entity\Display\EntityViewDisplayInterface; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\FieldableEntityInterface; +use Drupal\Core\Entity\Query\QueryInterface; +use Drupal\Core\Entity\Query\Sql\Query; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Render\Markup; use Drupal\Core\Session\AccountInterface; @@ -691,6 +694,34 @@ function ncms_ui_views_data_alter(&$data) { ]; } +/** + * Implements hook_entity_query_tag__TAG_alter(). + * + * Exclude trashed nodes from auto complete matches. + */ +function ncms_ui_entity_query_tag__entity_reference_alter(QueryInterface $query) : void { + /** @var \Drupal\ncms_ui\ContentSpaceManager $content_space_manager */ + $content_space_manager = \Drupal::service('ncms_ui.content_space.manager'); + $content_space_id = $content_space_manager->getCurrentContentSpaceId(); + if ($content_space_id && $query instanceof Query && $query->hasTag('entity_reference') && $query->hasTag('node_access')) { + // First load the node ids of all trashed nodes. + $result = \Drupal::entityTypeManager()->getStorage('content_moderation_state')->loadByProperties([ + 'content_entity_type_id' => 'node', + 'moderation_state' => 'trash', + ]); + $node_ids = $result ? array_map(function (ContentModerationStateInterface $content_moderation) { + return $content_moderation->get('content_entity_id')->value; + }, $result) : []; + + // Then add a condition to the query to exclude these. + if (!empty($node_ids)) { + $query->condition('nid', $node_ids, 'NOT IN'); + } + // Add by last updated timestamp. + $query->sort('changed', 'DESC'); + } +} + /** * Implements hook_views_query_alter(). */ @@ -725,11 +756,11 @@ function ncms_ui_views_pre_render(ViewExecutable $view) { * Implements hook_node_access_records(). */ function ncms_ui_node_access_records(NodeInterface $node) { - if (!$node->hasField('field_content_space')) { - return []; + $grants = []; + if (!$node instanceof ContentInterface) { + return $grants; } - $grants = []; $grants[] = [ 'realm' => ContentSpaceManager::NODE_ACCESS_REALM, 'gid' => 0, @@ -740,7 +771,7 @@ function ncms_ui_node_access_records(NodeInterface $node) { ]; // Get the content space id from the current node if it's available. - $content_space_id = !$node->field_content_space->isEmpty() ? $node->field_content_space->entity->tid->value : NULL; + $content_space_id = $node->getContentSpace()?->tid?->value; if (!$content_space_id) { return $grants; } diff --git a/html/modules/custom/ncms_ui/src/Plugin/Field/FieldWidget/EntityReferenceBrowserTableWidgetNcms.php b/html/modules/custom/ncms_ui/src/Plugin/Field/FieldWidget/EntityReferenceBrowserTableWidgetNcms.php index 356d299f..168c96d2 100644 --- a/html/modules/custom/ncms_ui/src/Plugin/Field/FieldWidget/EntityReferenceBrowserTableWidgetNcms.php +++ b/html/modules/custom/ncms_ui/src/Plugin/Field/FieldWidget/EntityReferenceBrowserTableWidgetNcms.php @@ -49,10 +49,19 @@ protected function displayCurrentSelection($details_id, array $field_parents, ar $entity_browser = $this->getEntityBrowser(); $add_more_button_label = $entity_browser->getDisplay()->getConfiguration()['link_text']; try { + $header = $this->buildTableHeaders(); + if (!$this->isSortable()) { + unset($header[0]); + } $table = [ '#type' => 'table', - '#header' => $this->buildTableHeaders(), - '#attributes' => ['class' => ['table--widget-entity_reference_browser_table_widget']], + '#header' => $header, + '#attributes' => [ + 'class' => array_filter([ + 'table--widget-entity_reference_browser_table_widget', + $this->isSortable() ? 'table--widget-entity_reference_browser_table_widget--sortable' : NULL, + ]), + ], '#empty' => $this->t('No articles added yet. Use the @button_label button below to add articles.', [ '@button_label' => $add_more_button_label, ]), @@ -96,7 +105,7 @@ public function buildTableRows(array $entities, $details_id, $field_parents) { } $rowData[] = array_filter([ - 'handle' => $this->buildSortableHandle(), + 'handle' => $this->isSortable() ? $this->buildSortableHandle() : NULL, 'title-preview' => $this->getFirstColumn($entity), 'status' => $this->getAdditionalFieldsColumn($entity), 'actions' => [ @@ -118,6 +127,17 @@ public function buildTableRows(array $entities, $details_id, $field_parents) { return $rowData; } + /** + * Check if the table should be sortable. + * + * @return bool + * TRUE if the table should be sortable, FALSE otherwise. + */ + private function isSortable() { + $cardinality = $this->fieldDefinition->getFieldStorageDefinition()->getCardinality(); + return $cardinality > 1 || $cardinality == -1; + } + /** * Get the entity browser used with this widget. *