Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NXDRIVE-2889: Display system notification for document review #4682

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
dcdd820
Added Workflow class to fetch and send notification
swetayadav1 Feb 9, 2024
14bb33d
Merge branch 'master' of https://github.com/nuxeo/nuxeo-drive into wi…
swetayadav1 Feb 9, 2024
3818273
Added display_pending_task and get_task_url method
swetayadav1 Feb 12, 2024
3a26c41
Merge branch 'wip-NXDRIVE-2889-Display-notification-for-document-revi…
swetayadav1 Feb 12, 2024
3e61bf7
NXDRIVE-2889: Display notification for document review
swetayadav1 Feb 19, 2024
7ea5d58
NXDRIVE-2889: Display Notification for Document Review
swetayadav1 Mar 7, 2024
adf6c38
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 18, 2024
d866c25
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 18, 2024
9fb0128
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 18, 2024
45c3ae6
Merge branch 'master' of https://github.com/nuxeo/nuxeo-drive into wi…
swetayadav1 Mar 19, 2024
8557589
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 19, 2024
d01a702
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 19, 2024
19a5fcb
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 19, 2024
10e8417
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 19, 2024
2d97277
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 19, 2024
92e8c70
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 20, 2024
1737a5a
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 21, 2024
dda777f
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 21, 2024
9566896
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 21, 2024
028eb69
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 21, 2024
614ffdd
NXDRIVE-2889: Display system notification for document review
swetayadav1 Mar 22, 2024
57fdf4d
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 1, 2024
7c97b06
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 1, 2024
30d5f70
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 1, 2024
042ddb7
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 2, 2024
ce92e33
NXDRIVE-2889: Display system notification for document review: remove…
swetayadav1 Apr 2, 2024
e0f2328
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 3, 2024
27ccb5f
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 4, 2024
5d031b5
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 5, 2024
be2a8e9
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 8, 2024
bdb284e
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 8, 2024
bba1de2
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 9, 2024
023651b
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 9, 2024
b2aa890
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 9, 2024
f88a444
Merge branch 'master' of https://github.com/nuxeo/nuxeo-drive into wi…
swetayadav1 Apr 9, 2024
e943724
NXDRIVE-2889: Display system notification for document review
swetayadav1 Apr 15, 2024
9baee8a
Merge branch 'master' of https://github.com/nuxeo/nuxeo-drive into wi…
swetayadav1 May 16, 2024
b254c53
NXDRIVE-2899: Display new workflow feature on features tab (#4793)
swetayadav1 May 16, 2024
f2dcd88
NXDRIVE-2889: Display system notification for document review
swetayadav1 May 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changes/5.5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ Release date: `2024-xx-xx`

- [NXDRIVE-2](https://jira.nuxeo.com/browse/NXDRIVE-2):

### Task Management

- [NXDRIVE-2889](https://jira.nuxeo.com/browse/NXDRIVE-2889): Display system notification for document review
- [NXDRIVE-2899](https://jira.nuxeo.com/browse/NXDRIVE-2899): Display new workflow feature on Features tab

## GUI

- [NXDRIVE-2900](https://jira.nuxeo.com/browse/NXDRIVE-2900): Update license headers for Nuxeo addons
Expand Down
68 changes: 68 additions & 0 deletions nxdrive/client/workflow/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from datetime import datetime, timedelta, timezone
from logging import getLogger
from typing import TYPE_CHECKING, Dict, List

from nuxeo.models import Task

from nxdrive.engine.engine import Engine

if TYPE_CHECKING:
from ..remote_client import Remote # noqa

Check warning on line 10 in nxdrive/client/workflow/__init__.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/client/workflow/__init__.py#L10

Added line #L10 was not covered by tests

log = getLogger(__name__)


class Workflow:
"""Workflow Management for document Review"""

def __init__(self, remote: "Remote") -> None:
self.remote = remote

def fetch_document(self, tasks_list: Dict, engine: Engine) -> None:
"""Fetch document details"""
first_task = tasks_list[0]
doc_id = first_task.targetDocumentIds[0]["id"]
task_id = first_task.id

response = self.remote.documents.get(doc_id)
if response:
engine.send_task_notification(task_id, response.path)
else:
log.error("Failed to fetch document details.")

def get_pending_tasks(self, engine: Engine, initial_run: bool = True) -> List[Task]: # type: ignore
"""Get Tasks for document review"""
try:
options = {"userId": self.remote.user_id}
tasks = self.remote.tasks.get(options)

if tasks:
if not initial_run:
tasks = self.filter_tasks(tasks)

if tasks:
if len(tasks) > 1:
# Send generic notification for multiple tasks
engine.send_task_notification(
tasks[0].targetDocumentIds[0]["id"], ""
)
else:
# Fetch document data
self.fetch_document(tasks, engine)
else:
log.info("No Task for processing...")
else:
log.info("No Task for processing...")
except Exception as exec:
log.error(f"Exception occurred while Fetching Tasks: {exec}")

@staticmethod
def filter_tasks(tasks: List[Task]) -> List[Task]:
"""Filter new tasks created within the last hour"""
last_hour = datetime.now(tz=timezone.utc) - timedelta(minutes=60)
log.info("Filtering tasks created in the last hour.")
return [
task
for task in tasks
if datetime.strptime(task.created, "%Y-%m-%dT%H:%M:%S.%f%z") > last_hour
]
2 changes: 2 additions & 0 deletions nxdrive/data/i18n/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
"FEATURE_DIRECT_EDIT": "Edit any of document’s content from their Summary tab even if they are not synchronized.",
"FEATURE_S3": "Improve the speed of your uploads by leveraging the AWS infrastructure. Even enabled, this feature will be effective only for Nuxeo Cloud customers and for Nuxeo servers with S3 Direct Upload addon installed and up-to-date.",
"FEATURE_SYNCHRONIZATION": "Enable or disable the bidirectional synchronization between the local environment and the Nuxeo Platform.\nA restart is needed to apply changes.",
"FEATURE_TASKS_MANAGEMENT": "Handle your tasks from Nuxeo Drive and receive notifications and reminders when a new task is assigned to you.",
"FEEDBACK_LINK": "Something is missing? Share your feedback here.",
"FILE_ALREADY_EXISTS": "There is already a file named \"%1\" in this folder. Do you want to replace it with the one you're moving?",
"FILE_ALREADY_EXISTS_HEADER": "A duplicate file has been found.",
Expand Down Expand Up @@ -287,6 +288,7 @@
"OTHER": "Other",
"PASSWORD": "Password",
"PERSONAL_SPACE": "Personal space",
"PENDING_DOCUMENT_REVIEWS": "Awaiting document review %1",
"PROXY": "Proxy",
"PROXY_APPLIED": "Proxy settings have been updated",
"PROXY_CHANGE_SETTINGS": "Proxy",
Expand Down
7 changes: 7 additions & 0 deletions nxdrive/data/icons/tasks.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 16 additions & 4 deletions nxdrive/data/qml/Systray.qml
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,27 @@ Rectangle {
}
}

// Icon 2: open remote server's URL
// Icon 2: Show pending Task list
IconLabel {
icon: MdiFont.Icon.minus
Image {
source: "../icons/tasks.svg"
anchors.fill: parent
}
color: "#FFFFFF"
enabled: feat_tasks_management.enabled
opacity: feat_tasks_management.enabled ? 1.0 : 0.2
}

// Icon 3: open remote server's URL
IconLabel {
icon: MdiFont.Icon.nuxeo
iconColor: secondaryIcon
onClicked: api.open_remote_server(accountSelect.getRole("uid"))
tooltip: api.get_hostname_from_url(accountSelect.getRole("server_url"))
}

// Icon 3: open local sync root folder
// Icon 4: open local sync root folder
IconLabel {
icon: MdiFont.Icon.folder
iconColor: secondaryIcon
Expand All @@ -170,7 +182,7 @@ Rectangle {
opacity: feat_synchronization.enabled ? 1.0 : 0.5
}

// Icon 4: open the Direct Transfer window
// Icon 5: open the Direct Transfer window
IconLabel {
icon: MdiFont.Icon.directTransfert
iconColor: secondaryIcon
Expand All @@ -180,7 +192,7 @@ Rectangle {
opacity: feat_direct_transfer.enabled ? 1.0 : 0.5
}

// Icon 5: sub-menu
// Icon 6: sub-menu
IconLabel {
id: settingsContainer
icon: MdiFont.Icon.dotsVertical
Expand Down
22 changes: 22 additions & 0 deletions nxdrive/engine/engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
directTransferNewFolderError = pyqtSignal()
directTransferNewFolderSuccess = pyqtSignal(str)
directTransferSessionFinished = pyqtSignal(str, str, str)
displayPendingTask = pyqtSignal(str, str, str)

type = "NXDRIVE"
# Folder locker - LocalFolder processor can prevent
Expand Down Expand Up @@ -747,6 +748,24 @@
}
return urls[self.force_ui or self.wui]

def get_task_url(self, remote_ref: str, /, *, edit: bool = False) -> str:
"""
Build the task's URL based on the server's UI.
Default is Web-UI. In case of unknown UI, use the default value.
:param remote_ref: The task remote reference (UID) of the
task we want to show metadata.
:param edit: Show the metadata edit page instead of the task.
:return: The complete URL.
"""
repo = self.remote.client.repository
page = ("view_documents", "view_drive_metadata")[edit]

Check warning on line 761 in nxdrive/engine/engine.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/engine/engine.py#L760-L761

Added lines #L760 - L761 were not covered by tests

urls = {

Check warning on line 763 in nxdrive/engine/engine.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/engine/engine.py#L763

Added line #L763 was not covered by tests
"jsf": f"{self.server_url}tasks/{repo}/{remote_ref}/{page}",
"web": f"{self.server_url}ui#!/tasks/{remote_ref}",
}
return urls[self.force_ui or self.wui]

Check warning on line 767 in nxdrive/engine/engine.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/engine/engine.py#L767

Added line #L767 was not covered by tests

def is_syncing(self) -> bool:
return self._sync_started

Expand Down Expand Up @@ -1581,6 +1600,9 @@

return full_name

def send_task_notification(self, task_id: str, remote_path: str, /) -> None:
self.displayPendingTask.emit(self.uid, task_id, remote_path)

Check warning on line 1604 in nxdrive/engine/engine.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/engine/engine.py#L1604

Added line #L1604 was not covered by tests


@dataclass
class ServerBindingSettings:
Expand Down
1 change: 1 addition & 0 deletions nxdrive/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
direct_edit=True,
direct_transfer=True,
document_type_selection=False,
tasks_management=False,
s3=False,
)

Expand Down
15 changes: 14 additions & 1 deletion nxdrive/gui/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@
def _balance_percents(self, result: Dict[str, float], /) -> Dict[str, float]:
"""Return an altered version of the dict in which no value is under a minimum threshold."""

result = {k: v for k, v in sorted(result.items(), key=lambda item: item[1])}
result = dict(sorted(result.items(), key=lambda item: item[1]))

Check warning on line 579 in nxdrive/gui/api.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/api.py#L579

Added line #L579 was not covered by tests
keys = list(result)
min_threshold = 10
data = 0.0
Expand Down Expand Up @@ -1108,3 +1108,16 @@
"""Return the URL to a remote document based on its reference."""
engine = self._manager.engines.get(uid)
return engine.get_metadata_url(remote_ref) if engine else ""

@pyqtSlot(str, str, str)
def display_pending_task(
self, uid: str, remote_ref: str, remote_path: str, /
) -> None:
log.info(f"Should open remote document ({remote_path!r})")
try:
engine = self._manager.engines.get(uid)
if engine:
url = engine.get_task_url(remote_ref)
engine.open_remote(url=url)
except Exception as exec:
log.exception(f"Remote task cannot be opened: {exec}")
20 changes: 20 additions & 0 deletions nxdrive/gui/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
from urllib.parse import unquote_plus, urlparse

from nxdrive.client.workflow import Workflow

from ..behavior import Behavior
from ..constants import (
APP_NAME,
Expand Down Expand Up @@ -216,6 +218,8 @@
if MAC:
self._setup_notification_center()

# Initiate workflow when drive starts if tasks managemnt feature is enable
self.workflow = self.init_workflow()

Check warning on line 222 in nxdrive/gui/application.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/application.py#L222

Added line #L222 was not covered by tests
# Application update
self.manager.updater.appUpdated.connect(self.quit)
self.manager.updater.serverIncompatible.connect(self._server_incompatible)
Expand Down Expand Up @@ -273,6 +277,7 @@
self.document_type_selection_feature_model = FeatureModel(
Feature.document_type_selection
)
self.tasks_management_feature_model = FeatureModel(Feature.tasks_management)

Check warning on line 280 in nxdrive/gui/application.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/application.py#L280

Added line #L280 was not covered by tests
self.conflicts_model = FileModel(self.translate)
self.errors_model = FileModel(self.translate)
self.engine_model = EngineModel(self)
Expand Down Expand Up @@ -373,6 +378,15 @@

self.manager.featureUpdate.connect(self._update_feature_state)

def init_workflow(self) -> Workflow:
if not self.manager.engines:
return
for engine in self.manager.engines.copy().values():
self.workflow = Workflow(engine.remote)
if Feature.tasks_management:
self.workflow.get_pending_tasks(engine)
return self.workflow

Check warning on line 388 in nxdrive/gui/application.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/application.py#L382-L388

Added lines #L382 - L388 were not covered by tests

def _update_feature_state(self, name: str, value: bool, /) -> None:
"""Check if the feature model exists from *name* then update it with *value*."""
feature = getattr(self, f"{name}_feature_model", None)
Expand All @@ -384,6 +398,9 @@
if feature.restart_needed:
self.manager.restartNeeded.emit()

if feature.enabled and feature == self.tasks_management_feature_model:
self.init_workflow()

Check warning on line 402 in nxdrive/gui/application.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/application.py#L401-L402

Added lines #L401 - L402 were not covered by tests

def _center_on_screen(self, window: QQuickView, /) -> None:
"""Display and center the window on the screen."""
# Display the window
Expand Down Expand Up @@ -471,6 +488,9 @@
context.setContextProperty(
"feat_document_type_selection", self.document_type_selection_feature_model
)
context.setContextProperty(

Check warning on line 491 in nxdrive/gui/application.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/gui/application.py#L491

Added line #L491 was not covered by tests
"feat_tasks_management", self.tasks_management_feature_model
)
context.setContextProperty(
"feat_synchronization", self.synchronization_feature_model
)
Expand Down
15 changes: 14 additions & 1 deletion nxdrive/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,12 @@
from .objects import Binder, EngineDef, Metrics, Session
from .options import DEFAULT_LOG_LEVEL_FILE, Options
from .osi import AbstractOSIntegration
from .poll_workers import DatabaseBackupWorker, ServerOptionsUpdater, SyncAndQuitWorker
from .poll_workers import (
DatabaseBackupWorker,
ServerOptionsUpdater,
SyncAndQuitWorker,
WorkflowWorker,
)
from .qt.imports import QT_VERSION_STR, QObject, pyqtSignal, pyqtSlot
from .updater import updater
from .updater.constants import Login
Expand Down Expand Up @@ -217,6 +222,9 @@ def __init__(self, home: Path, /) -> None:
# Create the server's configuration getter verification thread
self._create_db_backup_worker()

# Create the workflow worker if workflow_managerment feature is enable
self._create_workflow_worker()

# Setup analytics tracker
self.tracker = self.create_tracker()

Expand Down Expand Up @@ -405,6 +413,11 @@ def _create_db_backup_worker(self) -> None:
if self.db_backup_worker:
self.started.connect(self.db_backup_worker.thread.start)

def _create_workflow_worker(self) -> None:
self.workflow_worker = WorkflowWorker(self)
if self.workflow_worker:
self.started.connect(self.workflow_worker.thread.start)

@if_frozen
def _create_extension_listener(self) -> None:
self._extension_listener = self.osi.get_extension_listener()
Expand Down
33 changes: 32 additions & 1 deletion nxdrive/notification.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@
else:
self.dao.update_notification(notification)
self._notifications[notification.uid] = notification

self.newNotification.emit(notification)

def trigger_notification(self, uid: str, /) -> None:
Expand Down Expand Up @@ -520,6 +519,32 @@
)


class DisplayPendingTask(Notification):
"""Display a notification for pending tasks"""

def __init__(self, engine_uid: str, remote_ref: str, remote_path: str, /) -> None:
values = [remote_path]
super().__init__(

Check warning on line 527 in nxdrive/notification.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/notification.py#L526-L527

Added lines #L526 - L527 were not covered by tests
uid="PENDING_DOCUMENT_REVIEWS",
title="Review Document",
description=Translator.get("PENDING_DOCUMENT_REVIEWS", values=values),
level=Notification.LEVEL_INFO,
flags=(
Notification.FLAG_PERSISTENT
| Notification.FLAG_BUBBLE
| Notification.FLAG_ACTIONABLE
| Notification.FLAG_DISCARD_ON_TRIGGER
| Notification.FLAG_REMOVE_ON_DISCARD
),
action="display_pending_task",
action_args=(
engine_uid,
remote_ref,
remote_path,
),
)


class DefaultNotificationService(NotificationService):
def init_signals(self) -> None:
self._manager.initEngine.connect(self._connect_engine)
Expand All @@ -539,6 +564,7 @@
engine.directTransferSessionFinished.connect(
self._direct_transfer_session_finshed
)
engine.displayPendingTask.connect(self._display_pending_task)

Check warning on line 567 in nxdrive/notification.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/notification.py#L567

Added line #L567 was not covered by tests

def _direct_transfer_error(self, file: Path, /) -> None:
"""Display a notification when a Direct Transfer is in error."""
Expand Down Expand Up @@ -635,3 +661,8 @@
engine_uid = self.sender().uid
notif = InvalidCredentialNotification(engine_uid)
self.send_notification(notif)

def _display_pending_task(
self, engine_uid: str, remote_ref: str, remote_path: str, /
) -> None:
self.send_notification(DisplayPendingTask(engine_uid, remote_ref, remote_path))

Check warning on line 668 in nxdrive/notification.py

View check run for this annotation

Codecov / codecov/patch

nxdrive/notification.py#L668

Added line #L668 was not covered by tests
Loading
Loading