@yancyyu/openhermit 1.6.37 → 1.6.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/dist-renderer/assets/ProjectEditorOverlay-krO5vQxX.js +58 -0
  2. package/dist-renderer/assets/{TeamGraphOverlay-DYT3bwFR.js → TeamGraphOverlay-DqhQzcTr.js} +1 -1
  3. package/dist-renderer/assets/{_basePickBy-Dbt_EU-e.js → _basePickBy-B7kSYPxr.js} +1 -1
  4. package/dist-renderer/assets/{_baseUniq-DWo68sXI.js → _baseUniq-CnjxqwAk.js} +1 -1
  5. package/dist-renderer/assets/{arc-DXH1iZQK.js → arc-CLeZuINP.js} +1 -1
  6. package/dist-renderer/assets/{architectureDiagram-VXUJARFQ-cjffS2Qr.js → architectureDiagram-VXUJARFQ-QKtqaqdY.js} +1 -1
  7. package/dist-renderer/assets/{blockDiagram-VD42YOAC-BKdZF02Y.js → blockDiagram-VD42YOAC-BqdrzO_f.js} +1 -1
  8. package/dist-renderer/assets/{c4Diagram-YG6GDRKO-CN27pqaI.js → c4Diagram-YG6GDRKO-gwPlCxDC.js} +1 -1
  9. package/dist-renderer/assets/channel-DpMHF50r.js +1 -0
  10. package/dist-renderer/assets/{chunk-4BX2VUAB-CXPCI7g_.js → chunk-4BX2VUAB-C6XLurL4.js} +1 -1
  11. package/dist-renderer/assets/{chunk-55IACEB6-BGAXQZRC.js → chunk-55IACEB6-Ds6quhEP.js} +1 -1
  12. package/dist-renderer/assets/{chunk-B4BG7PRW-TPDaA_KQ.js → chunk-B4BG7PRW-5UlA1_e9.js} +1 -1
  13. package/dist-renderer/assets/{chunk-DI55MBZ5-D1ADe_tq.js → chunk-DI55MBZ5-ywFrqIsY.js} +1 -1
  14. package/dist-renderer/assets/{chunk-FMBD7UC4-Beimtg3a.js → chunk-FMBD7UC4-C7ifUA17.js} +1 -1
  15. package/dist-renderer/assets/{chunk-QN33PNHL-OjNBu854.js → chunk-QN33PNHL-BxGCo80U.js} +1 -1
  16. package/dist-renderer/assets/{chunk-QZHKN3VN-DinqvbH8.js → chunk-QZHKN3VN-B2CuaZs6.js} +1 -1
  17. package/dist-renderer/assets/{chunk-TZMSLE5B-BfFtlPSZ.js → chunk-TZMSLE5B-Ds1hInvp.js} +1 -1
  18. package/dist-renderer/assets/classDiagram-2ON5EDUG-CBYCBVRl.js +1 -0
  19. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-CBYCBVRl.js +1 -0
  20. package/dist-renderer/assets/clone-DcMF6Psb.js +1 -0
  21. package/dist-renderer/assets/{cose-bilkent-S5V4N54A-D9z9Dgt7.js → cose-bilkent-S5V4N54A-Cz1GVtLp.js} +1 -1
  22. package/dist-renderer/assets/{dagre-6UL2VRFP-n1g-DhEE.js → dagre-6UL2VRFP-BrmR-P4h.js} +1 -1
  23. package/dist-renderer/assets/{diagram-PSM6KHXK-BvxFq-BE.js → diagram-PSM6KHXK-DbNjC5Rg.js} +1 -1
  24. package/dist-renderer/assets/{diagram-QEK2KX5R-wVnJuwza.js → diagram-QEK2KX5R-qkRX5_Mq.js} +1 -1
  25. package/dist-renderer/assets/{diagram-S2PKOQOG-B707WJQw.js → diagram-S2PKOQOG-CyL5rCv2.js} +1 -1
  26. package/dist-renderer/assets/{erDiagram-Q2GNP2WA-C-_1dGHs.js → erDiagram-Q2GNP2WA-Dox3-bA5.js} +1 -1
  27. package/dist-renderer/assets/{flowDiagram-NV44I4VS-CMTSi3H6.js → flowDiagram-NV44I4VS-BtkaxlDL.js} +1 -1
  28. package/dist-renderer/assets/{ganttDiagram-JELNMOA3-DZ0bNrAA.js → ganttDiagram-JELNMOA3-Dhy_d9GK.js} +1 -1
  29. package/dist-renderer/assets/{gitGraphDiagram-V2S2FVAM-DNVfGooQ.js → gitGraphDiagram-V2S2FVAM-B5XRhIQA.js} +1 -1
  30. package/dist-renderer/assets/{graph-865j_tM_.js → graph-CsoEwUhS.js} +1 -1
  31. package/dist-renderer/assets/{index-C_F9N5x-.js → index-BWPWmJNo.js} +1 -1
  32. package/dist-renderer/assets/{index-LwDIsXJN.js → index-Bu2R-Se7.js} +586 -740
  33. package/dist-renderer/assets/index-CnWV3BhG.css +32 -0
  34. package/dist-renderer/assets/{index-DuUaf8at.js → index-D-3KgskL.js} +1 -1
  35. package/dist-renderer/assets/{index-BTx1nc4T.js → index-DGEBzLNT.js} +1 -1
  36. package/dist-renderer/assets/{index-2EW-eu3q.js → index-NhHNs2Oo.js} +1 -1
  37. package/dist-renderer/assets/{index-4dEMStJj.js → index-h17WuEyf.js} +1 -1
  38. package/dist-renderer/assets/{infoDiagram-HS3SLOUP-CyqtElLq.js → infoDiagram-HS3SLOUP-hMGmNojH.js} +1 -1
  39. package/dist-renderer/assets/{journeyDiagram-XKPGCS4Q-BvjQ0Hm0.js → journeyDiagram-XKPGCS4Q-DXV2rBDl.js} +1 -1
  40. package/dist-renderer/assets/{kanban-definition-3W4ZIXB7-CJJ-k0zT.js → kanban-definition-3W4ZIXB7-Bf99WLRy.js} +1 -1
  41. package/dist-renderer/assets/{layout-CnV6rQAG.js → layout-C3XWrpwo.js} +1 -1
  42. package/dist-renderer/assets/{linear-Cw3UQgyX.js → linear-OEEcn8KN.js} +1 -1
  43. package/dist-renderer/assets/{mindmap-definition-VGOIOE7T-C5tDaGSK.js → mindmap-definition-VGOIOE7T-Dpi3S2x4.js} +1 -1
  44. package/dist-renderer/assets/{pieDiagram-ADFJNKIX-CiIpPsau.js → pieDiagram-ADFJNKIX-xTPPhtNx.js} +1 -1
  45. package/dist-renderer/assets/{quadrantDiagram-AYHSOK5B-C3gtowNj.js → quadrantDiagram-AYHSOK5B-euniyDlz.js} +1 -1
  46. package/dist-renderer/assets/{requirementDiagram-UZGBJVZJ-CXBTrAnU.js → requirementDiagram-UZGBJVZJ-D9Uiw4kF.js} +1 -1
  47. package/dist-renderer/assets/{sankeyDiagram-TZEHDZUN-wziX77xG.js → sankeyDiagram-TZEHDZUN-CySU4nED.js} +1 -1
  48. package/dist-renderer/assets/{sequenceDiagram-WL72ISMW-sYqopcrj.js → sequenceDiagram-WL72ISMW-JVGpET6V.js} +1 -1
  49. package/dist-renderer/assets/splashScene-D0YB9uxm.js +17 -0
  50. package/dist-renderer/assets/{stateDiagram-FKZM4ZOC-Bl1-0_Cp.js → stateDiagram-FKZM4ZOC-B2FY5qqi.js} +1 -1
  51. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DcoMiR8H.js +1 -0
  52. package/dist-renderer/assets/{timeline-definition-IT6M3QCI-CIRjJUBo.js → timeline-definition-IT6M3QCI-DmycNUUe.js} +1 -1
  53. package/dist-renderer/assets/{treemap-GDKQZRPO-CVPuNe1n.js → treemap-GDKQZRPO-DPq4gZuB.js} +1 -1
  54. package/dist-renderer/assets/{xychartDiagram-PRI3JC2R-3nT9yHwp.js → xychartDiagram-PRI3JC2R-J6VVJzRq.js} +1 -1
  55. package/dist-renderer/index.html +20 -53
  56. package/package.json +25 -18
  57. package/src/main/ipc/extensions.ts +30 -50
  58. package/src/main/server.ts +890 -247
  59. package/src/main/services/extensions/ExtensionFacadeService.ts +4 -56
  60. package/src/main/services/extensions/catalog/PluginCatalogService.ts +4 -2
  61. package/src/main/services/extensions/library/McpLibraryService.ts +243 -0
  62. package/src/main/services/session-intelligence/ConversationTelemetryService.ts +1101 -0
  63. package/src/main/services/session-intelligence/LocalSessionScanner.ts +512 -0
  64. package/src/main/services/session-intelligence/SessionUsageParser.ts +4 -4
  65. package/src/main/services/session-intelligence/UsageTelemetryService.ts +14 -1
  66. package/src/main/services/system-manager/SystemManagerConfigService.ts +122 -0
  67. package/src/main/services/system-manager/SystemManagerPtyService.ts +233 -0
  68. package/src/main/services/system-manager/WorkflowPromptService.ts +75 -0
  69. package/src/main/services/teams-mvp/TaskDispatchService.ts +32 -8
  70. package/src/main/services/teams-mvp/TeamProvisioningService.ts +39 -2
  71. package/src/main/services/teams-mvp/TeamWorkspaceService.ts +22 -4
  72. package/src/main/utils/teamProjectResolution.ts +15 -0
  73. package/src/renderer/App.tsx +8 -4
  74. package/src/renderer/api/httpClient.ts +174 -38
  75. package/src/renderer/api/providers.ts +23 -2
  76. package/src/renderer/assets/participant-avatars/01.svg +3 -0
  77. package/src/renderer/assets/participant-avatars/02.svg +3 -0
  78. package/src/renderer/assets/participant-avatars/03.svg +3 -0
  79. package/src/renderer/assets/participant-avatars/04.svg +3 -0
  80. package/src/renderer/assets/participant-avatars/05.svg +3 -0
  81. package/src/renderer/assets/participant-avatars/06.svg +3 -0
  82. package/src/renderer/assets/participant-avatars/07.svg +3 -0
  83. package/src/renderer/assets/participant-avatars/08.svg +3 -0
  84. package/src/renderer/assets/participant-avatars/09.svg +3 -0
  85. package/src/renderer/assets/participant-avatars/10.svg +3 -0
  86. package/src/renderer/assets/participant-avatars/11.svg +3 -0
  87. package/src/renderer/assets/participant-avatars/12.svg +3 -0
  88. package/src/renderer/assets/participant-avatars/13.svg +3 -0
  89. package/src/renderer/components/common/TerminalPane.tsx +213 -0
  90. package/src/renderer/components/dashboard/DashboardView.tsx +9 -36
  91. package/src/renderer/components/extensions/ExtensionStoreView.tsx +12 -221
  92. package/src/renderer/components/extensions/ExtensionsSubTabTrigger.tsx +1 -1
  93. package/src/renderer/components/extensions/mcp/McpLibraryEnableDialog.tsx +305 -0
  94. package/src/renderer/components/extensions/mcp/McpLibraryEntryDialog.tsx +418 -0
  95. package/src/renderer/components/extensions/mcp/McpLibraryPanel.tsx +404 -0
  96. package/src/renderer/components/extensions/plugins/PluginCard.tsx +10 -2
  97. package/src/renderer/components/extensions/plugins/PluginsPanel.tsx +40 -22
  98. package/src/renderer/components/extensions/skills/SkillsLibraryPanel.tsx +335 -0
  99. package/src/renderer/components/layout/PaneContent.tsx +8 -1
  100. package/src/renderer/components/layout/Sidebar.tsx +11 -54
  101. package/src/renderer/components/layout/SortableTab.tsx +20 -31
  102. package/src/renderer/components/layout/TabBar.tsx +1 -1
  103. package/src/renderer/components/layout/TabContextMenu.tsx +1 -1
  104. package/src/renderer/components/runtime/ProviderRuntimeSettingsDialog.tsx +768 -157
  105. package/src/renderer/components/schedules/SchedulesView.tsx +51 -462
  106. package/src/renderer/components/schedules/calendar/CalendarDayView.tsx +173 -0
  107. package/src/renderer/components/schedules/calendar/CalendarEventBlock.tsx +113 -0
  108. package/src/renderer/components/schedules/calendar/CalendarHeader.tsx +148 -0
  109. package/src/renderer/components/schedules/calendar/CalendarMonthView.tsx +142 -0
  110. package/src/renderer/components/schedules/calendar/CalendarWeekView.tsx +219 -0
  111. package/src/renderer/components/schedules/calendar/ScheduleCalendarBoard.tsx +41 -0
  112. package/src/renderer/components/schedules/calendar/TeamGanttView.tsx +405 -0
  113. package/src/renderer/components/schedules/calendar/computeOccurrences.ts +234 -0
  114. package/src/renderer/components/schedules/calendar/index.ts +2 -0
  115. package/src/renderer/components/schedules/calendar/types.ts +44 -0
  116. package/src/renderer/components/settings/SettingsTabs.tsx +50 -55
  117. package/src/renderer/components/settings/SettingsView.tsx +30 -35
  118. package/src/renderer/components/settings/components/SettingsSectionHeader.tsx +5 -1
  119. package/src/renderer/components/settings/components/SettingsSelect.tsx +5 -3
  120. package/src/renderer/components/settings/components/SettingsToggle.tsx +2 -2
  121. package/src/renderer/components/settings/sections/AdvancedSection.tsx +11 -42
  122. package/src/renderer/components/settings/sections/CliStatusSection.tsx +71 -112
  123. package/src/renderer/components/settings/sections/ConfigEditorDialog.tsx +1 -1
  124. package/src/renderer/components/settings/sections/GeneralSection.tsx +11 -3
  125. package/src/renderer/components/settings/sections/HarnessSection.tsx +18 -14
  126. package/src/renderer/components/settings/sections/PlatformsSection.tsx +3 -3
  127. package/src/renderer/components/settings/sections/TaskBusSection.tsx +33 -40
  128. package/src/renderer/components/settings/sections/index.ts +0 -1
  129. package/src/renderer/components/sidebar/SidebarSessions.tsx +182 -4
  130. package/src/renderer/components/sidebar/SidebarTaskItem.tsx +4 -4
  131. package/src/renderer/components/sidebar/WorkspaceBrowser.tsx +39 -4
  132. package/src/renderer/components/splash/splashScene.ts +121 -929
  133. package/src/renderer/components/system-manager/FolderBrowser.tsx +163 -0
  134. package/src/renderer/components/system-manager/SystemManagerView.tsx +351 -0
  135. package/src/renderer/components/tasks/TasksView.tsx +112 -134
  136. package/src/renderer/components/team/CcSessionsSection.tsx +431 -89
  137. package/src/renderer/components/team/CollapsibleTeamSection.tsx +17 -32
  138. package/src/renderer/components/team/TeamDetailView.tsx +325 -114
  139. package/src/renderer/components/team/TeamListView.tsx +108 -123
  140. package/src/renderer/components/team/dialogs/CreateTaskDialog.tsx +2 -2
  141. package/src/renderer/components/team/dialogs/CreateTeamDialog.tsx +84 -306
  142. package/src/renderer/components/team/dialogs/EditTeamDialog.tsx +259 -342
  143. package/src/renderer/components/team/dialogs/GlobalTaskDetailDialog.tsx +1 -1
  144. package/src/renderer/components/team/dialogs/LaunchTeamDialog.tsx +17 -15
  145. package/src/renderer/components/team/dialogs/PlatformBindingDialog.tsx +221 -0
  146. package/src/renderer/components/team/dialogs/PlatformManualForm.tsx +7 -0
  147. package/src/renderer/components/team/dialogs/PlatformSetupQR.tsx +1 -1
  148. package/src/renderer/components/team/dialogs/RuntimeConfigDialog.tsx +361 -0
  149. package/src/renderer/components/team/dialogs/platformMeta.ts +122 -11
  150. package/src/renderer/components/team/dialogs/useTeamEditForm.ts +17 -5
  151. package/src/renderer/components/team/kanban/KanbanBoard.tsx +9 -9
  152. package/src/renderer/components/team/members/MemberCard.tsx +14 -47
  153. package/src/renderer/components/team/members/MemberDetailDialog.tsx +3 -95
  154. package/src/renderer/components/team/members/MemberDetailStats.tsx +50 -65
  155. package/src/renderer/components/team/messages/MessageComposer.tsx +8 -110
  156. package/src/renderer/components/team/messages/MessagesPanel.tsx +131 -114
  157. package/src/renderer/components/team/schedule/ScheduleStatusBadge.tsx +2 -2
  158. package/src/renderer/components/team/tools/AddMcpInline.tsx +57 -0
  159. package/src/renderer/components/team/tools/AddSkillInline.tsx +61 -0
  160. package/src/renderer/components/team/tools/McpChip.tsx +45 -0
  161. package/src/renderer/components/team/tools/SkillChip.tsx +35 -0
  162. package/src/renderer/components/team/tools/ToolsSection.tsx +556 -0
  163. package/src/renderer/hooks/useExtensionsTabState.ts +3 -114
  164. package/src/renderer/index.css +39 -22
  165. package/src/renderer/index.html +17 -50
  166. package/src/renderer/store/index.ts +2 -1
  167. package/src/renderer/store/slices/scheduleSlice.ts +1 -1
  168. package/src/renderer/store/slices/teamSlice.ts +45 -168
  169. package/src/renderer/utils/claudeCodeOnlyProviders.ts +3 -10
  170. package/src/renderer/utils/memberHelpers.ts +5 -17
  171. package/src/renderer/utils/openCodeRuntimeDeliveryDiagnostics.ts +4 -2
  172. package/src/renderer/utils/providerSlashCommands.ts +0 -5
  173. package/src/renderer/utils/scheduleFormatters.ts +3 -1
  174. package/src/renderer/utils/teamMessageFiltering.ts +14 -1
  175. package/src/renderer/utils/teamModelAvailability.ts +18 -2
  176. package/src/shared/types/api.ts +121 -2
  177. package/src/shared/types/ccConnect.ts +2 -0
  178. package/src/shared/types/extensions/api.ts +9 -0
  179. package/src/shared/types/extensions/index.ts +4 -0
  180. package/src/shared/types/extensions/mcp.ts +41 -0
  181. package/src/shared/types/index.ts +3 -0
  182. package/src/shared/types/systemManager.ts +49 -0
  183. package/src/shared/types/team.ts +29 -0
  184. package/src/shared/types/terminal.ts +4 -2
  185. package/src/shared/utils/extensionNormalizers.ts +29 -0
  186. package/src/shared/utils/providerExtensionCapabilities.ts +2 -2
  187. package/dist-renderer/assets/ProjectEditorOverlay-Va_Vz-zz.js +0 -52
  188. package/dist-renderer/assets/channel-5dJIx68e.js +0 -1
  189. package/dist-renderer/assets/classDiagram-2ON5EDUG-BMGXWJ2d.js +0 -1
  190. package/dist-renderer/assets/classDiagram-v2-WZHVMYZB-BMGXWJ2d.js +0 -1
  191. package/dist-renderer/assets/clone-D7FWfGY9.js +0 -1
  192. package/dist-renderer/assets/index-B2z_IyRH.css +0 -1
  193. package/dist-renderer/assets/splashScene-C8lWNnm4.js +0 -1
  194. package/dist-renderer/assets/stateDiagram-v2-4FDKWEC3-DOYYvDbi.js +0 -1
  195. package/src/main/services/extensions/catalog/GlamaMcpEnrichmentService.ts +0 -190
  196. package/src/main/services/extensions/catalog/McpCatalogAggregator.ts +0 -150
  197. package/src/main/services/extensions/catalog/OfficialMcpRegistryService.ts +0 -381
  198. package/src/main/services/extensions/install/McpInstallService.ts +0 -407
  199. package/src/main/services/extensions/state/McpInstallationStateService.ts +0 -42
  200. package/src/renderer/components/extensions/mcp/McpServerCard.tsx +0 -314
  201. package/src/renderer/components/extensions/mcp/McpServerDetailDialog.tsx +0 -765
  202. package/src/renderer/components/extensions/mcp/McpServersPanel.tsx +0 -593
  203. package/src/renderer/components/extensions/skills/SkillDetailDialog.tsx +0 -372
  204. package/src/renderer/components/extensions/skills/SkillImportDialog.tsx +0 -343
  205. package/src/renderer/components/extensions/skills/SkillsPanel.tsx +0 -659
