diff --git a/package.json b/package.json index 121adffe67..dbf7652914 100644 --- a/package.json +++ b/package.json @@ -263,6 +263,12 @@ } ] }, + "githubPullRequests.queriesRefreshInterval": { + "type": "number", + "default": 0, + "minimum": 0, + "markdownDescription": "%githubPullRequests.queriesRefreshInterval.markdownDescription%" + }, "githubPullRequests.labelCreated": { "type": "array", "items": { diff --git a/package.nls.json b/package.nls.json index 73c02b7684..228a11dc89 100644 --- a/package.nls.json +++ b/package.nls.json @@ -29,6 +29,7 @@ "githubPullRequests.queries.markdownDescription": "Specifies what queries should be used in the GitHub Pull Requests tree. All queries are made against **the currently opened repos**. Each query object has a `label` that will be shown in the tree and a search `query` using [GitHub search syntax](https://help.github.com/en/articles/understanding-the-search-syntax). By default these queries define the categories \"Copilot on My Behalf\", \"Local Pull Request Branches\", \"Waiting For My Review\", \"Assigned To Me\" and \"Created By Me\". If you want to preserve these, make sure they are still in the array when you modify the setting. \n\n**Variables available:**\n - `${user}` - currently logged in user \n - `${owner}` - repository owner, ex. `microsoft` in `microsoft/vscode` \n - `${repository}` - repository name, ex. `vscode` in `microsoft/vscode` \n - `${today-Nd}` - date N days ago, ex. `${today-7d}` becomes `2025-01-04`\n\n**Example custom queries:**\n```json\n\"githubPullRequests.queries\": [\n {\n \"label\": \"Waiting For My Review\",\n \"query\": \"is:open review-requested:${user}\"\n },\n {\n \"label\": \"Mentioned Me\",\n \"query\": \"is:open mentions:${user}\"\n },\n {\n \"label\": \"Recent Activity\",\n \"query\": \"is:open updated:>${today-7d}\"\n }\n]\n```", "githubPullRequests.queries.label.description": "The label to display for the query in the Pull Requests tree.", "githubPullRequests.queries.query.description": "The GitHub search query for finding pull requests. Use GitHub search syntax with variables like ${user}, ${owner}, ${repository}. Example: 'is:open author:${user}' finds your open pull requests.", + "githubPullRequests.queriesRefreshInterval.markdownDescription": "Automatically refresh pull requests queries at the specified interval. Set to `0` to disable auto-refresh. The minimum refresh interval is 5 minutes.", "githubPullRequests.queries.copilotOnMyBehalf": "Copilot on My Behalf", "githubPullRequests.queries.waitingForMyReview": "Waiting For My Review", "githubPullRequests.queries.assignedToMe": "Assigned To Me", diff --git a/src/@types/vscode.proposed.chatParticipantAdditions.d.ts b/src/@types/vscode.proposed.chatParticipantAdditions.d.ts index 71520fa1ec..aa7001a3d2 100644 --- a/src/@types/vscode.proposed.chatParticipantAdditions.d.ts +++ b/src/@types/vscode.proposed.chatParticipantAdditions.d.ts @@ -105,6 +105,7 @@ declare module 'vscode' { isComplete?: boolean; toolSpecificData?: ChatTerminalToolInvocationData; fromSubAgent?: boolean; + presentation?: 'hidden' | 'hiddenAfterComplete' | undefined; constructor(toolName: string, toolCallId: string, isError?: boolean); } diff --git a/src/@types/vscode.proposed.chatSessionsProvider.d.ts b/src/@types/vscode.proposed.chatSessionsProvider.d.ts index bd4e624430..772fc387b9 100644 --- a/src/@types/vscode.proposed.chatSessionsProvider.d.ts +++ b/src/@types/vscode.proposed.chatSessionsProvider.d.ts @@ -95,6 +95,11 @@ declare module 'vscode' { */ description?: string | MarkdownString; + /** + * An optional badge that provides additional context about the chat session. + */ + badge?: string | MarkdownString; + /** * An optional status indicating the current state of the session. */ diff --git a/src/common/settingKeys.ts b/src/common/settingKeys.ts index 1376c4c7bc..4e82eecbf2 100644 --- a/src/common/settingKeys.ts +++ b/src/common/settingKeys.ts @@ -23,6 +23,7 @@ export type NotificationVariants = 'off' | 'pullRequests'; export const POST_CREATE = 'postCreate'; export const POST_DONE = 'postDone'; export const QUERIES = 'queries'; +export const QUERIES_REFRESH_INTERVAL = 'queriesRefreshInterval'; export const PULL_REQUEST_LABELS = 'labelCreated'; export const FOCUSED_MODE = 'focusedMode'; export const CREATE_DRAFT = 'createDraft'; diff --git a/src/view/prsTreeDataProvider.ts b/src/view/prsTreeDataProvider.ts index e433636fca..54b9b0c53d 100644 --- a/src/view/prsTreeDataProvider.ts +++ b/src/view/prsTreeDataProvider.ts @@ -11,7 +11,7 @@ import { AuthProvider } from '../common/authentication'; import { commands, contexts } from '../common/executeCommands'; import { Disposable } from '../common/lifecycle'; import Logger from '../common/logger'; -import { FILE_LIST_LAYOUT, PR_SETTINGS_NAMESPACE, QUERIES, REMOTES } from '../common/settingKeys'; +import { FILE_LIST_LAYOUT, PR_SETTINGS_NAMESPACE, QUERIES, QUERIES_REFRESH_INTERVAL, REMOTES } from '../common/settingKeys'; import { ITelemetry } from '../common/telemetry'; import { createPRNodeIdentifier } from '../common/uri'; import { EXTENSION_ID } from '../constants'; @@ -47,6 +47,7 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T private _initialized: boolean = false; private _notificationsProvider?: NotificationsManager; private _notificationClearTimeout: NodeJS.Timeout | undefined; + private _autoRefreshTimer: NodeJS.Timeout | undefined; get view(): vscode.TreeView { return this._view; @@ -94,6 +95,10 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T clearTimeout(this._notificationClearTimeout); this._notificationClearTimeout = undefined; } + if (this._autoRefreshTimer) { + clearInterval(this._autoRefreshTimer); + this._autoRefreshTimer = undefined; + } } }); @@ -150,6 +155,9 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T if (e.affectsConfiguration(`${PR_SETTINGS_NAMESPACE}.${FILE_LIST_LAYOUT}`)) { this.refreshAll(); } + if (e.affectsConfiguration(`${PR_SETTINGS_NAMESPACE}.${QUERIES_REFRESH_INTERVAL}`)) { + this.setupAutoRefresh(); + } })); this._register(this._view.onDidChangeCheckboxState(e => TreeUtils.processCheckboxUpdates(e, []))); @@ -160,6 +168,47 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T this._register(this._view.onDidCollapseElement(collapsed => { this.prsTreeModel.updateExpandedQueries(collapsed.element, false); })); + + // Initialize auto-refresh timer + this.setupAutoRefresh(); + } + + private setupAutoRefresh(): void { + // Clear existing timer if any + if (this._autoRefreshTimer) { + clearInterval(this._autoRefreshTimer); + this._autoRefreshTimer = undefined; + } + + // Get the refresh interval setting in minutes + const config = vscode.workspace.getConfiguration(PR_SETTINGS_NAMESPACE); + const intervalMinutes = config.get(QUERIES_REFRESH_INTERVAL, 0); + + // If interval is 0, auto-refresh is disabled + if (intervalMinutes === 0) { + return; + } + + // Enforce minimum of 5 minutes + const actualIntervalMinutes = Math.max(intervalMinutes, 5); + const intervalMs = actualIntervalMinutes * 60 * 1000; + + // Set up the timer + this._autoRefreshTimer = setInterval(() => { + Logger.appendLine('Auto-refreshing pull requests queries', 'PullRequestsTreeDataProvider'); + this.prsTreeModel.forceClearCache(); + this.tryReset(true); + this.fireRefresh(); + }, intervalMs); + + Logger.appendLine(`Auto-refresh enabled with interval of ${actualIntervalMinutes} minutes`, 'PullRequestsTreeDataProvider'); + } + + private resetAutoRefreshTimer(): void { + // Only reset if auto-refresh is currently enabled + if (this._autoRefreshTimer) { + this.setupAutoRefresh(); + } } private filterNotificationsToKnown(notifications: PullRequestModel[]): PullRequestModel[] { @@ -373,9 +422,7 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T } } - private refreshAllQueryResults(reset?: boolean) { - this.tryReset(!!reset); - + private fireRefresh() { if (!this._children || this._children.length === 0) { this._onDidChangeTreeData.fire(); return; @@ -388,6 +435,15 @@ export class PullRequestsTreeDataProvider extends Disposable implements vscode.T this.refreshQueryResultsForFolder(); } + private refreshAllQueryResults(reset?: boolean) { + this.tryReset(!!reset); + + // Reset the auto-refresh timer whenever a refresh is triggered + this.resetAutoRefreshTimer(); + + this.fireRefresh(); + } + private refreshQueryResultsForFolder(manager?: WorkspaceFolderNode, reset?: boolean) { if (!manager && this._children[0] instanceof WorkspaceFolderNode) { // Not permitted. There're multiple folder nodes, therefore must specify which one to refresh