npcts 0.1.0

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 (285) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +139 -0
  3. package/dist/adapters/base.d.ts +13 -0
  4. package/dist/adapters/base.js +1 -0
  5. package/dist/adapters/electron/bridge.d.ts +4 -0
  6. package/dist/adapters/electron/bridge.js +88 -0
  7. package/dist/adapters/index.d.ts +2 -0
  8. package/dist/adapters/index.js +3 -0
  9. package/dist/core/browser.d.ts +25 -0
  10. package/dist/core/browser.js +1 -0
  11. package/dist/core/chat.d.ts +41 -0
  12. package/dist/core/chat.js +1 -0
  13. package/dist/core/database.d.ts +56 -0
  14. package/dist/core/database.js +50 -0
  15. package/dist/core/files.d.ts +24 -0
  16. package/dist/core/files.js +15 -0
  17. package/dist/core/index.d.ts +9 -0
  18. package/dist/core/index.js +10 -0
  19. package/dist/core/jobs.d.ts +20 -0
  20. package/dist/core/jobs.js +1 -0
  21. package/dist/core/layout.d.ts +30 -0
  22. package/dist/core/layout.js +41 -0
  23. package/dist/core/stream.d.ts +10 -0
  24. package/dist/core/stream.js +1 -0
  25. package/dist/core/types.d.ts +23 -0
  26. package/dist/core/types.js +1 -0
  27. package/dist/core/utils.d.ts +19 -0
  28. package/dist/core/utils.js +19 -0
  29. package/dist/index.d.ts +25 -0
  30. package/dist/index.js +29 -0
  31. package/dist/ui/chat/components/ChatHeaderBar.d.ts +13 -0
  32. package/dist/ui/chat/components/ChatHeaderBar.js +32 -0
  33. package/dist/ui/chat/components/ChatInterface.d.ts +10 -0
  34. package/dist/ui/chat/components/ChatInterface.js +19 -0
  35. package/dist/ui/chat/components/ChatMessage.d.ts +7 -0
  36. package/dist/ui/chat/components/ChatMessage.js +10 -0
  37. package/dist/ui/chat/components/ChatPane.d.ts +20 -0
  38. package/dist/ui/chat/components/ChatPane.js +20 -0
  39. package/dist/ui/chat/components/ChatView.d.ts +10 -0
  40. package/dist/ui/chat/components/ChatView.js +36 -0
  41. package/dist/ui/chat/components/ConversationList.d.ts +28 -0
  42. package/dist/ui/chat/components/ConversationList.js +113 -0
  43. package/dist/ui/chat/components/InPaneSearchBar.d.ts +12 -0
  44. package/dist/ui/chat/components/InPaneSearchBar.js +44 -0
  45. package/dist/ui/chat/components/InputArea.d.ts +7 -0
  46. package/dist/ui/chat/components/InputArea.js +46 -0
  47. package/dist/ui/chat/components/MessageAttachments.d.ts +5 -0
  48. package/dist/ui/chat/components/MessageAttachments.js +6 -0
  49. package/dist/ui/chat/components/MessageItem.d.ts +28 -0
  50. package/dist/ui/chat/components/MessageItem.js +43 -0
  51. package/dist/ui/chat/components/PredictiveTextOverlay.d.ts +10 -0
  52. package/dist/ui/chat/components/PredictiveTextOverlay.js +75 -0
  53. package/dist/ui/chat/context/ChatContext.d.ts +33 -0
  54. package/dist/ui/chat/context/ChatContext.js +157 -0
  55. package/dist/ui/chat/hooks/useAutoScroll.d.ts +1 -0
  56. package/dist/ui/chat/hooks/useAutoScroll.js +11 -0
  57. package/dist/ui/chat/index.d.ts +7 -0
  58. package/dist/ui/chat/index.js +7 -0
  59. package/dist/ui/dashboard/ChartWidget.d.ts +18 -0
  60. package/dist/ui/dashboard/ChartWidget.js +98 -0
  61. package/dist/ui/dashboard/QueryWidget.d.ts +29 -0
  62. package/dist/ui/dashboard/QueryWidget.js +117 -0
  63. package/dist/ui/dashboard/TableWidget.d.ts +14 -0
  64. package/dist/ui/dashboard/TableWidget.js +117 -0
  65. package/dist/ui/dashboard/Widget.d.ts +40 -0
  66. package/dist/ui/dashboard/Widget.js +26 -0
  67. package/dist/ui/dashboard/WidgetBuilder.d.ts +47 -0
  68. package/dist/ui/dashboard/WidgetBuilder.js +286 -0
  69. package/dist/ui/dashboard/WidgetGrid.d.ts +19 -0
  70. package/dist/ui/dashboard/WidgetGrid.js +11 -0
  71. package/dist/ui/dashboard/index.d.ts +8 -0
  72. package/dist/ui/dashboard/index.js +4 -0
  73. package/dist/ui/dialogs/BrowserUrlDialog.d.ts +8 -0
  74. package/dist/ui/dialogs/BrowserUrlDialog.js +203 -0
  75. package/dist/ui/dialogs/index.d.ts +1 -0
  76. package/dist/ui/dialogs/index.js +1 -0
  77. package/dist/ui/editors/ImageEditor.d.ts +49 -0
  78. package/dist/ui/editors/ImageEditor.js +264 -0
  79. package/dist/ui/editors/index.d.ts +2 -0
  80. package/dist/ui/editors/index.js +1 -0
  81. package/dist/ui/execution/ExecutionFilters.d.ts +11 -0
  82. package/dist/ui/execution/ExecutionFilters.js +27 -0
  83. package/dist/ui/execution/ExecutionHistoryList.d.ts +19 -0
  84. package/dist/ui/execution/ExecutionHistoryList.js +35 -0
  85. package/dist/ui/execution/index.d.ts +3 -0
  86. package/dist/ui/execution/index.js +2 -0
  87. package/dist/ui/files/components/FileTree.d.ts +18 -0
  88. package/dist/ui/files/components/FileTree.js +61 -0
  89. package/dist/ui/files/components/Sidebar.d.ts +18 -0
  90. package/dist/ui/files/components/Sidebar.js +67 -0
  91. package/dist/ui/files/components/index.d.ts +2 -0
  92. package/dist/ui/files/components/index.js +2 -0
  93. package/dist/ui/files/context/FileSystemContext.d.ts +23 -0
  94. package/dist/ui/files/context/FileSystemContext.js +65 -0
  95. package/dist/ui/files/context/index.d.ts +1 -0
  96. package/dist/ui/files/context/index.js +1 -0
  97. package/dist/ui/files/index.d.ts +2 -0
  98. package/dist/ui/files/index.js +2 -0
  99. package/dist/ui/hooks/index.d.ts +4 -0
  100. package/dist/ui/hooks/index.js +3 -0
  101. package/dist/ui/hooks/useDebounce.d.ts +8 -0
  102. package/dist/ui/hooks/useDebounce.js +18 -0
  103. package/dist/ui/hooks/usePaneTracking.d.ts +15 -0
  104. package/dist/ui/hooks/usePaneTracking.js +20 -0
  105. package/dist/ui/hooks/useQuery.d.ts +25 -0
  106. package/dist/ui/hooks/useQuery.js +71 -0
  107. package/dist/ui/index.d.ts +19 -0
  108. package/dist/ui/index.js +20 -0
  109. package/dist/ui/jinx/JinxEditor.d.ts +20 -0
  110. package/dist/ui/jinx/JinxEditor.js +34 -0
  111. package/dist/ui/jinx/JinxTree.d.ts +14 -0
  112. package/dist/ui/jinx/JinxTree.js +65 -0
  113. package/dist/ui/jinx/index.d.ts +3 -0
  114. package/dist/ui/jinx/index.js +2 -0
  115. package/dist/ui/knowledge-graph/KGControls.d.ts +12 -0
  116. package/dist/ui/knowledge-graph/KGControls.js +21 -0
  117. package/dist/ui/knowledge-graph/KGStats.d.ts +13 -0
  118. package/dist/ui/knowledge-graph/KGStats.js +18 -0
  119. package/dist/ui/knowledge-graph/KnowledgeGraphViewer.d.ts +22 -0
  120. package/dist/ui/knowledge-graph/KnowledgeGraphViewer.js +16 -0
  121. package/dist/ui/knowledge-graph/index.d.ts +4 -0
  122. package/dist/ui/knowledge-graph/index.js +3 -0
  123. package/dist/ui/layout/components/AppShell.d.ts +8 -0
  124. package/dist/ui/layout/components/AppShell.js +19 -0
  125. package/dist/ui/layout/components/ContentPaneContainer.d.ts +8 -0
  126. package/dist/ui/layout/components/ContentPaneContainer.js +95 -0
  127. package/dist/ui/layout/components/LayoutNode.d.ts +8 -0
  128. package/dist/ui/layout/components/LayoutNode.js +12 -0
  129. package/dist/ui/layout/components/PaneHeader.d.ts +17 -0
  130. package/dist/ui/layout/components/PaneHeader.js +40 -0
  131. package/dist/ui/layout/components/SplitView.d.ts +8 -0
  132. package/dist/ui/layout/components/SplitView.js +51 -0
  133. package/dist/ui/layout/components/Studio.d.ts +7 -0
  134. package/dist/ui/layout/components/Studio.js +12 -0
  135. package/dist/ui/layout/components/contextMenus/BrowserContextMenu.d.ts +13 -0
  136. package/dist/ui/layout/components/contextMenus/BrowserContextMenu.js +23 -0
  137. package/dist/ui/layout/components/contextMenus/EditorContextMenu.d.ts +15 -0
  138. package/dist/ui/layout/components/contextMenus/EditorContextMenu.js +32 -0
  139. package/dist/ui/layout/components/contextMenus/FileContextMenu.d.ts +15 -0
  140. package/dist/ui/layout/components/contextMenus/FileContextMenu.js +33 -0
  141. package/dist/ui/layout/components/contextMenus/PdfContextMenu.d.ts +13 -0
  142. package/dist/ui/layout/components/contextMenus/PdfContextMenu.js +23 -0
  143. package/dist/ui/layout/components/contextMenus/index.d.ts +4 -0
  144. package/dist/ui/layout/components/contextMenus/index.js +4 -0
  145. package/dist/ui/layout/components/index.d.ts +8 -0
  146. package/dist/ui/layout/components/index.js +8 -0
  147. package/dist/ui/layout/components/modals/AIEditModal.d.ts +9 -0
  148. package/dist/ui/layout/components/modals/AIEditModal.js +33 -0
  149. package/dist/ui/layout/components/modals/MemoryApprovalModal.d.ts +15 -0
  150. package/dist/ui/layout/components/modals/MemoryApprovalModal.js +23 -0
  151. package/dist/ui/layout/components/modals/PromptModal.d.ts +11 -0
  152. package/dist/ui/layout/components/modals/PromptModal.js +20 -0
  153. package/dist/ui/layout/components/modals/ResendModal.d.ts +16 -0
  154. package/dist/ui/layout/components/modals/ResendModal.js +22 -0
  155. package/dist/ui/layout/components/modals/index.d.ts +4 -0
  156. package/dist/ui/layout/components/modals/index.js +4 -0
  157. package/dist/ui/layout/context/LayoutContext.d.ts +32 -0
  158. package/dist/ui/layout/context/LayoutContext.js +144 -0
  159. package/dist/ui/layout/index.d.ts +2 -0
  160. package/dist/ui/layout/index.js +2 -0
  161. package/dist/ui/markdown/Markdown.d.ts +4 -0
  162. package/dist/ui/markdown/Markdown.js +4 -0
  163. package/dist/ui/memory/MemoryFilters.d.ts +12 -0
  164. package/dist/ui/memory/MemoryFilters.js +23 -0
  165. package/dist/ui/memory/MemoryList.d.ts +19 -0
  166. package/dist/ui/memory/MemoryList.js +36 -0
  167. package/dist/ui/memory/index.d.ts +3 -0
  168. package/dist/ui/memory/index.js +2 -0
  169. package/dist/ui/models/ModelCard.d.ts +16 -0
  170. package/dist/ui/models/ModelCard.js +30 -0
  171. package/dist/ui/models/ModelSelector.d.ts +13 -0
  172. package/dist/ui/models/ModelSelector.js +6 -0
  173. package/dist/ui/models/index.d.ts +3 -0
  174. package/dist/ui/models/index.js +2 -0
  175. package/dist/ui/npc/McpServerMenu.d.ts +15 -0
  176. package/dist/ui/npc/McpServerMenu.js +48 -0
  177. package/dist/ui/npc/NPCEditor.d.ts +21 -0
  178. package/dist/ui/npc/NPCEditor.js +17 -0
  179. package/dist/ui/npc/NPCList.d.ts +19 -0
  180. package/dist/ui/npc/NPCList.js +28 -0
  181. package/dist/ui/npc/index.d.ts +3 -0
  182. package/dist/ui/npc/index.js +2 -0
  183. package/dist/ui/photo/GalleryGrid.d.ts +25 -0
  184. package/dist/ui/photo/GalleryGrid.js +46 -0
  185. package/dist/ui/photo/ImageAdjustmentSliders.d.ts +37 -0
  186. package/dist/ui/photo/ImageAdjustmentSliders.js +56 -0
  187. package/dist/ui/photo/ImageLabelingCanvas.d.ts +47 -0
  188. package/dist/ui/photo/ImageLabelingCanvas.js +174 -0
  189. package/dist/ui/photo/ImageSourceTabs.d.ts +28 -0
  190. package/dist/ui/photo/ImageSourceTabs.js +46 -0
  191. package/dist/ui/photo/LayerPanel.d.ts +87 -0
  192. package/dist/ui/photo/LayerPanel.js +70 -0
  193. package/dist/ui/photo/Lightbox.d.ts +12 -0
  194. package/dist/ui/photo/Lightbox.js +90 -0
  195. package/dist/ui/photo/index.d.ts +6 -0
  196. package/dist/ui/photo/index.js +7 -0
  197. package/dist/ui/primitives/AutosizeTextarea.d.ts +8 -0
  198. package/dist/ui/primitives/AutosizeTextarea.js +17 -0
  199. package/dist/ui/primitives/Button.d.ts +7 -0
  200. package/dist/ui/primitives/Button.js +17 -0
  201. package/dist/ui/primitives/Card.d.ts +12 -0
  202. package/dist/ui/primitives/Card.js +8 -0
  203. package/dist/ui/primitives/Chart.d.ts +34 -0
  204. package/dist/ui/primitives/Chart.js +140 -0
  205. package/dist/ui/primitives/ContextMenu.d.ts +17 -0
  206. package/dist/ui/primitives/ContextMenu.js +33 -0
  207. package/dist/ui/primitives/DataTable.d.ts +13 -0
  208. package/dist/ui/primitives/DataTable.js +13 -0
  209. package/dist/ui/primitives/FileUpload.d.ts +10 -0
  210. package/dist/ui/primitives/FileUpload.js +24 -0
  211. package/dist/ui/primitives/ImageGrid.d.ts +21 -0
  212. package/dist/ui/primitives/ImageGrid.js +29 -0
  213. package/dist/ui/primitives/Input.d.ts +7 -0
  214. package/dist/ui/primitives/Input.js +10 -0
  215. package/dist/ui/primitives/Lightbox.d.ts +12 -0
  216. package/dist/ui/primitives/Lightbox.js +36 -0
  217. package/dist/ui/primitives/Modal.d.ts +10 -0
  218. package/dist/ui/primitives/Modal.js +33 -0
  219. package/dist/ui/primitives/RangeSlider.d.ts +13 -0
  220. package/dist/ui/primitives/RangeSlider.js +6 -0
  221. package/dist/ui/primitives/Select.d.ts +11 -0
  222. package/dist/ui/primitives/Select.js +10 -0
  223. package/dist/ui/primitives/Slider.d.ts +13 -0
  224. package/dist/ui/primitives/Slider.js +8 -0
  225. package/dist/ui/primitives/SortableList.d.ts +9 -0
  226. package/dist/ui/primitives/SortableList.js +19 -0
  227. package/dist/ui/primitives/Spinner.d.ts +2 -0
  228. package/dist/ui/primitives/Spinner.js +2 -0
  229. package/dist/ui/primitives/StarRating.d.ts +10 -0
  230. package/dist/ui/primitives/StarRating.js +10 -0
  231. package/dist/ui/primitives/Tabs.d.ts +15 -0
  232. package/dist/ui/primitives/Tabs.js +11 -0
  233. package/dist/ui/primitives/TagInput.d.ts +10 -0
  234. package/dist/ui/primitives/TagInput.js +25 -0
  235. package/dist/ui/primitives/index.d.ts +20 -0
  236. package/dist/ui/primitives/index.js +19 -0
  237. package/dist/ui/specialized/DiskUsageAnalyzer.d.ts +12 -0
  238. package/dist/ui/specialized/DiskUsageAnalyzer.js +38 -0
  239. package/dist/ui/specialized/OllamaModelManager.d.ts +2 -0
  240. package/dist/ui/specialized/OllamaModelManager.js +48 -0
  241. package/dist/ui/specialized/RichTextEditor.d.ts +8 -0
  242. package/dist/ui/specialized/RichTextEditor.js +64 -0
  243. package/dist/ui/specialized/SlideCanvas.d.ts +24 -0
  244. package/dist/ui/specialized/SlideCanvas.js +31 -0
  245. package/dist/ui/specialized/SpreadsheetGrid.d.ts +18 -0
  246. package/dist/ui/specialized/SpreadsheetGrid.js +28 -0
  247. package/dist/ui/specialized/StepEditor.d.ts +12 -0
  248. package/dist/ui/specialized/StepEditor.js +22 -0
  249. package/dist/ui/specialized/TerminalEmbed.d.ts +13 -0
  250. package/dist/ui/specialized/TerminalEmbed.js +50 -0
  251. package/dist/ui/specialized/index.d.ts +7 -0
  252. package/dist/ui/specialized/index.js +7 -0
  253. package/dist/ui/sql/SQLQueryEditor.d.ts +9 -0
  254. package/dist/ui/sql/SQLQueryEditor.js +10 -0
  255. package/dist/ui/sql/SQLResultsTable.d.ts +6 -0
  256. package/dist/ui/sql/SQLResultsTable.js +12 -0
  257. package/dist/ui/sql/SQLSchemaViewer.d.ts +14 -0
  258. package/dist/ui/sql/SQLSchemaViewer.js +18 -0
  259. package/dist/ui/sql/index.d.ts +3 -0
  260. package/dist/ui/sql/index.js +3 -0
  261. package/dist/ui/utils/cn.d.ts +1 -0
  262. package/dist/ui/utils/cn.js +1 -0
  263. package/dist/ui/utils/fileIcons.d.ts +2 -0
  264. package/dist/ui/utils/fileIcons.js +24 -0
  265. package/dist/ui/utils/fileUtils.d.ts +4 -0
  266. package/dist/ui/utils/fileUtils.js +11 -0
  267. package/dist/ui/utils/index.d.ts +3 -0
  268. package/dist/ui/utils/index.js +3 -0
  269. package/dist/ui/viewers/components/BrowserViewer.d.ts +9 -0
  270. package/dist/ui/viewers/components/BrowserViewer.js +44 -0
  271. package/dist/ui/viewers/components/CodeEditor.d.ts +11 -0
  272. package/dist/ui/viewers/components/CodeEditor.js +115 -0
  273. package/dist/ui/viewers/components/CsvViewer.d.ts +7 -0
  274. package/dist/ui/viewers/components/CsvViewer.js +18 -0
  275. package/dist/ui/viewers/components/ImageViewer.d.ts +7 -0
  276. package/dist/ui/viewers/components/ImageViewer.js +23 -0
  277. package/dist/ui/viewers/components/PdfViewer.d.ts +7 -0
  278. package/dist/ui/viewers/components/PdfViewer.js +29 -0
  279. package/dist/ui/viewers/components/Terminal.d.ts +7 -0
  280. package/dist/ui/viewers/components/Terminal.js +31 -0
  281. package/dist/ui/viewers/components/index.d.ts +6 -0
  282. package/dist/ui/viewers/components/index.js +6 -0
  283. package/dist/ui/viewers/index.d.ts +1 -0
  284. package/dist/ui/viewers/index.js +1 -0
  285. package/package.json +76 -0