@@ -1,241 +1,23 @@
1
1
  import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
 
3
3
  import { Button } from '@renderer/components/ui/button';
4
- import { Input } from '@renderer/components/ui/input';
5
- import { Popover, PopoverContent, PopoverTrigger } from '@renderer/components/ui/popover';
6
- import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
7
4
  import { getTeamColorSet } from '@renderer/constants/teamColors';
8
5
  import { useStore } from '@renderer/store';
9
6
  import { nameColorSet } from '@renderer/utils/projectColor';
10
- import { formatNextRun, getCronDescription } from '@renderer/utils/scheduleFormatters';
11
- import {
12
- AlertCircle,
13
- Calendar,
14
- ChevronDown,
15
- ChevronRight,
16
- Filter,
17
- Loader2,
18
- MoreHorizontal,
19
- Pencil,
20
- Play,
21
- Plus,
22
- Search,
23
- Square,
24
- Trash2,
25
- } from 'lucide-react';
7
+ import { Calendar, Plus } from 'lucide-react';
26
8
  import { useShallow } from 'zustand/react/shallow';
27
9
 
10
+ import { ScheduleCalendarBoard } from './calendar';
11
+ import type { CalendarViewMode } from './calendar';
28
12
  import { CcCronScheduleDialog } from '../team/schedule/CcCronScheduleDialog';
