Skip to content

Commit 8073dc9

Browse files
committed
feat(inbox): offer AI clarify in the guided processing clarify step (#1022)
1 parent a9e2a57 commit 8073dc9

4 files changed

Lines changed: 73 additions & 2 deletions

File tree

apps/desktop/src/components/InboxProcessingWizard.tsx

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { memo, useEffect, useRef, useState } from 'react';
2-
import { ArrowRight, BookOpen, Check, CheckCircle, ChevronLeft, ClipboardList, Clock, Trash2, User, X } from 'lucide-react';
3-
import { DEFAULT_PROJECT_COLOR, filterProjectsBySelectedArea, formatTimeEstimateLabel, safeFormatDate, safeParseDate, tFallback, type Area, type Project, type Task, type TaskDraft, type TaskDraftSetter, type TaskPriority, type TimeEstimate } from '@mindwtr/core';
2+
import { ArrowRight, BookOpen, Check, CheckCircle, ChevronLeft, ClipboardList, Clock, Loader2, Sparkles, Trash2, User, X } from 'lucide-react';
3+
import { DEFAULT_PROJECT_COLOR, filterProjectsBySelectedArea, formatTimeEstimateLabel, safeFormatDate, safeParseDate, tFallback, type AppData, type Area, type Project, type Task, type TaskDraft, type TaskDraftSetter, type TaskPriority, type TimeEstimate } from '@mindwtr/core';
44

55
import { cn } from '../lib/utils';
66
import { useNativeDateInputLocale } from '../hooks/use-native-date-input-locale';
@@ -15,6 +15,8 @@ import {
1515
type InboxProcessingOptionLists,
1616
type InboxProcessingVisibility,
1717
} from './views/inbox/inbox-processing-utils';
18+
import { TaskEditorAiPanels } from './Task/TaskEditorAiPanels';
19+
import { useTaskItemAi } from './Task/useTaskItemAi';
1820
import { TokenAutocompleteInput } from './Task/TokenAutocompleteInput';
1921
import { AutocompleteTextInput } from './ui/AutocompleteTextInput';
2022
import { AreaSelector } from './ui/AreaSelector';
@@ -89,6 +91,8 @@ export type InboxProcessingWizardProps = {
8991
showProjectInRefine: boolean;
9092
scheduleFields: InboxProcessingScheduleFieldsControls;
9193
visibleScheduleFieldKeys: InboxProcessingScheduleFieldKey[];
94+
/** Only for the AI-enabled switch behind the clarify step's assistant. */
95+
settings?: AppData['settings'];
9296
};
9397

9498
const PRIORITY_OPTIONS: TaskPriority[] = ['low', 'medium', 'high', 'urgent'];
@@ -158,6 +162,7 @@ export const InboxProcessingWizard = memo(function InboxProcessingWizard({
158162
showProjectInRefine,
159163
scheduleFields,
160164
visibleScheduleFieldKeys,
165+
settings,
161166
}: InboxProcessingWizardProps) {
162167
const { nativeDateInputLocale, dateFormatSetting } = useNativeDateInputLocale();
163168
const {
@@ -203,6 +208,28 @@ export const InboxProcessingWizard = memo(function InboxProcessingWizard({
203208
const setSelectedProjectId = (value: string | null) => setField('projectId', value ?? '');
204209
const setSelectedAreaId = (value: string | null) => setField('areaId', value ?? '');
205210

211+
// The same clarify action the task editor offers, on the task being
212+
// processed (#1022). Copilot stays off: the wizard makes no background AI
213+
// calls, only the one the user asks for.
214+
const ai = useTaskItemAi({
215+
taskId: processingTask?.id ?? '',
216+
settings,
217+
t,
218+
editTitle: draft.title,
219+
editDescription: draft.description,
220+
editContexts: draft.contexts,
221+
editTags: draft.tags,
222+
editStartTime: draft.startTime,
223+
editDueDate: draft.dueDate,
224+
editReviewAt: draft.reviewAt,
225+
contextOptions: allContexts,
226+
tagOptions: allTags,
227+
projectContext: null,
228+
timeEstimatesEnabled: showTimeEstimateField,
229+
setField,
230+
copilotEnabled: false,
231+
});
232+
206233
// After a long step is submitted the view is left scrolled to the bottom;
207234
// bring the panel top (title of the next task) back into view on advance.
208235
const panelRef = useRef<HTMLDivElement | null>(null);
@@ -396,6 +423,30 @@ export const InboxProcessingWizard = memo(function InboxProcessingWizard({
396423
/>
397424
</div>
398425
)}
426+
{ai.aiEnabled && (
427+
<div className="flex flex-col gap-2 text-xs">
428+
<div className="flex items-center gap-2">
429+
<button
430+
type="button"
431+
onClick={ai.handleAIClarify}
432+
disabled={ai.isAIWorking}
433+
aria-busy={ai.isAIWorking}
434+
className="inline-flex items-center gap-1.5 rounded-md px-2 py-1 font-medium text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-60"
435+
>
436+
{ai.isAIWorking
437+
? <Loader2 className="h-3.5 w-3.5 animate-spin" />
438+
: <Sparkles className="h-3.5 w-3.5" />}
439+
{t('taskEdit.aiClarify')}
440+
</button>
441+
{ai.isAIWorking && (
442+
<span role="status" aria-live="polite" className="text-muted-foreground">
443+
{tFallback(t, 'ai.working', 'Working...')}
444+
</span>
445+
)}
446+
</div>
447+
<TaskEditorAiPanels ai={ai} timeEstimatesEnabled={showTimeEstimateField} t={t} />
448+
</div>
449+
)}
399450
</div>
400451
</div>
401452
) : null}

apps/desktop/src/components/views/InboxProcessor.test.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1068,4 +1068,22 @@ describe('InboxProcessor', () => {
10681068
const [, updates] = updateTask.mock.calls[updateTask.mock.calls.length - 1] as [string, Task];
10691069
expect(updates.description).toBeUndefined();
10701070
});
1071+
1072+
it('offers AI clarify in the guided refine step when AI is on (#1022)', () => {
1073+
const { getByRole } = renderInboxProcessor({
1074+
settings: { ai: { enabled: true, provider: 'openai' } },
1075+
});
1076+
1077+
fireEvent.click(getByRole('button', { name: /process\.btn/i }));
1078+
1079+
expect(getByRole('button', { name: 'taskEdit.aiClarify' })).toBeInTheDocument();
1080+
});
1081+
1082+
it('leaves the refine step free of AI actions when AI is off', () => {
1083+
const { getByRole, queryByRole } = renderInboxProcessor();
1084+
1085+
fireEvent.click(getByRole('button', { name: /process\.btn/i }));
1086+
1087+
expect(queryByRole('button', { name: 'taskEdit.aiClarify' })).not.toBeInTheDocument();
1088+
});
10711089
});

apps/desktop/src/components/views/inbox/useInboxProcessingController.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -873,6 +873,7 @@ export function useInboxProcessingController({
873873
showProjectInRefine: projectFirst && showProjectStep,
874874
scheduleFields,
875875
visibleScheduleFieldKeys,
876+
settings,
876877
};
877878

878879
return {

docs/release-notes/unreleased.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Changes collected after `v1.1.6` and before the next version tag.
1414
- Recurrence: completing a repeating task late no longer creates a next copy whose start date sits after its own due date — start, due, and review dates now move forward together, keeping the gaps you set between them, and the new copy is never already overdue the moment it appears. Desktop and mobile.
1515
- Task editor: the Person field now appears automatically while a task is edited as Waiting For, so an existing task can be assigned to someone without first customizing the editor layout. Desktop and mobile. (#1021)
1616
- AI Copilot: suggestions now apply one piece at a time — tap the suggested context, time estimate, or any tag on its own, or apply all of them at once. Works in the task editor, the desktop list's add-task row, and mobile quick capture. (#1022)
17+
- Process Inbox: the guided clarify step now offers the AI clarify action when the AI assistant is switched on. Desktop. (#1022)
1718

1819
- Calendar: a task with a start date but no time now shows "All day" in the desktop month grid and the mobile schedule list, instead of a phantom midnight time (shown as "12:00" on 12-hour clocks).
1920
- Desktop: attachment links pointing at a folder (for example `D:\Media\Movies\`) now open in the file manager instead of failing with "Path is outside Mindwtr-managed locations". Links to files anywhere already worked; folders now match.

0 commit comments

Comments
 (0)