diff --git a/apps/desktop/src/app/chat/sidebar/index.tsx b/apps/desktop/src/app/chat/sidebar/index.tsx index f1587dcc3dc80..2e83cd75f199f 100644 --- a/apps/desktop/src/app/chat/sidebar/index.tsx +++ b/apps/desktop/src/app/chat/sidebar/index.tsx @@ -127,6 +127,7 @@ import { $sidebarSessionRankIds } from '@/store/sidebar-sort' import { type AppView, ARTIFACTS_ROUTE, + CRON_ROUTE, MESSAGING_ROUTE, SIDEBAR_NAV_AREA, type SidebarNavContribution, @@ -203,6 +204,13 @@ const SIDEBAR_NAV: SidebarNavItem[] = [ icon: props => , route: ARTIFACTS_ROUTE, keybindActionId: 'nav.artifacts' + }, + { + id: 'cron', + label: '', + icon: props => , + route: CRON_ROUTE, + keybindActionId: 'nav.cron' } ] @@ -1405,6 +1413,7 @@ export function ChatSidebar({ (item.id === 'skills' && currentView === 'skills') || (item.id === 'messaging' && currentView === 'messaging') || (item.id === 'artifacts' && currentView === 'artifacts') || + (item.id === 'cron' && currentView === 'cron') || // Contributed rows light up at their own route. (Boolean(item.route) && pathname === item.route) diff --git a/apps/desktop/src/app/cron/index.tsx b/apps/desktop/src/app/cron/index.tsx index 9f89b0d923fb0..ca18aaa2db444 100644 --- a/apps/desktop/src/app/cron/index.tsx +++ b/apps/desktop/src/app/cron/index.tsx @@ -356,6 +356,23 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt [jobs, query] ) + // Blueprint recipes render in the same list rail, below the jobs — clicking + // one opens the create dialog pre-seeded to that recipe. Same query key as + // the dialog's "Start from" dropdown, so the catalog is fetched once. + const blueprintsQuery = useQuery({ + queryKey: ['cron-blueprints'], + queryFn: async () => (await getAutomationBlueprints()).blueprints + }) + + const visibleBlueprints = useMemo(() => { + const list = blueprintsQuery.data ?? [] + const needle = query.trim().toLowerCase() + + return needle + ? list.filter(item => `${item.title} ${item.description}`.toLowerCase().includes(needle)) + : list + }, [blueprintsQuery.data, query]) + // Detail always reflects a concrete job: the explicitly selected one, else the // first visible row, so the right pane is never empty while jobs exist. const selectedJob = useMemo( @@ -480,7 +497,7 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt {loading && jobs.length === 0 ? ( - ) : totalCount === 0 ? ( + ) : totalCount === 0 && visibleBlueprints.length === 0 ? ( setEditor({ mode: 'create' })} size="sm"> @@ -521,6 +538,21 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt

{c.emptyTitleSearch}

)} setEditor({ mode: 'create' })} /> + {visibleBlueprints.length > 0 && ( + <> + {c.blueprints.tab} + {visibleBlueprints.map(item => ( + setEditor({ blueprintKey: item.key, mode: 'create' })} + rowKey={`blueprint-${item.key}`} + title={item.title} + /> + ))} + + )} {selectedJob ? ( @@ -919,10 +951,10 @@ function CronEditorDialog({ setDeliver(initial ? jobDeliver(initial) : DEFAULT_DELIVER) setModelChoice(initial && jobModel(initial) ? `${jobProvider(initial)}:${jobModel(initial)}` : MODEL_DEFAULT_VALUE) setSlotValues({}) - setTemplateChoice(CUSTOM_TEMPLATE) + setTemplateChoice(editor.mode === 'create' ? (editor.blueprintKey ?? CUSTOM_TEMPLATE) : CUSTOM_TEMPLATE) setError(null) setSaving(false) - }, [initial, open]) + }, [editor, initial, open]) // Seed the typed slots with the blueprint's defaults whenever a blueprint is // picked from "Start from" (and reset them when switching back to Custom). @@ -1232,7 +1264,12 @@ function CronEditorDialog({ ) } -type EditorState = { job: CronJob; mode: 'edit' } | { mode: 'closed' } | { mode: 'create' } +type EditorState = + | { job: CronJob; mode: 'edit' } + | { mode: 'closed' } + // `blueprintKey` pre-selects a blueprint in the create dialog's "Start from" + // dropdown (set when a recipe row in the list rail is clicked). + | { blueprintKey?: string; mode: 'create' } interface EditorValues { deliver: string diff --git a/apps/desktop/src/app/types.ts b/apps/desktop/src/app/types.ts index 743c2b95be019..fe9398d7bbf02 100644 --- a/apps/desktop/src/app/types.ts +++ b/apps/desktop/src/app/types.ts @@ -158,7 +158,7 @@ export type CommandDispatchResponse = | SendCommandDispatchResponse | PrefillCommandDispatchResponse -export type SidebarNavId = 'artifacts' | 'command-center' | 'messaging' | 'new-session' | 'settings' | 'skills' +export type SidebarNavId = 'artifacts' | 'command-center' | 'cron' | 'messaging' | 'new-session' | 'settings' | 'skills' export interface SidebarNavItem { /** Built-in view id, or a contributed row's namespaced contribution id. */ diff --git a/apps/desktop/src/i18n/en.ts b/apps/desktop/src/i18n/en.ts index 3160533d69d1a..35916ae65cc6c 100644 --- a/apps/desktop/src/i18n/en.ts +++ b/apps/desktop/src/i18n/en.ts @@ -1865,7 +1865,8 @@ export const en: Translations = { 'new-session': 'New session', skills: 'Capabilities', messaging: 'Messaging', - artifacts: 'Artifacts' + artifacts: 'Artifacts', + cron: 'Scheduled jobs' }, searchAria: 'Search sessions', searchPlaceholder: 'Search sessions…', diff --git a/apps/desktop/src/i18n/ja.ts b/apps/desktop/src/i18n/ja.ts index 6ff8e056ac5e5..a4e49cc8f6948 100644 --- a/apps/desktop/src/i18n/ja.ts +++ b/apps/desktop/src/i18n/ja.ts @@ -1689,7 +1689,8 @@ export const ja = defineLocale({ 'new-session': '新しいセッション', skills: 'スキルとツール', messaging: 'メッセージング', - artifacts: 'アーティファクト' + artifacts: 'アーティファクト', + cron: 'スケジュール済みジョブ' }, searchAria: 'セッションを検索', searchPlaceholder: 'セッションを検索…', diff --git a/apps/desktop/src/i18n/zh-hant.ts b/apps/desktop/src/i18n/zh-hant.ts index 9e1bfad1cc0c5..1020be810d1dd 100644 --- a/apps/desktop/src/i18n/zh-hant.ts +++ b/apps/desktop/src/i18n/zh-hant.ts @@ -1634,7 +1634,8 @@ export const zhHant = defineLocale({ 'new-session': '新工作階段', skills: '技能與工具', messaging: '訊息平台', - artifacts: '成品' + artifacts: '成品', + cron: '排程工作' }, searchAria: '搜尋工作階段', searchPlaceholder: '搜尋工作階段…', diff --git a/apps/desktop/src/i18n/zh.ts b/apps/desktop/src/i18n/zh.ts index b6063d1cb45fb..471fa8767a324 100644 --- a/apps/desktop/src/i18n/zh.ts +++ b/apps/desktop/src/i18n/zh.ts @@ -2056,7 +2056,8 @@ export const zh: Translations = { 'new-session': '新建会话', skills: '技能与工具', messaging: '消息平台', - artifacts: '产物' + artifacts: '产物', + cron: '定时任务' }, searchAria: '搜索会话', searchPlaceholder: '搜索会话…',