Skip to content

Commit b5a0ab6

Browse files
committed
filters
1 parent 164b23d commit b5a0ab6

3 files changed

Lines changed: 193 additions & 9 deletions

File tree

webviews/dashboardView/app.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import React, { useCallback, useEffect, useState } from 'react';
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';
1011
import { GlobalSessionItem } from './components/GlobalSessionItem';
1112
import { IssueItem } from './components/IssueItem';
1213
import { LoadingState } from './components/LoadingState';
@@ -38,6 +39,7 @@ function Dashboard() {
3839
const [refreshing, setRefreshing] = useState(false);
3940
const [issueSort, setIssueSort] = useState<'date-oldest' | 'date-newest'>('date-oldest');
4041
const [hoveredIssue, setHoveredIssue] = useState<IssueData | null>(null);
42+
const [globalFilter, setGlobalFilter] = useState<FilterState>({ showTasks: true, showProjects: true });
4143

4244
useEffect(() => {
4345
// Listen for messages from the extension
@@ -150,15 +152,19 @@ function Dashboard() {
150152
const mixedItems = isGlobal ? (() => {
151153
const mixed: Array<{ type: 'session', data: SessionData, index: number } | { type: 'project', data: ProjectData }> = [];
152154

153-
// Add sessions
154-
activeSessions.forEach((session, index) => {
155-
mixed.push({ type: 'session', data: session, index });
156-
});
155+
// Add sessions based on filter
156+
if (globalFilter.showTasks) {
157+
activeSessions.forEach((session, index) => {
158+
mixed.push({ type: 'session', data: session, index });
159+
});
160+
}
157161

158-
// Add projects
159-
recentProjects.forEach((project: ProjectData) => {
160-
mixed.push({ type: 'project', data: project });
161-
});
162+
// Add projects based on filter
163+
if (globalFilter.showProjects) {
164+
recentProjects.forEach((project: ProjectData) => {
165+
mixed.push({ type: 'project', data: project });
166+
});
167+
}
162168

163169
function shuffle<T>(array: T[]): T[] {
164170
for (let i = array.length - 1; i > 0; i--) {
@@ -258,7 +264,15 @@ function Dashboard() {
258264

259265
{/* Tasks Area */}
260266
<div className="tasks-area">
261-
<h2 className="area-header">{isGlobal ? 'Continue working on...' : 'Active tasks'}</h2>
267+
<div className="area-header-container">
268+
<h2 className="area-header">{isGlobal ? 'Continue working on...' : 'Active tasks'}</h2>
269+
{isGlobal && (
270+
<FilterButton
271+
filterState={globalFilter}
272+
onFilterChange={setGlobalFilter}
273+
/>
274+
)}
275+
</div>
262276
{dashboardState?.state === 'ready' && (
263277
<div className="section-count">
264278
{activeSessions.length || 0} task{activeSessions.length !== 1 ? 's' : ''}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import React, { useEffect, useRef, useState } from 'react';
7+
8+
export interface FilterState {
9+
showTasks: boolean;
10+
showProjects: boolean;
11+
}
12+
13+
interface FilterButtonProps {
14+
filterState: FilterState;
15+
onFilterChange: (filterState: FilterState) => void;
16+
}
17+
18+
export const FilterButton: React.FC<FilterButtonProps> = ({ filterState, onFilterChange }) => {
19+
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
20+
const dropdownRef = useRef<HTMLDivElement>(null);
21+
22+
// Close dropdown when clicking outside
23+
useEffect(() => {
24+
const handleClickOutside = (event: MouseEvent) => {
25+
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
26+
setIsDropdownOpen(false);
27+
}
28+
};
29+
30+
if (isDropdownOpen) {
31+
document.addEventListener('mousedown', handleClickOutside);
32+
}
33+
34+
return () => {
35+
document.removeEventListener('mousedown', handleClickOutside);
36+
};
37+
}, [isDropdownOpen]);
38+
39+
const handleToggleDropdown = () => {
40+
setIsDropdownOpen(!isDropdownOpen);
41+
};
42+
43+
const handleTasksToggle = () => {
44+
onFilterChange({
45+
...filterState,
46+
showTasks: !filterState.showTasks
47+
});
48+
};
49+
50+
const handleProjectsToggle = () => {
51+
onFilterChange({
52+
...filterState,
53+
showProjects: !filterState.showProjects
54+
});
55+
};
56+
57+
const getIcon = () => {
58+
const isFiltering = !filterState.showTasks || !filterState.showProjects;
59+
return isFiltering ? 'codicon-filter-filled' : 'codicon-filter';
60+
};
61+
62+
const getTooltip = () => {
63+
if (filterState.showTasks && filterState.showProjects) {
64+
return 'Filter items (showing all)';
65+
} else if (filterState.showTasks && !filterState.showProjects) {
66+
return 'Filter items (showing tasks only)';
67+
} else if (!filterState.showTasks && filterState.showProjects) {
68+
return 'Filter items (showing projects only)';
69+
} else {
70+
return 'Filter items (showing none)';
71+
}
72+
};
73+
74+
return (
75+
<div className="filter-dropdown" ref={dropdownRef}>
76+
<button
77+
className="filter-button"
78+
onClick={handleToggleDropdown}
79+
title={getTooltip()}
80+
>
81+
<span className={`codicon ${getIcon()}`}></span>
82+
</button>
83+
{isDropdownOpen && (
84+
<div className="filter-dropdown-menu">
85+
<div className="filter-dropdown-item" onClick={handleTasksToggle}>
86+
<span className={`codicon ${filterState.showTasks ? 'codicon-check' : 'codicon-blank'}`}></span>
87+
<span className="filter-dropdown-label">Tasks</span>
88+
</div>
89+
<div className="filter-dropdown-item" onClick={handleProjectsToggle}>
90+
<span className={`codicon ${filterState.showProjects ? 'codicon-check' : 'codicon-blank'}`}></span>
91+
<span className="filter-dropdown-label">Projects</span>
92+
</div>
93+
</div>
94+
)}
95+
</div>
96+
);
97+
};

webviews/dashboardView/index.css

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,79 @@ body {
190190
color: var(--vscode-foreground);
191191
}
192192

193+
.area-header-container {
194+
display: flex;
195+
align-items: center;
196+
justify-content: space-between;
197+
margin-bottom: 4px;
198+
}
199+
200+
.filter-button {
201+
background: transparent;
202+
border: none;
203+
color: var(--vscode-foreground);
204+
cursor: pointer;
205+
padding: 4px;
206+
border-radius: 3px;
207+
display: flex;
208+
align-items: center;
209+
justify-content: center;
210+
transition: background-color 0.2s ease;
211+
}
212+
213+
.filter-button:hover {
214+
background-color: var(--vscode-toolbar-hoverBackground);
215+
}
216+
217+
.filter-button:active {
218+
background-color: var(--vscode-toolbar-activeBackground);
219+
}
220+
221+
.filter-button .codicon {
222+
font-size: 14px;
223+
}
224+
225+
.filter-dropdown {
226+
position: relative;
227+
display: inline-block;
228+
}
229+
230+
.filter-dropdown-menu {
231+
position: absolute;
232+
top: 100%;
233+
right: 0;
234+
background: var(--vscode-menu-background);
235+
border: 1px solid var(--vscode-menu-border);
236+
border-radius: 3px;
237+
box-shadow: 0 2px 8px var(--vscode-widget-shadow);
238+
z-index: 1000;
239+
min-width: 120px;
240+
padding: 4px 0;
241+
}
242+
243+
.filter-dropdown-item {
244+
display: flex;
245+
align-items: center;
246+
padding: 6px 12px;
247+
cursor: pointer;
248+
color: var(--vscode-menu-foreground);
249+
transition: background-color 0.2s ease;
250+
}
251+
252+
.filter-dropdown-item:hover {
253+
background-color: var(--vscode-menu-selectionBackground);
254+
color: var(--vscode-menu-selectionForeground);
255+
}
256+
257+
.filter-dropdown-item .codicon {
258+
margin-right: 8px;
259+
font-size: 12px;
260+
}
261+
262+
.filter-dropdown-label {
263+
font-size: 13px;
264+
}
265+
193266
.area-content {
194267
flex: 1;
195268
overflow-y: auto;

0 commit comments

Comments
 (0)