Skip to content

Commit 820c92a

Browse files
committed
release: v0.1.0
1 parent 3bb9328 commit 820c92a

9 files changed

Lines changed: 73 additions & 36 deletions

File tree

package-lock.json

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

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "openflowkit",
33
"private": true,
4-
"version": "0.0.0",
4+
"version": "0.1.0",
55
"type": "module",
66
"homepage": "https://openflowkit.com",
77
"engines": {
@@ -74,4 +74,4 @@
7474
"vite-plugin-dts": "^3.9.1",
7575
"vitest": "^4.0.18"
7676
}
77-
}
77+
}

src/components/DesignSystem.integration.test.tsx

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { act, render, screen } from '@testing-library/react';
22
import type { CSSProperties } from 'react';
33
import { beforeEach, describe, expect, it, vi } from 'vitest';
4+
import { Position } from 'reactflow';
45
import type { DesignSystem } from '@/lib/types';
56
import { DEFAULT_DESIGN_SYSTEM, useFlowStore } from '@/store';
67
import CustomNode from './CustomNode';
@@ -77,16 +78,12 @@ describe('Design System integration', () => {
7778
const altSystem = createSystem({
7879
id: 'alt',
7980
name: 'Alt',
80-
colors: {
81-
nodeBackground: '#101820',
82-
nodeBorder: '#00d1ff',
83-
nodeText: '#f6f7f9',
84-
edge: '#ff0055',
85-
},
86-
components: {
87-
edge: { strokeWidth: 6 },
88-
},
8981
});
82+
altSystem.colors.nodeBackground = '#101820';
83+
altSystem.colors.nodeBorder = '#00d1ff';
84+
altSystem.colors.nodeText = '#f6f7f9';
85+
altSystem.colors.edge = '#ff0055';
86+
altSystem.components.edge.strokeWidth = 6;
9087

9188
useFlowStore.setState({
9289
designSystems: [defaultSystem, altSystem],
@@ -103,30 +100,24 @@ describe('Design System integration', () => {
103100
dragging={false}
104101
zIndex={1}
105102
data={{ label: 'Node A' }}
106-
positionAbsoluteX={0}
107-
positionAbsoluteY={0}
108103
isConnectable={true}
109104
xPos={0}
110105
yPos={0}
111-
sourcePosition="right"
112-
targetPosition="left"
106+
sourcePosition={Position.Right}
107+
targetPosition={Position.Left}
113108
/>
114109
);
115110

116111
const nodeContainer = screen.getByTestId('custom-node-container');
117-
expect(nodeContainer).toHaveStyle({
118-
backgroundColor: '#ffffff',
119-
borderColor: '#e2e8f0',
120-
});
112+
expect(nodeContainer.style.backgroundColor).toBe('rgb(255, 255, 255)');
113+
expect(nodeContainer.style.borderColor).toBe('rgb(226, 232, 240)');
121114

122115
act(() => {
123116
useFlowStore.getState().setActiveDesignSystem('alt');
124117
});
125118

126-
expect(nodeContainer).toHaveStyle({
127-
backgroundColor: '#101820',
128-
borderColor: '#00d1ff',
129-
});
119+
expect(nodeContainer.style.backgroundColor).toBe('rgb(16, 24, 32)');
120+
expect(nodeContainer.style.borderColor).toBe('rgb(0, 209, 255)');
130121
});
131122

132123
it('updates edge visual tokens when active design system changes', () => {
@@ -139,8 +130,8 @@ describe('Design System integration', () => {
139130
sourceY={0}
140131
targetX={100}
141132
targetY={100}
142-
sourcePosition="right"
143-
targetPosition="left"
133+
sourcePosition={Position.Right}
134+
targetPosition={Position.Left}
144135
selected={false}
145136
style={{}}
146137
/>
@@ -163,8 +154,8 @@ describe('Design System integration', () => {
163154
sourceY={0}
164155
targetX={100}
165156
targetY={100}
166-
sourcePosition="right"
167-
targetPosition="left"
157+
sourcePosition={Position.Right}
158+
targetPosition={Position.Left}
168159
selected={false}
169160
style={{}}
170161
/>

src/components/HomePage.integration.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ describe('HomePage integration flows', () => {
6969
renderHomePage();
7070

7171
fireEvent.click(screen.getByText('Settings'));
72-
expect(screen.getByRole('heading', { name: 'Settings' })).toBeInTheDocument();
73-
expect(screen.getByText('Flowpilot AI')).toBeInTheDocument();
72+
expect(screen.getByRole('heading', { name: 'Settings' })).toBeTruthy();
73+
expect(screen.getByText('Flowpilot AI')).toBeTruthy();
7474
});
7575

7676
it('restores a snapshot and launches editor when a snapshot card is clicked', () => {

src/components/SettingsModal/AISettings.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,17 @@ const PROVIDERS: ProviderMeta[] = [
9797
consoleName: 'Mistral Console (La Plateforme)',
9898
defaultModel: 'mistral-medium-latest',
9999
},
100+
{
101+
id: 'openrouter',
102+
name: 'OpenRouter',
103+
icon: '↔',
104+
color: '#111827',
105+
logoPath: '/logos/custom.svg',
106+
keyPlaceholder: 'sk-or-v1-...',
107+
keyLink: 'https://openrouter.ai/settings/keys',
108+
consoleName: 'OpenRouter Dashboard',
109+
defaultModel: 'google/gemini-2.5-flash',
110+
},
100111
{
101112
id: 'custom',
102113
name: 'Custom',
@@ -157,6 +168,11 @@ const PROVIDER_MODELS: Record<AIProvider, { id: string; translateKey: string }[]
157168
{ id: 'codestral-latest', translateKey: 'codestral-latest' },
158169
{ id: 'pixtral-large-latest', translateKey: 'pixtral-large-latest' },
159170
],
171+
openrouter: [
172+
{ id: 'google/gemini-2.5-flash', translateKey: 'google/gemini-2.5-flash' },
173+
{ id: 'openai/gpt-5-mini', translateKey: 'openai/gpt-5-mini' },
174+
{ id: 'anthropic/claude-sonnet-4', translateKey: 'anthropic/claude-sonnet-4' },
175+
],
160176
custom: [
161177
{ id: 'custom', translateKey: 'custom' },
162178
],

src/components/ui/SidebarItem.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ interface SidebarItemProps {
99
isActive?: boolean;
1010
className?: string;
1111
end?: boolean;
12+
testId?: string;
1213
}
1314

1415
/**
@@ -22,7 +23,8 @@ export const SidebarItem: React.FC<SidebarItemProps> = ({
2223
onClick,
2324
isActive: manualIsActive,
2425
className = '',
25-
end = false
26+
end = false,
27+
testId
2628
}) => {
2729
const baseStyles = "flex items-center gap-3 px-3 py-2.5 rounded-md text-sm transition-colors w-full text-left group";
2830
const activeStyles = "bg-[var(--brand-primary)]/10 text-[var(--brand-primary)] font-medium";
@@ -44,6 +46,7 @@ export const SidebarItem: React.FC<SidebarItemProps> = ({
4446
target={to.startsWith('http') ? "_blank" : undefined}
4547
rel={to.startsWith('http') ? "noopener noreferrer" : undefined}
4648
onClick={onClick}
49+
data-testid={testId}
4750
className={`
4851
${baseStyles}
4952
${manualIsActive ? activeStyles : inactiveStyles}
@@ -65,6 +68,7 @@ export const SidebarItem: React.FC<SidebarItemProps> = ({
6568
${className}
6669
`}
6770
onClick={onClick}
71+
data-testid={testId}
6872
>
6973
{content}
7074
</NavLink>
@@ -74,6 +78,7 @@ export const SidebarItem: React.FC<SidebarItemProps> = ({
7478
return (
7579
<button
7680
onClick={onClick}
81+
data-testid={testId}
7782
className={`
7883
${baseStyles}
7984
${manualIsActive ? activeStyles : inactiveStyles}

src/hooks/useAutoSave.test.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ function createTab(id: string, name: string, nodes: FlowNode[], edges: FlowEdge[
2929
};
3030
}
3131

32+
function noop(): void {
33+
// noop for legacy useAutoSave setup callbacks
34+
}
35+
3236
describe('useAutoSave', () => {
3337
beforeEach(() => {
3438
localStorage.clear();
@@ -45,7 +49,12 @@ describe('useAutoSave', () => {
4549
'tab-missing',
4650
[createNode('n1', 'Node 1')],
4751
[createEdge('e1', 'n1', 'n1')],
48-
setTabs
52+
setTabs,
53+
noop,
54+
noop,
55+
noop,
56+
noop,
57+
noop
4958
)
5059
);
5160

@@ -70,7 +79,12 @@ describe('useAutoSave', () => {
7079
'tab-1',
7180
newNodes,
7281
newEdges,
73-
setTabs
82+
setTabs,
83+
noop,
84+
noop,
85+
noop,
86+
noop,
87+
noop
7488
)
7589
);
7690

src/services/aiService.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
import { getSystemInstruction, ChatMessage, generateDiagramFromChat as generateDiagramFromChatGemini, chatWithDocsGemini } from './geminiService';
22

3-
export type AIProvider = 'gemini' | 'openai' | 'claude' | 'groq' | 'nvidia' | 'cerebras' | 'mistral' | 'custom';
3+
export type AIProvider = 'gemini' | 'openai' | 'claude' | 'groq' | 'nvidia' | 'cerebras' | 'mistral' | 'openrouter' | 'custom';
44

55
const PROVIDER_BASE_URLS: Record<string, string> = {
66
openai: 'https://api.openai.com/v1',
77
groq: 'https://api.groq.com/openai/v1',
88
nvidia: 'https://integrate.api.nvidia.com/v1',
99
cerebras: 'https://api.cerebras.ai/v1',
1010
mistral: 'https://api.mistral.ai/v1',
11+
openrouter: 'https://openrouter.ai/api/v1',
1112
};
1213

1314
const DEFAULT_MODELS: Record<string, string> = {
@@ -18,6 +19,7 @@ const DEFAULT_MODELS: Record<string, string> = {
1819
nvidia: 'meta/llama-4-scout-17b-16e-instruct',
1920
cerebras: 'gpt-oss-120b',
2021
mistral: 'mistral-medium-latest',
22+
openrouter: 'google/gemini-2.5-flash',
2123
custom: 'gpt-4o',
2224
};
2325

@@ -31,6 +33,7 @@ function getEnvApiKey(provider: AIProvider): string | undefined {
3133
case 'nvidia': return import.meta.env.VITE_NVIDIA_API_KEY;
3234
case 'cerebras': return import.meta.env.VITE_CEREBRAS_API_KEY;
3335
case 'mistral': return import.meta.env.VITE_MISTRAL_API_KEY;
36+
case 'openrouter': return import.meta.env.VITE_OPENROUTER_API_KEY;
3437
case 'custom': return import.meta.env.VITE_CUSTOM_AI_API_KEY;
3538
default: return undefined;
3639
}

src/store.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,20 +70,28 @@ interface ViewSettings {
7070
}
7171

7272

73-
export type AIProvider = 'gemini' | 'openai' | 'claude' | 'groq' | 'nvidia' | 'cerebras' | 'mistral' | 'custom';
73+
export type AIProvider = 'gemini' | 'openai' | 'claude' | 'groq' | 'nvidia' | 'cerebras' | 'mistral' | 'openrouter' | 'custom';
74+
75+
export interface CustomHeaderConfig {
76+
key: string;
77+
value: string;
78+
enabled?: boolean;
79+
}
7480

7581
export interface AISettings {
7682
provider: AIProvider;
7783
apiKey?: string;
7884
model?: string;
7985
customBaseUrl?: string;
86+
customHeaders?: CustomHeaderConfig[];
8087
}
8188

8289
export const DEFAULT_AI_SETTINGS: AISettings = {
8390
provider: 'gemini',
8491
apiKey: undefined,
8592
model: undefined,
8693
customBaseUrl: undefined,
94+
customHeaders: [],
8795
};
8896

8997
export interface BrandConfig {

0 commit comments

Comments
 (0)