Skip to content

Commit 85f3b7e

Browse files
committed
tag setting, display and filter
1 parent 121fcf3 commit 85f3b7e

File tree

2 files changed

+107
-24
lines changed

2 files changed

+107
-24
lines changed

src/renderer/components/TaskLibrary/NewTaskModal.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export default function NewTaskModal({ open, onClose, onSuccess }: NewTaskModalP
3131
const [taskName, setTaskName] = useState('');
3232
const [description, setDescription] = useState('');
3333
const [selectedTaskId, setSelectedTaskId] = useState('');
34+
const [tag, setTag] = useState('OTHER');
3435
const [isSubmitting, setIsSubmitting] = useState(false);
3536
const [error, setError] = useState('');
3637
const { addNotification } = useNotification();
@@ -57,6 +58,7 @@ export default function NewTaskModal({ open, onClose, onSuccess }: NewTaskModalP
5758
form.set('task_name', taskName.trim());
5859
form.set('description', description.trim());
5960
form.set('source_task_id', selectedTaskId);
61+
form.set('tag', tag);
6062

6163
const response = await fetch(url, {
6264
method: 'POST',
@@ -79,6 +81,7 @@ export default function NewTaskModal({ open, onClose, onSuccess }: NewTaskModalP
7981
setTaskName('');
8082
setDescription('');
8183
setSelectedTaskId('');
84+
setTag('OTHER');
8285
} else {
8386
setError(result.message || 'Failed to create task');
8487
}
@@ -97,6 +100,7 @@ export default function NewTaskModal({ open, onClose, onSuccess }: NewTaskModalP
97100
setTaskName('');
98101
setDescription('');
99102
setSelectedTaskId('');
103+
setTag('OTHER');
100104
setError('');
101105
onClose();
102106
};
@@ -151,6 +155,19 @@ export default function NewTaskModal({ open, onClose, onSuccess }: NewTaskModalP
151155
)}
152156
</FormControl>
153157

158+
<FormControl>
159+
<FormLabel>Tag</FormLabel>
160+
<Select
161+
value={tag}
162+
onChange={(_, value) => setTag(value || 'OTHER')}
163+
required
164+
>
165+
<Option value="TRAIN">TRAIN</Option>
166+
<Option value="EVAL">EVAL</Option>
167+
<Option value="OTHER">OTHER</Option>
168+
</Select>
169+
</FormControl>
170+
154171
{error && (
155172
<Alert color="danger">
156173
{error}

src/renderer/components/TaskLibrary/TaskLibrary.tsx

Lines changed: 90 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import Typography from '@mui/joy/Typography';
88
import Box from '@mui/joy/Box';
99
import IconButton from '@mui/joy/IconButton';
1010
import Button from '@mui/joy/Button';
11+
import Select from '@mui/joy/Select';
12+
import Option from '@mui/joy/Option';
1113
import { useMemo, useState } from 'react';
1214
import {
1315
RectangleVerticalIcon,
@@ -35,29 +37,49 @@ export default function TaskLibrary() {
3537
// local overlay for create/edit/delete without waiting for refetch
3638
const [overlayTasks, setOverlayTasks] = useState<any[]>([]);
3739

40+
// Filtering state
41+
const [sourceFilter, setSourceFilter] = useState<'all' | 'gallery' | 'local'>('all');
42+
const [tagFilter, setTagFilter] = useState<string>('all');
43+
3844
const tasks = useMemo(() => {
3945
const localGallery: any[] = localGalleryResp?.data ?? [];
4046
const remoteGallery: any[] = remoteGalleryResp?.data ?? [];
4147

42-
const localGalleryMapped = localGallery.map((g: any) => ({
43-
id: `local:${g.subdir || g.id || g.name}`,
44-
title: g.name || g.title || g.task_name || 'Task',
45-
description: g.description || '',
46-
_isLocal: true,
47-
_subdir: g.subdir,
48-
}));
49-
50-
const remoteGalleryMapped = remoteGallery.map((g: any) => ({
51-
id: `gallery:${g.subdir || g.id || g.name}`,
52-
title: g.name || g.title || g.task_name || 'Task',
53-
description: g.description || '',
54-
_isGallery: true,
55-
_subdir: g.subdir,
56-
}));
48+
const localGalleryMapped = localGallery.map((g: any) => ({
49+
id: `local:${g.subdir || g.id || g.name}`,
50+
title: g.name || g.title || g.task_name || 'Task',
51+
description: g.description || '',
52+
_isLocal: true,
53+
_subdir: g.subdir,
54+
_tag: g.tag || 'OTHER',
55+
}));
56+
57+
const remoteGalleryMapped = remoteGallery.map((g: any) => ({
58+
id: `gallery:${g.subdir || g.id || g.name}`,
59+
title: g.name || g.title || g.task_name || 'Task',
60+
description: g.description || '',
61+
_isGallery: true,
62+
_subdir: g.subdir,
63+
_tag: g.tag || 'OTHER',
64+
}));
5765

5866
return [...localGalleryMapped, ...remoteGalleryMapped, ...overlayTasks];
5967
}, [localGalleryResp, remoteGalleryResp, overlayTasks]);
6068

69+
// Filter tasks based on source and tag filters
70+
const filteredTasks = useMemo(() => {
71+
return tasks.filter((task) => {
72+
// Source filter
73+
if (sourceFilter === 'gallery' && !task._isGallery) return false;
74+
if (sourceFilter === 'local' && !task._isLocal) return false;
75+
76+
// Tag filter
77+
if (tagFilter !== 'all' && task._tag !== tagFilter) return false;
78+
79+
return true;
80+
});
81+
}, [tasks, sourceFilter, tagFilter]);
82+
6183
// modal state to show TaskModal when creating/viewing a task
6284
const [modalOpen, setModalOpen] = useState(false);
6385
const [modalTask, setModalTask] = useState<any | null>(null);
@@ -207,14 +229,51 @@ export default function TaskLibrary() {
207229
</Button>
208230
</Box>
209231
</Box>
232+
233+
{/* Filter Controls */}
234+
<Box sx={{ px: 2, py: 1, display: 'flex', gap: 2, alignItems: 'center' }}>
235+
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
236+
<Typography level="body-sm" sx={{ minWidth: 'fit-content' }}>
237+
Source:
238+
</Typography>
239+
<Select
240+
value={sourceFilter}
241+
onChange={(_, value) => setSourceFilter(value || 'all')}
242+
size="sm"
243+
sx={{ minWidth: 100 }}
244+
>
245+
<Option value="all">All</Option>
246+
<Option value="gallery">Gallery</Option>
247+
<Option value="local">Local</Option>
248+
</Select>
249+
</Box>
250+
251+
<Box sx={{ display: 'flex', gap: 1, alignItems: 'center' }}>
252+
<Typography level="body-sm" sx={{ minWidth: 'fit-content' }}>
253+
Tag:
254+
</Typography>
255+
<Select
256+
value={tagFilter}
257+
onChange={(_, value) => setTagFilter(value || 'all')}
258+
size="sm"
259+
sx={{ minWidth: 100 }}
260+
>
261+
<Option value="all">All</Option>
262+
<Option value="TRAIN">TRAIN</Option>
263+
<Option value="EVAL">EVAL</Option>
264+
<Option value="OTHER">OTHER</Option>
265+
</Select>
266+
</Box>
267+
</Box>
268+
210269
<List
211270
sx={{
212271
overflow: 'auto',
213272
gap: 1,
214273
pt: 2,
215274
}}
216275
>
217-
{tasks.map((task: any) => (
276+
{filteredTasks.map((task: any) => (
218277
<ListItem
219278
key={task.id}
220279
sx={{
@@ -234,20 +293,27 @@ export default function TaskLibrary() {
234293
<Typography level="body-sm" textColor="text.tertiary">
235294
{task.description}
236295
</Typography>
237-
{task._isLocal && (
238-
<Box sx={{ mt: 0.5 }}>
296+
<Box sx={{ mt: 0.5, display: 'flex', gap: 0.5, flexWrap: 'wrap' }}>
297+
{task._isLocal && (
239298
<Chip size="sm" color="success" variant="soft">
240299
Local
241300
</Chip>
242-
</Box>
243-
)}
244-
{task._isGallery && (
245-
<Box sx={{ mt: 0.5 }}>
301+
)}
302+
{task._isGallery && (
246303
<Chip size="sm" color="primary" variant="soft">
247304
Gallery
248305
</Chip>
249-
</Box>
250-
)}
306+
)}
307+
{task._tag && (
308+
<Chip
309+
size="sm"
310+
color={task._tag === 'TRAIN' ? 'warning' : task._tag === 'EVAL' ? 'info' : 'neutral'}
311+
variant="soft"
312+
>
313+
{task._tag}
314+
</Chip>
315+
)}
316+
</Box>
251317
</ListItemContent>
252318

253319
<Box

0 commit comments

Comments
 (0)