Skip to content

Commit fb19648

Browse files
committed
Cleanup
1 parent 61ebcee commit fb19648

File tree

8 files changed

+214
-340
lines changed

8 files changed

+214
-340
lines changed

package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -885,13 +885,6 @@
885885
]
886886
},
887887
"commands": [
888-
{
889-
"command": "pr.openTasksDashboard",
890-
"title": "%command.pr.openTasksDashboard.title%",
891-
"category": "%command.pull.request.category%",
892-
"icon": "$(dashboard)",
893-
"when": "config.githubPullRequests.projectTasksDashboard.enabled"
894-
},
895888
{
896889
"command": "githubpr.remoteAgent",
897890
"title": "%command.githubpr.remoteAgent.title%",
@@ -1809,6 +1802,13 @@
18091802
"command": "pr.cancelCodingAgent",
18101803
"title": "%command.pr.cancelCodingAgent.title%",
18111804
"category": "%command.pull.request.category%"
1805+
},
1806+
{
1807+
"command": "pr.projectTasksDashboard.open",
1808+
"title": "%command.pr.projectTasksDashboard.open.title%",
1809+
"category": "%command.pull.request.category%",
1810+
"icon": "$(dashboard)",
1811+
"when": "config.githubPullRequests.projectTasksDashboard.enabled"
18121812
}
18131813
],
18141814
"languages": [

package.nls.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
"view.github.active.pull.request.name": "Review Pull Request",
176176
"view.github.active.pull.request.welcome.name": "Active Pull Request",
177177
"command.pull.request.category": "GitHub Pull Requests",
178-
"command.pr.openTasksDashboard.title": "Open Dashboard",
178+
"command.pr.projectTasksDashboard.open.title": "Open Dashboard",
179179
"command.pr.createDashboard.title": "Create Dashboard",
180180
"customEditor.github.tasks.displayName": "GitHub Tasks Editor",
181181
"command.githubpr.remoteAgent.title": "Remote agent integration",

src/commands.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ export function registerCommands(
11321132
));
11331133

