diff --git a/services/drupal/composer.patches.json b/services/drupal/composer.patches.json index 400fdc864..3f8374750 100644 --- a/services/drupal/composer.patches.json +++ b/services/drupal/composer.patches.json @@ -259,6 +259,7 @@ "Add Last revision to payload and fix canonical error on DANSE report page": "patches/last_revision-3452539.patch" }, "drupal/danse": { + "Add Bulk Operation for marking notifications as seen or unseen": "patches/notification-seen-unseen-action.diff", "Fix issue with Prune job": "patches/danse-fix-prune-job.diff" } } diff --git a/services/drupal/config/sync/user.role.authenticated.yml b/services/drupal/config/sync/user.role.authenticated.yml index 5768de270..7e80039b9 100644 --- a/services/drupal/config/sync/user.role.authenticated.yml +++ b/services/drupal/config/sync/user.role.authenticated.yml @@ -79,6 +79,7 @@ permissions: - 'create webform content' - 'delete own files' - 'edit own paragraph library items' + - 'execute danse_notification_seen_action danse_notification' - 'execute entity:publish_action block_content' - 'execute entity:publish_action media' - 'execute entity:publish_action menu_link_content' diff --git a/services/drupal/config/sync/views.view.notifications.yml b/services/drupal/config/sync/views.view.notifications.yml index 16131051f..64fcbf964 100644 --- a/services/drupal/config/sync/views.view.notifications.yml +++ b/services/drupal/config/sync/views.view.notifications.yml @@ -10,6 +10,7 @@ dependencies: - group - node - user + - views_bulk_operations id: notifications label: Notifications module: views @@ -26,6 +27,68 @@ display: display_options: title: 'All Notifications' fields: + 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: '' + plugin_id: views_bulk_operations_bulk_form + 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 + ajax_loader: false + buttons: false + action_title: Action + clear_on_exposed: true + force_selection_info: false + selected_actions: + - + action_id: danse_notification_seen_action + preconfiguration: + add_confirmation: false reference_node_transition: id: reference_node_transition table: danse_event @@ -76,6 +139,73 @@ display: hide_empty: false empty_zero: false hide_alter_empty: true + seen: + id: seen + table: danse_notification + field: seen + relationship: none + group_type: group + admin_label: '' + entity_type: danse_notification + entity_field: seen + plugin_id: field + label: Seen + 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: unicode-yes-no + format_custom_false: '' + format_custom_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 title: id: title table: node_field_data @@ -622,7 +752,119 @@ display: validate_options: { } break_phrase: false not: false - filters: { } + filters: + seen: + id: seen + table: danse_notification + field: seen + relationship: none + group_type: group + admin_label: '' + entity_type: danse_notification + entity_field: seen + plugin_id: boolean + operator: '=' + value: '0' + group: 1 + exposed: true + expose: + operator_id: '' + label: Seen + description: '' + use_operator: false + operator: seen_op + operator_limit_selection: false + operator_list: { } + identifier: seen + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + paragraphs_library_contributor: '0' + layout_editor: '0' + alerts_manager: '0' + block_manager: '0' + system_editor: '0' + system_webmaster: '0' + menu_admin: '0' + administrator: '0' + beta_tester: '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: { } + gid: + id: gid + table: group_content_field_data + field: gid + relationship: group_content + group_type: group + admin_label: '' + entity_type: group_content + entity_field: gid + plugin_id: entity_reference + operator: or + value: { } + group: 1 + exposed: true + expose: + operator_id: gid_op + label: 'Web Area' + description: '' + use_operator: false + operator: gid_op + operator_limit_selection: false + operator_list: { } + identifier: gid + required: false + remember: false + multiple: false + remember_roles: + authenticated: authenticated + anonymous: '0' + paragraphs_library_contributor: '0' + layout_editor: '0' + alerts_manager: '0' + block_manager: '0' + system_editor: '0' + system_webmaster: '0' + menu_admin: '0' + administrator: '0' + beta_tester: '0' + 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 + handler: 'default:group' + widget: autocomplete + handler_settings: + target_bundles: + web_area: web_area + sort: + field: _none + direction: ASC + auto_create: false + auto_create_bundle: '' style: type: table options: @@ -760,7 +1002,7 @@ display: views_ajax_get: ajax_get: false cache_metadata: - max-age: -1 + max-age: 0 contexts: - 'languages:language_content' - 'languages:language_interface' @@ -775,7 +1017,22 @@ display: display_plugin: page position: 1 display_options: + empty: + area: + id: area + table: views + field: area + relationship: none + group_type: group + admin_label: '' + plugin_id: text + empty: true + content: + value: 'All caught up! No new notifications.' + format: filtered_html + tokenize: false defaults: + empty: false sorts: true display_extenders: views_ajax_get: @@ -791,7 +1048,7 @@ display: parent: system.admin_content context: '0' cache_metadata: - max-age: -1 + max-age: 0 contexts: - 'languages:language_content' - 'languages:language_interface' diff --git a/services/drupal/patches/notification-seen-unseen-action.diff b/services/drupal/patches/notification-seen-unseen-action.diff new file mode 100644 index 000000000..c1247a2e0 --- /dev/null +++ b/services/drupal/patches/notification-seen-unseen-action.diff @@ -0,0 +1,135 @@ +diff --git a/src/Entity/Notification.php b/src/Entity/Notification.php +index 5aebcd8..2a47972 100644 +--- a/src/Entity/Notification.php ++++ b/src/Entity/Notification.php +@@ -78,6 +78,21 @@ class Notification extends ContentEntityBase implements NotificationInterface { + return $this; + } + ++ /** ++ * {@inheritdoc} ++ */ ++ public function markUnseen(): NotificationInterface { ++ try { ++ $this ++ ->set('seen', FALSE) ++ ->save(); ++ } ++ catch (EntityStorageException $e) { ++ // @todo Log this exception. ++ } ++ return $this; ++ } ++ + /** + * {@inheritdoc} + */ +diff --git a/src/Entity/NotificationInterface.php b/src/Entity/NotificationInterface.php +index e3c4082..39e02eb 100644 +--- a/src/Entity/NotificationInterface.php ++++ b/src/Entity/NotificationInterface.php +@@ -33,6 +33,14 @@ interface NotificationInterface extends ContentEntityInterface { + */ + public function markSeen(): NotificationInterface; + ++ /** ++ * Marks the notification as un-seen. ++ * ++ * @return \Drupal\danse\Entity\NotificationInterface ++ * Self. ++ */ ++ public function markUnseen(): NotificationInterface; ++ + /** + * Marks the notification as delivered. + * +diff --git a/src/Plugin/Action/NotificationSeenAction.php b/src/Plugin/Action/NotificationSeenAction.php +new file mode 100644 +index 0000000..feae3ab +--- /dev/null ++++ b/src/Plugin/Action/NotificationSeenAction.php +@@ -0,0 +1,84 @@ ++get('seen')->value; ++ // If it's 'seen' (TRUE) then mark it unseen and vice versa ++ filter_var($seen, FILTER_VALIDATE_BOOL) ? $entity->markUnseen() : $entity->markSeen(); ++ return $this->t('Successfully marked notification as @seen.', ['@seen' => filter_var($seen, FILTER_VALIDATE_BOOL) ? $this->t('unseen') : $this->t('seen')]); ++ } ++ catch (\LogicException $e) { ++ // @todo Error handling? ++ } ++ } ++ } ++ ++ /** ++ * {@inheritDoc} ++ */ ++ public function access($object, AccountInterface $account = NULL, $return_as_object = FALSE) { ++ // @todo: Is there any permissions we want to have for this? DANSE doesn't offer any permissions for the entities it provides ++ return AccessResult::allowed(); ++ } ++ ++ /** ++ * @param bool $success ++ * ++ * @param array $results ++ * @param array $operations ++ * ++ * @return \Symfony\Component\HttpFoundation\RedirectResponse|null ++ */ ++ public static function finished($success, array $results, array $operations): ?RedirectResponse { ++ if ($success) { ++ foreach ($results['operations'] as $item) { ++ // Default fallback to maintain backwards compatibility: ++ // if api version equals to "1" and type equals to "status", ++ // previous message is displayed, otherwise we display exactly what's ++ // specified in the action. ++ if ($item['type'] === 'status' && $results['api_version'] === '1') { ++ $message = static::translate('@operation', [ ++ '@operation' => $item['message'], ++ ]); ++ } ++ else { ++ $message = new FormattableMarkup('@message', [ ++ '@message' => $item['message'], ++ ]); ++ } ++ static::message($message, $item['type']); ++ } ++ } ++ else { ++ $message = static::translate('Finished with an error.'); ++ static::message($message, 'error'); ++ } ++ return NULL; ++ } ++ ++} diff --git a/services/drupal/web/modules/custom/epa_workflow/src/Plugin/views/field/EpaWorkflowReferenceTransitionBase.php b/services/drupal/web/modules/custom/epa_workflow/src/Plugin/views/field/EpaWorkflowReferenceTransitionBase.php index b26bf3a5e..73a74bd3a 100644 --- a/services/drupal/web/modules/custom/epa_workflow/src/Plugin/views/field/EpaWorkflowReferenceTransitionBase.php +++ b/services/drupal/web/modules/custom/epa_workflow/src/Plugin/views/field/EpaWorkflowReferenceTransitionBase.php @@ -88,7 +88,7 @@ public function getTransitionRevisionIds(ResultRow $values) { ) { $payload = $event->get('payload')->value; $payload_values = json_decode($payload, TRUE); - $transition_revision_ids['from'] = $payload_values['entity']['last_revision']; + $transition_revision_ids['from'] = $payload_values['entity']['prev_revision']; /** @var \Drupal\node\NodeStorageInterface $node_storage */ $node_storage = $this->entityTypeManager->getStorage('node');