Skip to content

Commit 88b249e

Browse files
authored
Merge branch 'main' into feat/add-deployment-decorator-standard
2 parents 88a82cc + 9062306 commit 88b249e

File tree

8 files changed

+144
-40
lines changed

8 files changed

+144
-40
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { describe, it, expect, vi, beforeEach } from 'vitest';
2+
import { render, screen, fireEvent } from '@testing-library/react';
3+
import { LogoutButton } from './LogoutButton.js';
4+
import { authService } from '../../authService.js';
5+
6+
vi.mock('../../authService.js', () => ({
7+
authService: {
8+
logout: vi.fn(),
9+
},
10+
}));
11+
12+
describe('LogoutButton', () => {
13+
beforeEach(() => {
14+
vi.clearAllMocks();
15+
});
16+
17+
it('renders a logout button', () => {
18+
render(<LogoutButton />);
19+
const button = screen.getByRole('button', { name: /logout/i });
20+
expect(button).toBeInTheDocument();
21+
});
22+
23+
it('has correct styling', () => {
24+
render(<LogoutButton />);
25+
const button = screen.getByRole('button', { name: /logout/i });
26+
expect(button).toHaveStyle({
27+
position: 'absolute',
28+
top: '10px',
29+
right: '10px',
30+
});
31+
});
32+
33+
it('calls authService.logout when clicked', async () => {
34+
render(<LogoutButton />);
35+
const button = screen.getByRole('button', { name: /logout/i });
36+
37+
fireEvent.click(button);
38+
39+
await new Promise(resolve => setTimeout(resolve, 0));
40+
41+
expect(authService.logout).toHaveBeenCalled();
42+
});
43+
44+
it('button text is "Logout"', () => {
45+
render(<LogoutButton />);
46+
const button = screen.getByRole('button');
47+
expect(button.textContent).toBe('Logout');
48+
});
49+
});
50+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import React from 'react';
2+
import { authService } from '../../authService.js';
3+
4+
export const LogoutButton: React.FC = () => {
5+
const handleLogout = async () => {
6+
await authService.logout();
7+
};
8+
9+
return (
10+
<button onClick={handleLogout} style={{ position: 'absolute', top: 10, right: 10 }}>
11+
Logout
12+
</button>
13+
);
14+
};

calm-hub-ui/src/index.tsx

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,12 @@ import './index.css';
22
import React from 'react';
33
import ReactDOM from 'react-dom/client';
44
import ProtectedRoute from './ProtectedRoute.js';
5-
import { isAuthServiceEnabled, authService } from './authService.js';
5+
import { isAuthServiceEnabled } from './authService.js';
66
import App from './App.js';
7+
import { LogoutButton } from './components/logout-button/LogoutButton.js';
78

89
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
910

10-
const LogoutButton: React.FC = () => {
11-
const handleLogout = async () => {
12-
await authService.logout();
13-
};
14-
15-
return (
16-
<button onClick={handleLogout} style={{ position: 'absolute', top: 10, right: 10 }}>
17-
Logout
18-
</button>
19-
);
20-
};
21-
2211
const isAuthenticationEnabled = isAuthServiceEnabled();
2312

