diff --git a/package.json b/package.json index 7f701f5f9e..89caa8f65a 100644 --- a/package.json +++ b/package.json @@ -1505,6 +1505,31 @@ "title": "%command.notifications.sortByPriority.title%", "category": "%command.notifications.category%" }, + { + "command": "notifications.filterByAll", + "title": "%command.notifications.filterByAll.title%", + "category": "%command.notifications.category%" + }, + { + "command": "notifications.filterByOpen", + "title": "%command.notifications.filterByOpen.title%", + "category": "%command.notifications.category%" + }, + { + "command": "notifications.filterByClosed", + "title": "%command.notifications.filterByClosed.title%", + "category": "%command.notifications.category%" + }, + { + "command": "notifications.filterByIssues", + "title": "%command.notifications.filterByIssues.title%", + "category": "%command.notifications.category%" + }, + { + "command": "notifications.filterByPullRequests", + "title": "%command.notifications.filterByPullRequests.title%", + "category": "%command.notifications.category%" + }, { "command": "notification.openOnGitHub", "title": "%command.notifications.openOnGitHub.title%", @@ -2158,6 +2183,26 @@ "command": "notifications.sortByPriority", "when": "false" }, + { + "command": "notifications.filterByAll", + "when": "false" + }, + { + "command": "notifications.filterByOpen", + "when": "false" + }, + { + "command": "notifications.filterByClosed", + "when": "false" + }, + { + "command": "notifications.filterByIssues", + "when": "false" + }, + { + "command": "notifications.filterByPullRequests", + "when": "false" + }, { "command": "notifications.loadMore", "when": "false" @@ -2295,6 +2340,31 @@ "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", "group": "sortNotifications@2" }, + { + "command": "notifications.filterByAll", + "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", + "group": "sortNotifications@3" + }, + { + "command": "notifications.filterByOpen", + "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", + "group": "sortNotifications@4" + }, + { + "command": "notifications.filterByClosed", + "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", + "group": "sortNotifications@5" + }, + { + "command": "notifications.filterByIssues", + "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", + "group": "sortNotifications@6" + }, + { + "command": "notifications.filterByPullRequests", + "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", + "group": "sortNotifications@7" + }, { "command": "notifications.refresh", "when": "gitHubOpenRepositoryCount != 0 && github:initialized && view == notifications:github", diff --git a/package.nls.json b/package.nls.json index 7405c4f414..64a5589518 100644 --- a/package.nls.json +++ b/package.nls.json @@ -286,6 +286,11 @@ "command.notifications.loadMore.title": "Load More Notifications", "command.notifications.sortByTimestamp.title": "Sort by Timestamp", "command.notifications.sortByPriority.title": "Sort by Priority using Copilot", + "command.notifications.filterByAll.title": "Filter by All", + "command.notifications.filterByOpen.title": "Filter by Open", + "command.notifications.filterByClosed.title": "Filter by Closed", + "command.notifications.filterByIssues.title": "Filter by Issues", + "command.notifications.filterByPullRequests.title": "Filter by Pull Requests", "command.notifications.openOnGitHub.title": "Open on GitHub", "command.notifications.markAsRead.title": "Mark as Read", "command.notification.chatSummarizeNotification.title": "Summarize With Copilot", diff --git a/src/notifications/notificationItem.ts b/src/notifications/notificationItem.ts index 00f979191c..7a2c62af38 100644 --- a/src/notifications/notificationItem.ts +++ b/src/notifications/notificationItem.ts @@ -11,6 +11,14 @@ export enum NotificationsSortMethod { Priority = 'Priority' } +export enum NotificationFilterMethod { + All = 'All', + Open = 'open', + Closed = 'closed', + Issues = 'issues', + PullRequests = 'pullRequests' +} + export type NotificationTreeDataItem = NotificationTreeItem | LoadMoreNotificationsTreeItem; export interface LoadMoreNotificationsTreeItem { diff --git a/src/notifications/notificationsFeatureRegistar.ts b/src/notifications/notificationsFeatureRegistar.ts index 6b103e7838..c4c661fbbd 100644 --- a/src/notifications/notificationsFeatureRegistar.ts +++ b/src/notifications/notificationsFeatureRegistar.ts @@ -10,7 +10,7 @@ import { CredentialStore } from '../github/credentials'; import { RepositoriesManager } from '../github/repositoriesManager'; import { chatCommand } from '../lm/utils'; import { NotificationsDecorationProvider } from './notificationDecorationProvider'; -import { isNotificationTreeItem, NotificationsSortMethod, NotificationTreeDataItem } from './notificationItem'; +import { isNotificationTreeItem, NotificationFilterMethod, NotificationsSortMethod, NotificationTreeDataItem } from './notificationItem'; import { NotificationsManager } from './notificationsManager'; import { NotificationsProvider } from './notificationsProvider'; import { NotificationsTreeData } from './notificationsView'; @@ -69,6 +69,71 @@ export class NotificationsFeatureRegister implements vscode.Disposable { this, ), ); + this._disposables.push( + vscode.commands.registerCommand( + 'notifications.filterByAll', + async () => { + /* __GDPR__ + "notifications.filterByAll" : {} + */ + this._telemetry.sendTelemetryEvent('notifications.filterByAll'); + notificationsManager.filterMethod = NotificationFilterMethod.All; + }, + this, + ), + ); + this._disposables.push( + vscode.commands.registerCommand( + 'notifications.filterByOpen', + async () => { + /* __GDPR__ + "notifications.filterByOpen" : {} + */ + this._telemetry.sendTelemetryEvent('notifications.filterByOpen'); + notificationsManager.filterMethod = NotificationFilterMethod.Open; + }, + this, + ), + ); + this._disposables.push( + vscode.commands.registerCommand( + 'notifications.filterByClosed', + async () => { + /* __GDPR__ + "notifications.filterByClosed" : {} + */ + this._telemetry.sendTelemetryEvent('notifications.filterByClosed'); + notificationsManager.filterMethod = NotificationFilterMethod.Closed; + }, + this, + ), + ); + this._disposables.push( + vscode.commands.registerCommand( + 'notifications.filterByIssues', + async () => { + /* __GDPR__ + "notifications.filterByIssues" : {} + */ + this._telemetry.sendTelemetryEvent('notifications.filterByIssues'); + notificationsManager.filterMethod = NotificationFilterMethod.Issues; + }, + this, + ), + ); + this._disposables.push( + vscode.commands.registerCommand( + 'notifications.filterByPullRequests', + async () => { + /* __GDPR__ + "notifications.filterByPullRequests" : {} + */ + this._telemetry.sendTelemetryEvent('notifications.filterByPullRequests'); + notificationsManager.filterMethod = NotificationFilterMethod.PullRequests; + }, + this, + ), + ); this._disposables.push( vscode.commands.registerCommand( 'notifications.refresh', diff --git a/src/notifications/notificationsManager.ts b/src/notifications/notificationsManager.ts index 9e417ebb9a..3be6b2b920 100644 --- a/src/notifications/notificationsManager.ts +++ b/src/notifications/notificationsManager.ts @@ -5,7 +5,9 @@ import * as vscode from 'vscode'; import { dispose } from '../common/utils'; -import { NotificationsSortMethod, NotificationTreeItem } from './notificationItem'; +import { IssueModel } from '../github/issueModel'; +import { PullRequestModel } from '../github/pullRequestModel'; +import { NotificationFilterMethod, NotificationsSortMethod, NotificationTreeItem } from './notificationItem'; import { NotificationsProvider } from './notificationsProvider'; export interface INotificationTreeItems { @@ -28,9 +30,22 @@ export class NotificationsManager { this._onDidChangeSortingMethod.fire(); } + private _filterMethod: NotificationFilterMethod = NotificationFilterMethod.All; + public get filterMethod(): NotificationFilterMethod { return this._filterMethod; } + public set filterMethod(value: NotificationFilterMethod) { + if (this._filterMethod === value) { + return; + } + this._filterMethod = value; + this._onDidChangeFilterMethod.fire(); + } + private readonly _onDidChangeSortingMethod = new vscode.EventEmitter(); readonly onDidChangeSortingMethod = this._onDidChangeSortingMethod.event; + private readonly _onDidChangeFilterMethod = new vscode.EventEmitter(); + readonly onDidChangeFilterMethod = this._onDidChangeFilterMethod.event; + private _hasNextPage: boolean = false; private _notifications = new Map(); @@ -38,6 +53,8 @@ export class NotificationsManager { constructor(private readonly _notificationProvider: NotificationsProvider) { this._disposable.push(this._onDidChangeNotifications); + this._disposable.push(this._onDidChangeSortingMethod); + this._disposable.push(this._onDidChangeFilterMethod); } dispose() { @@ -56,9 +73,11 @@ export class NotificationsManager { public async getNotifications(compute: boolean, pageCount: number): Promise { if (!compute) { const notifications = Array.from(this._notifications.values()); + const filteredNotifications = this._filterNotifications(notifications); + const sortedFilteredNotifications = this._sortNotifications(filteredNotifications); return { - notifications: this._sortNotifications(notifications), + notifications: sortedFilteredNotifications, hasNextPage: this._hasNextPage }; } @@ -82,7 +101,6 @@ export class NotificationsManager { if (!model) { return; } - notificationItems.set(notification.key, { notification, model, kind: 'notification' }); @@ -115,8 +133,11 @@ export class NotificationsManager { const notifications = Array.from(this._notifications.values()); this._onDidChangeNotifications.fire(notifications); + const filteredNotifications = this._filterNotifications(notifications); + const sortedFilteredNotifications = this._sortNotifications(filteredNotifications); + return { - notifications: this._sortNotifications(notifications), + notifications: sortedFilteredNotifications, hasNextPage: this._hasNextPage }; } @@ -148,4 +169,22 @@ export class NotificationsManager { return notifications; } + + private _filterNotifications(notifications: NotificationTreeItem[]): NotificationTreeItem[] { + return notifications.filter(notification => { + const model = notification.model; + switch (this._filterMethod) { + case NotificationFilterMethod.All: + return true; + case NotificationFilterMethod.Open: + return model.isOpen; + case NotificationFilterMethod.Closed: + return model.isClosed; + case NotificationFilterMethod.Issues: + return (model instanceof IssueModel) && !(model instanceof PullRequestModel); + case NotificationFilterMethod.PullRequests: + return model instanceof PullRequestModel; + } + }); + } } \ No newline at end of file diff --git a/src/notifications/notificationsView.ts b/src/notifications/notificationsView.ts index 5a7f2a40f4..203efba381 100644 --- a/src/notifications/notificationsView.ts +++ b/src/notifications/notificationsView.ts @@ -28,6 +28,9 @@ export class NotificationsTreeData implements vscode.TreeDataProvider { this.refresh(true); })); + this._disposables.push(this._notificationsManager.onDidChangeFilterMethod(() => { + this.refresh(true); + })); } async getTreeItem(element: NotificationTreeDataItem): Promise {