Skip to content

Commit 5835b02

Browse files
feat: changing logic for connect button to MCP (#155)
1 parent 5f60adb commit 5835b02

File tree

4 files changed

+146
-2
lines changed

4 files changed

+146
-2
lines changed

src/components/ControlPlanes/ControlPlaneCard/ControlPlaneCard.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727

2828
import { YamlViewButtonWithLoader } from '../../Yaml/YamlViewButtonWithLoader.tsx';
2929
import { useToast } from '../../../context/ToastContext.tsx';
30+
import { canConnectToMCP } from '../controlPlanes.ts';
3031

3132
interface Props {
3233
controlPlane: ListControlPlanesType;
@@ -59,6 +60,8 @@ export function ControlPlaneCard({
5960
const name = controlPlane.metadata.name;
6061
const namespace = controlPlane.metadata.namespace;
6162

63+
const isConnectButtonEnabled = canConnectToMCP(controlPlane);
64+
6265
return (
6366
<>
6467
<Card key={`${name}--${namespace}`} className={styles.card}>
@@ -106,7 +109,7 @@ export function ControlPlaneCard({
106109
resourceType={'managedcontrolplanes'}
107110
/>
108111
<ConnectButton
109-
disabled={controlPlane.status?.status !== ReadyStatus.Ready}
112+
disabled={!isConnectButtonEnabled}
110113
controlPlaneName={name}
111114
projectName={projectName}
112115
workspaceName={workspace.metadata.name ?? ''}
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import { describe, it, expect } from 'vitest';
2+
3+
import {
4+
ControlPlaneType,
5+
ControlPlaneStatusCondition,
6+
ReadyStatus,
7+
} from '../../lib/api/types/crate/controlPlanes';
8+
import { canConnectToMCP } from './controlPlanes';
9+
10+
const createCondition = (
11+
overrides: Partial<ControlPlaneStatusCondition>,
12+
): ControlPlaneStatusCondition => ({
13+
type: 'Unknown',
14+
status: false,
15+
reason: 'DefaultReason',
16+
message: 'Default message',
17+
lastTransitionTime: new Date().toISOString(),
18+
...overrides,
19+
});
20+
21+
const createControlPlane = (
22+
conditions: ControlPlaneStatusCondition[],
23+
): ControlPlaneType => ({
24+
metadata: {
25+
name: '',
26+
namespace: '',
27+
},
28+
spec: {
29+
components: {
30+
crossplane: undefined,
31+
btpServiceOperator: undefined,
32+
externalSecretsOperator: undefined,
33+
kyverno: undefined,
34+
flux: undefined,
35+
},
36+
},
37+
status: {
38+
conditions,
39+
status: ReadyStatus.Ready,
40+
access: undefined,
41+
},
42+
});
43+
44+
const baseConditions = [
45+
createCondition({ type: 'APIServerHealthy', status: 'True' }),
46+
createCondition({ type: 'AuthenticationHealthy', status: 'True' }),
47+
createCondition({ type: 'AuthorizationHealthy', status: 'True' }),
48+
];
49+
50+
describe('canConnectToMCP', () => {
51+
it('returns true when all required conditions are True', () => {
52+
const controlPlane = createControlPlane([...baseConditions]);
53+
expect(canConnectToMCP(controlPlane)).toBe(true);
54+
});
55+
56+
it('returns false when one required condition is missing', () => {
57+
const controlPlane = createControlPlane([
58+
createCondition({ type: 'APIServerHealthy', status: 'True' }),
59+
createCondition({ type: 'AuthorizationHealthy', status: 'True' }),
60+
]);
61+
expect(canConnectToMCP(controlPlane)).toBe(false);
62+
});
63+
64+
it('returns false when one required condition has status "False"', () => {
65+
const controlPlane = createControlPlane([
66+
createCondition({ type: 'APIServerHealthy', status: 'True' }),
67+
createCondition({ type: 'AuthenticationHealthy', status: 'False' }),
68+
createCondition({ type: 'AuthorizationHealthy', status: 'True' }),
69+
]);
70+
expect(canConnectToMCP(controlPlane)).toBe(false);
71+
});
72+
73+
it('returns true even if other conditions exist', () => {
74+
const controlPlane = createControlPlane([
75+
...baseConditions,
76+
createCondition({ type: 'SomethingElse', status: 'True' }),
77+
]);
78+
expect(canConnectToMCP(controlPlane)).toBe(true);
79+
});
80+
81+
it('returns true when required statuses are lowercase', () => {
82+
const controlPlane = createControlPlane(
83+
baseConditions.map((c) => ({
84+
...c,
85+
status: 'true',
86+
})),
87+
);
88+
expect(canConnectToMCP(controlPlane)).toBe(true);
89+
});
90+
91+
it('returns true when required statuses are boolean', () => {
92+
const controlPlane = createControlPlane(
93+
baseConditions.map((c) => ({
94+
...c,
95+
status: true,
96+
})),
97+
);
98+
expect(canConnectToMCP(controlPlane)).toBe(true);
99+
});
100+
101+
it('returns false when there are no conditions', () => {
102+
const controlPlane = createControlPlane([]);
103+
expect(canConnectToMCP(controlPlane)).toBe(false);
104+
});
105+
106+
it('returns false when status field is missing', () => {
107+
const controlPlane = {
108+
metadata: {
109+
name: '',
110+
namespace: '',
111+
},
112+
spec: {
113+
components: {
114+
crossplane: undefined,
115+
btpServiceOperator: undefined,
116+
externalSecretsOperator: undefined,
117+
kyverno: undefined,
118+
flux: undefined,
119+
},
120+
},
121+
} as ControlPlaneType;
122+
expect(canConnectToMCP(controlPlane)).toBe(false);
123+
});
124+
});
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { ControlPlaneType } from '../../lib/api/types/crate/controlPlanes';
2+
3+
export const canConnectToMCP = (controlPlane: ControlPlaneType): boolean => {
4+
const conditions = controlPlane.status?.conditions ?? [];
5+
6+
return [
7+
'APIServerHealthy',
8+
'AuthenticationHealthy',
9+
'AuthorizationHealthy',
10+
].every((type) =>
11+
conditions.some(
12+
(condition) =>
13+
condition.type === type &&
14+
String(condition.status).toLowerCase() === 'true',
15+
),
16+
);
17+
};

src/lib/api/types/crate/controlPlanes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ export interface ControlPlaneStatusType {
4444

4545
export interface ControlPlaneStatusCondition {
4646
type: string;
47-
status: boolean;
47+
status: boolean | string;
4848
reason: string;
4949
message: string;
5050
lastTransitionTime: string;

0 commit comments

Comments
 (0)