11341134
context.subscriptions.push(
1135-
vscode.commands.registerCommand('pr.openTasksDashboard', async () => {
1135+
vscode.commands.registerCommand('pr.projectTasksDashboard.open', async () => {
11361136
tasksDashboard.showOrCreateDashboard();
11371137
})
11381138
);

src/github/tasksDashboard.ts

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,15 @@ import { RepositoriesManager } from './repositoriesManager';
1212

1313
export class TasksDashboardManager extends Disposable implements vscode.WebviewPanelSerializer {
1414
public static readonly viewType = 'github-pull-request.projectTasksDashboard';
15+
private static readonly viewTitle = vscode.l10n.t('Tasks Dashboard');
1516

1617
private _currentView: {
1718
readonly webview: vscode.WebviewPanel;
1819
readonly dashboardProvider: DashboardWebviewProvider;
1920
readonly disposables: vscode.Disposable[];
2021
} | undefined;
2122

22-
private readonly statusBarItem?: vscode.StatusBarItem;
23-
24-
private readonly viewTitle = vscode.l10n.t('Tasks Dashboard');
23+
private _statusBarItem?: vscode.StatusBarItem;
2524

2625
constructor(
2726
private readonly _context: vscode.ExtensionContext,
@@ -31,15 +30,14 @@ export class TasksDashboardManager extends Disposable implements vscode.WebviewP
3130
) {
3231
super();
3332

34-
// Create status bar item for task dashboard if enabled
35-
const dashboardEnabled = vscode.workspace.getConfiguration('githubPullRequests').get<boolean>('projectTasksDashboard.enabled', false);
36-
if (dashboardEnabled) {
37-
(this as any).statusBarItem = this._register(vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100));
38-
this.statusBarItem!.text = '$(dashboard) Tasks';
39-
this.statusBarItem!.tooltip = vscode.l10n.t('Open GitHub Tasks Dashboard');
40-
this.statusBarItem!.command = 'pr.openTasksDashboard';
41-
this.statusBarItem!.show();
42-
}
33+
// Create status bar item for launching dashboard
34+
this.updateStatusBarItem();
35+
36+
this._register(vscode.workspace.onDidChangeConfiguration(e => {
37+
if (e.affectsConfiguration('githubPullRequests.projectTasksDashboard.enabled')) {
38+
this.updateStatusBarItem();
39+
}
40+
}));
4341

4442
// Register webview panel serializer for tasks dashboard
4543
this._register(vscode.window.registerWebviewPanelSerializer(TasksDashboardManager.viewType, this));
@@ -50,6 +48,28 @@ export class TasksDashboardManager extends Disposable implements vscode.WebviewP
5048

5149
this._currentView?.disposables.forEach(d => d.dispose());
5250
this._currentView = undefined;
51+
52+
this._statusBarItem?.dispose();
53+
this._statusBarItem = undefined;
54+
}
55+
56+
private updateStatusBarItem(): void {
57+
const dashboardEnabled = vscode.workspace.getConfiguration('githubPullRequests')
58+
.get<boolean>('projectTasksDashboard.enabled', false);
59+
60+
if (dashboardEnabled && !this._statusBarItem) {
61+
// Create status bar item if it doesn't exist and is now enabled
62+
this._statusBarItem = this._register(vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, 100));
63+
this._statusBarItem.text = '$(dashboard) Tasks';
64+
this._statusBarItem.tooltip = vscode.l10n.t('Open GitHub Tasks Dashboard');
65+
this._statusBarItem.command = 'pr.projectTasksDashboard.open';
66+
this._statusBarItem.show();
67+
} else if (!dashboardEnabled && this._statusBarItem) {
68+
// Hide and dispose status bar item if it exists and is now disabled
69+
this._statusBarItem.hide();
70+
this._statusBarItem.dispose();
71+
this._statusBarItem = undefined;
72+
}
5373
}
5474

5575
public async deserializeWebviewPanel(webviewPanel: vscode.WebviewPanel, _state: {}): Promise<void> {
@@ -69,7 +89,7 @@ export class TasksDashboardManager extends Disposable implements vscode.WebviewP
6989
};
7090

7191
webviewPanel.iconPath = vscode.Uri.joinPath(this._context.extensionUri, 'resources/icons/github_logo.png');
72-
webviewPanel.title = this.viewTitle;
92+
webviewPanel.title = TasksDashboardManager.viewTitle;
7393

7494
const issueQuery = this.getIssueQuery();
7595

@@ -114,7 +134,7 @@ export class TasksDashboardManager extends Disposable implements vscode.WebviewP
114134

115135
const newWebviewPanel = vscode.window.createWebviewPanel(
116136
TasksDashboardManager.viewType,
117-
this.viewTitle,
137+
TasksDashboardManager.viewTitle,
118138
vscode.ViewColumn.Active,
119139
{
120140
enableScripts: true,

webviews/dashboardView/app.tsx

Lines changed: 41 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import React, { useCallback, useEffect, useState } from 'react';
5+
import React, { useCallback, useEffect, useMemo, useState } from 'react';
66

77
import { render } from 'react-dom';
88
import { ChatInput } from './components/ChatInput';
99
import { EmptyState } from './components/EmptyState';
10-
import { FilterButton, FilterState } from './components/FilterButton';
1110
import { GlobalSessionItem } from './components/GlobalSessionItem';
1211
import { IssueItem } from './components/IssueItem';
1312
import { LoadingState } from './components/LoadingState';
@@ -19,27 +18,11 @@ export function main() {
1918
render(<Dashboard />, document.getElementById('app'));
2019
}
2120

22-
// Check if a session is associated with a specific issue
23-
function isSessionAssociatedWithIssue(session: SessionData, issue: IssueData): boolean {
24-
if (session.isLocal) return false;
25-
26-
// Use the same logic as findAssociatedSession
27-
const sessionTitle = session.title.toLowerCase();
28-
const issueNumber = `#${issue.number}`;
29-
const issueTitle = issue.title.toLowerCase();
30-
31-
// Match by issue number reference or similar title
32-
return sessionTitle.includes(issueNumber) ||
33-
sessionTitle.includes(issueTitle) ||
34-
issueTitle.includes(sessionTitle);
35-
}
36-
3721
function Dashboard() {
3822
const [dashboardState, setDashboardState] = useState<DashboardState | null>(null);
3923
const [refreshing, setRefreshing] = useState(false);
4024
const [issueSort, setIssueSort] = useState<'date-oldest' | 'date-newest'>('date-oldest');
4125
const [hoveredIssue, setHoveredIssue] = useState<IssueData | null>(null);
42-
const [globalFilter, setGlobalFilter] = useState<FilterState>({ showTasks: true, showProjects: true });
4326
const [chatInputValue, setChatInputValue] = useState('');
4427
const [focusTrigger, setFocusTrigger] = useState(0);
4528

@@ -185,74 +168,61 @@ function Dashboard() {
185168
}, [dashboardState]);
186169

187170
// Derived state from discriminated union with proper type narrowing
188-
const isGlobal = dashboardState?.isGlobal;
189-
const issueQuery = dashboardState && !dashboardState.isGlobal ? (dashboardState as DashboardReady).issueQuery || '' : '';
190-
const milestoneIssues = dashboardState && !dashboardState.isGlobal && dashboardState.state === 'ready' ? (dashboardState as DashboardReady).milestoneIssues : [];
191-
const activeSessions = dashboardState?.state === 'ready' ? dashboardState.activeSessions : [];
192-
const recentProjects = dashboardState && dashboardState.isGlobal && dashboardState.state === 'ready' ? (dashboardState as GlobalDashboardReady).recentProjects : [];
193-
const currentBranch = dashboardState && !dashboardState.isGlobal && dashboardState.state === 'ready' ? (dashboardState as DashboardReady).currentBranch : undefined;
171+
const isGlobal = dashboardState?.isGlobal ?? false;
172+
const isReady = dashboardState?.state === 'ready';
173+
174+
const readyState = (isReady && !isGlobal) ? dashboardState as DashboardReady : null;
175+
const globalReadyState = (isReady && isGlobal) ? dashboardState as GlobalDashboardReady : null;
176+
177+
const issueQuery = readyState?.issueQuery || '';
178+
const milestoneIssues = readyState?.milestoneIssues || [];
179+
const activeSessions = isReady ? dashboardState.activeSessions : [];
180+
const recentProjects = globalReadyState?.recentProjects || [];
181+
const currentBranch = readyState?.currentBranch;
194182

195183
// For global dashboards, create a mixed array of sessions and projects
196-
const mixedItems = isGlobal ? (() => {
184+
const mixedItems = useMemo(() => {
185+
if (!isGlobal) return [];
186+
197187
const mixed: Array<{ type: 'session', data: SessionData, index: number } | { type: 'project', data: ProjectData }> = [];
198188

199-
// Add sessions based on filter
200-
if (globalFilter.showTasks) {
201-
activeSessions.forEach((session, index) => {
202-
mixed.push({ type: 'session', data: session, index });
203-
});
204-
}
189+
activeSessions.forEach((session, index) => {
190+
mixed.push({ type: 'session', data: session, index });
191+
});
205192

206-
// Add projects based on filter
207-
if (globalFilter.showProjects) {
208-
recentProjects.forEach((project: ProjectData) => {
209-
mixed.push({ type: 'project', data: project });
210-
});
211-
}
193+
recentProjects.forEach((project: ProjectData) => {
194+
mixed.push({ type: 'project', data: project });
195+
});
212196

213-
function shuffle<T>(array: T[]): T[] {
214-
for (let i = array.length - 1; i > 0; i--) {
215-
const j = Math.floor(Math.random() * (i + 1));
216-
const tmp = array[i];
217-
array[i] = array[j];
218-
array[j] = tmp;
219-
}
220-
return array;
197+
// Simple shuffle algorithm
198+
for (let i = mixed.length - 1; i > 0; i--) {
199+
const j = Math.floor(Math.random() * (i + 1));
200+
[mixed[i], mixed[j]] = [mixed[j], mixed[i]];
221201
}
222202

223-
shuffle(mixed);
224-
225-
// Sort by recency - sessions first, then projects, but could be enhanced with actual timestamps
226203
return mixed;
227-
})() : [];
204+
}, [isGlobal, activeSessions, recentProjects]);
228205

229206
return (
230207
<div className={`dashboard-container${isGlobal ? ' global-dashboard' : ''}`}>
231208
{!isGlobal && (
232209
<div className={`dashboard-header${isGlobal ? ' global-header' : ''}`}>
233-
<h1 className="dashboard-title">
234-
{isGlobal ? 'Visual Studio Code - Insiders' : 'My Tasks'}
235-
</h1>
210+
<h1 className="dashboard-title">My Tasks</h1>
236211
<div className="header-buttons">
237-
{dashboardState?.state === 'ready' && !dashboardState.isGlobal &&
238-
((dashboardState as DashboardReady).currentBranch) &&
239-
((dashboardState as DashboardReady).currentBranch !== 'main') &&
240-
((dashboardState as DashboardReady).currentBranch !== 'master') && (
212+
{readyState?.currentBranch &&
213+
readyState.currentBranch !== 'main' &&
214+
readyState.currentBranch !== 'master' && (
241215
<button
242216
className="switch-to-main-button"
243217
onClick={handleSwitchToMain}
244-
title={`Switch from ${(dashboardState as DashboardReady).currentBranch} to main`}
218+
title={`Switch from ${readyState.currentBranch} to main`}
245219
>
246220
<span className="codicon codicon-git-branch"></span>
247221
<span>Switch to main</span>
248222
</button>
249223
)}
250224
<button className="refresh-button" onClick={handleRefresh} disabled={refreshing} title="Refresh dashboard">
251-
{refreshing ? (
252-
<span className="codicon codicon-sync codicon-modifier-spin"></span>
253-
) : (
254-
<span className="codicon codicon-refresh"></span>
255-
)}
225+
<span className={`codicon ${refreshing ? 'codicon-sync codicon-modifier-spin' : 'codicon-refresh'}`}></span>
256226
</button>
257227
</div>
258228
</div>
@@ -274,11 +244,7 @@ function Dashboard() {
274244

275245
{/* Issues/Projects Area */}
276246
<div className="issues-area">
277-
{isGlobal ? (
278-
<>
279-
{/* Empty for now, everything moved to tasks area */}
280-
</>
281-
) : (
247+
{!isGlobal && (
282248
<>
283249
<div className="area-header milestone-header">
284250
<h3
@@ -287,14 +253,14 @@ function Dashboard() {
287253
>
288254
{issueQuery ? extractMilestoneFromQuery(issueQuery) : 'Issues'}
289255
</h3>
290-
{dashboardState?.state === 'ready' && (
256+
{isReady && (
291257
<SortDropdown
292258
issueSort={issueSort}
293259
onSortChange={setIssueSort}
294260
/>
295261
)}
296262
</div>
297-
{dashboardState?.state === 'ready' && (
263+
{isReady && (
298264
<div
299265
className="section-count clickable-count"
300266
onClick={handleIssueCountClick}
@@ -306,9 +272,9 @@ function Dashboard() {
306272
<div className="area-content">
307273
{dashboardState?.state === 'loading' ? (
308274
<LoadingState message="Loading issues..." />
309-
) : dashboardState?.state === 'ready' && !milestoneIssues.length ? (
275+
) : isReady && !milestoneIssues.length ? (
310276
<EmptyState message={`No issues found for ${issueQuery ? extractMilestoneFromQuery(issueQuery).toLowerCase() : 'issues'}`} />
311-
) : dashboardState?.state === 'ready' ? (
277+
) : isReady ? (
312278
getSortedIssues(milestoneIssues).map((issue) => {
313279
const associatedSession = findAssociatedSession(issue);
314280
return (
@@ -339,24 +305,18 @@ function Dashboard() {
339305
<div className="area-header-container">
340306
<h2 className="area-header">
341307
{isGlobal ? 'Continue working on...' :
342-
dashboardState?.state === 'ready' ?
308+
isReady ?
343309
`${activeSessions.length || 0} active task${activeSessions.length !== 1 ? 's' : ''}` :
344310
'Active tasks'
345311
}
346312
</h2>
347-
{isGlobal && (
348-
<FilterButton
349-
filterState={globalFilter}
350-
onFilterChange={setGlobalFilter}
351-
/>
352-
)}
353313
</div>
354314
<div className="area-content">
355315
{dashboardState?.state === 'loading' ? (
356316
<LoadingState message="Loading tasks..." />
357-
) : dashboardState?.state === 'ready' && !activeSessions.length && (!isGlobal || !recentProjects.length) ? (
317+
) : isReady && !activeSessions.length && (!isGlobal || !recentProjects.length) ? (
358318
<EmptyState message="No active tasks found" />
359-
) : dashboardState?.state === 'ready' ? (
319+
) : isReady ? (
360320
<>
361321
{isGlobal ? (
362322
// Render mixed items for global dashboard
@@ -401,7 +361,7 @@ function Dashboard() {
401361
index={index}
402362
onSessionClick={() => handleSessionClick(session)}
403363
onPullRequestClick={handlePullRequestClick}
404-
isHighlighted={hoveredIssue !== null && isSessionAssociatedWithIssue(session, hoveredIssue)}
364+
isHighlighted={hoveredIssue !== null && findAssociatedSession(hoveredIssue)?.id === session.id}
405365
/>
406366
))
407367
)}

0 commit comments

Comments
 (0)