29
- import { ScheduleRunLogDialog } from '../team/schedule/ScheduleRunLogDialog';
30
- import { ScheduleRunRow } from '../team/schedule/ScheduleRunRow';
31
- import { ScheduleStatusBadge } from '../team/schedule/ScheduleStatusBadge';
32
13
 
33
- import type { Schedule, ScheduleRun } from '@shared/types';
34
-
35
- // =============================================================================
36
- // ScheduleListItem
37
- // =============================================================================
38
-
39
- interface ScheduleListItemProps {
40
- schedule: Schedule;
41
- onEdit: (schedule: Schedule) => void;
42
- onDelete: (id: string) => void;
43
- onPause: (id: string) => void;
44
- onResume: (id: string) => void;
45
- onTeamClick: (teamName: string) => void;
46
- teamColor: string;
47
- teamDisplayName: string;
48
- deleting?: boolean;
49
- }
50
-
51
- const ScheduleListItem = ({
52
- schedule,
53
- onEdit,
54
- onDelete,
55
- onPause,
56
- onResume,
57
- onTeamClick,
58
- teamColor,
59
- teamDisplayName,
60
- deleting = false,
61
- }: ScheduleListItemProps): React.JSX.Element => {
62
- const [expanded, setExpanded] = useState(false);
63
- const [selectedRun, setSelectedRun] = useState<ScheduleRun | null>(null);
64
- const runs = useStore(useShallow((s) => s.scheduleRuns[schedule.id] ?? []));
65
- const runsLoading = useStore((s) => s.scheduleRunsLoading[schedule.id] ?? false);
66
- const fetchRunHistory = useStore((s) => s.fetchRunHistory);
67
-
68
- const handleExpand = useCallback(() => {
69
- const next = !expanded;
70
- setExpanded(next);
71
- if (next && runs.length === 0 && !runsLoading) {
72
- void fetchRunHistory(schedule.id);
73
- }
74
- }, [expanded, runs.length, runsLoading, fetchRunHistory, schedule.id]);
75
-
76
- return (
77
- <div className="rounded-xl border border-[var(--color-border-subtle)] bg-white/[0.025] font-sans shadow-[0_14px_32px_rgba(0,0,0,0.14)] transition-colors hover:border-[var(--color-border-emphasis)] hover:bg-white/[0.04]">
78
- {/* Main row */}
79
- <div className="flex items-center gap-3 px-4 py-3.5">
80
- {/* Expand toggle */}
81
- <button
82
- type="button"
83
- className="shrink-0 text-[var(--color-text-muted)] hover:text-[var(--color-text-secondary)]"
84
- onClick={handleExpand}
85
- >
86
- {expanded ? <ChevronDown className="size-4" /> : <ChevronRight className="size-4" />}
87
- </button>
88
-
89
- {/* Status badge */}
90
- <ScheduleStatusBadge status={schedule.status} />
91
-
92
- {/* Label & cron description */}
93
- <div className="min-w-0 flex-1">
94
- <div className="flex items-center gap-2">
95
- <span className="truncate text-sm font-medium text-[var(--color-text)]">
96
- {schedule.label || getCronDescription(schedule.cronExpression)}
97
- </span>
98
- </div>
99
- {schedule.label ? (
100
- <span className="text-xs text-[var(--color-text-muted)]">
101
- {getCronDescription(schedule.cronExpression)}
102
- </span>
103
- ) : null}
104
- </div>
105
-
106
- {/* Team badge */}
107
- <button
108
- type="button"
109
- className="flex shrink-0 items-center gap-1.5 rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1 text-xs text-[var(--color-text-secondary)] transition-colors hover:border-[var(--color-border-emphasis)] hover:text-[var(--color-text)]"
110
- onClick={() => onTeamClick(schedule.teamName)}
111
- >
112
- <span className="size-2 shrink-0 rounded-full" style={{ backgroundColor: teamColor }} />
113
- {teamDisplayName}
114
- </button>
115
-
116
- {/* Next run */}
117
- <Tooltip>
118
- <TooltipTrigger asChild>
119
- <span className="shrink-0 rounded-full bg-white/[0.035] px-2 py-1 text-xs text-[var(--color-text-muted)]">
120
- 下次:{formatNextRun(schedule.nextRunAt)}
121
- </span>
122
- </TooltipTrigger>
123
- {schedule.nextRunAt ? (
124
- <TooltipContent side="top" className="text-xs">
125
- {new Date(schedule.nextRunAt).toLocaleString()}
126
- </TooltipContent>
127
- ) : null}
128
- </Tooltip>
129
-
130
- {/* Timezone */}
131
- <span className="hidden shrink-0 text-xs text-[var(--color-text-muted)] lg:inline">
132
- {schedule.timezone}
133
- </span>
134
-
135
- {/* Actions */}
136
- <div className="flex shrink-0 items-center gap-1">
137
- <Tooltip>
138
- <TooltipTrigger asChild>
139
- <Button
140
- variant="ghost"
141
- size="sm"
142
- className="size-7 p-0 text-red-400 hover:bg-red-500/10 hover:text-red-300"
143
- onClick={() => onDelete(schedule.id)}
144
- disabled={deleting}
145
- >
146
- {deleting ? (
147
- <Loader2 className="size-3.5 animate-spin" />
148
- ) : (
149
- <Trash2 className="size-3.5" />
150
- )}
151
- </Button>
152
- </TooltipTrigger>
153
- <TooltipContent side="top">删除</TooltipContent>
154
- </Tooltip>
155
-
156
- <Popover>
157
- <PopoverTrigger asChild>
158
- <Button variant="ghost" size="sm" className="size-7 p-0">
159
- <MoreHorizontal className="size-3.5" />
160
- </Button>
161
- </PopoverTrigger>
162
- <PopoverContent align="end" className="w-40 p-1">
163
- <button
164
- type="button"
165
- className="flex w-full items-center rounded-sm px-2 py-1.5 text-xs text-[var(--color-text)] hover:bg-[var(--color-surface-raised)]"
166
- onClick={() => onEdit(schedule)}
167
- >
168
- <Pencil className="mr-2 size-3.5" />
169
- 编辑
170
- </button>
171
- {schedule.status === 'active' ? (
172
- <button
173
- type="button"
174
- className="flex w-full items-center rounded-sm px-2 py-1.5 text-xs text-[var(--color-text)] hover:bg-[var(--color-surface-raised)]"
175
- onClick={() => onPause(schedule.id)}
176
- >
177
- <Square className="mr-2 size-3.5" />
178
- 停止
179
- </button>
180
- ) : (
181
- <button
182
- type="button"
183
- className="flex w-full items-center rounded-sm px-2 py-1.5 text-xs text-[var(--color-text)] hover:bg-[var(--color-surface-raised)]"
184
- onClick={() => onResume(schedule.id)}
185
- >
186
- <Play className="mr-2 size-3.5" />
187
- 启用
188
- </button>
189
- )}
190
- </PopoverContent>
191
- </Popover>
192
- </div>
193
- </div>
194
-
195
- {/* Expanded: Run history */}
196
- {expanded ? (
197
- <div className="border-t border-white/[0.06] bg-black/10">
198
- {runsLoading ? (
199
- <div className="flex items-center justify-center py-4 text-xs text-[var(--color-text-muted)]">
200
- 正在加载运行历史...
201
- </div>
202
- ) : runs.length === 0 ? (
203
- <div className="flex items-center justify-center py-4 text-xs text-[var(--color-text-muted)]">
204
- 暂无运行记录
205
- </div>
206
- ) : (
207
- <div className="max-h-[240px] overflow-y-auto">
208
- {runs.slice(0, 15).map((run) => (
209
- <ScheduleRunRow key={run.id} run={run} onClick={setSelectedRun} />
210
- ))}
211
- </div>
212
- )}
213
- </div>
214
- ) : null}
215
-
216
- {/* Run Log Dialog */}
217
- <ScheduleRunLogDialog
218
- open={selectedRun != null}
219
- run={selectedRun}
220
- scheduleId={schedule.id}
221
- onClose={() => setSelectedRun(null)}
222
- />
223
- </div>
224
- );
225
- };
226
-
227
- // =============================================================================
228
- // SchedulesView
229
- // =============================================================================
14
+ import type { Schedule } from '@shared/types';
230
15
 
