@marktoflow/gui 2.0.0-alpha.4 → 2.0.1

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 (194) hide show
  1. package/README.md +48 -170
  2. package/client.log +0 -0
  3. package/dist/client/assets/index-DQeR1ew6.css +1 -0
  4. package/dist/client/assets/index-LbIVPHbD.js +833 -0
  5. package/dist/client/assets/index-LbIVPHbD.js.map +1 -0
  6. package/dist/client/index.html +2 -2
  7. package/dist/client/marktoflow-logo.png +0 -0
  8. package/dist/server/{server/index.js → index.js} +53 -6
  9. package/dist/server/index.js.map +1 -0
  10. package/dist/server/routes/admin.js +95 -0
  11. package/dist/server/routes/admin.js.map +1 -0
  12. package/dist/server/{server/routes → routes}/ai.js +2 -2
  13. package/dist/server/{server/routes → routes}/ai.js.map +1 -1
  14. package/dist/server/routes/collaboration.js +104 -0
  15. package/dist/server/routes/collaboration.js.map +1 -0
  16. package/dist/server/routes/execute.js +230 -0
  17. package/dist/server/routes/execute.js.map +1 -0
  18. package/dist/server/routes/executions.js +125 -0
  19. package/dist/server/routes/executions.js.map +1 -0
  20. package/dist/server/routes/form.js +160 -0
  21. package/dist/server/routes/form.js.map +1 -0
  22. package/dist/server/routes/settings.js +90 -0
  23. package/dist/server/routes/settings.js.map +1 -0
  24. package/dist/server/routes/templates.js +106 -0
  25. package/dist/server/routes/templates.js.map +1 -0
  26. package/dist/server/routes/versions.js +101 -0
  27. package/dist/server/routes/versions.js.map +1 -0
  28. package/dist/server/{server/routes → routes}/workflows.js +37 -1
  29. package/dist/server/routes/workflows.js.map +1 -0
  30. package/dist/server/services/AIService.js +152 -0
  31. package/dist/server/services/AIService.js.map +1 -0
  32. package/dist/server/services/ExecutionManager.js +571 -0
  33. package/dist/server/services/ExecutionManager.js.map +1 -0
  34. package/dist/server/services/VersionService.js +65 -0
  35. package/dist/server/services/VersionService.js.map +1 -0
  36. package/dist/server/{server/services → services}/WorkflowService.js +166 -17
  37. package/dist/server/services/WorkflowService.js.map +1 -0
  38. package/dist/server/{server/services → services}/agents/copilot-provider.js +32 -0
  39. package/dist/server/services/agents/copilot-provider.js.map +1 -0
  40. package/dist/server/{server/websocket → websocket}/index.js +54 -0
  41. package/dist/server/websocket/index.js.map +1 -0
  42. package/dist/{server/shared → shared}/constants.js +9 -0
  43. package/dist/shared/constants.js.map +1 -0
  44. package/dist/shared/settings.js +51 -0
  45. package/dist/shared/settings.js.map +1 -0
  46. package/package.json +32 -14
  47. package/public/marktoflow-logo.png +0 -0
  48. package/scripts/flatten-dist.js +69 -0
  49. package/server.log +0 -0
  50. package/tests/integration/fixtures/test-workflow.md +6 -0
  51. package/.turbo/turbo-build.log +0 -26
  52. package/dist/client/assets/index-C90Y_aBX.js +0 -678
  53. package/dist/client/assets/index-C90Y_aBX.js.map +0 -1
  54. package/dist/client/assets/index-CRWeQ3NN.css +0 -1
  55. package/dist/server/server/index.js.map +0 -1
  56. package/dist/server/server/routes/execute.js +0 -63
  57. package/dist/server/server/routes/execute.js.map +0 -1
  58. package/dist/server/server/routes/workflows.js.map +0 -1
  59. package/dist/server/server/services/AIService.js +0 -69
  60. package/dist/server/server/services/AIService.js.map +0 -1
  61. package/dist/server/server/services/WorkflowService.js.map +0 -1
  62. package/dist/server/server/services/agents/copilot-provider.js.map +0 -1
  63. package/dist/server/server/websocket/index.js.map +0 -1
  64. package/dist/server/shared/constants.js.map +0 -1
  65. package/playwright.config.ts +0 -27
  66. package/postcss.config.js +0 -6
  67. package/src/client/App.tsx +0 -520
  68. package/src/client/components/Canvas/Canvas.tsx +0 -423
  69. package/src/client/components/Canvas/ExecutionOverlay.tsx +0 -847
  70. package/src/client/components/Canvas/ForEachNode.tsx +0 -128
  71. package/src/client/components/Canvas/IfElseNode.tsx +0 -126
  72. package/src/client/components/Canvas/NodeContextMenu.tsx +0 -188
  73. package/src/client/components/Canvas/OutputNode.tsx +0 -111
  74. package/src/client/components/Canvas/ParallelNode.tsx +0 -140
  75. package/src/client/components/Canvas/StepNode.tsx +0 -106
  76. package/src/client/components/Canvas/SubWorkflowNode.tsx +0 -141
  77. package/src/client/components/Canvas/SwitchNode.tsx +0 -164
  78. package/src/client/components/Canvas/Toolbar.tsx +0 -189
  79. package/src/client/components/Canvas/TransformNode.tsx +0 -185
  80. package/src/client/components/Canvas/TriggerNode.tsx +0 -128
  81. package/src/client/components/Canvas/TryCatchNode.tsx +0 -164
  82. package/src/client/components/Canvas/WhileNode.tsx +0 -129
  83. package/src/client/components/Canvas/index.ts +0 -24
  84. package/src/client/components/Editor/InputsEditor.tsx +0 -458
  85. package/src/client/components/Editor/NewStepWizard.tsx +0 -344
  86. package/src/client/components/Editor/StepEditor.tsx +0 -532
  87. package/src/client/components/Editor/YamlEditor.tsx +0 -160
  88. package/src/client/components/Panels/PropertiesPanel.tsx +0 -589
  89. package/src/client/components/Prompt/ChangePreview.tsx +0 -281
  90. package/src/client/components/Prompt/PromptHistoryPanel.tsx +0 -209
  91. package/src/client/components/Prompt/PromptInput.tsx +0 -108
  92. package/src/client/components/Sidebar/Sidebar.tsx +0 -343
  93. package/src/client/components/common/Breadcrumb.tsx +0 -40
  94. package/src/client/components/common/Button.tsx +0 -68
  95. package/src/client/components/common/ContextMenu.tsx +0 -202
  96. package/src/client/components/common/KeyboardShortcuts.tsx +0 -143
  97. package/src/client/components/common/Modal.tsx +0 -93
  98. package/src/client/components/common/Tabs.tsx +0 -57
  99. package/src/client/components/common/ThemeToggle.tsx +0 -63
  100. package/src/client/components/index.ts +0 -32
  101. package/src/client/hooks/index.ts +0 -4
  102. package/src/client/hooks/useAIPrompt.ts +0 -108
  103. package/src/client/hooks/useCanvas.ts +0 -247
  104. package/src/client/hooks/useWebSocket.ts +0 -164
  105. package/src/client/hooks/useWorkflow.ts +0 -138
  106. package/src/client/main.tsx +0 -10
  107. package/src/client/stores/canvasStore.ts +0 -348
  108. package/src/client/stores/editorStore.ts +0 -133
  109. package/src/client/stores/executionStore.ts +0 -440
  110. package/src/client/stores/index.ts +0 -4
  111. package/src/client/stores/layoutStore.ts +0 -103
  112. package/src/client/stores/navigationStore.ts +0 -49
  113. package/src/client/stores/promptStore.ts +0 -113
  114. package/src/client/stores/themeStore.ts +0 -75
  115. package/src/client/stores/workflowStore.ts +0 -177
  116. package/src/client/styles/globals.css +0 -346
  117. package/src/client/utils/cn.ts +0 -9
  118. package/src/client/utils/index.ts +0 -4
  119. package/src/client/utils/serviceIcons.tsx +0 -97
  120. package/src/client/utils/stepValidation.ts +0 -155
  121. package/src/client/utils/workflowToGraph.ts +0 -299
  122. package/src/server/index.ts +0 -114
  123. package/src/server/routes/ai.ts +0 -91
  124. package/src/server/routes/execute.ts +0 -71
  125. package/src/server/routes/tools.ts +0 -970
  126. package/src/server/routes/workflows.ts +0 -106
  127. package/src/server/services/AIService.ts +0 -105
  128. package/src/server/services/FileWatcher.ts +0 -69
  129. package/src/server/services/WorkflowService.ts +0 -441
  130. package/src/server/services/agents/claude-code-provider.ts +0 -320
  131. package/src/server/services/agents/claude-provider.ts +0 -248
  132. package/src/server/services/agents/codex-provider.ts +0 -398
  133. package/src/server/services/agents/copilot-provider.ts +0 -311
  134. package/src/server/services/agents/demo-provider.ts +0 -184
  135. package/src/server/services/agents/index.ts +0 -31
  136. package/src/server/services/agents/ollama-provider.ts +0 -267
  137. package/src/server/services/agents/prompts.ts +0 -509
  138. package/src/server/services/agents/registry.ts +0 -310
  139. package/src/server/services/agents/types.ts +0 -146
  140. package/src/server/websocket/index.ts +0 -104
  141. package/src/shared/constants.ts +0 -180
  142. package/src/shared/types.ts +0 -179
  143. package/tailwind.config.ts +0 -73
  144. package/tests/e2e/app.spec.ts +0 -90
  145. package/tests/e2e/canvas.spec.ts +0 -128
  146. package/tests/e2e/workflow.spec.ts +0 -185
  147. package/tests/integration/api.test.ts +0 -452
  148. package/tests/integration/testApp.ts +0 -31
  149. package/tests/setup.ts +0 -72
  150. package/tests/unit/ForEachNode.test.tsx +0 -218
  151. package/tests/unit/IfElseNode.test.tsx +0 -188
  152. package/tests/unit/ParallelNode.test.tsx +0 -264
  153. package/tests/unit/SwitchNode.test.tsx +0 -252
  154. package/tests/unit/TransformNode.test.tsx +0 -386
  155. package/tests/unit/TryCatchNode.test.tsx +0 -243
  156. package/tests/unit/WhileNode.test.tsx +0 -226
  157. package/tests/unit/canvasStore.test.ts +0 -502
  158. package/tests/unit/codexProvider.test.ts +0 -399
  159. package/tests/unit/components.test.tsx +0 -151
  160. package/tests/unit/executionStore.test.ts +0 -527
  161. package/tests/unit/layoutStore.test.ts +0 -194
  162. package/tests/unit/navigationStore.test.ts +0 -152
  163. package/tests/unit/serviceIcons.test.ts +0 -197
  164. package/tests/unit/stepValidation.test.ts +0 -226
  165. package/tests/unit/themeStore.test.ts +0 -141
  166. package/tests/unit/workflowToGraph.test.ts +0 -289
  167. package/tsconfig.json +0 -29
  168. package/tsconfig.server.json +0 -28
  169. package/vite.config.ts +0 -31
  170. package/vitest.config.ts +0 -26
  171. /package/dist/server/{server/routes → routes}/tools.js +0 -0
  172. /package/dist/server/{server/routes → routes}/tools.js.map +0 -0
  173. /package/dist/server/{server/services → services}/FileWatcher.js +0 -0
  174. /package/dist/server/{server/services → services}/FileWatcher.js.map +0 -0
  175. /package/dist/server/{server/services → services}/agents/claude-code-provider.js +0 -0
  176. /package/dist/server/{server/services → services}/agents/claude-code-provider.js.map +0 -0
  177. /package/dist/server/{server/services → services}/agents/claude-provider.js +0 -0
  178. /package/dist/server/{server/services → services}/agents/claude-provider.js.map +0 -0
  179. /package/dist/server/{server/services → services}/agents/codex-provider.js +0 -0
  180. /package/dist/server/{server/services → services}/agents/codex-provider.js.map +0 -0
  181. /package/dist/server/{server/services → services}/agents/demo-provider.js +0 -0
  182. /package/dist/server/{server/services → services}/agents/demo-provider.js.map +0 -0
  183. /package/dist/server/{server/services → services}/agents/index.js +0 -0
  184. /package/dist/server/{server/services → services}/agents/index.js.map +0 -0
  185. /package/dist/server/{server/services → services}/agents/ollama-provider.js +0 -0
  186. /package/dist/server/{server/services → services}/agents/ollama-provider.js.map +0 -0
  187. /package/dist/server/{server/services → services}/agents/prompts.js +0 -0
  188. /package/dist/server/{server/services → services}/agents/prompts.js.map +0 -0
  189. /package/dist/server/{server/services → services}/agents/registry.js +0 -0
  190. /package/dist/server/{server/services → services}/agents/registry.js.map +0 -0
  191. /package/dist/server/{server/services → services}/agents/types.js +0 -0
  192. /package/dist/server/{server/services → services}/agents/types.js.map +0 -0
  193. /package/dist/{server/shared → shared}/types.js +0 -0
  194. /package/dist/{server/shared → shared}/types.js.map +0 -0
