Skip to content

Commit 4e77f42

Browse files
added new components, bug fixes, docs updates
1 parent 0743033 commit 4e77f42

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+1472
-121
lines changed

README.md

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,47 @@
4646
- **Conversation Memory** - Maintain context across workflow executions
4747

4848
### 🔗 **Rich Integrations**
49-
- See the [Nodes Reference](https://code-forge-temple.github.io/agentic-signal/docs/nodes/overview) for all supported integrations and node types.
50-
- **More integrations coming soon** - Discord, Slack, Notion, Airtable, and many more!
49+
50+
#### Node Types
51+
52+
- [Data Source](https://agentic-signal.com/docs/nodes/input/data-source)
53+
- [AI Data Processing](https://agentic-signal.com/docs/nodes/ai/llm-process)
54+
- [AI Tool](https://agentic-signal.com/docs/nodes/ai/ai-tool)
55+
- [HTTP Data](https://agentic-signal.com/docs/nodes/input/http-data)
56+
- [JSON Reformatter](https://agentic-signal.com/docs/nodes/data/json-reformatter)
57+
- [Stock Analysis](https://agentic-signal.com/docs/nodes/data/stock-analysis)
58+
- [Async Data Aggregator](https://agentic-signal.com/docs/nodes/data/async-data-aggregator)
59+
- [Data Validation](https://agentic-signal.com/docs/nodes/data/data-validation)
60+
- [Chart](https://agentic-signal.com/docs/nodes/output/chart)
61+
- [Data Flow Spy](https://agentic-signal.com/docs/nodes/output/data-flow-spy)
62+
- [Timer](https://agentic-signal.com/docs/nodes/input/timer)
63+
- [Reddit Post](https://agentic-signal.com/docs/nodes/output/reddit-post) *(PRO)*
64+
- [Slack Input](https://agentic-signal.com/docs/nodes/input/slack-input) *(PRO)*
65+
- [Slack Output](https://agentic-signal.com/docs/nodes/output/slack-output) *(PRO)*
66+
67+
> See the full [Nodes Reference](https://agentic-signal.com/docs/nodes/overview) for details on all node types.
68+
69+
#### Workflows
70+
71+
Explore ready-to-use workflow templates in the [Workflow Examples](https://agentic-signal.com/docs/workflows/overview).
72+
73+
#### AI & Tool Integrations
74+
75+
- **Ollama LLMs**: Use local language models for text analysis and generation.
76+
- **Google Services**: Gmail, Google Drive, Google Calendar.
77+
- **Weather APIs**: Real-time weather data.
78+
- **Search Engines**: DuckDuckGo, Brave Search.
79+
- **Financial Analysis**: Stock market data analysis with technical indicators.
80+
- **Date/Time Tools**: Get current date and time.
81+
- **Slack**: Send and receive messages via Slack slash commands using Socket Mode. *(PRO)*
82+
- **Reddit**: Automatically post text or link content to subreddits via OAuth2. *(PRO)*
83+
- **Custom APIs**: Integrate any REST API via HTTP Data node.
84+
- **More integrations coming soon** - Discord, Notion, Airtable, and many more!
5185

5286
## 🚀 Quick Start
5387

54-
See the [Quick Start](https://code-forge-temple.github.io/agentic-signal/docs/getting-started/windows-app/quick-start) for setup and configuration instructions.
88+
- Windows/Linux/macOS App: [quick start](https://agentic-signal.com/docs/getting-started/windows-app/quick-start) for setup and configuration instructions, or
89+
- Web App: [installation](https://agentic-signal.com/docs/getting-started/web-app/installation) & [quick start](https://agentic-signal.com/docs/getting-started/web-app/quick-start) (includes Docker option)
5590

5691
## 🤝 Contributing
5792

client/bun.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
"react-syntax-highlighter": "^15.6.1",
3838
"remark-gfm": "^4.0.0",
3939
"uuid": "^11.1.0",
40-
"zod": "^3.25.64"
40+
"zod": "^3.25.64",
41+
"zod-to-json-schema": "^3.25.2"
4142
},
4243
"devDependencies": {
4344
"@eslint/js": "^9.25.0",

client/src/components/App/App.tsx

Lines changed: 79 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import '@xyflow/react/dist/style.css';
99
import './App.scss';
1010
import {useWorkflow} from '../../hooks/useWorkflow';
1111
import {nodeFactory, nodeTypes} from '../nodes';
12-
import {useCallback} from 'react';
12+
import {useCallback, useState} from 'react';
1313
import {Dock} from '../Dock';
1414
import {v4 as uuidv4} from 'uuid';
1515
import {useSnackbar} from 'notistack'
@@ -20,6 +20,7 @@ import {NODE_TYPE as TOOL_NODE_TYPE} from '../nodes/ToolNode/constants';
2020
import {useFullscreen} from '../../hooks/useFullscreen';
2121
import {getDefaultUserConfigValues} from '../../types/ollama.types';
2222
import {Chip} from '@mui/material';
23+
import {ConfirmDialog} from '../ConfirmDialog';
2324

2425

2526
const getId = () => uuidv4();
@@ -44,6 +45,32 @@ function deleteByPath (obj: Record<string, any>, path: string): void {
4445
}
4546
}
4647

48+
function remapNodeAndEdgeIds (nodes: any[], edges: any[]) {
49+
const idMap = new Map<string, string>(
50+
nodes.map((node: any) => [node.id, getId()])
51+
);
52+
53+
const remappedNodes = nodes.map((node: any) => ({
54+
...node,
55+
id: idMap.get(node.id)!
56+
}));
57+
58+
const remappedEdges = edges.map((edge: any) => {
59+
const newSource = idMap.get(edge.source) ?? edge.source;
60+
const newTarget = idMap.get(edge.target) ?? edge.target;
61+
const newId = `xy-edge__${newSource}${edge.sourceHandle ?? ''}-${newTarget}${edge.targetHandle ?? ''}`;
62+
63+
return {
64+
...edge,
65+
source: newSource,
66+
target: newTarget,
67+
id: newId
68+
};
69+
});
70+
71+
return {remappedNodes, remappedEdges};
72+
}
73+
4774
const descriptorMap = Object.fromEntries(
4875
nodeRegistry.map(desc => [desc.type, desc])
4976
);
@@ -62,10 +89,17 @@ function AppFlow () {
6289
setEdges,
6390
} = useWorkflow();
6491
const {enqueueSnackbar} = useSnackbar();
92+
const [pendingWorkflow, setPendingWorkflow] = useState<{nodes: any[], edges: any[]} | null>(null);
6593

6694
useFullscreen();
6795

6896
const handleSave = () => {
97+
if (nodes.length === 0 && edges.length === 0) {
98+
enqueueSnackbar('Nothing to save.', {variant: 'info'});
99+
100+
return;
101+
}
102+
69103
const sanitizedNodes = nodes.map(node => {
70104
const nodeData = JSON.parse(JSON.stringify(node.data));
71105
const toSanitize = Array.isArray(nodeData.toSanitize) ? nodeData.toSanitize : [];
@@ -173,8 +207,14 @@ function AppFlow () {
173207
return updatedNode;
174208
});
175209

176-
setNodes(hydratedNodes);
177-
setEdges(data.edges || []);
210+
const {remappedNodes, remappedEdges} = remapNodeAndEdgeIds(hydratedNodes, data.edges || []);
211+
212+
if (nodes.length > 0) {
213+
setPendingWorkflow({nodes: remappedNodes, edges: remappedEdges});
214+
} else {
215+
setNodes(remappedNodes);
216+
setEdges(remappedEdges);
217+
}
178218
} catch (error) {
179219
enqueueSnackbar('Failed to load workflow: ' + (error instanceof Error ? error.message : String(error)), {variant: 'error'});
180220
} finally {
@@ -184,6 +224,32 @@ function AppFlow () {
184224
reader.readAsText(file);
185225
};
186226

227+
const handleMergeWorkflow = () => {
228+
if (!pendingWorkflow) return;
229+
230+
const maxY = Math.max(...nodes.map(n => n.position.y + (n.measured?.height ?? 40)));
231+
const minX = Math.min(...nodes.map(n => n.position.x));
232+
const yOffset = maxY + 100;
233+
const pendingMinY = Math.min(...pendingWorkflow.nodes.map((n: any) => n.position.y));
234+
const pendingMinX = Math.min(...pendingWorkflow.nodes.map((n: any) => n.position.x));
235+
const shiftedNodes = pendingWorkflow.nodes.map((node: any) => ({
236+
...node,
237+
position: {
238+
x: node.position.x - pendingMinX + minX,
239+
y: node.position.y + yOffset - pendingMinY}
240+
}));
241+
242+
setNodes([...nodes, ...shiftedNodes]);
243+
setEdges([...edges, ...pendingWorkflow.edges]);
244+
};
245+
246+
const handleReplaceWorkflow = () => {
247+
if (!pendingWorkflow) return;
248+
249+
setNodes(pendingWorkflow.nodes);
250+
setEdges(pendingWorkflow.edges);
251+
};
252+
187253
const onDragOver = useCallback((event: React.DragEvent) => {
188254
event.preventDefault();
189255
event.dataTransfer.dropEffect = 'move';
@@ -213,6 +279,16 @@ function AppFlow () {
213279
return (
214280
<>
215281
<Dock onSave={handleSave} onLoad={handleLoad} onClear={handleClear} />
282+
<ConfirmDialog
283+
open={pendingWorkflow !== null}
284+
onClose={() => setPendingWorkflow(null)}
285+
title="Load Workflow"
286+
message="A workflow is already loaded. Would you like to add to the existing workflow or replace it?"
287+
confirmLabel="Add to Existing"
288+
cancelLabel="Replace"
289+
onConfirm={handleMergeWorkflow}
290+
onCancel={handleReplaceWorkflow}
291+
/>
216292
<ReactFlow
217293
nodes={nodes}
218294
edges={edges}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/************************************************************************
2+
* Copyright (C) 2025 Code Forge Temple *
3+
* This file is part of agentic-signal project *
4+
* See the LICENSE file in the project root for license details. *
5+
************************************************************************/
6+
7+
import {Button, Typography} from "@mui/material";
8+
import {BaseDialog} from "../BaseDialog";
9+
10+
export interface ConfirmDialogProps {
11+
open: boolean;
12+
onClose: () => void;
13+
title: string;
14+
message: string;
15+
confirmLabel?: string;
16+
cancelLabel?: string;
17+
onConfirm: () => void;
18+
onCancel?: () => void;
19+
}
20+
21+
export function ConfirmDialog ({
22+
open,
23+
onClose,
24+
title,
25+
message,
26+
confirmLabel = "Confirm",
27+
cancelLabel = "Cancel",
28+
onConfirm,
29+
onCancel,
30+
}: ConfirmDialogProps) {
31+
const handleCancel = () => {
32+
onCancel?.();
33+
onClose();
34+
};
35+
36+
const handleConfirm = () => {
37+
onConfirm();
38+
onClose();
39+
};
40+
41+
return (
42+
<BaseDialog
43+
open={open}
44+
onClose={onClose}
45+
title={title}
46+
maxWidth="sm"
47+
fullWidth={false}
48+
actions={
49+
<>
50+
<Button onClick={handleCancel}>{cancelLabel}</Button>
51+
<Button variant="contained" onClick={handleConfirm}>{confirmLabel}</Button>
52+
</>
53+
}
54+
>
55+
<Typography>{message}</Typography>
56+
</BaseDialog>
57+
);
58+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./ConfirmDialog";

client/src/components/FieldsetGroup/FieldsetGroup.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import {FormControl, FormLabel} from "@mui/material";
1111
type FieldsetGroupProps = {
1212
children: ReactNode;
1313
title: string;
14+
height?: string;
1415
};
1516

16-
export const FieldsetGroup = ({children, title}: FieldsetGroupProps) => {
17+
export const FieldsetGroup = ({children, title, height}: FieldsetGroupProps) => {
1718
return (
1819
<FormControl component="fieldset"
1920
sx={{
@@ -22,8 +23,9 @@ export const FieldsetGroup = ({children, title}: FieldsetGroupProps) => {
2223
border: '1px solid',
2324
borderColor: 'divider',
2425
borderRadius: 2,
25-
pt: 2, pb: 0, pl: 2, pr: 2,
26+
pt: 2, pb: 2, pl: 2, pr: 2,
2627
mb: 2,
28+
height: height || 'auto',
2729
}}
2830
>
2931
<FormLabel

client/src/components/MarkdownRenderer/MarkdownRenderer.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
display: flex;
1717
flex-direction: column;
1818

19+
img {
20+
width: 100%;
21+
}
22+
1923
table {
2024
border-collapse: collapse;
2125
width: 100%;

client/src/components/MarkdownRenderer/utils.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -29,32 +29,4 @@ export const extractFromMarkdown = (markdown: string, type: EXTRACTION_TYPE): st
2929
}
3030

3131
return results;
32-
}
33-
34-
const extensionLangMap: Record<string, string> = {
35-
js: 'javascript',
36-
ts: 'typescript',
37-
tsx: 'tsx',
38-
json: 'json',
39-
html: 'html',
40-
css: 'css',
41-
scss: 'scss',
42-
md: 'markdown',
43-
xml: 'xml',
44-
csv: 'csv',
45-
yaml: 'yaml',
46-
yml: 'yaml',
47-
ini: 'ini',
48-
sh: 'bash',
49-
sql: 'sql',
50-
py: 'python',
51-
java: 'java',
52-
c: 'c',
53-
cpp: 'cpp',
54-
h: 'c',
55-
bat: 'bat'
56-
};
57-
58-
export const fileExtensionToCodeBlockLang = (extension: string | undefined): string => {
59-
return extensionLangMap[extension?.toLowerCase() || ''] ?? '';
60-
};
32+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
RedditPostNode
2+
SlackInputNode
3+
SlackOutputNode

0 commit comments

Comments
 (0)