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.
- package/LICENSE +21 -0
- package/README.md +139 -0
- package/dist/adapters/base.d.ts +13 -0
- package/dist/adapters/base.js +1 -0
- package/dist/adapters/electron/bridge.d.ts +4 -0
- package/dist/adapters/electron/bridge.js +88 -0
- package/dist/adapters/index.d.ts +2 -0
- package/dist/adapters/index.js +3 -0
- package/dist/core/browser.d.ts +25 -0
- package/dist/core/browser.js +1 -0
- package/dist/core/chat.d.ts +41 -0
- package/dist/core/chat.js +1 -0
- package/dist/core/database.d.ts +56 -0
- package/dist/core/database.js +50 -0
- package/dist/core/files.d.ts +24 -0
- package/dist/core/files.js +15 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.js +10 -0
- package/dist/core/jobs.d.ts +20 -0
- package/dist/core/jobs.js +1 -0
- package/dist/core/layout.d.ts +30 -0
- package/dist/core/layout.js +41 -0
- package/dist/core/stream.d.ts +10 -0
- package/dist/core/stream.js +1 -0
- package/dist/core/types.d.ts +23 -0
- package/dist/core/types.js +1 -0
- package/dist/core/utils.d.ts +19 -0
- package/dist/core/utils.js +19 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +29 -0
- package/dist/ui/chat/components/ChatHeaderBar.d.ts +13 -0
- package/dist/ui/chat/components/ChatHeaderBar.js +32 -0
- package/dist/ui/chat/components/ChatInterface.d.ts +10 -0
- package/dist/ui/chat/components/ChatInterface.js +19 -0
- package/dist/ui/chat/components/ChatMessage.d.ts +7 -0
- package/dist/ui/chat/components/ChatMessage.js +10 -0
- package/dist/ui/chat/components/ChatPane.d.ts +20 -0
- package/dist/ui/chat/components/ChatPane.js +20 -0
- package/dist/ui/chat/components/ChatView.d.ts +10 -0
- package/dist/ui/chat/components/ChatView.js +36 -0
- package/dist/ui/chat/components/ConversationList.d.ts +28 -0
- package/dist/ui/chat/components/ConversationList.js +113 -0
- package/dist/ui/chat/components/InPaneSearchBar.d.ts +12 -0
- package/dist/ui/chat/components/InPaneSearchBar.js +44 -0
- package/dist/ui/chat/components/InputArea.d.ts +7 -0
- package/dist/ui/chat/components/InputArea.js +46 -0
- package/dist/ui/chat/components/MessageAttachments.d.ts +5 -0
- package/dist/ui/chat/components/MessageAttachments.js +6 -0
- package/dist/ui/chat/components/MessageItem.d.ts +28 -0
- package/dist/ui/chat/components/MessageItem.js +43 -0
- package/dist/ui/chat/components/PredictiveTextOverlay.d.ts +10 -0
- package/dist/ui/chat/components/PredictiveTextOverlay.js +75 -0
- package/dist/ui/chat/context/ChatContext.d.ts +33 -0
- package/dist/ui/chat/context/ChatContext.js +157 -0
- package/dist/ui/chat/hooks/useAutoScroll.d.ts +1 -0
- package/dist/ui/chat/hooks/useAutoScroll.js +11 -0
- package/dist/ui/chat/index.d.ts +7 -0
- package/dist/ui/chat/index.js +7 -0
- package/dist/ui/dashboard/ChartWidget.d.ts +18 -0
- package/dist/ui/dashboard/ChartWidget.js +98 -0
- package/dist/ui/dashboard/QueryWidget.d.ts +29 -0
- package/dist/ui/dashboard/QueryWidget.js +117 -0
- package/dist/ui/dashboard/TableWidget.d.ts +14 -0
- package/dist/ui/dashboard/TableWidget.js +117 -0
- package/dist/ui/dashboard/Widget.d.ts +40 -0
- package/dist/ui/dashboard/Widget.js +26 -0
- package/dist/ui/dashboard/WidgetBuilder.d.ts +47 -0
- package/dist/ui/dashboard/WidgetBuilder.js +286 -0
- package/dist/ui/dashboard/WidgetGrid.d.ts +19 -0
- package/dist/ui/dashboard/WidgetGrid.js +11 -0
- package/dist/ui/dashboard/index.d.ts +8 -0
- package/dist/ui/dashboard/index.js +4 -0
- package/dist/ui/dialogs/BrowserUrlDialog.d.ts +8 -0
- package/dist/ui/dialogs/BrowserUrlDialog.js +203 -0
- package/dist/ui/dialogs/index.d.ts +1 -0
- package/dist/ui/dialogs/index.js +1 -0
- package/dist/ui/editors/ImageEditor.d.ts +49 -0
- package/dist/ui/editors/ImageEditor.js +264 -0
- package/dist/ui/editors/index.d.ts +2 -0
- package/dist/ui/editors/index.js +1 -0
- package/dist/ui/execution/ExecutionFilters.d.ts +11 -0
- package/dist/ui/execution/ExecutionFilters.js +27 -0
- package/dist/ui/execution/ExecutionHistoryList.d.ts +19 -0
- package/dist/ui/execution/ExecutionHistoryList.js +35 -0
- package/dist/ui/execution/index.d.ts +3 -0
- package/dist/ui/execution/index.js +2 -0
- package/dist/ui/files/components/FileTree.d.ts +18 -0
- package/dist/ui/files/components/FileTree.js +61 -0
- package/dist/ui/files/components/Sidebar.d.ts +18 -0
- package/dist/ui/files/components/Sidebar.js +67 -0
- package/dist/ui/files/components/index.d.ts +2 -0
- package/dist/ui/files/components/index.js +2 -0
- package/dist/ui/files/context/FileSystemContext.d.ts +23 -0
- package/dist/ui/files/context/FileSystemContext.js +65 -0
- package/dist/ui/files/context/index.d.ts +1 -0
- package/dist/ui/files/context/index.js +1 -0
- package/dist/ui/files/index.d.ts +2 -0
- package/dist/ui/files/index.js +2 -0
- package/dist/ui/hooks/index.d.ts +4 -0
- package/dist/ui/hooks/index.js +3 -0
- package/dist/ui/hooks/useDebounce.d.ts +8 -0
- package/dist/ui/hooks/useDebounce.js +18 -0
- package/dist/ui/hooks/usePaneTracking.d.ts +15 -0
- package/dist/ui/hooks/usePaneTracking.js +20 -0
- package/dist/ui/hooks/useQuery.d.ts +25 -0
- package/dist/ui/hooks/useQuery.js +71 -0
- package/dist/ui/index.d.ts +19 -0
- package/dist/ui/index.js +20 -0
- package/dist/ui/jinx/JinxEditor.d.ts +20 -0
- package/dist/ui/jinx/JinxEditor.js +34 -0
- package/dist/ui/jinx/JinxTree.d.ts +14 -0
- package/dist/ui/jinx/JinxTree.js +65 -0
- package/dist/ui/jinx/index.d.ts +3 -0
- package/dist/ui/jinx/index.js +2 -0
- package/dist/ui/knowledge-graph/KGControls.d.ts +12 -0
- package/dist/ui/knowledge-graph/KGControls.js +21 -0
- package/dist/ui/knowledge-graph/KGStats.d.ts +13 -0
- package/dist/ui/knowledge-graph/KGStats.js +18 -0
- package/dist/ui/knowledge-graph/KnowledgeGraphViewer.d.ts +22 -0
- package/dist/ui/knowledge-graph/KnowledgeGraphViewer.js +16 -0
- package/dist/ui/knowledge-graph/index.d.ts +4 -0
- package/dist/ui/knowledge-graph/index.js +3 -0
- package/dist/ui/layout/components/AppShell.d.ts +8 -0
- package/dist/ui/layout/components/AppShell.js +19 -0
- package/dist/ui/layout/components/ContentPaneContainer.d.ts +8 -0
- package/dist/ui/layout/components/ContentPaneContainer.js +95 -0
- package/dist/ui/layout/components/LayoutNode.d.ts +8 -0
- package/dist/ui/layout/components/LayoutNode.js +12 -0
- package/dist/ui/layout/components/PaneHeader.d.ts +17 -0
- package/dist/ui/layout/components/PaneHeader.js +40 -0
- package/dist/ui/layout/components/SplitView.d.ts +8 -0
- package/dist/ui/layout/components/SplitView.js +51 -0
- package/dist/ui/layout/components/Studio.d.ts +7 -0
- package/dist/ui/layout/components/Studio.js +12 -0
- package/dist/ui/layout/components/contextMenus/BrowserContextMenu.d.ts +13 -0
- package/dist/ui/layout/components/contextMenus/BrowserContextMenu.js +23 -0
- package/dist/ui/layout/components/contextMenus/EditorContextMenu.d.ts +15 -0
- package/dist/ui/layout/components/contextMenus/EditorContextMenu.js +32 -0
- package/dist/ui/layout/components/contextMenus/FileContextMenu.d.ts +15 -0
- package/dist/ui/layout/components/contextMenus/FileContextMenu.js +33 -0
- package/dist/ui/layout/components/contextMenus/PdfContextMenu.d.ts +13 -0
- package/dist/ui/layout/components/contextMenus/PdfContextMenu.js +23 -0
- package/dist/ui/layout/components/contextMenus/index.d.ts +4 -0
- package/dist/ui/layout/components/contextMenus/index.js +4 -0
- package/dist/ui/layout/components/index.d.ts +8 -0
- package/dist/ui/layout/components/index.js +8 -0
- package/dist/ui/layout/components/modals/AIEditModal.d.ts +9 -0
- package/dist/ui/layout/components/modals/AIEditModal.js +33 -0
- package/dist/ui/layout/components/modals/MemoryApprovalModal.d.ts +15 -0
- package/dist/ui/layout/components/modals/MemoryApprovalModal.js +23 -0
- package/dist/ui/layout/components/modals/PromptModal.d.ts +11 -0
- package/dist/ui/layout/components/modals/PromptModal.js +20 -0
- package/dist/ui/layout/components/modals/ResendModal.d.ts +16 -0
- package/dist/ui/layout/components/modals/ResendModal.js +22 -0
- package/dist/ui/layout/components/modals/index.d.ts +4 -0
- package/dist/ui/layout/components/modals/index.js +4 -0
- package/dist/ui/layout/context/LayoutContext.d.ts +32 -0
- package/dist/ui/layout/context/LayoutContext.js +144 -0
- package/dist/ui/layout/index.d.ts +2 -0
- package/dist/ui/layout/index.js +2 -0
- package/dist/ui/markdown/Markdown.d.ts +4 -0
- package/dist/ui/markdown/Markdown.js +4 -0
- package/dist/ui/memory/MemoryFilters.d.ts +12 -0
- package/dist/ui/memory/MemoryFilters.js +23 -0
- package/dist/ui/memory/MemoryList.d.ts +19 -0
- package/dist/ui/memory/MemoryList.js +36 -0
- package/dist/ui/memory/index.d.ts +3 -0
- package/dist/ui/memory/index.js +2 -0
- package/dist/ui/models/ModelCard.d.ts +16 -0
- package/dist/ui/models/ModelCard.js +30 -0
- package/dist/ui/models/ModelSelector.d.ts +13 -0
- package/dist/ui/models/ModelSelector.js +6 -0
- package/dist/ui/models/index.d.ts +3 -0
- package/dist/ui/models/index.js +2 -0
- package/dist/ui/npc/McpServerMenu.d.ts +15 -0
- package/dist/ui/npc/McpServerMenu.js +48 -0
- package/dist/ui/npc/NPCEditor.d.ts +21 -0
- package/dist/ui/npc/NPCEditor.js +17 -0
- package/dist/ui/npc/NPCList.d.ts +19 -0
- package/dist/ui/npc/NPCList.js +28 -0
- package/dist/ui/npc/index.d.ts +3 -0
- package/dist/ui/npc/index.js +2 -0
- package/dist/ui/photo/GalleryGrid.d.ts +25 -0
- package/dist/ui/photo/GalleryGrid.js +46 -0
- package/dist/ui/photo/ImageAdjustmentSliders.d.ts +37 -0
- package/dist/ui/photo/ImageAdjustmentSliders.js +56 -0
- package/dist/ui/photo/ImageLabelingCanvas.d.ts +47 -0
- package/dist/ui/photo/ImageLabelingCanvas.js +174 -0
- package/dist/ui/photo/ImageSourceTabs.d.ts +28 -0
- package/dist/ui/photo/ImageSourceTabs.js +46 -0
- package/dist/ui/photo/LayerPanel.d.ts +87 -0
- package/dist/ui/photo/LayerPanel.js +70 -0
- package/dist/ui/photo/Lightbox.d.ts +12 -0
- package/dist/ui/photo/Lightbox.js +90 -0
- package/dist/ui/photo/index.d.ts +6 -0
- package/dist/ui/photo/index.js +7 -0
- package/dist/ui/primitives/AutosizeTextarea.d.ts +8 -0
- package/dist/ui/primitives/AutosizeTextarea.js +17 -0
- package/dist/ui/primitives/Button.d.ts +7 -0
- package/dist/ui/primitives/Button.js +17 -0
- package/dist/ui/primitives/Card.d.ts +12 -0
- package/dist/ui/primitives/Card.js +8 -0
- package/dist/ui/primitives/Chart.d.ts +34 -0
- package/dist/ui/primitives/Chart.js +140 -0
- package/dist/ui/primitives/ContextMenu.d.ts +17 -0
- package/dist/ui/primitives/ContextMenu.js +33 -0
- package/dist/ui/primitives/DataTable.d.ts +13 -0
- package/dist/ui/primitives/DataTable.js +13 -0
- package/dist/ui/primitives/FileUpload.d.ts +10 -0
- package/dist/ui/primitives/FileUpload.js +24 -0
- package/dist/ui/primitives/ImageGrid.d.ts +21 -0
- package/dist/ui/primitives/ImageGrid.js +29 -0
- package/dist/ui/primitives/Input.d.ts +7 -0
- package/dist/ui/primitives/Input.js +10 -0
- package/dist/ui/primitives/Lightbox.d.ts +12 -0
- package/dist/ui/primitives/Lightbox.js +36 -0
- package/dist/ui/primitives/Modal.d.ts +10 -0
- package/dist/ui/primitives/Modal.js +33 -0
- package/dist/ui/primitives/RangeSlider.d.ts +13 -0
- package/dist/ui/primitives/RangeSlider.js +6 -0
- package/dist/ui/primitives/Select.d.ts +11 -0
- package/dist/ui/primitives/Select.js +10 -0
- package/dist/ui/primitives/Slider.d.ts +13 -0
- package/dist/ui/primitives/Slider.js +8 -0
- package/dist/ui/primitives/SortableList.d.ts +9 -0
- package/dist/ui/primitives/SortableList.js +19 -0
- package/dist/ui/primitives/Spinner.d.ts +2 -0
- package/dist/ui/primitives/Spinner.js +2 -0
- package/dist/ui/primitives/StarRating.d.ts +10 -0
- package/dist/ui/primitives/StarRating.js +10 -0
- package/dist/ui/primitives/Tabs.d.ts +15 -0
- package/dist/ui/primitives/Tabs.js +11 -0
- package/dist/ui/primitives/TagInput.d.ts +10 -0
- package/dist/ui/primitives/TagInput.js +25 -0
- package/dist/ui/primitives/index.d.ts +20 -0
- package/dist/ui/primitives/index.js +19 -0
- package/dist/ui/specialized/DiskUsageAnalyzer.d.ts +12 -0
- package/dist/ui/specialized/DiskUsageAnalyzer.js +38 -0
- package/dist/ui/specialized/OllamaModelManager.d.ts +2 -0
- package/dist/ui/specialized/OllamaModelManager.js +48 -0
- package/dist/ui/specialized/RichTextEditor.d.ts +8 -0
- package/dist/ui/specialized/RichTextEditor.js +64 -0
- package/dist/ui/specialized/SlideCanvas.d.ts +24 -0
- package/dist/ui/specialized/SlideCanvas.js +31 -0
- package/dist/ui/specialized/SpreadsheetGrid.d.ts +18 -0
- package/dist/ui/specialized/SpreadsheetGrid.js +28 -0
- package/dist/ui/specialized/StepEditor.d.ts +12 -0
- package/dist/ui/specialized/StepEditor.js +22 -0
- package/dist/ui/specialized/TerminalEmbed.d.ts +13 -0
- package/dist/ui/specialized/TerminalEmbed.js +50 -0
- package/dist/ui/specialized/index.d.ts +7 -0
- package/dist/ui/specialized/index.js +7 -0
- package/dist/ui/sql/SQLQueryEditor.d.ts +9 -0
- package/dist/ui/sql/SQLQueryEditor.js +10 -0
- package/dist/ui/sql/SQLResultsTable.d.ts +6 -0
- package/dist/ui/sql/SQLResultsTable.js +12 -0
- package/dist/ui/sql/SQLSchemaViewer.d.ts +14 -0
- package/dist/ui/sql/SQLSchemaViewer.js +18 -0
- package/dist/ui/sql/index.d.ts +3 -0
- package/dist/ui/sql/index.js +3 -0
- package/dist/ui/utils/cn.d.ts +1 -0
- package/dist/ui/utils/cn.js +1 -0
- package/dist/ui/utils/fileIcons.d.ts +2 -0
- package/dist/ui/utils/fileIcons.js +24 -0
- package/dist/ui/utils/fileUtils.d.ts +4 -0
- package/dist/ui/utils/fileUtils.js +11 -0
- package/dist/ui/utils/index.d.ts +3 -0
- package/dist/ui/utils/index.js +3 -0
- package/dist/ui/viewers/components/BrowserViewer.d.ts +9 -0
- package/dist/ui/viewers/components/BrowserViewer.js +44 -0
- package/dist/ui/viewers/components/CodeEditor.d.ts +11 -0
- package/dist/ui/viewers/components/CodeEditor.js +115 -0
- package/dist/ui/viewers/components/CsvViewer.d.ts +7 -0
- package/dist/ui/viewers/components/CsvViewer.js +18 -0
- package/dist/ui/viewers/components/ImageViewer.d.ts +7 -0
- package/dist/ui/viewers/components/ImageViewer.js +23 -0
- package/dist/ui/viewers/components/PdfViewer.d.ts +7 -0
- package/dist/ui/viewers/components/PdfViewer.js +29 -0
- package/dist/ui/viewers/components/Terminal.d.ts +7 -0
- package/dist/ui/viewers/components/Terminal.js +31 -0
- package/dist/ui/viewers/components/index.d.ts +6 -0
- package/dist/ui/viewers/components/index.js +6 -0
- package/dist/ui/viewers/index.d.ts +1 -0
- package/dist/ui/viewers/index.js +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface Layer {
|
|
3
|
+
id: string;
|
|
4
|
+
type: string;
|
|
5
|
+
name: string;
|
|
6
|
+
visible: boolean;
|
|
7
|
+
params: Record<string, any>;
|
|
8
|
+
transform?: {
|
|
9
|
+
x: number;
|
|
10
|
+
y: number;
|
|
11
|
+
rotation: number;
|
|
12
|
+
scaleX: number;
|
|
13
|
+
scaleY: number;
|
|
14
|
+
};
|
|
15
|
+
mask?: any;
|
|
16
|
+
}
|
|
17
|
+
export declare const LAYER_TYPES: {
|
|
18
|
+
readonly ADJUSTMENTS: {
|
|
19
|
+
readonly name: "Adjustments";
|
|
20
|
+
readonly icon: import("lucide-react").LucideIcon;
|
|
21
|
+
readonly defaultParams: {
|
|
22
|
+
readonly exposure: 0;
|
|
23
|
+
readonly contrast: 0;
|
|
24
|
+
readonly highlights: 0;
|
|
25
|
+
readonly shadows: 0;
|
|
26
|
+
readonly whites: 0;
|
|
27
|
+
readonly blacks: 0;
|
|
28
|
+
readonly saturation: 0;
|
|
29
|
+
readonly warmth: 0;
|
|
30
|
+
readonly tint: 0;
|
|
31
|
+
readonly pop: 0;
|
|
32
|
+
readonly vignette: 0;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
readonly TEXT: {
|
|
36
|
+
readonly name: "Text";
|
|
37
|
+
readonly icon: import("lucide-react").LucideIcon;
|
|
38
|
+
readonly defaultParams: {
|
|
39
|
+
readonly content: "Hello World";
|
|
40
|
+
readonly font: "Arial";
|
|
41
|
+
readonly size: 50;
|
|
42
|
+
readonly color: "#FFFFFF";
|
|
43
|
+
readonly x: 100;
|
|
44
|
+
readonly y: 100;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
readonly TRANSFORM: {
|
|
48
|
+
readonly name: "Transform";
|
|
49
|
+
readonly icon: import("lucide-react").LucideIcon;
|
|
50
|
+
readonly defaultParams: {
|
|
51
|
+
readonly rotation: 0;
|
|
52
|
+
readonly scaleX: 1;
|
|
53
|
+
readonly scaleY: 1;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
readonly GENERATIVE_FILL: {
|
|
57
|
+
readonly name: "Generative Fill";
|
|
58
|
+
readonly icon: import("lucide-react").LucideIcon;
|
|
59
|
+
readonly defaultParams: {
|
|
60
|
+
readonly prompt: "";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
export type LayerType = keyof typeof LAYER_TYPES;
|
|
65
|
+
interface LayerItemProps {
|
|
66
|
+
layer: Layer;
|
|
67
|
+
isSelected: boolean;
|
|
68
|
+
onSelect: () => void;
|
|
69
|
+
onToggleVisibility: () => void;
|
|
70
|
+
onDelete: () => void;
|
|
71
|
+
onDragStart?: (e: React.DragEvent) => void;
|
|
72
|
+
onDragEnd?: () => void;
|
|
73
|
+
onDragOver?: (e: React.DragEvent) => void;
|
|
74
|
+
onDrop?: (e: React.DragEvent) => void;
|
|
75
|
+
}
|
|
76
|
+
export declare const LayerItem: React.FC<LayerItemProps>;
|
|
77
|
+
interface LayerPanelProps {
|
|
78
|
+
layers: Layer[];
|
|
79
|
+
selectedLayerId: string | null;
|
|
80
|
+
onSelectLayer: (id: string) => void;
|
|
81
|
+
onToggleVisibility: (id: string) => void;
|
|
82
|
+
onDeleteLayer: (id: string) => void;
|
|
83
|
+
onAddLayer: (type: LayerType) => void;
|
|
84
|
+
onReorderLayers?: (fromIndex: number, toIndex: number) => void;
|
|
85
|
+
}
|
|
86
|
+
export declare const LayerPanel: React.FC<LayerPanelProps>;
|
|
87
|
+
export default LayerPanel;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Eye, EyeOff, GripVertical, Trash2, Layers, Sliders, Type, RotateCw, Sparkles } from 'lucide-react';
|
|
3
|
+
export const LAYER_TYPES = {
|
|
4
|
+
ADJUSTMENTS: {
|
|
5
|
+
name: 'Adjustments',
|
|
6
|
+
icon: Sliders,
|
|
7
|
+
defaultParams: { exposure: 0, contrast: 0, highlights: 0, shadows: 0, whites: 0, blacks: 0, saturation: 0, warmth: 0, tint: 0, pop: 0, vignette: 0 }
|
|
8
|
+
},
|
|
9
|
+
TEXT: {
|
|
10
|
+
name: 'Text',
|
|
11
|
+
icon: Type,
|
|
12
|
+
defaultParams: { content: 'Hello World', font: 'Arial', size: 50, color: '#FFFFFF', x: 100, y: 100 }
|
|
13
|
+
},
|
|
14
|
+
TRANSFORM: {
|
|
15
|
+
name: 'Transform',
|
|
16
|
+
icon: RotateCw,
|
|
17
|
+
defaultParams: { rotation: 0, scaleX: 1, scaleY: 1 }
|
|
18
|
+
},
|
|
19
|
+
GENERATIVE_FILL: {
|
|
20
|
+
name: 'Generative Fill',
|
|
21
|
+
icon: Sparkles,
|
|
22
|
+
defaultParams: { prompt: '' }
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
export const LayerItem = ({ layer, isSelected, onSelect, onToggleVisibility, onDelete, onDragStart, onDragEnd, onDragOver, onDrop }) => {
|
|
26
|
+
const layerConfig = LAYER_TYPES[layer.type];
|
|
27
|
+
const IconComponent = layerConfig?.icon || Layers;
|
|
28
|
+
return (React.createElement("div", { className: `flex items-center gap-2 p-2 rounded cursor-pointer transition-colors
|
|
29
|
+
${isSelected ? 'bg-blue-600/30 border border-blue-500/50' : 'hover:bg-gray-700/50'}`, onClick: onSelect, draggable: true, onDragStart: onDragStart, onDragEnd: onDragEnd, onDragOver: onDragOver, onDrop: onDrop },
|
|
30
|
+
React.createElement(GripVertical, { size: 14, className: "text-gray-500 cursor-grab" }),
|
|
31
|
+
React.createElement("button", { onClick: (e) => { e.stopPropagation(); onToggleVisibility(); }, className: "p-1 hover:bg-gray-600 rounded" }, layer.visible ? (React.createElement(Eye, { size: 14, className: "text-gray-300" })) : (React.createElement(EyeOff, { size: 14, className: "text-gray-500" }))),
|
|
32
|
+
React.createElement(IconComponent, { size: 14, className: "text-gray-400" }),
|
|
33
|
+
React.createElement("span", { className: `flex-1 text-sm truncate ${layer.visible ? 'text-gray-200' : 'text-gray-500'}` }, layer.name),
|
|
34
|
+
React.createElement("button", { onClick: (e) => { e.stopPropagation(); onDelete(); }, className: "p-1 hover:bg-red-600/30 rounded opacity-0 group-hover:opacity-100 transition-opacity" },
|
|
35
|
+
React.createElement(Trash2, { size: 12, className: "text-gray-400 hover:text-red-400" }))));
|
|
36
|
+
};
|
|
37
|
+
export const LayerPanel = ({ layers, selectedLayerId, onSelectLayer, onToggleVisibility, onDeleteLayer, onAddLayer, onReorderLayers }) => {
|
|
38
|
+
const [draggedIndex, setDraggedIndex] = React.useState(null);
|
|
39
|
+
const handleDragStart = (index) => (e) => {
|
|
40
|
+
setDraggedIndex(index);
|
|
41
|
+
e.dataTransfer.effectAllowed = 'move';
|
|
42
|
+
};
|
|
43
|
+
const handleDragOver = (index) => (e) => {
|
|
44
|
+
e.preventDefault();
|
|
45
|
+
e.dataTransfer.dropEffect = 'move';
|
|
46
|
+
};
|
|
47
|
+
const handleDrop = (targetIndex) => (e) => {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
if (draggedIndex !== null && draggedIndex !== targetIndex && onReorderLayers) {
|
|
50
|
+
onReorderLayers(draggedIndex, targetIndex);
|
|
51
|
+
}
|
|
52
|
+
setDraggedIndex(null);
|
|
53
|
+
};
|
|
54
|
+
return (React.createElement("div", { className: "flex flex-col h-full" },
|
|
55
|
+
React.createElement("div", { className: "flex items-center justify-between p-2 border-b border-gray-700" },
|
|
56
|
+
React.createElement("div", { className: "flex items-center gap-2 text-sm font-medium" },
|
|
57
|
+
React.createElement(Layers, { size: 14 }),
|
|
58
|
+
React.createElement("span", null, "Layers")),
|
|
59
|
+
React.createElement("div", { className: "flex gap-1" }, Object.keys(LAYER_TYPES).map((type) => {
|
|
60
|
+
const config = LAYER_TYPES[type];
|
|
61
|
+
const Icon = config.icon;
|
|
62
|
+
return (React.createElement("button", { key: type, onClick: () => onAddLayer(type), className: "p-1.5 hover:bg-gray-700 rounded", title: `Add ${config.name} Layer` },
|
|
63
|
+
React.createElement(Icon, { size: 14 })));
|
|
64
|
+
}))),
|
|
65
|
+
React.createElement("div", { className: "flex-1 overflow-y-auto p-2 space-y-1" }, layers.length === 0 ? (React.createElement("div", { className: "text-center text-gray-500 text-sm py-4" }, "No layers. Click + to add one.")) : ([...layers].reverse().map((layer, reversedIndex) => {
|
|
66
|
+
const actualIndex = layers.length - 1 - reversedIndex;
|
|
67
|
+
return (React.createElement(LayerItem, { key: layer.id, layer: layer, isSelected: layer.id === selectedLayerId, onSelect: () => onSelectLayer(layer.id), onToggleVisibility: () => onToggleVisibility(layer.id), onDelete: () => onDeleteLayer(layer.id), onDragStart: handleDragStart(actualIndex), onDragEnd: () => setDraggedIndex(null), onDragOver: handleDragOver(actualIndex), onDrop: handleDrop(actualIndex) }));
|
|
68
|
+
})))));
|
|
69
|
+
};
|
|
70
|
+
export default LayerPanel;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface LightboxProps {
|
|
3
|
+
images: string[];
|
|
4
|
+
currentIndex: number;
|
|
5
|
+
isOpen: boolean;
|
|
6
|
+
onClose: () => void;
|
|
7
|
+
onNavigate: (index: number) => void;
|
|
8
|
+
onDownload?: (path: string) => void;
|
|
9
|
+
renderImage?: (path: string) => React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare const Lightbox: React.FC<LightboxProps>;
|
|
12
|
+
export default Lightbox;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React, { useCallback, useEffect } from 'react';
|
|
2
|
+
import { X, ChevronLeft, ChevronRight, ZoomIn, ZoomOut, Download, RotateCw } from 'lucide-react';
|
|
3
|
+
export const Lightbox = ({ images, currentIndex, isOpen, onClose, onNavigate, onDownload, renderImage }) => {
|
|
4
|
+
const [zoom, setZoom] = React.useState(1);
|
|
5
|
+
const [rotation, setRotation] = React.useState(0);
|
|
6
|
+
const currentImage = images[currentIndex];
|
|
7
|
+
const hasNext = currentIndex < images.length - 1;
|
|
8
|
+
const hasPrev = currentIndex > 0;
|
|
9
|
+
const handlePrev = useCallback(() => {
|
|
10
|
+
if (hasPrev) {
|
|
11
|
+
onNavigate(currentIndex - 1);
|
|
12
|
+
setZoom(1);
|
|
13
|
+
setRotation(0);
|
|
14
|
+
}
|
|
15
|
+
}, [currentIndex, hasPrev, onNavigate]);
|
|
16
|
+
const handleNext = useCallback(() => {
|
|
17
|
+
if (hasNext) {
|
|
18
|
+
onNavigate(currentIndex + 1);
|
|
19
|
+
setZoom(1);
|
|
20
|
+
setRotation(0);
|
|
21
|
+
}
|
|
22
|
+
}, [currentIndex, hasNext, onNavigate]);
|
|
23
|
+
const handleKeyDown = useCallback((e) => {
|
|
24
|
+
switch (e.key) {
|
|
25
|
+
case 'Escape':
|
|
26
|
+
onClose();
|
|
27
|
+
break;
|
|
28
|
+
case 'ArrowLeft':
|
|
29
|
+
handlePrev();
|
|
30
|
+
break;
|
|
31
|
+
case 'ArrowRight':
|
|
32
|
+
handleNext();
|
|
33
|
+
break;
|
|
34
|
+
case '+':
|
|
35
|
+
case '=':
|
|
36
|
+
setZoom(z => Math.min(5, z + 0.25));
|
|
37
|
+
break;
|
|
38
|
+
case '-':
|
|
39
|
+
setZoom(z => Math.max(0.25, z - 0.25));
|
|
40
|
+
break;
|
|
41
|
+
case 'r':
|
|
42
|
+
setRotation(r => (r + 90) % 360);
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
}, [onClose, handlePrev, handleNext]);
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
if (isOpen) {
|
|
48
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
49
|
+
return () => document.removeEventListener('keydown', handleKeyDown);
|
|
50
|
+
}
|
|
51
|
+
}, [isOpen, handleKeyDown]);
|
|
52
|
+
// Reset zoom/rotation when image changes
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
setZoom(1);
|
|
55
|
+
setRotation(0);
|
|
56
|
+
}, [currentIndex]);
|
|
57
|
+
if (!isOpen || !currentImage)
|
|
58
|
+
return null;
|
|
59
|
+
return (React.createElement("div", { className: "fixed inset-0 z-[100] bg-black/95 flex flex-col" },
|
|
60
|
+
React.createElement("div", { className: "flex items-center justify-between p-4 bg-black/50" },
|
|
61
|
+
React.createElement("div", { className: "text-sm text-gray-400" },
|
|
62
|
+
currentIndex + 1,
|
|
63
|
+
" / ",
|
|
64
|
+
images.length),
|
|
65
|
+
React.createElement("div", { className: "flex items-center gap-2" },
|
|
66
|
+
React.createElement("button", { onClick: () => setZoom(z => Math.max(0.25, z - 0.25)), className: "p-2 hover:bg-gray-800 rounded", title: "Zoom out" },
|
|
67
|
+
React.createElement(ZoomOut, { size: 18 })),
|
|
68
|
+
React.createElement("span", { className: "text-sm text-gray-400 w-12 text-center" },
|
|
69
|
+
Math.round(zoom * 100),
|
|
70
|
+
"%"),
|
|
71
|
+
React.createElement("button", { onClick: () => setZoom(z => Math.min(5, z + 0.25)), className: "p-2 hover:bg-gray-800 rounded", title: "Zoom in" },
|
|
72
|
+
React.createElement(ZoomIn, { size: 18 })),
|
|
73
|
+
React.createElement("button", { onClick: () => setRotation(r => (r + 90) % 360), className: "p-2 hover:bg-gray-800 rounded", title: "Rotate" },
|
|
74
|
+
React.createElement(RotateCw, { size: 18 })),
|
|
75
|
+
onDownload && (React.createElement("button", { onClick: () => onDownload(currentImage), className: "p-2 hover:bg-gray-800 rounded", title: "Download" },
|
|
76
|
+
React.createElement(Download, { size: 18 }))),
|
|
77
|
+
React.createElement("button", { onClick: onClose, className: "p-2 hover:bg-gray-800 rounded ml-4", title: "Close (Esc)" },
|
|
78
|
+
React.createElement(X, { size: 20 })))),
|
|
79
|
+
React.createElement("div", { className: "flex-1 flex items-center justify-center overflow-hidden relative" },
|
|
80
|
+
hasPrev && (React.createElement("button", { onClick: handlePrev, className: "absolute left-4 p-3 bg-black/50 hover:bg-black/70 rounded-full transition-colors z-10" },
|
|
81
|
+
React.createElement(ChevronLeft, { size: 24 }))),
|
|
82
|
+
React.createElement("div", { className: "max-w-full max-h-full overflow-auto flex items-center justify-center", style: { cursor: zoom > 1 ? 'grab' : 'default' } }, renderImage ? renderImage(currentImage) : (React.createElement("img", { src: currentImage, alt: currentImage.split('/').pop() || 'Image', className: "max-w-full max-h-full object-contain transition-transform duration-200", style: {
|
|
83
|
+
transform: `scale(${zoom}) rotate(${rotation}deg)`
|
|
84
|
+
}, draggable: false }))),
|
|
85
|
+
hasNext && (React.createElement("button", { onClick: handleNext, className: "absolute right-4 p-3 bg-black/50 hover:bg-black/70 rounded-full transition-colors z-10" },
|
|
86
|
+
React.createElement(ChevronRight, { size: 24 })))),
|
|
87
|
+
React.createElement("div", { className: "p-4 bg-black/50 text-center" },
|
|
88
|
+
React.createElement("span", { className: "text-sm text-gray-400" }, currentImage.split('/').pop()))));
|
|
89
|
+
};
|
|
90
|
+
export default Lightbox;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { ImageAdjustmentSliders, AdjustmentSlider, calculateFilterStyle, defaultAdjustments, type ImageAdjustments } from './ImageAdjustmentSliders';
|
|
2
|
+
export { LayerPanel, LayerItem, LAYER_TYPES, type Layer, type LayerType } from './LayerPanel';
|
|
3
|
+
export { GalleryGrid, ViewModeToggle, type GalleryImage } from './GalleryGrid';
|
|
4
|
+
export { Lightbox } from './Lightbox';
|
|
5
|
+
export { ImageLabelingCanvas, LabelingToolbar, LabelList, type ImageLabel, type LabelCoords, type LabelingTool } from './ImageLabelingCanvas';
|
|
6
|
+
export { ImageSourceTabs, PathEditor, type ImageSource } from './ImageSourceTabs';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Photo editing and gallery components
|
|
2
|
+
export { ImageAdjustmentSliders, AdjustmentSlider, calculateFilterStyle, defaultAdjustments } from './ImageAdjustmentSliders';
|
|
3
|
+
export { LayerPanel, LayerItem, LAYER_TYPES } from './LayerPanel';
|
|
4
|
+
export { GalleryGrid, ViewModeToggle } from './GalleryGrid';
|
|
5
|
+
export { Lightbox } from './Lightbox';
|
|
6
|
+
export { ImageLabelingCanvas, LabelingToolbar, LabelList } from './ImageLabelingCanvas';
|
|
7
|
+
export { ImageSourceTabs, PathEditor } from './ImageSourceTabs';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface AutosizeTextareaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
3
|
+
value: string;
|
|
4
|
+
minRows?: number;
|
|
5
|
+
maxRows?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare const AutosizeTextarea: React.FC<AutosizeTextareaProps>;
|
|
8
|
+
export default AutosizeTextarea;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
export const AutosizeTextarea = ({ value, minRows = 1, maxRows = 10, ...props }) => {
|
|
3
|
+
const textareaRef = useRef(null);
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const textarea = textareaRef.current;
|
|
6
|
+
if (!textarea)
|
|
7
|
+
return;
|
|
8
|
+
textarea.style.height = 'auto';
|
|
9
|
+
const scrollHeight = textarea.scrollHeight;
|
|
10
|
+
const lineHeight = parseInt(window.getComputedStyle(textarea).lineHeight);
|
|
11
|
+
const minHeight = lineHeight * minRows;
|
|
12
|
+
const maxHeight = lineHeight * maxRows;
|
|
13
|
+
textarea.style.height = `${Math.min(Math.max(scrollHeight, minHeight), maxHeight)}px`;
|
|
14
|
+
}, [value, minRows, maxRows]);
|
|
15
|
+
return React.createElement("textarea", { ref: textareaRef, value: value, ...props });
|
|
16
|
+
};
|
|
17
|
+
export default AutosizeTextarea;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export const Button = ({ variant = "secondary", size = "md", className = "", children, ...props }) => {
|
|
3
|
+
const baseStyles = "rounded font-medium transition-all disabled:opacity-50";
|
|
4
|
+
const variantStyles = {
|
|
5
|
+
primary: "bg-blue-600 hover:bg-blue-700 text-white",
|
|
6
|
+
secondary: "bg-gray-700 hover:bg-gray-600 text-gray-100",
|
|
7
|
+
danger: "bg-red-600 hover:bg-red-700 text-white",
|
|
8
|
+
ghost: "hover:bg-gray-700 text-gray-300",
|
|
9
|
+
};
|
|
10
|
+
const sizeStyles = {
|
|
11
|
+
sm: "px-2 py-1 text-xs",
|
|
12
|
+
md: "px-3 py-2 text-sm",
|
|
13
|
+
lg: "px-4 py-3 text-base",
|
|
14
|
+
};
|
|
15
|
+
return (React.createElement("button", { className: `${baseStyles} ${variantStyles[variant]}
|
|
16
|
+
${sizeStyles[size]} ${className}`, ...props }, children));
|
|
17
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { LucideIcon } from 'lucide-react';
|
|
3
|
+
interface CardProps {
|
|
4
|
+
title?: string;
|
|
5
|
+
icon?: LucideIcon;
|
|
6
|
+
iconColor?: string;
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
className?: string;
|
|
9
|
+
onContextMenu?: (e: React.MouseEvent) => void;
|
|
10
|
+
}
|
|
11
|
+
export declare const Card: React.FC<CardProps>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const Card = ({ title, icon: Icon, iconColor = 'text-gray-400', children, className = '', onContextMenu }) => {
|
|
3
|
+
return (React.createElement("div", { className: `theme-bg-tertiary p-4 rounded-lg flex flex-col h-full relative ${className}`, onContextMenu: onContextMenu },
|
|
4
|
+
(title || Icon) && (React.createElement("div", { className: "flex items-center gap-3 mb-2 flex-shrink-0" },
|
|
5
|
+
Icon && React.createElement(Icon, { className: iconColor, size: 18 }),
|
|
6
|
+
title && (React.createElement("h4", { className: "font-semibold theme-text-secondary truncate" }, title)))),
|
|
7
|
+
React.createElement("div", { className: "flex-1 overflow-hidden" }, children)));
|
|
8
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ChartDataset {
|
|
3
|
+
label: string;
|
|
4
|
+
data: number[];
|
|
5
|
+
color?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface ChartProps {
|
|
8
|
+
type: 'line' | 'bar';
|
|
9
|
+
labels: (string | Date)[];
|
|
10
|
+
datasets: ChartDataset[];
|
|
11
|
+
height?: number;
|
|
12
|
+
showLegend?: boolean;
|
|
13
|
+
showGrid?: boolean;
|
|
14
|
+
fillArea?: boolean;
|
|
15
|
+
timeUnit?: 'day' | 'week' | 'month' | 'year';
|
|
16
|
+
}
|
|
17
|
+
export declare const Chart: React.FC<ChartProps>;
|
|
18
|
+
export interface QueryChartConfig {
|
|
19
|
+
x: string;
|
|
20
|
+
y: string;
|
|
21
|
+
type?: 'line' | 'bar';
|
|
22
|
+
groupBy?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface QueryChartProps {
|
|
25
|
+
data: Record<string, unknown>[];
|
|
26
|
+
config: QueryChartConfig;
|
|
27
|
+
height?: number;
|
|
28
|
+
showLegend?: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* QueryChart - renders a chart from SQL query results
|
|
32
|
+
* Automatically detects column names from AS aliases in config
|
|
33
|
+
*/
|
|
34
|
+
export declare const QueryChart: React.FC<QueryChartProps>;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import React, { useMemo } from 'react';
|
|
2
|
+
import { Line, Bar } from 'react-chartjs-2';
|
|
3
|
+
import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, BarElement, Title, Tooltip, Legend, Filler, TimeScale, TimeSeriesScale } from 'chart.js';
|
|
4
|
+
// Register chart.js scales and components
|
|
5
|
+
// Note: The consuming app should import 'chartjs-adapter-date-fns' for time scale support
|
|
6
|
+
ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, BarElement, Title, Tooltip, Legend, Filler, TimeScale, TimeSeriesScale);
|
|
7
|
+
const defaultColors = [
|
|
8
|
+
'#8b5cf6', // purple
|
|
9
|
+
'#3b82f6', // blue
|
|
10
|
+
'#facc15', // yellow
|
|
11
|
+
'#ef4444', // red
|
|
12
|
+
'#22c55e', // green
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Detects if labels appear to be date/time values
|
|
16
|
+
*/
|
|
17
|
+
const detectTimeSeries = (labels) => {
|
|
18
|
+
if (labels.length === 0)
|
|
19
|
+
return false;
|
|
20
|
+
const first = labels[0];
|
|
21
|
+
if (first instanceof Date)
|
|
22
|
+
return !isNaN(first.getTime());
|
|
23
|
+
if (typeof first === 'string') {
|
|
24
|
+
// Check for date-like patterns
|
|
25
|
+
return first.includes('-') || first.includes(':');
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Converts string labels to Date objects if they look like dates
|
|
31
|
+
*/
|
|
32
|
+
const normalizeLabels = (labels) => {
|
|
33
|
+
return labels.map(label => {
|
|
34
|
+
if (label instanceof Date)
|
|
35
|
+
return label;
|
|
36
|
+
if (typeof label === 'string' && (label.includes('-') || label.includes(':'))) {
|
|
37
|
+
const date = new Date(label);
|
|
38
|
+
if (!isNaN(date.getTime()))
|
|
39
|
+
return date;
|
|
40
|
+
}
|
|
41
|
+
return label;
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
export const Chart = ({ type, labels: rawLabels, datasets, height = 300, showLegend = true, showGrid = true, fillArea, timeUnit = 'day' }) => {
|
|
45
|
+
const labels = useMemo(() => normalizeLabels(rawLabels), [rawLabels]);
|
|
46
|
+
const isTimeSeries = useMemo(() => detectTimeSeries(labels), [labels]);
|
|
47
|
+
const shouldFill = fillArea ?? (type === 'line');
|
|
48
|
+
const data = useMemo(() => ({
|
|
49
|
+
labels,
|
|
50
|
+
datasets: datasets.map((ds, i) => ({
|
|
51
|
+
label: ds.label,
|
|
52
|
+
data: ds.data,
|
|
53
|
+
backgroundColor: type === 'bar'
|
|
54
|
+
? (ds.color || defaultColors[i % defaultColors.length])
|
|
55
|
+
: `${ds.color || defaultColors[i % defaultColors.length]}33`,
|
|
56
|
+
borderColor: ds.color || defaultColors[i % defaultColors.length],
|
|
57
|
+
borderWidth: type === 'line' ? 2 : 1,
|
|
58
|
+
fill: shouldFill,
|
|
59
|
+
tension: 0.3,
|
|
60
|
+
}))
|
|
61
|
+
}), [labels, datasets, type, shouldFill]);
|
|
62
|
+
const options = useMemo(() => ({
|
|
63
|
+
responsive: true,
|
|
64
|
+
maintainAspectRatio: false,
|
|
65
|
+
plugins: {
|
|
66
|
+
legend: {
|
|
67
|
+
display: showLegend && datasets.length > 1,
|
|
68
|
+
position: 'top',
|
|
69
|
+
labels: { color: '#9ca3af' }
|
|
70
|
+
},
|
|
71
|
+
tooltip: {
|
|
72
|
+
mode: 'index',
|
|
73
|
+
intersect: false
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
scales: {
|
|
77
|
+
x: isTimeSeries ? {
|
|
78
|
+
type: 'time',
|
|
79
|
+
time: {
|
|
80
|
+
unit: timeUnit,
|
|
81
|
+
tooltipFormat: 'MMM dd, yyyy'
|
|
82
|
+
},
|
|
83
|
+
ticks: { color: '#9ca3af' },
|
|
84
|
+
grid: { display: showGrid, color: '#374151' }
|
|
85
|
+
} : {
|
|
86
|
+
type: 'category',
|
|
87
|
+
ticks: { color: '#9ca3af' },
|
|
88
|
+
grid: { display: showGrid, color: '#374151' }
|
|
89
|
+
},
|
|
90
|
+
y: {
|
|
91
|
+
ticks: { color: '#9ca3af' },
|
|
92
|
+
grid: { display: showGrid, color: '#374151' }
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}), [showLegend, showGrid, isTimeSeries, timeUnit, datasets.length]);
|
|
96
|
+
const Component = type === 'line' ? Line : Bar;
|
|
97
|
+
return React.createElement("div", { style: { height }, className: "w-full" },
|
|
98
|
+
React.createElement(Component, { data: data, options: options }));
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* QueryChart - renders a chart from SQL query results
|
|
102
|
+
* Automatically detects column names from AS aliases in config
|
|
103
|
+
*/
|
|
104
|
+
export const QueryChart = ({ data, config, height = 300, showLegend = true }) => {
|
|
105
|
+
const { chartType, labels, datasets } = useMemo(() => {
|
|
106
|
+
if (!data || data.length === 0 || !config) {
|
|
107
|
+
return { chartType: 'bar', labels: [], datasets: [] };
|
|
108
|
+
}
|
|
109
|
+
const dataKeys = Object.keys(data[0]);
|
|
110
|
+
const chartType = config.type || 'bar';
|
|
111
|
+
// Find x-axis key - check for AS alias first, then exact match
|
|
112
|
+
const xAxisKey = dataKeys.find(key => key.toLowerCase() === config.x.toLowerCase().split(' as ')[1]?.trim()) || dataKeys.find(key => key.toLowerCase() === config.x.toLowerCase()) || dataKeys[0];
|
|
113
|
+
// Parse y-axis expressions (comma-separated for multi-series)
|
|
114
|
+
const yAxisExpressions = config.y
|
|
115
|
+
? config.y.split(',').map(s => s.trim())
|
|
116
|
+
: [];
|
|
117
|
+
// Build datasets
|
|
118
|
+
const datasets = yAxisExpressions.map((yExpr, index) => {
|
|
119
|
+
const yAxisKey = dataKeys.find(key => key.toLowerCase() === yExpr.toLowerCase().split(' as ')[1]?.trim()) || dataKeys.find(key => key.toLowerCase() === yExpr.toLowerCase());
|
|
120
|
+
return {
|
|
121
|
+
label: yAxisKey || yExpr,
|
|
122
|
+
data: data.map(d => parseFloat(String(d[yAxisKey || ''])) || 0),
|
|
123
|
+
color: defaultColors[index % defaultColors.length]
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
// Build labels (x-axis values)
|
|
127
|
+
const labels = data.map(d => {
|
|
128
|
+
const xValue = d[xAxisKey];
|
|
129
|
+
if (typeof xValue === 'string' && (xValue.includes('-') || xValue.includes(':'))) {
|
|
130
|
+
return new Date(xValue);
|
|
131
|
+
}
|
|
132
|
+
return String(xValue);
|
|
133
|
+
});
|
|
134
|
+
return { chartType, labels, datasets };
|
|
135
|
+
}, [data, config]);
|
|
136
|
+
if (datasets.length === 0) {
|
|
137
|
+
return React.createElement("div", { className: "theme-text-secondary text-sm" }, "Not enough data or chart is misconfigured.");
|
|
138
|
+
}
|
|
139
|
+
return (React.createElement(Chart, { type: chartType, labels: labels, datasets: datasets, height: height, showLegend: showLegend }));
|
|
140
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface ContextMenuProps {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
children: React.ReactNode;
|
|
7
|
+
}
|
|
8
|
+
export declare const ContextMenu: React.FC<ContextMenuProps>;
|
|
9
|
+
interface ContextMenuItemProps {
|
|
10
|
+
onClick: () => void;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
icon?: React.ReactNode;
|
|
13
|
+
children: React.ReactNode;
|
|
14
|
+
}
|
|
15
|
+
export declare const ContextMenuItem: React.FC<ContextMenuItemProps>;
|
|
16
|
+
export declare const ContextMenuSeparator: React.FC;
|
|
17
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
|
+
export const ContextMenu = ({ x, y, onClose, children, }) => {
|
|
3
|
+
const menuRef = useRef(null);
|
|
4
|
+
useEffect(() => {
|
|
5
|
+
const handleClickOutside = (e) => {
|
|
6
|
+
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
7
|
+
onClose();
|
|
8
|
+
}
|
|
9
|
+
};
|
|
10
|
+
const handleEscape = (e) => {
|
|
11
|
+
if (e.key === "Escape") {
|
|
12
|
+
onClose();
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
16
|
+
document.addEventListener("keydown", handleEscape);
|
|
17
|
+
return () => {
|
|
18
|
+
document.removeEventListener("mousedown", handleClickOutside);
|
|
19
|
+
document.removeEventListener("keydown", handleEscape);
|
|
20
|
+
};
|
|
21
|
+
}, [onClose]);
|
|
22
|
+
return (React.createElement(React.Fragment, null,
|
|
23
|
+
React.createElement("div", { className: "fixed inset-0 z-40", onClick: onClose }),
|
|
24
|
+
React.createElement("div", { ref: menuRef, className: "fixed theme-bg-secondary theme-border border rounded \n shadow-lg py-1 z-50 min-w-[160px]", style: { top: `${y}px`, left: `${x}px` } }, children)));
|
|
25
|
+
};
|
|
26
|
+
export const ContextMenuItem = ({ onClick, disabled = false, icon, children, }) => {
|
|
27
|
+
return (React.createElement("button", { onClick: onClick, disabled: disabled, className: "flex items-center gap-2 px-4 py-2 theme-hover w-full \n text-left theme-text-primary text-sm disabled:opacity-50 \n disabled:cursor-not-allowed" },
|
|
28
|
+
icon && React.createElement("span", { className: "flex-shrink-0" }, icon),
|
|
29
|
+
React.createElement("span", null, children)));
|
|
30
|
+
};
|
|
31
|
+
export const ContextMenuSeparator = () => {
|
|
32
|
+
return React.createElement("div", { className: "border-t theme-border my-1" });
|
|
33
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface DataTableProps<T = any> {
|
|
3
|
+
data: T[];
|
|
4
|
+
columns: Array<{
|
|
5
|
+
key: string;
|
|
6
|
+
header: string;
|
|
7
|
+
render?: (value: any, row: T, index: number) => React.ReactNode;
|
|
8
|
+
}>;
|
|
9
|
+
className?: string;
|
|
10
|
+
maxHeight?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const DataTable: <T extends Record<string, any>>({ data, columns, className, maxHeight }: DataTableProps<T>) => React.JSX.Element;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export const DataTable = ({ data, columns, className = '', maxHeight = '400px' }) => {
|
|
3
|
+
if (!data || data.length === 0) {
|
|
4
|
+
return (React.createElement("div", { className: "text-center theme-text-muted text-sm p-4" }, "No data available"));
|
|
5
|
+
}
|
|
6
|
+
return (React.createElement("div", { className: `overflow-auto theme-border border rounded-lg ${className}`, style: { maxHeight } },
|
|
7
|
+
React.createElement("table", { className: "w-full text-sm text-left" },
|
|
8
|
+
React.createElement("thead", { className: "theme-bg-tertiary sticky top-0" },
|
|
9
|
+
React.createElement("tr", null, columns.map((col) => (React.createElement("th", { key: col.key, className: "p-2 font-semibold" }, col.header))))),
|
|
10
|
+
React.createElement("tbody", { className: "theme-bg-primary divide-y theme-divide" }, data.map((row, rowIndex) => (React.createElement("tr", { key: rowIndex }, columns.map((col) => (React.createElement("td", { key: col.key, className: "p-2 font-mono truncate max-w-xs" }, col.render
|
|
11
|
+
? col.render(row[col.key], row, rowIndex)
|
|
12
|
+
: String(row[col.key] ?? '')))))))))));
|
|
13
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
interface FileUploadProps {
|
|
3
|
+
accept?: string;
|
|
4
|
+
multiple?: boolean;
|
|
5
|
+
onFilesSelected: (files: File[]) => void;
|
|
6
|
+
children?: React.ReactNode;
|
|
7
|
+
className?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const FileUpload: React.FC<FileUploadProps>;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { Upload } from 'lucide-react';
|
|
3
|
+
import { Button } from './Button';
|
|
4
|
+
export const FileUpload = ({ accept = '*', multiple = false, onFilesSelected, children, className = '' }) => {
|
|
5
|
+
const inputRef = useRef(null);
|
|
6
|
+
const handleClick = () => {
|
|
7
|
+
inputRef.current?.click();
|
|
8
|
+
};
|
|
9
|
+
const handleChange = (e) => {
|
|
10
|
+
const files = Array.from(e.target.files || []);
|
|
11
|
+
if (files.length > 0) {
|
|
12
|
+
onFilesSelected(files);
|
|
13
|
+
}
|
|
14
|
+
// Reset input
|
|
15
|
+
if (inputRef.current) {
|
|
16
|
+
inputRef.current.value = '';
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
return (React.createElement(React.Fragment, null,
|
|
20
|
+
React.createElement("input", { ref: inputRef, type: "file", accept: accept, multiple: multiple, className: "hidden", onChange: handleChange }),
|
|
21
|
+
React.createElement(Button, { onClick: handleClick, className: className }, children || (React.createElement(React.Fragment, null,
|
|
22
|
+
React.createElement(Upload, { size: 16 }),
|
|
23
|
+
" Upload Files")))));
|
|
24
|
+
};
|