@@ -0,0 +1,117 @@
1
+ import React, { useState, useMemo } from 'react';
2
+ import { ChevronUp, ChevronDown, Search, Download, Copy } from 'lucide-react';
3
+ export const TableWidget = ({ data, columns: propColumns, maxHeight = 400, sortable = true, searchable = true, pagination = true, pageSize = 10, onRowClick, onExport }) => {
4
+ const [sortColumn, setSortColumn] = useState(null);
5
+ const [sortDirection, setSortDirection] = useState('asc');
6
+ const [searchTerm, setSearchTerm] = useState('');
7
+ const [currentPage, setCurrentPage] = useState(0);
8
+ // Derive columns from data if not provided
9
+ const columns = useMemo(() => {
10
+ if (propColumns)
11
+ return propColumns;
12
+ if (data.length === 0)
13
+ return [];
14
+ return Object.keys(data[0]);
15
+ }, [data, propColumns]);
16
+ // Filter data by search term
17
+ const filteredData = useMemo(() => {
18
+ if (!searchTerm)
19
+ return data;
20
+ const term = searchTerm.toLowerCase();
21
+ return data.filter(row => columns.some(col => String(row[col] ?? '').toLowerCase().includes(term)));
22
+ }, [data, columns, searchTerm]);
23
+ // Sort data
24
+ const sortedData = useMemo(() => {
25
+ if (!sortColumn)
26
+ return filteredData;
27
+ return [...filteredData].sort((a, b) => {
28
+ const aVal = a[sortColumn];
29
+ const bVal = b[sortColumn];
30
+ if (aVal === null || aVal === undefined)
31
+ return 1;
32
+ if (bVal === null || bVal === undefined)
33
+ return -1;
34
+ if (typeof aVal === 'number' && typeof bVal === 'number') {
35
+ return sortDirection === 'asc' ? aVal - bVal : bVal - aVal;
36
+ }
37
+ const aStr = String(aVal);
38
+ const bStr = String(bVal);
39
+ return sortDirection === 'asc'
40
+ ? aStr.localeCompare(bStr)
41
+ : bStr.localeCompare(aStr);
42
+ });
43
+ }, [filteredData, sortColumn, sortDirection]);
44
+ // Paginate data
45
+ const paginatedData = useMemo(() => {
46
+ if (!pagination)
47
+ return sortedData;
48
+ const start = currentPage * pageSize;
49
+ return sortedData.slice(start, start + pageSize);
50
+ }, [sortedData, pagination, currentPage, pageSize]);
51
+ const totalPages = Math.ceil(sortedData.length / pageSize);
52
+ const handleSort = (column) => {
53
+ if (!sortable)
54
+ return;
55
+ if (sortColumn === column) {
56
+ setSortDirection(d => d === 'asc' ? 'desc' : 'asc');
57
+ }
58
+ else {
59
+ setSortColumn(column);
60
+ setSortDirection('asc');
61
+ }
62
+ };
63
+ const handleCopyCell = (value) => {
64
+ navigator.clipboard.writeText(String(value ?? ''));
65
+ };
66
+ if (data.length === 0) {
67
+ return (React.createElement("div", { className: "flex items-center justify-center h-32 text-gray-500" }, "No data available"));
68
+ }
69
+ return (React.createElement("div", { className: "flex flex-col h-full" },
70
+ (searchable || onExport) && (React.createElement("div", { className: "flex items-center gap-2 mb-2" },
71
+ searchable && (React.createElement("div", { className: "flex-1 relative" },
72
+ React.createElement(Search, { size: 14, className: "absolute left-2 top-1/2 -translate-y-1/2 text-gray-500" }),
73
+ React.createElement("input", { type: "text", value: searchTerm, onChange: (e) => {
74
+ setSearchTerm(e.target.value);
75
+ setCurrentPage(0);
76
+ }, placeholder: "Search...", className: "w-full pl-8 pr-3 py-1.5 bg-gray-800 border border-gray-700 rounded text-sm" }))),
77
+ onExport && (React.createElement("button", { onClick: () => onExport(sortedData), className: "p-1.5 hover:bg-gray-700 rounded text-gray-400", title: "Export" },
78
+ React.createElement(Download, { size: 14 }))))),
79
+ React.createElement("div", { className: "flex-1 overflow-auto border border-gray-700 rounded", style: { maxHeight } },
80
+ React.createElement("table", { className: "w-full text-sm" },
81
+ React.createElement("thead", { className: "sticky top-0 bg-gray-800 z-10" },
82
+ React.createElement("tr", null, columns.map(col => (React.createElement("th", { key: col, onClick: () => handleSort(col), className: `px-3 py-2 text-left font-medium text-gray-300 border-b border-gray-700
83
+ ${sortable ? 'cursor-pointer hover:bg-gray-700' : ''}` },
84
+ React.createElement("div", { className: "flex items-center gap-1" },
85
+ React.createElement("span", { className: "truncate" }, col),
86
+ sortable && sortColumn === col && (sortDirection === 'asc'
87
+ ? React.createElement(ChevronUp, { size: 12 })
88
+ : React.createElement(ChevronDown, { size: 12 })))))))),
89
+ React.createElement("tbody", null, paginatedData.map((row, rowIndex) => (React.createElement("tr", { key: rowIndex, onClick: () => onRowClick?.(row, rowIndex), className: `border-b border-gray-800 hover:bg-gray-800/50
90
+ ${onRowClick ? 'cursor-pointer' : ''}` }, columns.map(col => (React.createElement("td", { key: col, className: "px-3 py-2 text-gray-300 group relative" },
91
+ React.createElement("div", { className: "truncate max-w-[200px]", title: String(row[col] ?? '') }, formatCellValue(row[col])),
92
+ React.createElement("button", { onClick: (e) => {
93
+ e.stopPropagation();
94
+ handleCopyCell(row[col]);
95
+ }, className: "absolute right-1 top-1/2 -translate-y-1/2 p-1\n opacity-0 group-hover:opacity-100 hover:bg-gray-700 rounded" },
96
+ React.createElement(Copy, { size: 10 }))))))))))),
97
+ pagination && totalPages > 1 && (React.createElement("div", { className: "flex items-center justify-between mt-2 text-sm text-gray-400" },
98
+ React.createElement("span", null,
99
+ currentPage * pageSize + 1,
100
+ "-",
101
+ Math.min((currentPage + 1) * pageSize, sortedData.length),
102
+ " of ",
103
+ sortedData.length),
104
+ React.createElement("div", { className: "flex gap-1" },
105
+ React.createElement("button", { onClick: () => setCurrentPage(p => Math.max(0, p - 1)), disabled: currentPage === 0, className: "px-2 py-1 rounded hover:bg-gray-700 disabled:opacity-50" }, "Prev"),
106
+ React.createElement("button", { onClick: () => setCurrentPage(p => Math.min(totalPages - 1, p + 1)), disabled: currentPage >= totalPages - 1, className: "px-2 py-1 rounded hover:bg-gray-700 disabled:opacity-50" }, "Next"))))));
107
+ };
108
+ function formatCellValue(value) {
109
+ if (value === null || value === undefined)
110
+ return '—';
111
+ if (typeof value === 'boolean')
112
+ return value ? 'Yes' : 'No';
113
+ if (typeof value === 'object')
114
+ return JSON.stringify(value);
115
+ return String(value);
116
+ }
117
+ export default TableWidget;
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ export interface WidgetProps {
3
+ title: string;
4
+ icon?: React.ReactNode;
5
+ iconColor?: string;
6
+ loading?: boolean;
7
+ error?: string | null;
8
+ children: React.ReactNode;
9
+ className?: string;
10
+ headerActions?: React.ReactNode;
11
+ onContextMenu?: (e: React.MouseEvent) => void;
12
+ }
13
+ export declare const Widget: React.FC<WidgetProps>;
14
+ export interface StatWidgetProps {
15
+ value: string | number;
16
+ label?: string;
17
+ trend?: {
18
+ value: number;
19
+ direction: 'up' | 'down';
20
+ };
21
+ className?: string;
22
+ }
23
+ export declare const StatValue: React.FC<StatWidgetProps>;
24
+ export interface StatListProps {
25
+ items: Array<{
26
+ label: string;
27
+ value: string | number;
28
+ }>;
29
+ className?: string;
30
+ }
31
+ export declare const StatList: React.FC<StatListProps>;
32
+ export interface WidgetToggleProps {
33
+ options: Array<{
34
+ label: string;
35
+ value: string;
36
+ }>;
37
+ activeValue: string;
38
+ onChange: (value: string) => void;
39
+ }
40
+ export declare const WidgetToggle: React.FC<WidgetToggleProps>;
@@ -0,0 +1,26 @@
1
+ import React from 'react';
2
+ import { Loader } from 'lucide-react';
3
+ export const Widget = ({ title, icon, iconColor = 'text-gray-400', loading = false, error = null, children, className = '', headerActions, onContextMenu }) => {
4
+ return (React.createElement("div", { className: `theme-bg-tertiary p-4 rounded-lg flex flex-col h-full ${className}`, onContextMenu: onContextMenu },
5
+ React.createElement("div", { className: "flex justify-between items-start flex-shrink-0 mb-2" },
6
+ React.createElement("div", { className: "flex items-center gap-3 flex-1" },
7
+ icon && React.createElement("span", { className: iconColor }, icon),
8
+ React.createElement("h4", { className: "font-semibold theme-text-secondary truncate" }, title)),
9
+ headerActions),
10
+ React.createElement("div", { className: "flex-1 overflow-hidden" }, loading ? (React.createElement("div", { className: "flex items-center justify-center h-full" },
11
+ React.createElement(Loader, { className: "animate-spin text-blue-400", size: 24 }))) : error ? (React.createElement("div", { className: "text-red-400 p-2 text-xs overflow-auto" }, error)) : (children))));
12
+ };
13
+ export const StatValue = ({ value, label, trend, className = '' }) => (React.createElement("div", { className: `flex flex-col ${className}` },
14
+ React.createElement("p", { className: "text-3xl font-bold theme-text-primary" }, value),
15
+ label && React.createElement("p", { className: "text-sm theme-text-secondary mt-1" }, label),
16
+ trend && (React.createElement("p", { className: `text-sm mt-1 ${trend.direction === 'up' ? 'text-green-400' : 'text-red-400'}` },
17
+ trend.direction === 'up' ? '↑' : '↓',
18
+ " ",
19
+ Math.abs(trend.value),
20
+ "%"))));
21
+ export const StatList = ({ items, className = '' }) => (React.createElement("ul", { className: `space-y-1 text-sm theme-text-secondary ${className}` }, items.map((item, i) => (React.createElement("li", { key: i, className: "flex justify-between" },
22
+ React.createElement("span", null, item.label),
23
+ React.createElement("span", { className: "font-bold" }, item.value))))));
24
+ export const WidgetToggle = ({ options, activeValue, onChange }) => (React.createElement("div", { className: "flex items-center gap-1" }, options.map(opt => (React.createElement("button", { key: opt.value, onClick: () => onChange(opt.value), className: `px-2 py-0.5 text-xs rounded ${activeValue === opt.value
25
+ ? 'theme-button-primary'
26
+ : 'theme-button theme-hover'}` }, opt.label)))));
@@ -0,0 +1,47 @@
1
+ import React from 'react';
2
+ export interface WidgetConfig {
3
+ id?: string;
4
+ title: string;
5
+ type: 'table' | 'chart' | 'stat' | 'stat_list' | 'line_chart' | 'bar_chart';
6
+ query: string;
7
+ iconName?: string;
8
+ iconColor?: string;
9
+ span?: number;
10
+ chartConfig?: {
11
+ x: string;
12
+ y: string;
13
+ type: 'line' | 'bar';
14
+ groupBy?: string;
15
+ };
16
+ toggleOptions?: Array<{
17
+ label: string;
18
+ modifier: string;
19
+ }>;
20
+ builder?: {
21
+ table: string;
22
+ selectedColumns: string[];
23
+ selectExpressions?: string[];
24
+ };
25
+ }
26
+ export interface SchemaColumn {
27
+ name: string;
28
+ type: string;
29
+ }
30
+ export interface WidgetBuilderProps {
31
+ isOpen: boolean;
32
+ onClose: () => void;
33
+ onSave: (widget: WidgetConfig) => void;
34
+ widget?: Partial<WidgetConfig>;
35
+ tables: string[];
36
+ fetchSchema: (tableName: string) => Promise<SchemaColumn[]>;
37
+ executeQuery?: (query: string) => Promise<{
38
+ result?: unknown[];
39
+ error?: string;
40
+ }>;
41
+ context?: {
42
+ query?: string;
43
+ result?: Record<string, unknown>[];
44
+ };
45
+ generateId?: () => string;
46
+ }
47
+ export declare const WidgetBuilder: React.FC<WidgetBuilderProps>;
@@ -0,0 +1,286 @@
1
+ import React, { useState, useEffect, useCallback } from 'react';
2
+ import { X, Play, Loader } from 'lucide-react';
3
+ const defaultGenerateId = () => `widget_${Math.random().toString(36).substring(2, 11)}`;
4
+ const WIDGET_TYPES = [
5
+ { value: 'table', label: 'Table' },
6
+ { value: 'chart', label: 'Chart' },
7
+ { value: 'stat', label: 'Single Stat' },
8
+ { value: 'stat_list', label: 'Stat List' },
9
+ ];
10
+ const CHART_TYPES = [
11
+ { value: 'bar', label: 'Bar Chart' },
12
+ { value: 'line', label: 'Line Chart' },
13
+ ];
14
+ /**
15
+ * Parses a SQL query to extract builder configuration
16
+ */
17
+ const parseQueryForBuilder = (query) => {
18
+ if (!query) {
19
+ return { isComplex: false, builderConfig: {} };
20
+ }
21
+ // Check for complex query patterns
22
+ const complexityPattern = /\bJOIN\b|\bUNION\b|\bWITH\b/i;
23
+ const isComplex = complexityPattern.test(query);
24
+ if (isComplex) {
25
+ return { isComplex: true, builderConfig: {} };
26
+ }
27
+ // Extract table name
28
+ const fromMatch = query.match(/\bFROM\s+([a-zA-Z0-9_]+)/i);
29
+ if (!fromMatch) {
30
+ return { isComplex: true, builderConfig: {} };
31
+ }
32
+ const table = fromMatch[1];
33
+ // Extract SELECT expressions
34
+ const selectMatch = query.match(/\bSELECT\s+(.*?)(?=\bFROM)/is);
35
+ const selectExpressions = selectMatch
36
+ ? selectMatch[1].split(',').map(s => s.trim())
37
+ : ['*'];
38
+ // Extract columns from expressions
39
+ const extractedBaseColumns = new Set();
40
+ const keywordBlacklist = new Set([
41
+ 'COUNT', 'SUM', 'AVG', 'MIN', 'MAX', 'DISTINCT', 'FROM', 'WHERE',
42
+ 'GROUP', 'ORDER', 'BY', 'LIMIT', 'CASE', 'WHEN', 'THEN', 'ELSE',
43
+ 'END', 'AS', 'IN', 'LIKE', 'IS', 'BETWEEN', 'AND', 'OR', 'NOT',
44
+ 'NULL', 'STRFTIME', 'LENGTH'
45
+ ]);
46
+ selectExpressions.forEach(expr => {
47
+ const columnCandidates = expr.matchAll(/\b([a-zA-Z0-9_]+)\b/g);
48
+ for (const match of columnCandidates) {
49
+ if (match[1] && !keywordBlacklist.has(match[1].toUpperCase())) {
50
+ extractedBaseColumns.add(match[1]);
51
+ }
52
+ }
53
+ });
54
+ return {
55
+ isComplex: false,
56
+ builderConfig: {
57
+ table,
58
+ selectedColumns: Array.from(extractedBaseColumns),
59
+ selectExpressions
60
+ }
61
+ };
62
+ };
63
+ export const WidgetBuilder = ({ isOpen, onClose, onSave, widget, tables, fetchSchema, executeQuery, context, generateId = defaultGenerateId }) => {
64
+ const isEditMode = Boolean(widget?.id);
65
+ const parsedData = widget?.query ? parseQueryForBuilder(widget.query) : { isComplex: false, builderConfig: {} };
66
+ // Mode state
67
+ const [mode, setMode] = useState(parsedData.isComplex ? 'advanced' : 'builder');
68
+ const isComplexQuery = parsedData.isComplex;
69
+ // Form state
70
+ const [title, setTitle] = useState(widget?.title || '');
71
+ const [type, setType] = useState(widget?.type || 'table');
72
+ const [query, setQuery] = useState(widget?.query || '');
73
+ const [selectedTable, setSelectedTable] = useState(parsedData.builderConfig.table || '');
74
+ const [selectedColumns, setSelectedColumns] = useState(parsedData.builderConfig.selectedColumns || []);
75
+ // Chart config
76
+ const [xCol, setXCol] = useState(widget?.chartConfig?.x || '');
77
+ const [yCol, setYCol] = useState(widget?.chartConfig?.y || '');
78
+ const [chartType, setChartType] = useState(widget?.chartConfig?.type || 'bar');
79
+ const [groupBy, setGroupBy] = useState(widget?.chartConfig?.groupBy || '');
80
+ // Toggle options for filtering
81
+ const [toggleOptions, setToggleOptions] = useState(widget?.toggleOptions || []);
82
+ // Schema/columns state
83
+ const [availableColumns, setAvailableColumns] = useState([]);
84
+ const [outputColumns, setOutputColumns] = useState([]);
85
+ // Testing state
86
+ const [testStatus, setTestStatus] = useState({ loading: false, error: null });
87
+ // Initialize from context if provided
88
+ useEffect(() => {
89
+ if (context?.result?.[0] && !isEditMode) {
90
+ const columns = Object.keys(context.result[0]);
91
+ setOutputColumns(columns.map(name => ({ name, type: 'RESULT_COL' })));
92
+ setXCol(columns[0] || '');
93
+ setYCol(columns.length > 1 ? columns[1] : '');
94
+ setQuery(context.query || '');
95
+ setType('chart');
96
+ setMode('advanced');
97
+ }
98
+ }, [context, isEditMode]);
99
+ // Load schema when table changes
100
+ useEffect(() => {
101
+ if (selectedTable && mode === 'builder') {
102
+ fetchSchema(selectedTable).then(schema => {
103
+ setAvailableColumns(schema || []);
104
+ if (!type.includes('chart')) {
105
+ setOutputColumns(schema || []);
106
+ }
107
+ });
108
+ }
109
+ }, [selectedTable, fetchSchema, mode, type]);
110
+ // Auto-generate query in builder mode
111
+ useEffect(() => {
112
+ if (mode === 'builder' && selectedTable && !type.includes('chart')) {
113
+ const cols = selectedColumns.length > 0 ? selectedColumns.join(', ') : '*';
114
+ setQuery(`SELECT ${cols} FROM ${selectedTable}`);
115
+ }
116
+ }, [mode, selectedTable, selectedColumns, type]);
117
+ // Test query and get output columns
118
+ const testQuery = useCallback(async () => {
119
+ if (!executeQuery || !query)
120
+ return;
121
+ setTestStatus({ loading: true, error: null });
122
+ try {
123
+ const testQ = `${query.replace(/;$/, '')} LIMIT 1`;
124
+ const result = await executeQuery(testQ);
125
+ if (result.error) {
126
+ throw new Error(result.error);
127
+ }
128
+ if (result.result && Array.isArray(result.result) && result.result.length > 0) {
129
+ const cols = Object.keys(result.result[0]);
130
+ setOutputColumns(cols.map(name => ({ name, type: 'RESULT_COL' })));
131
+ }
132
+ setTestStatus({ loading: false, error: null });
133
+ }
134
+ catch (err) {
135
+ setTestStatus({ loading: false, error: err.message });
136
+ }
137
+ }, [executeQuery, query]);
138
+ const handleSave = () => {
139
+ let finalQuery = query;
140
+ // Build query in builder mode for charts
141
+ if (mode === 'builder' && type.includes('chart') && selectedTable) {
142
+ const selectParts = [];
143
+ if (xCol)
144
+ selectParts.push(xCol);
145
+ if (yCol) {
146
+ yCol.split(',').forEach(expr => {
147
+ const trimmed = expr.trim();
148
+ if (trimmed && !selectParts.includes(trimmed)) {
149
+ selectParts.push(trimmed);
150
+ }
151
+ });
152
+ }
153
+ if (selectParts.length > 0) {
154
+ finalQuery = `SELECT ${selectParts.join(', ')} FROM ${selectedTable}`;
155
+ if (groupBy) {
156
+ finalQuery += ` GROUP BY ${groupBy}`;
157
+ }
158
+ else if (xCol && selectParts.length > 1) {
159
+ const xBase = xCol.split(/\s+AS\s+/i)[0].trim();
160
+ finalQuery += ` GROUP BY ${xBase}`;
161
+ }
162
+ if (xCol) {
163
+ const xBase = xCol.split(/\s+AS\s+/i)[0].trim();
164
+ finalQuery += ` ORDER BY ${xBase}`;
165
+ }
166
+ }
167
+ }
168
+ const widgetConfig = {
169
+ id: widget?.id || generateId(),
170
+ title: title || 'Custom Widget',
171
+ type,
172
+ query: finalQuery,
173
+ iconName: widget?.iconName || 'Settings2',
174
+ iconColor: widget?.iconColor || 'text-blue-400',
175
+ span: type.includes('chart') ? 2 : 1,
176
+ chartConfig: type.includes('chart') ? {
177
+ x: xCol,
178
+ y: yCol,
179
+ type: chartType,
180
+ groupBy: groupBy || undefined
181
+ } : undefined,
182
+ toggleOptions: toggleOptions.length > 0 ? toggleOptions : undefined,
183
+ builder: mode === 'builder' ? {
184
+ table: selectedTable,
185
+ selectedColumns
186
+ } : undefined
187
+ };
188
+ onSave(widgetConfig);
189
+ onClose();
190
+ };
191
+ const handleToggleChange = (index, field, value) => {
192
+ const newToggles = [...toggleOptions];
193
+ newToggles[index][field] = value;
194
+ setToggleOptions(newToggles);
195
+ };
196
+ const addToggle = () => {
197
+ setToggleOptions([...toggleOptions, { label: 'New', modifier: '' }]);
198
+ };
199
+ const removeToggle = (index) => {
200
+ setToggleOptions(toggleOptions.filter((_, i) => i !== index));
201
+ };
202
+ if (!isOpen)
203
+ return null;
204
+ return (React.createElement("div", { className: "fixed inset-0 bg-black/70 flex items-center justify-center z-[60]" },
205
+ React.createElement("div", { className: "theme-bg-secondary p-6 rounded-lg shadow-xl w-full max-w-2xl max-h-[90vh] flex flex-col" },
206
+ React.createElement("div", { className: "flex justify-between items-center mb-4 flex-shrink-0" },
207
+ React.createElement("h3", { className: "text-lg font-semibold" }, isEditMode ? 'Edit Widget' : 'Create Widget'),
208
+ React.createElement("button", { onClick: onClose, className: "p-1 rounded-full theme-hover" },
209
+ React.createElement(X, { size: 20 }))),
210
+ React.createElement("div", { className: "flex border-b theme-border mb-4 flex-shrink-0" },
211
+ React.createElement("button", { onClick: () => !isComplexQuery && setMode('builder'), className: `px-4 py-2 text-sm ${mode === 'builder' ? 'border-b-2 border-blue-500' : 'theme-text-secondary'} ${isComplexQuery ? 'opacity-50 cursor-not-allowed' : ''}`, title: isComplexQuery ? "Cannot use builder for complex queries" : "" }, "Builder"),
212
+ React.createElement("button", { onClick: () => setMode('advanced'), className: `px-4 py-2 text-sm ${mode === 'advanced' ? 'border-b-2 border-blue-500' : 'theme-text-secondary'}` }, "Advanced SQL")),
213
+ React.createElement("div", { className: "flex-1 overflow-y-auto space-y-4 pr-2" },
214
+ React.createElement("div", { className: "p-3 border theme-border rounded-lg theme-bg-tertiary" },
215
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Title"),
216
+ React.createElement("input", { type: "text", value: title, onChange: e => setTitle(e.target.value), className: "w-full theme-input mt-1", placeholder: "e.g., Daily Active Users" })),
217
+ React.createElement("div", { className: "p-3 border theme-border rounded-lg theme-bg-tertiary space-y-3" },
218
+ React.createElement("h4", { className: "text-sm font-semibold theme-text-primary" }, "Data Source"),
219
+ mode === 'builder' ? (React.createElement(React.Fragment, null,
220
+ React.createElement("div", null,
221
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Table"),
222
+ React.createElement("select", { value: selectedTable, onChange: e => {
223
+ setSelectedTable(e.target.value);
224
+ setSelectedColumns([]);
225
+ }, className: "w-full theme-input mt-1" },
226
+ React.createElement("option", { value: "" }, "Select a table..."),
227
+ tables.map(t => (React.createElement("option", { key: t, value: t }, t))))),
228
+ selectedTable && !type.includes('chart') && (React.createElement("div", null,
229
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Columns"),
230
+ React.createElement("div", { className: "max-h-32 overflow-y-auto theme-bg-primary p-2 rounded mt-1" }, availableColumns.map(col => (React.createElement("div", { key: col.name, className: "flex items-center" },
231
+ React.createElement("input", { type: "checkbox", id: `col-${col.name}`, checked: selectedColumns.includes(col.name), onChange: e => {
232
+ setSelectedColumns(prev => e.target.checked
233
+ ? [...prev, col.name]
234
+ : prev.filter(c => c !== col.name));
235
+ }, className: "w-4 h-4 theme-checkbox" }),
236
+ React.createElement("label", { htmlFor: `col-${col.name}`, className: "ml-2 text-sm" },
237
+ col.name,
238
+ " ",
239
+ React.createElement("span", { className: "text-yellow-400" },
240
+ "(",
241
+ col.type,
242
+ ")")))))))))) : (React.createElement("div", null,
243
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "SQL Query"),
244
+ React.createElement("textarea", { value: query, onChange: e => setQuery(e.target.value), rows: 6, className: "w-full theme-input mt-1 font-mono text-sm", placeholder: "SELECT * FROM table_name LIMIT 100" }),
245
+ executeQuery && (React.createElement("button", { onClick: testQuery, className: "text-xs theme-button-subtle mt-2 flex items-center gap-1", disabled: testStatus.loading },
246
+ testStatus.loading ? React.createElement(Loader, { size: 12, className: "animate-spin" }) : React.createElement(Play, { size: 12 }),
247
+ testStatus.loading ? 'Testing...' : 'Test Query & Get Columns')),
248
+ testStatus.error && (React.createElement("p", { className: "text-red-400 text-xs mt-1" }, testStatus.error))))),
249
+ React.createElement("div", { className: "p-3 border theme-border rounded-lg theme-bg-tertiary space-y-3" },
250
+ React.createElement("h4", { className: "text-sm font-semibold theme-text-primary" }, "Visualization"),
251
+ React.createElement("div", null,
252
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Display As"),
253
+ React.createElement("select", { value: type, onChange: e => setType(e.target.value), className: "w-full theme-input mt-1" }, WIDGET_TYPES.map(opt => (React.createElement("option", { key: opt.value, value: opt.value }, opt.label))))),
254
+ type.includes('chart') && (React.createElement(React.Fragment, null,
255
+ React.createElement("div", { className: "grid grid-cols-2 gap-3" },
256
+ React.createElement("div", null,
257
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "X-Axis"),
258
+ React.createElement("textarea", { value: xCol, onChange: e => setXCol(e.target.value), className: "w-full theme-input mt-1 font-mono text-sm", rows: 2, placeholder: "e.g., strftime('%Y-%m-%d', timestamp) as date" }),
259
+ outputColumns.length > 0 && (React.createElement("div", { className: "text-xs theme-text-secondary mt-1" },
260
+ "Available: ",
261
+ outputColumns.map(c => c.name).join(', ')))),
262
+ React.createElement("div", null,
263
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Y-Axis (comma separated for multi-series)"),
264
+ React.createElement("textarea", { value: yCol, onChange: e => setYCol(e.target.value), className: "w-full theme-input mt-1 font-mono text-sm", rows: 2, placeholder: "e.g., COUNT(*) as count" }))),
265
+ React.createElement("div", { className: "grid grid-cols-2 gap-3" },
266
+ React.createElement("div", null,
267
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "Chart Type"),
268
+ React.createElement("select", { value: chartType, onChange: e => setChartType(e.target.value), className: "w-full theme-input mt-1" }, CHART_TYPES.map(opt => (React.createElement("option", { key: opt.value, value: opt.value }, opt.label))))),
269
+ React.createElement("div", null,
270
+ React.createElement("label", { className: "text-xs font-semibold theme-text-secondary uppercase tracking-wider" }, "GROUP BY (optional)"),
271
+ React.createElement("input", { type: "text", value: groupBy, onChange: e => setGroupBy(e.target.value), className: "w-full theme-input mt-1 font-mono text-sm", placeholder: "e.g., strftime('%Y-%m-%d', timestamp)" })))))),
272
+ React.createElement("div", { className: "p-3 border theme-border rounded-lg theme-bg-tertiary space-y-3" },
273
+ React.createElement("div", { className: "flex justify-between items-center" },
274
+ React.createElement("h4", { className: "text-sm font-semibold theme-text-primary" }, "Filter Toggles (optional)"),
275
+ React.createElement("button", { onClick: addToggle, className: "text-xs theme-button-subtle" }, "+ Add Toggle")),
276
+ toggleOptions.map((toggle, index) => (React.createElement("div", { key: index, className: "flex gap-2 items-start" },
277
+ React.createElement("div", { className: "flex-1" },
278
+ React.createElement("input", { type: "text", value: toggle.label, onChange: e => handleToggleChange(index, 'label', e.target.value), className: "w-full theme-input text-sm", placeholder: "Label (e.g., 7d)" })),
279
+ React.createElement("div", { className: "flex-[2]" },
280
+ React.createElement("input", { type: "text", value: toggle.modifier, onChange: e => handleToggleChange(index, 'modifier', e.target.value), className: "w-full theme-input text-sm font-mono", placeholder: "WHERE timestamp >= date('now', '-7 days')" })),
281
+ React.createElement("button", { onClick: () => removeToggle(index), className: "p-1 text-red-400 hover:text-red-300" },
282
+ React.createElement(X, { size: 16 }))))))),
283
+ React.createElement("div", { className: "flex justify-end gap-3 mt-6 pt-4 border-t theme-border flex-shrink-0" },
284
+ React.createElement("button", { onClick: onClose, className: "theme-button px-4 py-2 text-sm rounded" }, "Cancel"),
285
+ React.createElement("button", { onClick: handleSave, className: "theme-button-primary px-4 py-2 text-sm rounded" }, isEditMode ? 'Save Changes' : 'Create Widget')))));
286
+ };
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+ export interface WidgetGridProps {
3
+ children: React.ReactNode;
4
+ columns?: number | {
5
+ sm?: number;
6
+ md?: number;
7
+ lg?: number;
8
+ xl?: number;
9
+ };
10
+ gap?: number;
11
+ className?: string;
12
+ }
13
+ export declare const WidgetGrid: React.FC<WidgetGridProps>;
14
+ export interface WidgetSpanProps {
15
+ span?: number;
16
+ children: React.ReactNode;
17
+ className?: string;
18
+ }
19
+ export declare const WidgetSpan: React.FC<WidgetSpanProps>;
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ export const WidgetGrid = ({ children, columns = { sm: 1, md: 2, lg: 3, xl: 4 }, gap = 16, className = '' }) => {
3
+ const gridClass = typeof columns === 'number'
4
+ ? ''
5
+ : `grid-cols-${columns.sm || 1} md:grid-cols-${columns.md || 2} lg:grid-cols-${columns.lg || 3} xl:grid-cols-${columns.xl || 4}`;
6
+ const gridStyle = typeof columns === 'number'
7
+ ? { gridTemplateColumns: `repeat(${columns}, 1fr)`, gap }
8
+ : { gap };
9
+ return (React.createElement("div", { className: `grid ${gridClass} ${className}`, style: gridStyle }, children));
10
+ };
11
+ export const WidgetSpan = ({ span = 1, children, className = '' }) => (React.createElement("div", { className: className, style: { gridColumn: `span ${span}` } }, children));
@@ -0,0 +1,8 @@
1
+ export { Widget, StatValue, StatList, WidgetToggle } from './Widget';
2
+ export type { WidgetProps, StatWidgetProps, StatListProps, WidgetToggleProps } from './Widget';
3
+ export { WidgetGrid, WidgetSpan } from './WidgetGrid';
4
+ export type { WidgetGridProps, WidgetSpanProps } from './WidgetGrid';
5
+ export { QueryWidget } from './QueryWidget';
6
+ export type { QueryWidgetConfig, QueryWidgetProps } from './QueryWidget';
7
+ export { WidgetBuilder } from './WidgetBuilder';
8
+ export type { WidgetBuilderProps, WidgetConfig, SchemaColumn } from './WidgetBuilder';
@@ -0,0 +1,4 @@
1
+ export { Widget, StatValue, StatList, WidgetToggle } from './Widget';
2
+ export { WidgetGrid, WidgetSpan } from './WidgetGrid';
3
+ export { QueryWidget } from './QueryWidget';
4
+ export { WidgetBuilder } from './WidgetBuilder';
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ declare const BrowserUrlDialog: ({ isOpen, onClose, onNavigate, currentPath }: {
3
+ isOpen: any;
4
+ onClose: any;
5
+ onNavigate: any;
6
+ currentPath: any;
7
+ }) => React.JSX.Element;
8
+ export default BrowserUrlDialog;