machinaos 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.template +71 -0
- package/LICENSE +21 -0
- package/README.md +87 -0
- package/bin/cli.js +159 -0
- package/client/.dockerignore +45 -0
- package/client/Dockerfile +68 -0
- package/client/eslint.config.js +29 -0
- package/client/index.html +13 -0
- package/client/nginx.conf +66 -0
- package/client/package.json +48 -0
- package/client/src/App.tsx +27 -0
- package/client/src/Dashboard.tsx +1173 -0
- package/client/src/ParameterPanel.tsx +301 -0
- package/client/src/components/AIAgentNode.tsx +321 -0
- package/client/src/components/APIKeyValidator.tsx +118 -0
- package/client/src/components/ClaudeChatModelNode.tsx +18 -0
- package/client/src/components/ConditionalEdge.tsx +189 -0
- package/client/src/components/CredentialsModal.tsx +306 -0
- package/client/src/components/EdgeConditionEditor.tsx +443 -0
- package/client/src/components/GeminiChatModelNode.tsx +18 -0
- package/client/src/components/GenericNode.tsx +357 -0
- package/client/src/components/LocationParameterPanel.tsx +154 -0
- package/client/src/components/ModelNode.tsx +286 -0
- package/client/src/components/OpenAIChatModelNode.tsx +18 -0
- package/client/src/components/OutputPanel.tsx +471 -0
- package/client/src/components/ParameterRenderer.tsx +1874 -0
- package/client/src/components/SkillEditorModal.tsx +417 -0
- package/client/src/components/SquareNode.tsx +797 -0
- package/client/src/components/StartNode.tsx +250 -0
- package/client/src/components/ToolkitNode.tsx +365 -0
- package/client/src/components/TriggerNode.tsx +463 -0
- package/client/src/components/auth/LoginPage.tsx +247 -0
- package/client/src/components/auth/ProtectedRoute.tsx +59 -0
- package/client/src/components/base/BaseChatModelNode.tsx +271 -0
- package/client/src/components/icons/AIProviderIcons.tsx +50 -0
- package/client/src/components/maps/GoogleMapsPicker.tsx +137 -0
- package/client/src/components/maps/MapsPreviewPanel.tsx +110 -0
- package/client/src/components/maps/index.ts +26 -0
- package/client/src/components/parameterPanel/InputSection.tsx +1094 -0
- package/client/src/components/parameterPanel/LocationPanelLayout.tsx +65 -0
- package/client/src/components/parameterPanel/MapsSection.tsx +92 -0
- package/client/src/components/parameterPanel/MiddleSection.tsx +571 -0
- package/client/src/components/parameterPanel/OutputSection.tsx +81 -0
- package/client/src/components/parameterPanel/ParameterPanelLayout.tsx +82 -0
- package/client/src/components/parameterPanel/ToolSchemaEditor.tsx +436 -0
- package/client/src/components/parameterPanel/index.ts +42 -0
- package/client/src/components/shared/DataPanel.tsx +142 -0
- package/client/src/components/shared/JSONTreeRenderer.tsx +106 -0
- package/client/src/components/ui/AIResultModal.tsx +204 -0
- package/client/src/components/ui/AndroidSettingsPanel.tsx +401 -0
- package/client/src/components/ui/CodeEditor.tsx +81 -0
- package/client/src/components/ui/CollapsibleSection.tsx +88 -0
- package/client/src/components/ui/ComponentItem.tsx +154 -0
- package/client/src/components/ui/ComponentPalette.tsx +321 -0
- package/client/src/components/ui/ConsolePanel.tsx +1074 -0
- package/client/src/components/ui/ErrorBoundary.tsx +196 -0
- package/client/src/components/ui/InputNodesPanel.tsx +204 -0
- package/client/src/components/ui/MapSelector.tsx +314 -0
- package/client/src/components/ui/Modal.tsx +149 -0
- package/client/src/components/ui/NodeContextMenu.tsx +192 -0
- package/client/src/components/ui/NodeOutputPanel.tsx +1150 -0
- package/client/src/components/ui/OutputDisplayPanel.tsx +381 -0
- package/client/src/components/ui/SettingsPanel.tsx +243 -0
- package/client/src/components/ui/TopToolbar.tsx +736 -0
- package/client/src/components/ui/WhatsAppSettingsPanel.tsx +345 -0
- package/client/src/components/ui/WorkflowSidebar.tsx +294 -0
- package/client/src/config/antdTheme.ts +186 -0
- package/client/src/config/api.ts +54 -0
- package/client/src/contexts/AuthContext.tsx +221 -0
- package/client/src/contexts/ThemeContext.tsx +42 -0
- package/client/src/contexts/WebSocketContext.tsx +1971 -0
- package/client/src/factories/baseChatModelFactory.ts +256 -0
- package/client/src/hooks/useAndroidOperations.ts +164 -0
- package/client/src/hooks/useApiKeyValidation.ts +107 -0
- package/client/src/hooks/useApiKeys.ts +238 -0
- package/client/src/hooks/useAppTheme.ts +17 -0
- package/client/src/hooks/useComponentPalette.ts +51 -0
- package/client/src/hooks/useCopyPaste.ts +155 -0
- package/client/src/hooks/useDragAndDrop.ts +124 -0
- package/client/src/hooks/useDragVariable.ts +88 -0
- package/client/src/hooks/useExecution.ts +313 -0
- package/client/src/hooks/useParameterPanel.ts +176 -0
- package/client/src/hooks/useReactFlowNodes.ts +189 -0
- package/client/src/hooks/useToolSchema.ts +209 -0
- package/client/src/hooks/useWhatsApp.ts +196 -0
- package/client/src/hooks/useWorkflowManagement.ts +46 -0
- package/client/src/index.css +315 -0
- package/client/src/main.tsx +19 -0
- package/client/src/nodeDefinitions/aiAgentNodes.ts +336 -0
- package/client/src/nodeDefinitions/aiModelNodes.ts +340 -0
- package/client/src/nodeDefinitions/androidDeviceNodes.ts +140 -0
- package/client/src/nodeDefinitions/androidServiceNodes.ts +383 -0
- package/client/src/nodeDefinitions/chatNodes.ts +135 -0
- package/client/src/nodeDefinitions/codeNodes.ts +54 -0
- package/client/src/nodeDefinitions/documentNodes.ts +379 -0
- package/client/src/nodeDefinitions/index.ts +15 -0
- package/client/src/nodeDefinitions/locationNodes.ts +463 -0
- package/client/src/nodeDefinitions/schedulerNodes.ts +220 -0
- package/client/src/nodeDefinitions/skillNodes.ts +211 -0
- package/client/src/nodeDefinitions/toolNodes.ts +198 -0
- package/client/src/nodeDefinitions/utilityNodes.ts +284 -0
- package/client/src/nodeDefinitions/whatsappNodes.ts +865 -0
- package/client/src/nodeDefinitions/workflowNodes.ts +41 -0
- package/client/src/nodeDefinitions.ts +104 -0
- package/client/src/schemas/workflowSchema.ts +264 -0
- package/client/src/services/dynamicParameterService.ts +96 -0
- package/client/src/services/execution/aiAgentExecutionService.ts +35 -0
- package/client/src/services/executionService.ts +232 -0
- package/client/src/services/workflowApi.ts +91 -0
- package/client/src/store/useAppStore.ts +582 -0
- package/client/src/styles/theme.ts +508 -0
- package/client/src/styles/zIndex.ts +17 -0
- package/client/src/types/ComponentTypes.ts +39 -0
- package/client/src/types/EdgeCondition.ts +231 -0
- package/client/src/types/INodeProperties.ts +288 -0
- package/client/src/types/NodeTypes.ts +28 -0
- package/client/src/utils/formatters.ts +33 -0
- package/client/src/utils/googleMapsLoader.ts +140 -0
- package/client/src/utils/locationUtils.ts +85 -0
- package/client/src/utils/nodeUtils.ts +31 -0
- package/client/src/utils/workflow.ts +30 -0
- package/client/src/utils/workflowExport.ts +120 -0
- package/client/src/vite-env.d.ts +12 -0
- package/client/tailwind.config.js +60 -0
- package/client/tsconfig.json +25 -0
- package/client/tsconfig.node.json +11 -0
- package/client/vite.config.js +35 -0
- package/docker-compose.prod.yml +107 -0
- package/docker-compose.yml +104 -0
- package/docs-MachinaOs/README.md +85 -0
- package/docs-MachinaOs/deployment/docker.mdx +228 -0
- package/docs-MachinaOs/deployment/production.mdx +345 -0
- package/docs-MachinaOs/docs.json +75 -0
- package/docs-MachinaOs/faq.mdx +309 -0
- package/docs-MachinaOs/favicon.svg +5 -0
- package/docs-MachinaOs/installation.mdx +160 -0
- package/docs-MachinaOs/introduction.mdx +114 -0
- package/docs-MachinaOs/logo/dark.svg +6 -0
- package/docs-MachinaOs/logo/light.svg +6 -0
- package/docs-MachinaOs/nodes/ai-agent.mdx +216 -0
- package/docs-MachinaOs/nodes/ai-models.mdx +240 -0
- package/docs-MachinaOs/nodes/android.mdx +411 -0
- package/docs-MachinaOs/nodes/overview.mdx +181 -0
- package/docs-MachinaOs/nodes/schedulers.mdx +316 -0
- package/docs-MachinaOs/nodes/webhooks.mdx +330 -0
- package/docs-MachinaOs/nodes/whatsapp.mdx +305 -0
- package/docs-MachinaOs/quickstart.mdx +119 -0
- package/docs-MachinaOs/tutorials/ai-agent-workflow.mdx +177 -0
- package/docs-MachinaOs/tutorials/android-automation.mdx +242 -0
- package/docs-MachinaOs/tutorials/first-workflow.mdx +134 -0
- package/docs-MachinaOs/tutorials/whatsapp-automation.mdx +185 -0
- package/nul +0 -0
- package/package.json +70 -0
- package/scripts/build.js +158 -0
- package/scripts/check-ports.ps1 +33 -0
- package/scripts/clean.js +40 -0
- package/scripts/docker.js +93 -0
- package/scripts/kill-port.ps1 +154 -0
- package/scripts/start.js +210 -0
- package/scripts/stop.js +325 -0
- package/server/.dockerignore +44 -0
- package/server/Dockerfile +45 -0
- package/server/constants.py +249 -0
- package/server/core/__init__.py +1 -0
- package/server/core/cache.py +461 -0
- package/server/core/config.py +128 -0
- package/server/core/container.py +99 -0
- package/server/core/database.py +1211 -0
- package/server/core/logging.py +314 -0
- package/server/main.py +289 -0
- package/server/middleware/__init__.py +5 -0
- package/server/middleware/auth.py +89 -0
- package/server/models/__init__.py +1 -0
- package/server/models/auth.py +52 -0
- package/server/models/cache.py +24 -0
- package/server/models/database.py +211 -0
- package/server/models/nodes.py +455 -0
- package/server/package.json +9 -0
- package/server/pyproject.toml +72 -0
- package/server/requirements.txt +83 -0
- package/server/routers/__init__.py +1 -0
- package/server/routers/android.py +294 -0
- package/server/routers/auth.py +203 -0
- package/server/routers/database.py +151 -0
- package/server/routers/maps.py +142 -0
- package/server/routers/nodejs_compat.py +289 -0
- package/server/routers/webhook.py +90 -0
- package/server/routers/websocket.py +2127 -0
- package/server/routers/whatsapp.py +761 -0
- package/server/routers/workflow.py +200 -0
- package/server/services/__init__.py +1 -0
- package/server/services/ai.py +2415 -0
- package/server/services/android/__init__.py +27 -0
- package/server/services/android/broadcaster.py +114 -0
- package/server/services/android/client.py +608 -0
- package/server/services/android/manager.py +78 -0
- package/server/services/android/protocol.py +165 -0
- package/server/services/android_service.py +588 -0
- package/server/services/auth.py +131 -0
- package/server/services/chat_client.py +160 -0
- package/server/services/deployment/__init__.py +12 -0
- package/server/services/deployment/manager.py +706 -0
- package/server/services/deployment/state.py +47 -0
- package/server/services/deployment/triggers.py +275 -0
- package/server/services/event_waiter.py +785 -0
- package/server/services/execution/__init__.py +77 -0
- package/server/services/execution/cache.py +769 -0
- package/server/services/execution/conditions.py +373 -0
- package/server/services/execution/dlq.py +132 -0
- package/server/services/execution/executor.py +1351 -0
- package/server/services/execution/models.py +531 -0
- package/server/services/execution/recovery.py +235 -0
- package/server/services/handlers/__init__.py +126 -0
- package/server/services/handlers/ai.py +355 -0
- package/server/services/handlers/android.py +260 -0
- package/server/services/handlers/code.py +278 -0
- package/server/services/handlers/document.py +598 -0
- package/server/services/handlers/http.py +193 -0
- package/server/services/handlers/polyglot.py +105 -0
- package/server/services/handlers/tools.py +845 -0
- package/server/services/handlers/triggers.py +107 -0
- package/server/services/handlers/utility.py +822 -0
- package/server/services/handlers/whatsapp.py +476 -0
- package/server/services/maps.py +289 -0
- package/server/services/memory_store.py +103 -0
- package/server/services/node_executor.py +375 -0
- package/server/services/parameter_resolver.py +218 -0
- package/server/services/polyglot_client.py +169 -0
- package/server/services/scheduler.py +155 -0
- package/server/services/skill_loader.py +417 -0
- package/server/services/status_broadcaster.py +826 -0
- package/server/services/temporal/__init__.py +23 -0
- package/server/services/temporal/activities.py +344 -0
- package/server/services/temporal/client.py +76 -0
- package/server/services/temporal/executor.py +147 -0
- package/server/services/temporal/worker.py +251 -0
- package/server/services/temporal/workflow.py +355 -0
- package/server/services/temporal/ws_client.py +236 -0
- package/server/services/text.py +111 -0
- package/server/services/user_auth.py +172 -0
- package/server/services/websocket_client.py +29 -0
- package/server/services/workflow.py +597 -0
- package/server/skills/android-skill/SKILL.md +82 -0
- package/server/skills/assistant-personality/SKILL.md +45 -0
- package/server/skills/code-skill/SKILL.md +140 -0
- package/server/skills/http-skill/SKILL.md +161 -0
- package/server/skills/maps-skill/SKILL.md +170 -0
- package/server/skills/memory-skill/SKILL.md +154 -0
- package/server/skills/scheduler-skill/SKILL.md +84 -0
- package/server/skills/whatsapp-skill/SKILL.md +283 -0
- package/server/uv.lock +2916 -0
- package/server/whatsapp-rpc/.dockerignore +30 -0
- package/server/whatsapp-rpc/Dockerfile +44 -0
- package/server/whatsapp-rpc/Dockerfile.web +17 -0
- package/server/whatsapp-rpc/README.md +139 -0
- package/server/whatsapp-rpc/cli.js +95 -0
- package/server/whatsapp-rpc/configs/config.yaml +7 -0
- package/server/whatsapp-rpc/docker-compose.yml +35 -0
- package/server/whatsapp-rpc/docs/API.md +410 -0
- package/server/whatsapp-rpc/go.mod +67 -0
- package/server/whatsapp-rpc/go.sum +203 -0
- package/server/whatsapp-rpc/package.json +30 -0
- package/server/whatsapp-rpc/schema.json +1294 -0
- package/server/whatsapp-rpc/scripts/clean.cjs +66 -0
- package/server/whatsapp-rpc/scripts/cli.js +162 -0
- package/server/whatsapp-rpc/src/go/cmd/server/main.go +91 -0
- package/server/whatsapp-rpc/src/go/config/config.go +49 -0
- package/server/whatsapp-rpc/src/go/rpc/rpc.go +446 -0
- package/server/whatsapp-rpc/src/go/rpc/server.go +112 -0
- package/server/whatsapp-rpc/src/go/whatsapp/history.go +166 -0
- package/server/whatsapp-rpc/src/go/whatsapp/messages.go +390 -0
- package/server/whatsapp-rpc/src/go/whatsapp/service.go +2130 -0
- package/server/whatsapp-rpc/src/go/whatsapp/types.go +261 -0
- package/server/whatsapp-rpc/src/python/pyproject.toml +15 -0
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/__init__.py +4 -0
- package/server/whatsapp-rpc/src/python/whatsapp_rpc/client.py +427 -0
- package/server/whatsapp-rpc/web/app.py +609 -0
- package/server/whatsapp-rpc/web/requirements.txt +6 -0
- package/server/whatsapp-rpc/web/rpc_client.py +427 -0
- package/server/whatsapp-rpc/web/static/openapi.yaml +59 -0
- package/server/whatsapp-rpc/web/templates/base.html +150 -0
- package/server/whatsapp-rpc/web/templates/contacts.html +240 -0
- package/server/whatsapp-rpc/web/templates/dashboard.html +320 -0
- package/server/whatsapp-rpc/web/templates/groups.html +328 -0
- package/server/whatsapp-rpc/web/templates/messages.html +465 -0
- package/server/whatsapp-rpc/web/templates/messaging.html +681 -0
- package/server/whatsapp-rpc/web/templates/send.html +259 -0
- package/server/whatsapp-rpc/web/templates/settings.html +459 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protected Route component.
|
|
3
|
+
* Wraps content that requires authentication.
|
|
4
|
+
* Shows LoginPage if user is not authenticated.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { useAuth } from '../../contexts/AuthContext';
|
|
9
|
+
import LoginPage from './LoginPage';
|
|
10
|
+
|
|
11
|
+
interface ProtectedRouteProps {
|
|
12
|
+
children: React.ReactNode;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ children }) => {
|
|
16
|
+
const { isAuthenticated, isLoading } = useAuth();
|
|
17
|
+
|
|
18
|
+
// Show loading spinner while checking auth
|
|
19
|
+
if (isLoading) {
|
|
20
|
+
return (
|
|
21
|
+
<div style={{
|
|
22
|
+
display: 'flex',
|
|
23
|
+
justifyContent: 'center',
|
|
24
|
+
alignItems: 'center',
|
|
25
|
+
height: '100vh',
|
|
26
|
+
backgroundColor: '#0d1117',
|
|
27
|
+
color: '#c9d1d9'
|
|
28
|
+
}}>
|
|
29
|
+
<div style={{ textAlign: 'center' }}>
|
|
30
|
+
<div style={{
|
|
31
|
+
width: 40,
|
|
32
|
+
height: 40,
|
|
33
|
+
border: '3px solid #30363d',
|
|
34
|
+
borderTopColor: '#bd93f9',
|
|
35
|
+
borderRadius: '50%',
|
|
36
|
+
animation: 'spin 1s linear infinite',
|
|
37
|
+
margin: '0 auto 16px'
|
|
38
|
+
}} />
|
|
39
|
+
<style>{`
|
|
40
|
+
@keyframes spin {
|
|
41
|
+
to { transform: rotate(360deg); }
|
|
42
|
+
}
|
|
43
|
+
`}</style>
|
|
44
|
+
<p>Loading...</p>
|
|
45
|
+
</div>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Show login page if not authenticated
|
|
51
|
+
if (!isAuthenticated) {
|
|
52
|
+
return <LoginPage />;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Render protected content
|
|
56
|
+
return <>{children}</>;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export default ProtectedRoute;
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import { Handle, Position, NodeProps } from 'reactflow';
|
|
3
|
+
import { NodeData } from '../../types/NodeTypes';
|
|
4
|
+
import { useAppStore } from '../../store/useAppStore';
|
|
5
|
+
import { useWebSocket } from '../../contexts/WebSocketContext';
|
|
6
|
+
import { useApiKeys } from '../../hooks/useApiKeys';
|
|
7
|
+
import { useAppTheme } from '../../hooks/useAppTheme';
|
|
8
|
+
|
|
9
|
+
interface BaseChatModelNodeProps extends NodeProps<NodeData> {
|
|
10
|
+
providerId: string;
|
|
11
|
+
displayName: string;
|
|
12
|
+
icon: string;
|
|
13
|
+
color: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const BaseChatModelNode: React.FC<BaseChatModelNodeProps> = ({
|
|
17
|
+
id,
|
|
18
|
+
type,
|
|
19
|
+
data,
|
|
20
|
+
isConnectable,
|
|
21
|
+
selected,
|
|
22
|
+
providerId,
|
|
23
|
+
displayName,
|
|
24
|
+
icon,
|
|
25
|
+
color
|
|
26
|
+
}) => {
|
|
27
|
+
const theme = useAppTheme();
|
|
28
|
+
const { setSelectedNode } = useAppStore();
|
|
29
|
+
const [hasApiKey, setHasApiKey] = useState(false);
|
|
30
|
+
const [isConfigured, setIsConfigured] = useState(false);
|
|
31
|
+
const isDisabled = data?.disabled === true;
|
|
32
|
+
|
|
33
|
+
// Get node status from WebSocket context
|
|
34
|
+
const { getNodeStatus } = useWebSocket();
|
|
35
|
+
const { getStoredApiKey } = useApiKeys();
|
|
36
|
+
const nodeStatus = getNodeStatus(id);
|
|
37
|
+
const executionStatus = nodeStatus?.status || 'idle';
|
|
38
|
+
|
|
39
|
+
useEffect(() => {
|
|
40
|
+
const checkConfiguration = async () => {
|
|
41
|
+
try {
|
|
42
|
+
const apiKey = await getStoredApiKey(providerId);
|
|
43
|
+
const hasApiKeyStored = !!apiKey;
|
|
44
|
+
setHasApiKey(hasApiKeyStored);
|
|
45
|
+
|
|
46
|
+
const hasModel = data?.model && data.model.trim() !== '';
|
|
47
|
+
const configured = hasModel && hasApiKeyStored;
|
|
48
|
+
|
|
49
|
+
setIsConfigured(configured);
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error(`[BaseChatModelNode] ${displayName} ${id}: Configuration check error:`, error);
|
|
52
|
+
setHasApiKey(false);
|
|
53
|
+
setIsConfigured(false);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
checkConfiguration();
|
|
58
|
+
}, [data?.model, id, providerId, displayName, getStoredApiKey]);
|
|
59
|
+
|
|
60
|
+
const handleParametersClick = (e: React.MouseEvent) => {
|
|
61
|
+
e.stopPropagation();
|
|
62
|
+
setSelectedNode({ id, type, data, position: { x: 0, y: 0 } });
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// Get status indicator color based on execution state
|
|
66
|
+
const getStatusIndicatorColor = () => {
|
|
67
|
+
switch (executionStatus) {
|
|
68
|
+
case 'executing':
|
|
69
|
+
return theme.dracula.cyan; // Executing
|
|
70
|
+
case 'success':
|
|
71
|
+
return theme.dracula.green; // Success
|
|
72
|
+
case 'error':
|
|
73
|
+
return theme.dracula.red; // Error
|
|
74
|
+
default:
|
|
75
|
+
// Idle - use configuration status
|
|
76
|
+
return isConfigured ? theme.dracula.green : hasApiKey ? theme.dracula.orange : theme.dracula.red;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const getStatusTitle = () => {
|
|
81
|
+
switch (executionStatus) {
|
|
82
|
+
case 'executing':
|
|
83
|
+
return 'Executing...';
|
|
84
|
+
case 'success':
|
|
85
|
+
return 'Execution successful';
|
|
86
|
+
case 'error':
|
|
87
|
+
return `Error: ${nodeStatus?.data?.error || 'Unknown error'}`;
|
|
88
|
+
default:
|
|
89
|
+
return isConfigured
|
|
90
|
+
? 'Model configured and ready'
|
|
91
|
+
: hasApiKey
|
|
92
|
+
? 'API key found, model needs configuration'
|
|
93
|
+
: 'API key required';
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const isExecuting = executionStatus === 'executing';
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
style={{
|
|
102
|
+
position: 'relative',
|
|
103
|
+
display: 'flex',
|
|
104
|
+
flexDirection: 'column',
|
|
105
|
+
alignItems: 'center',
|
|
106
|
+
fontFamily: 'system-ui, -apple-system, sans-serif',
|
|
107
|
+
fontSize: theme.fontSize.xs,
|
|
108
|
+
cursor: 'pointer',
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
{/* Main Circular Node */}
|
|
112
|
+
<div
|
|
113
|
+
style={{
|
|
114
|
+
position: 'relative',
|
|
115
|
+
width: theme.nodeSize.square,
|
|
116
|
+
height: theme.nodeSize.square,
|
|
117
|
+
borderRadius: '50%',
|
|
118
|
+
background: isConfigured ? color : theme.colors.textMuted,
|
|
119
|
+
border: `2px solid ${selected ? theme.colors.focus : isExecuting ? theme.dracula.cyan : isConfigured ? color : theme.dracula.red}`,
|
|
120
|
+
display: 'flex',
|
|
121
|
+
alignItems: 'center',
|
|
122
|
+
justifyContent: 'center',
|
|
123
|
+
color: 'white',
|
|
124
|
+
fontSize: type === 'aiAgent' ? theme.fontSize.lg : theme.nodeSize.squareIcon,
|
|
125
|
+
fontWeight: theme.fontWeight.semibold,
|
|
126
|
+
transition: theme.transitions.fast,
|
|
127
|
+
boxShadow: selected
|
|
128
|
+
? `0 4px 12px ${theme.colors.focusRing}, 0 0 0 2px ${theme.colors.focusRing}`
|
|
129
|
+
: isExecuting
|
|
130
|
+
? `0 4px 12px ${theme.dracula.cyan}66, 0 0 0 3px ${theme.dracula.cyan}4D`
|
|
131
|
+
: isConfigured
|
|
132
|
+
? `0 2px 8px ${theme.colors.shadow}`
|
|
133
|
+
: `0 2px 8px ${theme.dracula.red}4D`,
|
|
134
|
+
animation: isExecuting ? 'pulse 1.5s ease-in-out infinite' : 'none',
|
|
135
|
+
opacity: isDisabled ? 0.5 : 1,
|
|
136
|
+
}}
|
|
137
|
+
>
|
|
138
|
+
{/* Disabled Overlay */}
|
|
139
|
+
{isDisabled && (
|
|
140
|
+
<div style={{
|
|
141
|
+
position: 'absolute',
|
|
142
|
+
top: 0,
|
|
143
|
+
left: 0,
|
|
144
|
+
right: 0,
|
|
145
|
+
bottom: 0,
|
|
146
|
+
backgroundColor: 'rgba(128, 128, 128, 0.4)',
|
|
147
|
+
borderRadius: 'inherit',
|
|
148
|
+
zIndex: 35,
|
|
149
|
+
display: 'flex',
|
|
150
|
+
alignItems: 'center',
|
|
151
|
+
justifyContent: 'center',
|
|
152
|
+
pointerEvents: 'none',
|
|
153
|
+
}}>
|
|
154
|
+
<span style={{ fontSize: '20px', opacity: 0.8, color: theme.colors.textSecondary }}>||</span>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
|
|
158
|
+
{/* Provider Icon */}
|
|
159
|
+
{icon}
|
|
160
|
+
|
|
161
|
+
{/* Parameters Button */}
|
|
162
|
+
<button
|
|
163
|
+
onClick={handleParametersClick}
|
|
164
|
+
style={{
|
|
165
|
+
position: 'absolute',
|
|
166
|
+
top: '-8px',
|
|
167
|
+
right: '-8px',
|
|
168
|
+
width: theme.nodeSize.paramButton,
|
|
169
|
+
height: theme.nodeSize.paramButton,
|
|
170
|
+
borderRadius: '50%',
|
|
171
|
+
backgroundColor: theme.colors.backgroundAlt,
|
|
172
|
+
border: `1px solid ${theme.colors.border}`,
|
|
173
|
+
cursor: 'pointer',
|
|
174
|
+
display: 'flex',
|
|
175
|
+
alignItems: 'center',
|
|
176
|
+
justifyContent: 'center',
|
|
177
|
+
fontSize: theme.fontSize.xs,
|
|
178
|
+
color: theme.colors.textSecondary,
|
|
179
|
+
fontWeight: '400',
|
|
180
|
+
transition: theme.transitions.fast,
|
|
181
|
+
zIndex: 30,
|
|
182
|
+
boxShadow: `0 1px 3px ${theme.colors.shadow}`
|
|
183
|
+
}}
|
|
184
|
+
title="Edit Model Parameters"
|
|
185
|
+
>
|
|
186
|
+
⚙️
|
|
187
|
+
</button>
|
|
188
|
+
|
|
189
|
+
{/* Configuration/Execution Status Indicator */}
|
|
190
|
+
<div
|
|
191
|
+
style={{
|
|
192
|
+
position: 'absolute',
|
|
193
|
+
top: '-4px',
|
|
194
|
+
left: '-4px',
|
|
195
|
+
width: theme.nodeSize.statusIndicator,
|
|
196
|
+
height: theme.nodeSize.statusIndicator,
|
|
197
|
+
borderRadius: '50%',
|
|
198
|
+
backgroundColor: getStatusIndicatorColor(),
|
|
199
|
+
border: `2px solid ${theme.colors.background}`,
|
|
200
|
+
boxShadow: isExecuting
|
|
201
|
+
? `0 0 8px ${theme.dracula.cyan}99`
|
|
202
|
+
: `0 1px 3px ${theme.colors.shadow}`,
|
|
203
|
+
zIndex: 30,
|
|
204
|
+
animation: isExecuting ? 'pulse 1s ease-in-out infinite' : 'none',
|
|
205
|
+
}}
|
|
206
|
+
title={getStatusTitle()}
|
|
207
|
+
/>
|
|
208
|
+
|
|
209
|
+
{/* Diamond Output Handle */}
|
|
210
|
+
<Handle
|
|
211
|
+
id="output-model"
|
|
212
|
+
type="source"
|
|
213
|
+
position={Position.Top}
|
|
214
|
+
isConnectable={isConnectable}
|
|
215
|
+
style={{
|
|
216
|
+
position: 'absolute',
|
|
217
|
+
top: '-6px',
|
|
218
|
+
left: '50%',
|
|
219
|
+
transform: 'translateX(-50%) rotate(45deg)',
|
|
220
|
+
width: theme.nodeSize.statusIndicator,
|
|
221
|
+
height: theme.nodeSize.statusIndicator,
|
|
222
|
+
backgroundColor: isConfigured ? color : theme.colors.textMuted,
|
|
223
|
+
border: `2px solid ${theme.colors.background}`,
|
|
224
|
+
borderRadius: '0',
|
|
225
|
+
opacity: isConfigured ? 1 : 0.6,
|
|
226
|
+
zIndex: 20
|
|
227
|
+
}}
|
|
228
|
+
title={isConfigured ? 'Model Configuration Output - Connect to AI Agent' : 'Connect to AI Agent (configure API key and model before running)'}
|
|
229
|
+
/>
|
|
230
|
+
|
|
231
|
+
{/* Diamond Input Handle for Prompt */}
|
|
232
|
+
<Handle
|
|
233
|
+
id="input-prompt"
|
|
234
|
+
type="target"
|
|
235
|
+
position={Position.Bottom}
|
|
236
|
+
isConnectable={isConnectable}
|
|
237
|
+
style={{
|
|
238
|
+
position: 'absolute',
|
|
239
|
+
bottom: '-6px',
|
|
240
|
+
left: '50%',
|
|
241
|
+
transform: 'translateX(-50%) rotate(45deg)',
|
|
242
|
+
width: theme.nodeSize.statusIndicator,
|
|
243
|
+
height: theme.nodeSize.statusIndicator,
|
|
244
|
+
backgroundColor: theme.colors.background,
|
|
245
|
+
border: `2px solid ${theme.colors.textMuted}`,
|
|
246
|
+
borderRadius: '0',
|
|
247
|
+
zIndex: 20
|
|
248
|
+
}}
|
|
249
|
+
title="Prompt Input (optional)"
|
|
250
|
+
/>
|
|
251
|
+
</div>
|
|
252
|
+
|
|
253
|
+
{/* Model Name Below Circle */}
|
|
254
|
+
<div
|
|
255
|
+
style={{
|
|
256
|
+
marginTop: theme.spacing.sm,
|
|
257
|
+
fontSize: theme.fontSize.sm,
|
|
258
|
+
fontWeight: theme.fontWeight.medium,
|
|
259
|
+
color: theme.colors.text,
|
|
260
|
+
lineHeight: '1.2',
|
|
261
|
+
textAlign: 'center',
|
|
262
|
+
maxWidth: '120px'
|
|
263
|
+
}}
|
|
264
|
+
>
|
|
265
|
+
{data?.label || displayName}
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
);
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
export default BaseChatModelNode;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// AI Provider Icons - Using @lobehub/icons for official brand logos
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { OpenAI, Claude, Gemini, Groq, OpenRouter, Cerebras } from '@lobehub/icons';
|
|
4
|
+
|
|
5
|
+
// Icon size constant for consistency
|
|
6
|
+
const ICON_SIZE = 28;
|
|
7
|
+
|
|
8
|
+
// Export icon components with consistent sizing
|
|
9
|
+
// Each provider has different available variants - use Avatar for consistency
|
|
10
|
+
export const OpenAIIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
11
|
+
<OpenAI.Avatar size={size} />
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export const ClaudeIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
15
|
+
<Claude.Color size={size} />
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
export const GeminiIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
19
|
+
<Gemini.Color size={size} />
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
// Groq uses Avatar variant (no Color variant available)
|
|
23
|
+
export const GroqIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
24
|
+
<Groq.Avatar size={size} />
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
// OpenRouter uses Avatar variant (no Color variant available)
|
|
28
|
+
export const OpenRouterIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
29
|
+
<OpenRouter.Avatar size={size} />
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
// Cerebras uses Color variant
|
|
33
|
+
export const CerebrasIcon: React.FC<{ size?: number }> = ({ size = ICON_SIZE }) => (
|
|
34
|
+
<Cerebras.Color size={size} />
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Map provider IDs to their icon components
|
|
38
|
+
export const AI_PROVIDER_ICONS: Record<string, React.FC<{ size?: number }>> = {
|
|
39
|
+
openai: OpenAIIcon,
|
|
40
|
+
anthropic: ClaudeIcon,
|
|
41
|
+
gemini: GeminiIcon,
|
|
42
|
+
groq: GroqIcon,
|
|
43
|
+
openrouter: OpenRouterIcon,
|
|
44
|
+
cerebras: CerebrasIcon,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Get icon component by provider ID
|
|
48
|
+
export const getAIProviderIcon = (providerId: string): React.FC<{ size?: number }> | null => {
|
|
49
|
+
return AI_PROVIDER_ICONS[providerId] || null;
|
|
50
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import React, { useEffect, useRef } from 'react';
|
|
2
|
+
import { loadGoogleMaps } from '../../utils/googleMapsLoader';
|
|
3
|
+
import { useAppTheme } from '../../hooks/useAppTheme';
|
|
4
|
+
|
|
5
|
+
interface GoogleMapsPickerProps {
|
|
6
|
+
lat: number;
|
|
7
|
+
lng: number;
|
|
8
|
+
onLocationClick: (lat: number, lng: number) => void;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
zoom?: number;
|
|
11
|
+
mapTypeId?: string;
|
|
12
|
+
height?: string;
|
|
13
|
+
width?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const GoogleMapsPicker: React.FC<GoogleMapsPickerProps> = ({
|
|
17
|
+
lat,
|
|
18
|
+
lng,
|
|
19
|
+
onLocationClick,
|
|
20
|
+
apiKey,
|
|
21
|
+
zoom = 13,
|
|
22
|
+
mapTypeId = 'ROADMAP',
|
|
23
|
+
height = '100%',
|
|
24
|
+
width = '100%'
|
|
25
|
+
}) => {
|
|
26
|
+
const theme = useAppTheme();
|
|
27
|
+
const mapRef = useRef<HTMLDivElement>(null);
|
|
28
|
+
const mapInstanceRef = useRef<google.maps.Map | null>(null);
|
|
29
|
+
const markerRef = useRef<google.maps.Marker | null>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!mapRef.current || !apiKey) return;
|
|
33
|
+
|
|
34
|
+
// Load Google Maps API using centralized loader
|
|
35
|
+
const loadAndInitialize = async () => {
|
|
36
|
+
try {
|
|
37
|
+
await loadGoogleMaps({
|
|
38
|
+
apiKey,
|
|
39
|
+
libraries: ['geometry']
|
|
40
|
+
});
|
|
41
|
+
initializeMap();
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.error('Failed to load Google Maps API:', error);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
loadAndInitialize();
|
|
48
|
+
|
|
49
|
+
function initializeMap() {
|
|
50
|
+
if (!mapRef.current || !window.google?.maps) return;
|
|
51
|
+
|
|
52
|
+
const mapOptions: google.maps.MapOptions = {
|
|
53
|
+
center: { lat, lng },
|
|
54
|
+
zoom,
|
|
55
|
+
mapTypeId: window.google.maps.MapTypeId[mapTypeId as keyof typeof google.maps.MapTypeId] || google.maps.MapTypeId.ROADMAP,
|
|
56
|
+
clickableIcons: false,
|
|
57
|
+
disableDefaultUI: false,
|
|
58
|
+
zoomControl: true,
|
|
59
|
+
mapTypeControl: true,
|
|
60
|
+
streetViewControl: true,
|
|
61
|
+
fullscreenControl: true
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
mapInstanceRef.current = new google.maps.Map(mapRef.current, mapOptions);
|
|
65
|
+
|
|
66
|
+
// Create marker
|
|
67
|
+
markerRef.current = new google.maps.Marker({
|
|
68
|
+
position: { lat, lng },
|
|
69
|
+
map: mapInstanceRef.current,
|
|
70
|
+
draggable: true,
|
|
71
|
+
title: 'Selected Location - Click or drag to change'
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
// Add click listeners
|
|
75
|
+
mapInstanceRef.current.addListener('click', (e: google.maps.MapMouseEvent) => {
|
|
76
|
+
if (e.latLng) {
|
|
77
|
+
const newLat = e.latLng.lat();
|
|
78
|
+
const newLng = e.latLng.lng();
|
|
79
|
+
onLocationClick(newLat, newLng);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Add marker drag listener
|
|
84
|
+
markerRef.current.addListener('dragend', (e: google.maps.MapMouseEvent) => {
|
|
85
|
+
if (e.latLng) {
|
|
86
|
+
const newLat = e.latLng.lat();
|
|
87
|
+
const newLng = e.latLng.lng();
|
|
88
|
+
onLocationClick(newLat, newLng);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}, [apiKey, lat, lng, zoom, mapTypeId]);
|
|
93
|
+
|
|
94
|
+
// Update marker position when coordinates change
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (markerRef.current && mapInstanceRef.current) {
|
|
97
|
+
const newPosition = { lat, lng };
|
|
98
|
+
markerRef.current.setPosition(newPosition);
|
|
99
|
+
mapInstanceRef.current.setCenter(newPosition);
|
|
100
|
+
}
|
|
101
|
+
}, [lat, lng]);
|
|
102
|
+
|
|
103
|
+
if (!apiKey) {
|
|
104
|
+
return (
|
|
105
|
+
<div style={{
|
|
106
|
+
height,
|
|
107
|
+
width,
|
|
108
|
+
display: 'flex',
|
|
109
|
+
alignItems: 'center',
|
|
110
|
+
justifyContent: 'center',
|
|
111
|
+
backgroundColor: theme.colors.backgroundAlt,
|
|
112
|
+
color: theme.colors.textSecondary,
|
|
113
|
+
fontSize: theme.fontSize.sm,
|
|
114
|
+
textAlign: 'center',
|
|
115
|
+
padding: theme.spacing.lg,
|
|
116
|
+
border: `1px solid ${theme.colors.border}`,
|
|
117
|
+
borderRadius: theme.borderRadius.sm
|
|
118
|
+
}}>
|
|
119
|
+
Google Maps API key required for map display
|
|
120
|
+
</div>
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div
|
|
126
|
+
ref={mapRef}
|
|
127
|
+
style={{
|
|
128
|
+
height,
|
|
129
|
+
width,
|
|
130
|
+
border: `1px solid ${theme.colors.border}`,
|
|
131
|
+
borderRadius: theme.borderRadius.sm
|
|
132
|
+
}}
|
|
133
|
+
/>
|
|
134
|
+
);
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
export default GoogleMapsPicker;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import GoogleMapsPicker from './GoogleMapsPicker';
|
|
3
|
+
import { useAppTheme } from '../../hooks/useAppTheme';
|
|
4
|
+
|
|
5
|
+
interface MapsPreviewPanelProps {
|
|
6
|
+
lat: number;
|
|
7
|
+
lng: number;
|
|
8
|
+
zoom?: number;
|
|
9
|
+
mapTypeId?: string;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
onLocationClick: (lat: number, lng: number) => void;
|
|
12
|
+
title?: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const MapsPreviewPanel: React.FC<MapsPreviewPanelProps> = ({
|
|
17
|
+
lat,
|
|
18
|
+
lng,
|
|
19
|
+
zoom = 13,
|
|
20
|
+
mapTypeId = 'ROADMAP',
|
|
21
|
+
apiKey,
|
|
22
|
+
onLocationClick,
|
|
23
|
+
title = 'Maps Preview',
|
|
24
|
+
description = 'Interactive map based on current parameters'
|
|
25
|
+
}) => {
|
|
26
|
+
const theme = useAppTheme();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<div
|
|
30
|
+
style={{
|
|
31
|
+
width: '100%',
|
|
32
|
+
height: '100%',
|
|
33
|
+
display: 'flex',
|
|
34
|
+
flexDirection: 'column',
|
|
35
|
+
backgroundColor: theme.colors.backgroundPanel
|
|
36
|
+
}}>
|
|
37
|
+
{/* Maps Header */}
|
|
38
|
+
<div style={{
|
|
39
|
+
padding: theme.spacing.lg,
|
|
40
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
41
|
+
backgroundColor: theme.colors.backgroundAlt,
|
|
42
|
+
flexShrink: 0
|
|
43
|
+
}}>
|
|
44
|
+
<h3 style={{
|
|
45
|
+
margin: 0,
|
|
46
|
+
fontSize: theme.fontSize.lg,
|
|
47
|
+
fontWeight: theme.fontWeight.semibold,
|
|
48
|
+
color: theme.colors.text,
|
|
49
|
+
display: 'flex',
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
gap: theme.spacing.sm
|
|
52
|
+
}}>
|
|
53
|
+
{title}
|
|
54
|
+
</h3>
|
|
55
|
+
<p style={{
|
|
56
|
+
margin: `${theme.spacing.xs} 0 0 0`,
|
|
57
|
+
fontSize: theme.fontSize.sm,
|
|
58
|
+
color: theme.colors.textSecondary
|
|
59
|
+
}}>
|
|
60
|
+
{description}
|
|
61
|
+
</p>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
{/* Maps Content */}
|
|
65
|
+
<div style={{
|
|
66
|
+
flex: 1,
|
|
67
|
+
padding: theme.spacing.md,
|
|
68
|
+
display: 'flex',
|
|
69
|
+
flexDirection: 'column'
|
|
70
|
+
}}>
|
|
71
|
+
<GoogleMapsPicker
|
|
72
|
+
lat={lat}
|
|
73
|
+
lng={lng}
|
|
74
|
+
onLocationClick={onLocationClick}
|
|
75
|
+
apiKey={apiKey}
|
|
76
|
+
zoom={zoom}
|
|
77
|
+
mapTypeId={mapTypeId}
|
|
78
|
+
height="100%"
|
|
79
|
+
width="100%"
|
|
80
|
+
/>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Coordinates Display */}
|
|
84
|
+
<div style={{
|
|
85
|
+
padding: theme.spacing.md,
|
|
86
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
87
|
+
backgroundColor: theme.colors.backgroundAlt,
|
|
88
|
+
fontSize: theme.fontSize.xs,
|
|
89
|
+
color: theme.colors.textSecondary,
|
|
90
|
+
fontFamily: 'monospace',
|
|
91
|
+
flexShrink: 0
|
|
92
|
+
}}>
|
|
93
|
+
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
|
94
|
+
<span>Lat: {lat.toFixed(6)}</span>
|
|
95
|
+
<span>Lng: {lng.toFixed(6)}</span>
|
|
96
|
+
</div>
|
|
97
|
+
<div style={{
|
|
98
|
+
marginTop: theme.spacing.xs,
|
|
99
|
+
textAlign: 'center',
|
|
100
|
+
fontSize: theme.fontSize.xs,
|
|
101
|
+
opacity: 0.7
|
|
102
|
+
}}>
|
|
103
|
+
Click or drag marker to update coordinates
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
export default MapsPreviewPanel;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Maps Components
|
|
2
|
+
export { default as GoogleMapsPicker } from './GoogleMapsPicker';
|
|
3
|
+
export { default as MapsPreviewPanel } from './MapsPreviewPanel';
|
|
4
|
+
|
|
5
|
+
// Re-export types for convenience
|
|
6
|
+
export interface GoogleMapsPickerProps {
|
|
7
|
+
lat: number;
|
|
8
|
+
lng: number;
|
|
9
|
+
onLocationClick: (lat: number, lng: number) => void;
|
|
10
|
+
apiKey?: string;
|
|
11
|
+
zoom?: number;
|
|
12
|
+
mapTypeId?: string;
|
|
13
|
+
height?: string;
|
|
14
|
+
width?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface MapsPreviewPanelProps {
|
|
18
|
+
lat: number;
|
|
19
|
+
lng: number;
|
|
20
|
+
zoom?: number;
|
|
21
|
+
mapTypeId?: string;
|
|
22
|
+
apiKey?: string;
|
|
23
|
+
onLocationClick: (lat: number, lng: number) => void;
|
|
24
|
+
title?: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
}
|