Skip to content

Commit

Permalink
Open notification subjects when selected
Browse files Browse the repository at this point in the history
  • Loading branch information
gizmo385 committed Dec 24, 2024
1 parent 52ae7f4 commit 52decab
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 12 deletions.
1 change: 1 addition & 0 deletions lazy_github/lib/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ class NotificationSettings(BaseModel):
"""Controls the settings for the optional notification feature, which relies on the standard GitHub CLI."""

enabled: bool = False
mark_notification_as_read_when_selected: bool = True


class BindingsSettings(BaseModel):
Expand Down
21 changes: 20 additions & 1 deletion lazy_github/lib/github/notifications.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import json
import re

from lazy_github.lib.context import LazyGithubContext
from lazy_github.lib.github.backends.cli import run_gh_cli_command
from lazy_github.lib.github.pull_requests import get_full_pull_request
from lazy_github.lib.logging import lg
from lazy_github.models.github import Notification
from lazy_github.models.github import FullPullRequest, Notification, NotificationSubject

NOTIFICATIONS_PAGE_COUNT = 30

_PULL_REQUEST_URL_REGEX = re.compile(r"[^:]+:[\/]+[^\/]+\/repos\/([^\/]+)\/([^\/]+)\/pulls\/(\d+)")


async def fetch_notifications(all: bool) -> list[Notification]:
"""Fetches notifications on GitHub. If all=True, then previously read notifications will also be returned"""
Expand All @@ -30,3 +35,17 @@ async def mark_notification_as_read(notification: Notification) -> None:
async def unread_notification_count() -> int:
"""Returns the number of currently unread notifications on GitHub"""
return len(await fetch_notifications(all=False))


async def extract_notification_subject(subject: NotificationSubject) -> FullPullRequest | None:
"""Attempts to connect the specified notification subject to another Github object, such as a PR"""
if not (LazyGithubContext.current_repo and subject.url):
return

try:
# Try and load a PR number from the subject URL
if matches := _PULL_REQUEST_URL_REGEX.match(subject.url):
pr_number = int(matches.group(3))
return await get_full_pull_request(LazyGithubContext.current_repo, pr_number)
except Exception:
return None
14 changes: 12 additions & 2 deletions lazy_github/ui/screens/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
from textual.coordinate import Coordinate
from textual.screen import ModalScreen
from textual.widgets import DataTable, Markdown, TabbedContent, TabPane
from textual.widgets.data_table import RowDoesNotExist

from lazy_github.lib.bindings import LazyGithubBindings
from lazy_github.lib.constants import BULLET_POINT, CHECKMARK
from lazy_github.lib.context import LazyGithubContext
from lazy_github.lib.github.notifications import fetch_notifications, mark_notification_as_read
from lazy_github.lib.messages import NotificationMarkedAsRead, NotificationSelected
from lazy_github.models.github import Notification
Expand Down Expand Up @@ -106,8 +108,11 @@ def compose(self) -> ComposeResult:
@on(NotificationMarkedAsRead)
async def notification_marked_read(self, message: NotificationMarkedAsRead) -> None:
await mark_notification_as_read(message.notification)
self.unread_tab.remove_notification(message.notification)
self.read_tab.add_notification(message.notification)
try:
self.unread_tab.remove_notification(message.notification)
self.read_tab.add_notification(message.notification)
except RowDoesNotExist:
pass

def action_view_read(self) -> None:
self.query_one(TabbedContent).active = "read"
Expand Down Expand Up @@ -166,6 +171,11 @@ def compose(self) -> ComposeResult:

@on(NotificationSelected)
async def handle_notification_selected(self, message: NotificationSelected) -> None:
if (
message.notification.unread
and LazyGithubContext.config.notifications.mark_notification_as_read_when_selected
):
await mark_notification_as_read(message.notification)
self.dismiss(message.notification)

async def action_close(self) -> None:
Expand Down
27 changes: 18 additions & 9 deletions lazy_github/ui/screens/primary.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from lazy_github.lib.github.auth import is_logged_in_to_cli
from lazy_github.lib.github.backends.protocol import GithubApiRequestFailed
from lazy_github.lib.github.issues import list_issues
from lazy_github.lib.github.notifications import unread_notification_count
from lazy_github.lib.github.notifications import extract_notification_subject, unread_notification_count
from lazy_github.lib.github.pull_requests import get_full_pull_request
from lazy_github.lib.logging import lg
from lazy_github.lib.messages import (
Expand Down Expand Up @@ -381,15 +381,24 @@ async def action_view_notifications(self) -> None:
notification = await self.app.push_screen_wait(NotificationsModal())
self.refresh_notification_count()

if notification:
self.notify("Opening selected notification")
# The thing we'll do most immediately is swap over to the repo associated with the notification
await self.main_view_pane.load_repository(notification.repository)
self.set_currently_loaded_repo(notification.repository)
if not notification:
return

# TODO: Once that's done, we need to determine what the subject of the repo is and how to handle it. For
# example, if the subject of the notification is a pull request then we should swap over to viewing that
# pull request.
# The thing we'll do most immediately is swap over to the repo associated with the notification
await self.main_view_pane.load_repository(notification.repository)
self.set_currently_loaded_repo(notification.repository)

# Try to determine the source of the notification more specifically than just the repo. If we can, then we'll
# load that more-specific subject (such as the pull request), otherwise we will settle for the already loaded
# repo.
subject = await extract_notification_subject(notification.subject)
match subject:
case None:
self.notify("Opening repository for notification")
return
case PartialPullRequest():
await self.main_view_pane.load_pull_request(subject)
self.notify("Opening pull request for notification")

async def on_mount(self) -> None:
if LazyGithubContext.config.notifications.enabled:
Expand Down

0 comments on commit 52decab

Please sign in to comment.