2413
root.render(

calm-hub-ui/src/visualizer/components/reactflow/edge-components/EdgeBadge.test.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { describe, it, expect, vi } from 'vitest';
22
import { render, fireEvent } from '@testing-library/react';
3-
import { EdgeBadge, getBadgeStyle } from './EdgeBadge';
4-
import { THEME } from '../theme';
3+
import { EdgeBadge } from './EdgeBadge.js';
4+
import { getBadgeStyle } from '../utils/edgeBadge.utils.js';
5+
import { THEME } from '../theme.js';
56

67
describe('EdgeBadge', () => {
78
const mockOnMouseEnter = vi.fn();

calm-hub-ui/src/visualizer/components/reactflow/edge-components/EdgeBadge.tsx

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Info, Shield, ArrowRight } from 'lucide-react';
2-
import { THEME } from '../theme.js';
3-
import type { EdgeBadgeStyle, EdgeBadgeProps } from '../../../contracts/contracts.js';
2+
import type { EdgeBadgeProps } from '../../../contracts/contracts.js';
43

54
export function EdgeBadge({
65
hasFlowInfo,
@@ -36,25 +35,3 @@ export function EdgeBadge({
3635
</div>
3736
);
3837
}
39-
40-
export function getBadgeStyle(hasFlowInfo: boolean, hasAIGF: boolean): EdgeBadgeStyle {
41-
if (hasFlowInfo) {
42-
return {
43-
background: `${THEME.colors.accent}20`,
44-
border: THEME.colors.accent,
45-
iconColor: THEME.colors.accent,
46-
};
47-
}
48-
if (hasAIGF) {
49-
return {
50-
background: `${THEME.colors.success}20`,
51-
border: THEME.colors.success,
52-
iconColor: THEME.colors.success,
53-
};
54-
}
55-
return {
56-
background: `${THEME.colors.muted}20`,
57-
border: THEME.colors.muted,
58-
iconColor: THEME.colors.muted,
59-
};
60-
}

calm-hub-ui/src/visualizer/components/reactflow/edge-components/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
export { EdgeBadge, getBadgeStyle } from './EdgeBadge.js';
1+
export { EdgeBadge } from './EdgeBadge.js';
2+
export { getBadgeStyle } from '../utils/edgeBadge.utils.js';
23
export { EdgeTooltip } from './EdgeTooltip.js';
34
export type {
45
EdgeBadgeProps,
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import { describe, it, expect } from 'vitest';
2+
import { getBadgeStyle } from './edgeBadge.utils.js';
3+
import { THEME } from '../theme.js';
4+
5+
describe('edgeBadge.utils', () => {
6+
describe('getBadgeStyle', () => {
7+
it('returns accent colors when hasFlowInfo is true', () => {
8+
const result = getBadgeStyle(true, false);
9+
expect(result).toEqual({
10+
background: `${THEME.colors.accent}20`,
11+
border: THEME.colors.accent,
12+
iconColor: THEME.colors.accent,
13+
});
14+
});
15+
16+
it('returns success colors when hasAIGF is true', () => {
17+
const result = getBadgeStyle(false, true);
18+
expect(result).toEqual({
19+
background: `${THEME.colors.success}20`,
20+
border: THEME.colors.success,
21+
iconColor: THEME.colors.success,
22+
});
23+
});
24+
25+
it('returns muted colors when both flags are false', () => {
26+
const result = getBadgeStyle(false, false);
27+
expect(result).toEqual({
28+
background: `${THEME.colors.muted}20`,
29+
border: THEME.colors.muted,
30+
iconColor: THEME.colors.muted,
31+
});
32+
});
33+
34+
it('prioritizes hasFlowInfo over hasAIGF when both are true', () => {
35+
const result = getBadgeStyle(true, true);
36+
expect(result).toEqual({
37+
background: `${THEME.colors.accent}20`,
38+
border: THEME.colors.accent,
39+
iconColor: THEME.colors.accent,
40+
});
41+
});
42+
43+
it('has the correct alpha value for background colors', () => {
44+
const result = getBadgeStyle(true, false);
45+
expect(result.background).toMatch(/^#[0-9a-f]+20$/i);
46+
});
47+
});
48+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { THEME } from '../theme.js';
2+
import type { EdgeBadgeStyle } from '../../../contracts/contracts.js';
3+
4+
export function getBadgeStyle(hasFlowInfo: boolean, hasAIGF: boolean): EdgeBadgeStyle {
5+
if (hasFlowInfo) {
6+
return {
7+
background: `${THEME.colors.accent}20`,
8+
border: THEME.colors.accent,
9+
iconColor: THEME.colors.accent,
10+
};
11+
}
12+
if (hasAIGF) {
13+
return {
14+
background: `${THEME.colors.success}20`,
15+
border: THEME.colors.success,
16+
iconColor: THEME.colors.success,
17+
};
18+
}
19+
return {
20+
background: `${THEME.colors.muted}20`,
21+
border: THEME.colors.muted,
22+
iconColor: THEME.colors.muted,
23+
};
24+
}

0 commit comments

Comments
 (0)