@@ -1,343 +0,0 @@
1
- import { useState, useCallback, useEffect } from 'react';
2
- import {
3
- FileText,
4
- FolderTree,
5
- ChevronRight,
6
- ChevronLeft,
7
- Plus,
8
- Search,
9
- Loader2,
10
- X,
11
- } from 'lucide-react';
12
- import { useWorkflowStore } from '../../stores/workflowStore';
13
- import { useNavigationStore } from '../../stores/navigationStore';
14
- import { useLayoutStore } from '../../stores/layoutStore';
15
-
16
- export function Sidebar() {
17
- const [activeTab, setActiveTab] = useState<'workflows' | 'tools'>(
18
- 'workflows'
19
- );
20
- const { workflows, selectedWorkflow, selectWorkflow } = useWorkflowStore();
21
- const { resetNavigation } = useNavigationStore();
22
- const { sidebarOpen, setSidebarOpen, breakpoint } = useLayoutStore();
23
-
24
- // Handle workflow selection - resets sub-workflow navigation
25
- const handleSelectWorkflow = useCallback(
26
- (path: string) => {
27
- resetNavigation();
28
- selectWorkflow(path);
29
- // Close sidebar on mobile after selection
30
- if (breakpoint === 'mobile') {
31
- setSidebarOpen(false);
32
- }
33
- },
34
- [resetNavigation, selectWorkflow, breakpoint, setSidebarOpen]
35
- );
36
-
37
- // Collapsed state for desktop
38
- if (!sidebarOpen && breakpoint !== 'mobile') {
39
- return (
40
- <button
41
- onClick={() => setSidebarOpen(true)}
42
- className="w-12 bg-panel-bg border-r border-node-border flex flex-col items-center py-4 gap-4 hover:bg-white/5 transition-colors"
43
- aria-label="Expand sidebar"
44
- >
45
- <ChevronRight className="w-4 h-4 text-gray-400" />
46
- <FolderTree className="w-5 h-5 text-primary" />
47
- </button>
48
- );
49
- }
50
-
51
- // Mobile overlay
52
- if (breakpoint === 'mobile') {
53
- if (!sidebarOpen) return null;
54
-
55
- return (
56
- <>
57
- {/* Backdrop */}
58
- <div
59
- className="fixed inset-0 bg-black/50 z-40 md:hidden"
60
- onClick={() => setSidebarOpen(false)}
61
- />
62
- {/* Sidebar */}
63
- <div className="fixed inset-y-0 left-0 w-72 bg-panel-bg border-r border-node-border flex flex-col z-50 md:hidden animate-slide-in-left">
64
- <SidebarContent
65
- activeTab={activeTab}
66
- setActiveTab={setActiveTab}
67
- workflows={workflows}
68
- selectedWorkflow={selectedWorkflow}
69
- onSelectWorkflow={handleSelectWorkflow}
70
- onClose={() => setSidebarOpen(false)}
71
- showClose
72
- />
73
- </div>
74
- </>
75
- );
76
- }
77
-
78
- // Desktop/Tablet sidebar
79
- return (
80
- <div className="w-64 bg-panel-bg border-r border-node-border flex flex-col">
81
- <SidebarContent
82
- activeTab={activeTab}
83
- setActiveTab={setActiveTab}
84
- workflows={workflows}
85
- selectedWorkflow={selectedWorkflow}
86
- onSelectWorkflow={handleSelectWorkflow}
87
- onClose={() => setSidebarOpen(false)}
88
- showClose={breakpoint === 'tablet'}
89
- />
90
- </div>
91
- );
92
- }
93
-
94
- interface SidebarContentProps {
95
- activeTab: 'workflows' | 'tools';
96
- setActiveTab: (tab: 'workflows' | 'tools') => void;
97
- workflows: Array<{ path: string; name: string }>;
98
- selectedWorkflow: string | null;
99
- onSelectWorkflow: (path: string) => void;
100
- onClose: () => void;
101
- showClose?: boolean;
102
- }
103
-
104
- function SidebarContent({
105
- activeTab,
106
- setActiveTab,
107
- workflows,
108
- selectedWorkflow,
109
- onSelectWorkflow,
110
- onClose,
111
- showClose,
112
- }: SidebarContentProps) {
113
- return (
114
- <>
115
- {/* Logo/Title */}
116
- <div className="p-4 border-b border-node-border flex items-center justify-between">
117
- <h1 className="text-lg font-semibold text-white flex items-center gap-2">
118
- <FolderTree className="w-5 h-5 text-primary" />
119
- Marktoflow
120
- </h1>
121
- {showClose && (
122
- <button
123
- onClick={onClose}
124
- className="w-8 h-8 rounded-lg flex items-center justify-center hover:bg-white/10 transition-colors"
125
- aria-label="Close sidebar"
126
- >
127
- <X className="w-4 h-4 text-gray-400" />
128
- </button>
129
- )}
130
- </div>
131
-
132
- {/* Tab buttons */}
133
- <div className="flex border-b border-node-border">
134
- <button
135
- onClick={() => setActiveTab('workflows')}
136
- className={`flex-1 px-4 py-2 text-sm font-medium transition-colors ${
137
- activeTab === 'workflows'
138
- ? 'text-primary border-b-2 border-primary'
139
- : 'text-gray-400 hover:text-white'
140
- }`}
141
- >
142
- Workflows
143
- </button>
144
- <button
145
- onClick={() => setActiveTab('tools')}
146
- className={`flex-1 px-4 py-2 text-sm font-medium transition-colors ${
147
- activeTab === 'tools'
148
- ? 'text-primary border-b-2 border-primary'
149
- : 'text-gray-400 hover:text-white'
150
- }`}
151
- >
152
- Tools
153
- </button>
154
- </div>
155
-
156
- {/* Search */}
157
- <div className="p-3 border-b border-node-border">
158
- <div className="relative">
159
- <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500" />
160
- <input
161
- type="text"
162
- placeholder={`Search ${activeTab}...`}
163
- className="w-full pl-9 pr-3 py-2 bg-node-bg border border-node-border rounded-lg text-sm text-white placeholder-gray-500 focus:outline-none focus:border-primary"
164
- />
165
- </div>
166
- </div>
167
-
168
- {/* Content */}
169
- <div className="flex-1 overflow-y-auto p-2">
170
- {activeTab === 'workflows' ? (
171
- <WorkflowList
172
- workflows={workflows}
173
- selectedWorkflow={selectedWorkflow}
174
- onSelect={onSelectWorkflow}
175
- />
176
- ) : (
177
- <ToolsPalette />
178
- )}
179
- </div>
180
-
181
- {/* New workflow button */}
182
- {activeTab === 'workflows' && (
183
- <div className="p-3 border-t border-node-border">
184
- <button className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-primary hover:bg-primary-dark text-white rounded-lg text-sm font-medium transition-colors">
185
- <Plus className="w-4 h-4" />
186
- New Workflow
187
- </button>
188
- </div>
189
- )}
190
- </>
191
- );
192
- }
193
-
194
- interface WorkflowListProps {
195
- workflows: Array<{ path: string; name: string }>;
196
- selectedWorkflow: string | null;
197
- onSelect: (path: string) => void;
198
- }
199
-
200
- function WorkflowList({
201
- workflows,
202
- selectedWorkflow,
203
- onSelect,
204
- }: WorkflowListProps) {
205
- if (workflows.length === 0) {
206
- return (
207
- <div className="text-center py-8 text-gray-500 text-sm">
208
- No workflows found
209
- </div>
210
- );
211
- }
212
-
213
- return (
214
- <div className="space-y-1">
215
- {workflows.map((workflow) => (
216
- <button
217
- key={workflow.path}
218
- onClick={() => onSelect(workflow.path)}
219
- className={`w-full flex items-center gap-2 px-3 py-2 rounded-lg text-left transition-colors ${
220
- selectedWorkflow === workflow.path
221
- ? 'bg-primary/10 text-primary'
222
- : 'text-gray-300 hover:bg-white/5'
223
- }`}
224
- >
225
- <FileText className="w-4 h-4 flex-shrink-0" />
226
- <span className="text-sm truncate">{workflow.name}</span>
227
- <ChevronRight className="w-4 h-4 ml-auto flex-shrink-0 opacity-50" />
228
- </button>
229
- ))}
230
- </div>
231
- );
232
- }
233
-
234
- export interface ToolDefinition {
235
- id: string;
236
- name: string;
237
- icon: string;
238
- category: string;
239
- description?: string;
240
- sdk?: string;
241
- authType?: string;
242
- actionCount?: number;
243
- actions?: string[];
244
- }
245
-
246
- // Fallback tools in case API is unavailable
247
- const fallbackTools: ToolDefinition[] = [
248
- { id: 'slack', name: 'Slack', icon: '💬', category: 'Communication', sdk: '@slack/web-api' },
249
- { id: 'github', name: 'GitHub', icon: '🐙', category: 'Development', sdk: '@octokit/rest' },
250
- { id: 'jira', name: 'Jira', icon: '📋', category: 'Project Management', sdk: 'jira.js' },
251
- { id: 'gmail', name: 'Gmail', icon: '📧', category: 'Communication', sdk: 'googleapis' },
252
- { id: 'http', name: 'HTTP', icon: '🌐', category: 'Network' },
253
- { id: 'claude', name: 'Claude', icon: '🤖', category: 'AI' },
254
- ];
255
-
256
- function ToolsPalette() {
257
- const [tools, setTools] = useState<ToolDefinition[]>(fallbackTools);
258
- const [loading, setLoading] = useState(true);
259
- const [searchQuery, setSearchQuery] = useState('');
260
-
261
- // Fetch tools from API
262
- useEffect(() => {
263
- async function fetchTools() {
264
- try {
265
- const response = await fetch('/api/tools');
266
- if (response.ok) {
267
- const data = await response.json();
268
- setTools(data.tools);
269
- }
270
- } catch (error) {
271
- console.error('Failed to fetch tools:', error);
272
- // Keep fallback tools
273
- } finally {
274
- setLoading(false);
275
- }
276
- }
277
- fetchTools();
278
- }, []);
279
-
280
- // Filter tools by search query
281
- const filteredTools = searchQuery
282
- ? tools.filter(
283
- (t) =>
284
- t.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
285
- t.category.toLowerCase().includes(searchQuery.toLowerCase()) ||
286
- t.description?.toLowerCase().includes(searchQuery.toLowerCase())
287
- )
288
- : tools;
289
-
290
- const categories = [...new Set(filteredTools.map((t) => t.category))];
291
-
292
- const handleDragStart = (e: React.DragEvent, tool: ToolDefinition) => {
293
- e.dataTransfer.setData('application/marktoflow-tool', JSON.stringify(tool));
294
- e.dataTransfer.effectAllowed = 'copy';
295
- };
296
-
297
- if (loading) {
298
- return (
299
- <div className="flex items-center justify-center py-8">
300
- <Loader2 className="w-5 h-5 text-gray-500 animate-spin" />
301
- </div>
302
- );
303
- }
304
-
305
- return (
306
- <div className="space-y-4">
307
- {categories.map((category) => (
308
- <div key={category}>
309
- <h3 className="text-xs font-medium text-gray-500 uppercase tracking-wider px-2 mb-2">
310
- {category}
311
- </h3>
312
- <div className="space-y-1">
313
- {filteredTools
314
- .filter((t) => t.category === category)
315
- .map((tool) => (
316
- <div
317
- key={tool.id}
318
- draggable
319
- onDragStart={(e) => handleDragStart(e, tool)}
320
- className="flex items-center gap-2 px-3 py-2 rounded-lg text-gray-300 hover:bg-white/5 cursor-grab active:cursor-grabbing transition-colors group"
321
- title={tool.description || (tool.sdk ? 'SDK: ' + tool.sdk : undefined)}
322
- >
323
- <span className="text-lg">{tool.icon}</span>
324
- <div className="flex-1 min-w-0">
325
- <span className="text-sm block truncate">{tool.name}</span>
326
- {tool.actionCount !== undefined && (
327
- <span className="text-xs text-gray-500">{tool.actionCount} actions</span>
328
- )}
329
- </div>
330
- </div>
331
- ))}
332
- </div>
333
- </div>
334
- ))}
335
-
336
- {filteredTools.length === 0 && (
337
- <div className="text-center py-8 text-gray-500 text-sm">
338
- No tools found
339
- </div>
340
- )}
341
- </div>
342
- );
343
- }
@@ -1,40 +0,0 @@
1
- import { ChevronRight, Home } from 'lucide-react';
2
-
3
- export interface BreadcrumbItem {
4
- id: string;
5
- name: string;
6
- path?: string;
7
- }
8
-
9
- interface BreadcrumbProps {
10
- items: BreadcrumbItem[];
11
- onNavigate: (item: BreadcrumbItem, index: number) => void;
12
- }
13
-
14
- export function Breadcrumb({ items, onNavigate }: BreadcrumbProps) {
15
- if (items.length <= 1) {
16
- return null;
17
- }
18
-
19
- return (
20
- <nav className="flex items-center gap-1 px-4 py-2 bg-panel-bg border-b border-node-border">
21
- {items.map((item, index) => (
22
- <div key={item.id} className="flex items-center">
23
- {index > 0 && <ChevronRight className="w-4 h-4 text-gray-600 mx-1" />}
24
- <button
25
- onClick={() => onNavigate(item, index)}
26
- className={`flex items-center gap-1.5 px-2 py-1 rounded text-sm transition-colors ${
27
- index === items.length - 1
28
- ? 'text-white font-medium cursor-default'
29
- : 'text-gray-400 hover:text-white hover:bg-white/5'
30
- }`}
31
- disabled={index === items.length - 1}
32
- >
33
- {index === 0 && <Home className="w-3.5 h-3.5" />}
34
- <span className="max-w-[150px] truncate">{item.name}</span>
35
- </button>
36
- </div>
37
- ))}
38
- </nav>
39
- );
40
- }
@@ -1,68 +0,0 @@
1
- import { forwardRef } from 'react';
2
- import { cn } from '../../utils/cn';
3
- import { Loader2 } from 'lucide-react';
4
-
5
- export interface ButtonProps
6
- extends React.ButtonHTMLAttributes<HTMLButtonElement> {
7
- variant?: 'primary' | 'secondary' | 'ghost' | 'destructive';
8
- size?: 'sm' | 'md' | 'lg';
9
- loading?: boolean;
10
- icon?: React.ReactNode;
11
- }
12
-
13
- const variantClasses = {
14
- primary:
15
- 'bg-primary hover:bg-primary-dark text-white border-transparent',
16
- secondary:
17
- 'bg-node-bg hover:bg-white/10 text-gray-300 border-node-border hover:border-primary',
18
- ghost: 'bg-transparent hover:bg-white/10 text-gray-300 border-transparent',
19
- destructive:
20
- 'bg-error/10 hover:bg-error/20 text-error border-error/20 hover:border-error',
21
- };
22
-
23
- const sizeClasses = {
24
- sm: 'px-2.5 py-1.5 text-xs',
25
- md: 'px-4 py-2 text-sm',
26
- lg: 'px-6 py-3 text-base',
27
- };
28
-
29
- export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
30
- (
31
- {
32
- className,
33
- variant = 'primary',
34
- size = 'md',
35
- loading,
36
- icon,
37
- disabled,
38
- children,
39
- ...props
40
- },
41
- ref
42
- ) => {
43
- return (
44
- <button
45
- ref={ref}
46
- disabled={disabled || loading}
47
- className={cn(
48
- 'inline-flex items-center justify-center gap-2 rounded-lg border font-medium transition-colors',
49
- 'focus:outline-none focus:ring-2 focus:ring-primary/50 focus:ring-offset-2 focus:ring-offset-panel-bg',
50
- 'disabled:opacity-50 disabled:cursor-not-allowed',
51
- variantClasses[variant],
52
- sizeClasses[size],
53
- className
54
- )}
55
- {...props}
56
- >
57
- {loading ? (
58
- <Loader2 className="w-4 h-4 animate-spin" />
59
- ) : (
60
- icon && <span className="flex-shrink-0">{icon}</span>
61
- )}
62
- {children}
63
- </button>
64
- );
65
- }
66
- );
67
-
68
- Button.displayName = 'Button';
@@ -1,202 +0,0 @@
1
- import * as ContextMenuPrimitive from '@radix-ui/react-context-menu';
2
- import { forwardRef } from 'react';
3
- import { cn } from '../../utils/cn';
4
-
5
- const ContextMenu = ContextMenuPrimitive.Root;
6
- const ContextMenuTrigger = ContextMenuPrimitive.Trigger;
7
- const ContextMenuGroup = ContextMenuPrimitive.Group;
8
- const ContextMenuPortal = ContextMenuPrimitive.Portal;
9
- const ContextMenuSub = ContextMenuPrimitive.Sub;
10
- const ContextMenuRadioGroup = ContextMenuPrimitive.RadioGroup;
11
-
12
- const ContextMenuSubTrigger = forwardRef<
13
- React.ElementRef<typeof ContextMenuPrimitive.SubTrigger>,
14
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubTrigger> & {
15
- inset?: boolean;
16
- }
17
- >(({ className, inset, children, ...props }, ref) => (
18
- <ContextMenuPrimitive.SubTrigger
19
- ref={ref}
20
- className={cn(
21
- 'flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
22
- 'focus:bg-white/10 data-[state=open]:bg-white/10',
23
- inset && 'pl-8',
24
- className
25
- )}
26
- {...props}
27
- >
28
- {children}
29
- <span className="ml-auto text-xs">▶</span>
30
- </ContextMenuPrimitive.SubTrigger>
31
- ));
32
- ContextMenuSubTrigger.displayName = ContextMenuPrimitive.SubTrigger.displayName;
33
-
34
- const ContextMenuSubContent = forwardRef<
35
- React.ElementRef<typeof ContextMenuPrimitive.SubContent>,
36
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.SubContent>
37
- >(({ className, ...props }, ref) => (
38
- <ContextMenuPrimitive.SubContent
39
- ref={ref}
40
- className={cn(
41
- 'z-50 min-w-[8rem] overflow-hidden rounded-md border border-node-border bg-panel-bg p-1 shadow-lg',
42
- 'data-[state=open]:animate-in data-[state=closed]:animate-out',
43
- 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
44
- 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
45
- className
46
- )}
47
- {...props}
48
- />
49
- ));
50
- ContextMenuSubContent.displayName = ContextMenuPrimitive.SubContent.displayName;
51
-
52
- const ContextMenuContent = forwardRef<
53
- React.ElementRef<typeof ContextMenuPrimitive.Content>,
54
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Content>
55
- >(({ className, ...props }, ref) => (
56
- <ContextMenuPrimitive.Portal>
57
- <ContextMenuPrimitive.Content
58
- ref={ref}
59
- className={cn(
60
- 'z-50 min-w-[12rem] overflow-hidden rounded-md border border-node-border bg-panel-bg p-1 shadow-lg',
61
- 'animate-in fade-in-80 data-[state=open]:animate-in data-[state=closed]:animate-out',
62
- 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0',
63
- 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95',
64
- className
65
- )}
66
- {...props}
67
- />
68
- </ContextMenuPrimitive.Portal>
69
- ));
70
- ContextMenuContent.displayName = ContextMenuPrimitive.Content.displayName;
71
-
72
- const ContextMenuItem = forwardRef<
73
- React.ElementRef<typeof ContextMenuPrimitive.Item>,
74
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Item> & {
75
- inset?: boolean;
76
- destructive?: boolean;
77
- }
78
- >(({ className, inset, destructive, ...props }, ref) => (
79
- <ContextMenuPrimitive.Item
80
- ref={ref}
81
- className={cn(
82
- 'relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none',
83
- 'focus:bg-white/10 focus:text-white',
84
- 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
85
- destructive && 'text-error focus:bg-error/10 focus:text-error',
86
- inset && 'pl-8',
87
- className
88
- )}
89
- {...props}
90
- />
91
- ));
92
- ContextMenuItem.displayName = ContextMenuPrimitive.Item.displayName;
93
-
94
- const ContextMenuCheckboxItem = forwardRef<
95
- React.ElementRef<typeof ContextMenuPrimitive.CheckboxItem>,
96
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.CheckboxItem>
97
- >(({ className, children, checked, ...props }, ref) => (
98
- <ContextMenuPrimitive.CheckboxItem
99
- ref={ref}
100
- className={cn(
101
- 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
102
- 'focus:bg-white/10 focus:text-white',
103
- 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
104
- className
105
- )}
106
- checked={checked}
107
- {...props}
108
- >
109
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
110
- <ContextMenuPrimitive.ItemIndicator>
111
- <span className="text-primary">✓</span>
112
- </ContextMenuPrimitive.ItemIndicator>
113
- </span>
114
- {children}
115
- </ContextMenuPrimitive.CheckboxItem>
116
- ));
117
- ContextMenuCheckboxItem.displayName = ContextMenuPrimitive.CheckboxItem.displayName;
118
-
119
- const ContextMenuRadioItem = forwardRef<
120
- React.ElementRef<typeof ContextMenuPrimitive.RadioItem>,
121
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.RadioItem>
122
- >(({ className, children, ...props }, ref) => (
123
- <ContextMenuPrimitive.RadioItem
124
- ref={ref}
125
- className={cn(
126
- 'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none',
127
- 'focus:bg-white/10 focus:text-white',
128
- 'data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
129
- className
130
- )}
131
- {...props}
132
- >
133
- <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
134
- <ContextMenuPrimitive.ItemIndicator>
135
- <span className="h-2 w-2 rounded-full bg-primary" />
136
- </ContextMenuPrimitive.ItemIndicator>
137
- </span>
138
- {children}
139
- </ContextMenuPrimitive.RadioItem>
140
- ));
141
- ContextMenuRadioItem.displayName = ContextMenuPrimitive.RadioItem.displayName;
142
-
143
- const ContextMenuLabel = forwardRef<
144
- React.ElementRef<typeof ContextMenuPrimitive.Label>,
145
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Label> & {
146
- inset?: boolean;
147
- }
148
- >(({ className, inset, ...props }, ref) => (
149
- <ContextMenuPrimitive.Label
150
- ref={ref}
151
- className={cn(
152
- 'px-2 py-1.5 text-xs font-semibold text-gray-400',
153
- inset && 'pl-8',
154
- className
155
- )}
156
- {...props}
157
- />
158
- ));
159
- ContextMenuLabel.displayName = ContextMenuPrimitive.Label.displayName;
160
-
161
- const ContextMenuSeparator = forwardRef<
162
- React.ElementRef<typeof ContextMenuPrimitive.Separator>,
163
- React.ComponentPropsWithoutRef<typeof ContextMenuPrimitive.Separator>
164
- >(({ className, ...props }, ref) => (
165
- <ContextMenuPrimitive.Separator
166
- ref={ref}
167
- className={cn('-mx-1 my-1 h-px bg-node-border', className)}
168
- {...props}
169
- />
170
- ));
171
- ContextMenuSeparator.displayName = ContextMenuPrimitive.Separator.displayName;
172
-
173
- const ContextMenuShortcut = ({
174
- className,
175
- ...props
176
- }: React.HTMLAttributes<HTMLSpanElement>) => {
177
- return (
178
- <span
179
- className={cn('ml-auto text-xs tracking-widest text-gray-500', className)}
180
- {...props}
181
- />
182
- );
183
- };
184
- ContextMenuShortcut.displayName = 'ContextMenuShortcut';
185
-
186
- export {
187
- ContextMenu,
188
- ContextMenuTrigger,
189
- ContextMenuContent,
190
- ContextMenuItem,
191
- ContextMenuCheckboxItem,
192
- ContextMenuRadioItem,
193
- ContextMenuLabel,
194
- ContextMenuSeparator,
195
- ContextMenuShortcut,
196
- ContextMenuGroup,
197
- ContextMenuPortal,
198
- ContextMenuSub,
199
- ContextMenuSubContent,
200
- ContextMenuSubTrigger,
201
- ContextMenuRadioGroup,
202
- };