231
16
  export const SchedulesView = (): React.JSX.Element => {
232
17
  const {
233
18
  schedules,
234
19
  schedulesLoading,
235
20
  fetchSchedules,
236
- pauseSchedule,
237
- resumeSchedule,
238
- deleteSchedule,
239
21
  openTeamTab,
240
22
  teamByName,
241
23
  } = useStore(
@@ -243,15 +25,11 @@ export const SchedulesView = (): React.JSX.Element => {
243
25
  schedules: s.schedules,
244
26
  schedulesLoading: s.schedulesLoading,
245
27
  fetchSchedules: s.fetchSchedules,
246
- pauseSchedule: s.pauseSchedule,
247
- resumeSchedule: s.resumeSchedule,
248
- deleteSchedule: s.deleteSchedule,
249
28
  openTeamTab: s.openTeamTab,
250
29
  teamByName: s.teamByName,
251
30
  }))
252
31
  );
253
32
 
254
- /** Resolve team color dot style for a given team name */
255
33
  const getTeamColor = useCallback(
256
34
  (teamName: string): string => {
257
35
  const team = teamByName[teamName];
@@ -266,75 +44,27 @@ export const SchedulesView = (): React.JSX.Element => {
266
44
  [teamByName]
267
45
  );
268
46
 
269
- const [searchQuery, setSearchQuery] = useState('');
270
- const [teamFilter, setTeamFilter] = useState<string | null>(null);
47
+ const [calendarView, setCalendarView] = useState<CalendarViewMode>('week');
271
48
  const [dialogOpen, setDialogOpen] = useState(false);
272
49
  const [editingSchedule, setEditingSchedule] = useState<Schedule | null>(null);
273
- const [deletingScheduleId, setDeletingScheduleId] = useState<string | null>(null);
274
- const [deleteError, setDeleteError] = useState<string | null>(null);
275
50
 
276
- // Fetch schedules on mount
277
51
  useEffect(() => {
278
52
  void fetchSchedules();
279
53
  }, [fetchSchedules]);
280
54
 
281
- // Derive unique team names
282
- const teamNames = useMemo(
55
+ const sortedSchedules = useMemo(
283
56
  () =>
284
- [...new Set(schedules.map((s) => s.teamName))].sort((a, b) =>
285
- getTeamDisplayName(a).localeCompare(getTeamDisplayName(b))
286
- ),
287
- [getTeamDisplayName, schedules]
288
- );
289
-
290
- // Filter and sort schedules
291
- const filteredSchedules = useMemo(() => {
292
- let result = schedules;
293
-
294
- // Filter by team
295
- if (teamFilter) {
296
- result = result.filter((s) => s.teamName === teamFilter);
297
- }
298
-
299
- // Filter by search query
300
- if (searchQuery.trim()) {
301
- const query = searchQuery.toLowerCase();
302
- result = result.filter((s) => {
303
- const teamDisplayName = getTeamDisplayName(s.teamName).toLowerCase();
304
- return (
305
- (s.label ?? '').toLowerCase().includes(query) ||
306
- teamDisplayName.includes(query) ||
307
- s.teamName.toLowerCase().includes(query) ||
308
- s.launchConfig.prompt.toLowerCase().includes(query) ||
309
- getCronDescription(s.cronExpression).toLowerCase().includes(query)
310
- );
311
- });
312
- }
313
-
314
- // Sort: active first, then by next run ascending
315
- return [...result].sort((a, b) => {
316
- // Active schedules first
317
- const statusOrder = { active: 0, paused: 1, disabled: 2 };
318
- const statusDiff = statusOrder[a.status] - statusOrder[b.status];
319
- if (statusDiff !== 0) return statusDiff;
320
-
321
- // Then by next run (soonest first)
322
- if (a.nextRunAt && b.nextRunAt) {
323
- return new Date(a.nextRunAt).getTime() - new Date(b.nextRunAt).getTime();
324
- }
325
- if (a.nextRunAt) return -1;
326
- if (b.nextRunAt) return 1;
327
- return 0;
328
- });
329
- }, [getTeamDisplayName, schedules, teamFilter, searchQuery]);
330
-
331
- const scheduleStats = useMemo(
332
- () => ({
333
- total: schedules.length,
334
- active: schedules.filter((schedule) => schedule.status === 'active').length,
335
- paused: schedules.filter((schedule) => schedule.status === 'paused').length,
336
- teams: new Set(schedules.map((schedule) => schedule.teamName)).size,
337
- }),
57
+ [...schedules].sort((a, b) => {
58
+ const statusOrder = { active: 0, paused: 1, disabled: 2 };
59
+ const statusDiff = statusOrder[a.status] - statusOrder[b.status];
60
+ if (statusDiff !== 0) return statusDiff;
61
+ if (a.nextRunAt && b.nextRunAt) {
62
+ return new Date(a.nextRunAt).getTime() - new Date(b.nextRunAt).getTime();
63
+ }
64
+ if (a.nextRunAt) return -1;
65
+ if (b.nextRunAt) return 1;
66
+ return 0;
67
+ }),
338
68
  [schedules]
339
69
  );
340
70
 
@@ -353,21 +83,6 @@ export const SchedulesView = (): React.JSX.Element => {
353
83
  setEditingSchedule(null);
354
84
  }, []);
355
85
 
356
- const handleDelete = useCallback(
357
- async (id: string) => {
358
- setDeletingScheduleId(id);
359
- setDeleteError(null);
360
- try {
361
- await deleteSchedule(id);
362
- } catch (err) {
363
- setDeleteError(err instanceof Error ? err.message : '删除计划失败');
364
- } finally {
365
- setDeletingScheduleId(null);
366
- }
367
- },
368
- [deleteSchedule]
369
- );
370
-
371
86
  const handleTeamClick = useCallback(
372
87
  (teamName: string) => {
373
88
  openTeamTab(teamName);
@@ -376,179 +91,53 @@ export const SchedulesView = (): React.JSX.Element => {
376
91
  );
377
92
 
378
93
  return (
379
- <div className="h-full overflow-y-auto bg-[var(--color-surface)]">
380
- <div className="mx-auto w-full max-w-6xl px-6 py-8">
381
- {/* Header */}
382
- <div className="mb-5 rounded-2xl border border-[var(--color-border-subtle)] bg-white/[0.025] p-4 shadow-[0_18px_42px_rgba(0,0,0,0.12)]">
383
- <div className="flex flex-wrap items-start justify-between gap-4">
384
- <div>
385
- <div className="flex items-center gap-3">
386
- <span className="flex size-9 items-center justify-center rounded-xl bg-blue-500/10 text-blue-400">
387
- <Calendar className="size-4" />
388
- </span>
389
- <div>
390
- <h1 className="text-lg font-semibold text-[var(--color-text)]">定时任务</h1>
391
- <p className="mt-0.5 text-xs text-[var(--color-text-muted)]">
392
- 集中管理所有团队的 Cron 计划、运行状态和历史记录。
393
- </p>
394
- </div>
395
- </div>
396
- {schedules.length > 0 ? (
397
- <div className="mt-4 flex flex-wrap gap-2">
398
- <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1 text-xs text-[var(--color-text-secondary)]">
399
- 全部 {scheduleStats.total}
400
- </span>
401
- <span className="rounded-full border border-emerald-400/15 bg-emerald-400/10 px-2.5 py-1 text-xs text-emerald-400">
402
- 运行中 {scheduleStats.active}
403
- </span>
404
- <span className="rounded-full border border-yellow-400/15 bg-yellow-400/10 px-2.5 py-1 text-xs text-yellow-400">
405
- 已暂停 {scheduleStats.paused}
406
- </span>
407
- <span className="rounded-full border border-white/10 bg-white/[0.04] px-2.5 py-1 text-xs text-[var(--color-text-secondary)]">
408
- 团队 {scheduleStats.teams}
409
- </span>
410
- </div>
411
- ) : null}
412
- </div>
413
- <Button size="sm" className="gap-1.5" onClick={handleCreate}>
414
- <Plus className="size-3.5" />
415
- 添加计划
416
- </Button>
417
- </div>
418
-
419
- {/* Filters row */}
94
+ <div className="flex h-full flex-col bg-[var(--color-surface)]">
95
+ {/* Minimal header */}
96
+ <div className="flex shrink-0 items-center justify-between px-4 pt-4 pb-2">
97
+ <div className="flex items-center gap-2">
98
+ <h1 className="flex items-center gap-2 text-xs font-medium uppercase tracking-wider" style={{ color: 'var(--color-text-muted)' }}>
99
+ <span className="text-cyan-400/40">#</span>
100
+ 定时任务
101
+ </h1>
420
102
  {schedules.length > 0 && (
421
- <div className="mt-4 flex flex-wrap items-center gap-3 rounded-xl border border-white/[0.06] bg-black/10 p-2">
422
- {/* Search */}
423
- <div className="relative min-w-[220px] flex-1">
424
- <Search className="absolute left-2.5 top-1/2 size-3.5 -translate-y-1/2 text-[var(--color-text-muted)]" />
425
- <Input
426
- placeholder="搜索计划..."
427
- value={searchQuery}
428
- onChange={(e) => setSearchQuery(e.target.value)}
429
- className="h-8 pl-8 text-xs"
430
- />
431
- </div>
432
-
433
- {/* Team filter */}
434
- {teamNames.length > 1 && (
435
- <Popover>
436
- <PopoverTrigger asChild>
437
- <Button variant="outline" size="sm" className="h-8 gap-1.5 text-xs">
438
- <Filter className="size-3" />
439
- {teamFilter ? (
440
- <>
441
- <span
442
- className="size-2 shrink-0 rounded-full"
443
- style={{ backgroundColor: getTeamColor(teamFilter) }}
444
- />
445
- {getTeamDisplayName(teamFilter)}
446
- </>
447
- ) : (
448
- '全部团队'
449
- )}
450
- </Button>
451
- </PopoverTrigger>
452
- <PopoverContent align="start" className="w-48 p-1">
453
- <button
454
- type="button"
455
- className={`flex w-full items-center rounded-sm px-2 py-1.5 text-xs ${
456
- !teamFilter
457
- ? 'font-medium text-[var(--color-text)]'
458
- : 'text-[var(--color-text-secondary)]'
459
- } hover:bg-[var(--color-surface-raised)]`}
460
- onClick={() => setTeamFilter(null)}
461
- >
462
- 全部团队
463
- </button>
464
- {teamNames.map((name) => (
465
- <button
466
- key={name}
467
- type="button"
468
- className={`flex w-full items-center gap-1.5 rounded-sm px-2 py-1.5 text-xs ${
469
- teamFilter === name
470
- ? 'font-medium text-[var(--color-text)]'
471
- : 'text-[var(--color-text-secondary)]'
472
- } hover:bg-[var(--color-surface-raised)]`}
473
- onClick={() => setTeamFilter(name)}
474
- >
475
- <span
476
- className="size-2 shrink-0 rounded-full"
477
- style={{ backgroundColor: getTeamColor(name) }}
478
- />
479
- {getTeamDisplayName(name)}
480
- </button>
481
- ))}
482
- </PopoverContent>
483
- </Popover>
484
- )}
485
- </div>
103
+ <span className="rounded-full px-2 py-0.5 text-[10px]" style={{ color: 'var(--color-text-muted)', background: 'rgba(148,163,184,0.06)' }}>
104
+ {schedules.filter((s) => s.status === 'active').length} 运行中
105
+ </span>
486
106
  )}
487
107
  </div>
108
+ <Button size="sm" variant="ghost" className="gap-1.5 text-xs" onClick={handleCreate}>
109
+ <Plus className="size-3.5" />
110
+ 添加计划
111
+ </Button>
112
+ </div>
488
113
 
489
- {deleteError ? (
490
- <div className="mb-3 flex items-center gap-2 rounded-md border border-red-500/30 bg-red-500/10 px-3 py-2 text-xs text-red-400">
491
- <AlertCircle className="size-3.5 shrink-0" />
492
- {deleteError}
493
- </div>
494
- ) : null}
495
-
496
- {/* Content */}
114
+ {/* Content — fills remaining space */}
115
+ <div className="flex-1 min-h-0 overflow-auto px-2 pb-4">
497
116
  {schedulesLoading && schedules.length === 0 ? (
498
- <div className="flex items-center justify-center py-12 text-sm text-[var(--color-text-muted)]">
117
+ <div className="flex items-center justify-center py-24 text-sm text-[var(--color-text-muted)]">
499
118
  正在加载计划...
500
119
  </div>
501
120
  ) : schedules.length === 0 ? (
502
- /* Global empty state */
503
- <div className="flex flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-[var(--color-border)] bg-white/[0.02] py-16 text-center">
504
- <div className="flex size-14 items-center justify-center rounded-2xl bg-blue-500/10 text-blue-400">
505
- <Calendar className="size-7" />
506
- </div>
507
- <div className="space-y-1.5">
508
- <p className="text-sm font-medium text-[var(--color-text-secondary)]">暂无定时任务</p>
509
- <p className="max-w-sm text-xs text-[var(--color-text-muted)]">
510
- 在任意团队中创建计划,即可使用 Cron 表达式自动运行团队。
511
- 所有团队的计划都会显示在这里。
512
- </p>
513
- </div>
514
- <Button size="sm" variant="outline" className="mt-2 gap-1.5" onClick={handleCreate}>
121
+ <div className="flex flex-col items-center justify-center gap-3 rounded-xl border border-dashed border-[var(--color-border)] py-20 text-center">
122
+ <Calendar className="size-6" style={{ color: 'var(--color-text-muted)', opacity: 0.4 }} />
123
+ <p className="text-xs" style={{ color: 'var(--color-text-muted)' }}>
124
+ 暂无定时任务。在团队中创建计划即可自动运行。
125
+ </p>
126
+ <Button size="sm" variant="ghost" className="mt-1 gap-1.5 text-xs" onClick={handleCreate}>
515
127
  <Plus className="size-3.5" />
516
128
  创建计划
517
129
  </Button>
518
130
  </div>
519
- ) : filteredSchedules.length === 0 ? (
520
- /* No results for current filters */
521
- <div className="flex flex-col items-center justify-center gap-2 rounded-xl border border-dashed border-[var(--color-border)] bg-white/[0.02] py-12 text-center">
522
- <Search className="size-8 text-[var(--color-text-muted)]" />
523
- <p className="text-sm text-[var(--color-text-muted)]">没有符合当前筛选条件的计划</p>
524
- <button
525
- type="button"
526
- className="text-xs text-[var(--color-text-secondary)] underline hover:text-[var(--color-text)]"
527
- onClick={() => {
528
- setSearchQuery('');
529
- setTeamFilter(null);
530
- }}
531
- >
532
- 清除筛选
533
- </button>
534
- </div>
535
131
  ) : (
536
- <div className="space-y-2">
537
- {filteredSchedules.map((schedule) => (
538
- <ScheduleListItem
539
- key={schedule.id}
540
- schedule={schedule}
541
- onEdit={handleEdit}
542
- onDelete={(id) => void handleDelete(id)}
543
- onPause={(id) => void pauseSchedule(id)}
544
- onResume={(id) => void resumeSchedule(id)}
545
- onTeamClick={handleTeamClick}
546
- teamColor={getTeamColor(schedule.teamName)}
547
- teamDisplayName={getTeamDisplayName(schedule.teamName)}
548
- deleting={deletingScheduleId === schedule.id}
549
- />
550
- ))}
551
- </div>
132
+ <ScheduleCalendarBoard
133
+ schedules={sortedSchedules}
134
+ viewMode={calendarView}
135
+ onViewModeChange={setCalendarView}
136
+ onEdit={handleEdit}
137
+ onTeamClick={handleTeamClick}
138
+ getTeamColor={getTeamColor}
139
+ getTeamDisplayName={getTeamDisplayName}
140
+ />
552
141
  )}
553
142
  </div>
554
143