Skip to content

Commit deb4bb0

Browse files
committed
Add github integration ui changes
1 parent e0134cf commit deb4bb0

File tree

10 files changed

+462
-56
lines changed

10 files changed

+462
-56
lines changed

gui/package.json

+3
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@nextui-org/react": "^2.3.6",
1515
"axios": "^1.7.2",
1616
"babel-plugin-styled-components": "^2.1.4",
17+
"chroma-js": "^2.4.2",
1718
"cookie": "^0.6.0",
1819
"diff2html": "^3.4.48",
1920
"framer-motion": "^11.2.4",
@@ -29,13 +30,15 @@
2930
"react-dom": "^18",
3031
"react-hot-toast": "^2.4.1",
3132
"react-loading-skeleton": "^3.4.0",
33+
"react-select": "^5.8.0",
3234
"react-syntax-highlighter": "^15.5.0",
3335
"react-transition-group": "^4.4.5",
3436
"sharp": "^0.33.4",
3537
"socket.io-client": "^2.5.0",
3638
"styled-components": "^6.1.11"
3739
},
3840
"devDependencies": {
41+
"@types/chroma-js": "^2.4.4",
3942
"@types/cookie": "^0.6.0",
4043
"@types/js-cookie": "^3.0.6",
4144
"@types/node": "^20",

gui/src/api/DashboardService.tsx

+23-12
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import api from './apiConfig';
2+
import {CreateProjectPayload, UpdateProjectPayload,} from '../../types/projectsTypes';
3+
import {FormStoryPayload} from '../../types/storyTypes';
24
import {
3-
CreateProjectPayload,
4-
UpdateProjectPayload,
5-
} from '../../types/projectsTypes';
6-
import { FormStoryPayload } from '../../types/storyTypes';
7-
import {
8-
CommentReBuildPayload,
95
CommentReBuildDesignStoryPayload,
6+
CommentReBuildPayload,
107
CreatePullRequestPayload,
118
} from '../../types/pullRequestsTypes';
12-
import { CreateOrUpdateLLMAPIKeyPayload } from '../../types/modelsTypes';
13-
import {
14-
CreateDesignStoryPayload,
15-
EditDesignStoryPayload,
16-
} from '../../types/designStoryTypes';
17-
import { authPayload } from '../../types/authTypes';
9+
import {CreateOrUpdateLLMAPIKeyPayload} from '../../types/modelsTypes';
10+
import {CreateDesignStoryPayload, EditDesignStoryPayload,} from '../../types/designStoryTypes';
11+
import {authPayload} from '../../types/authTypes';
1812

1913
export const checkHealth = () => {
2014
return api.get(`/health`);
@@ -180,3 +174,20 @@ export const rebuildDesignStory = (
180174
export const updateReviewViewedStatus = (story_id: number) => {
181175
return api.put(`/stories/design/review_viewed/${story_id}`, {});
182176
};
177+
178+
export const isGithubConnected = async () => {
179+
const response = await api.get(`/integrations/github`);
180+
const { integrated }: { integrated: boolean } = response.data;
181+
return integrated;
182+
}
183+
184+
export const getGithubRepos = async () => {
185+
const response = await api.get(`/integrations/github/repos`);
186+
const { repositories } = response.data;
187+
return repositories;
188+
}
189+
190+
export const deleteGithubIntegration = async () => {
191+
const response = await api.delete(`/integrations/github`);
192+
return response.data;
193+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
'use client';
2+
3+
import React, {useCallback, useEffect, useState} from 'react';
4+
5+
import styles from '../settings.module.css';
6+
import {deleteGithubIntegration, isGithubConnected} from "@/api/DashboardService";
7+
import {API_BASE_URL} from "@/api/apiConfig";
8+
9+
async function redirectToGithubIntegration() {
10+
try {
11+
window.location.href = `${API_BASE_URL}/integrations/github/authorize`;
12+
} catch (error) {
13+
console.error('Error: ', error);
14+
}
15+
}
16+
17+
const Integrations = () => {
18+
const [isExternalGitIntegration, setIsExternalGitIntegration] = useState<boolean | undefined>(null);
19+
useEffect(() => {
20+
(async function () {
21+
const gitIntegrated = await isGithubConnected();
22+
setIsExternalGitIntegration(gitIntegrated);
23+
})();
24+
}, []);
25+
26+
const deleteIntegration = async () => {
27+
await deleteGithubIntegration();
28+
const gitIntegrated = await isGithubConnected();
29+
setIsExternalGitIntegration(gitIntegrated);
30+
};
31+
32+
return (
33+
<div className="min-h-screen text-white">
34+
<div className="max-w-3xl mx-auto">
35+
<h2 className="text-xl font-semibold mb-4">Integrations</h2>
36+
<div>
37+
<div className={`flex items-center justify-between p-4 rounded-lg mb-3 ${styles.integration_container}`}>
38+
<div className="flex items-center">
39+
<div className="w-10 h-10 mr-4">
40+
<svg viewBox="0 0 24 24" className="fill-current">
41+
<path
42+
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/>
43+
</svg>
44+
</div>
45+
<div>
46+
<h3 className="text-white font-semibold">GitHub</h3>
47+
<p className="text-gray-400 text-sm">
48+
Integrate with GitHub to start working on your projects
49+
</p>
50+
</div>
51+
</div>
52+
{isExternalGitIntegration === undefined ? (<></>) : isExternalGitIntegration === false ? (
53+
<button
54+
onClick={() => redirectToGithubIntegration()}
55+
className="bg-white font-semibold text-black px-4 py-2 rounded-md transition-colors"
56+
>
57+
Connect
58+
</button>
59+
) : (
60+
<button
61+
onClick={() => deleteIntegration()}
62+
className="font-semibold text-gray-200 hover:text-white px-4 py-2 rounded-md transition-colors"
63+
>
64+
Delete
65+
</button>
66+
)}
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
);
72+
};
73+
74+
export default Integrations;

gui/src/app/settings/page.tsx

+10-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import Models from '@/app/settings/SettingsOptions/Models';
44
import CustomSidebar from '@/components/CustomSidebar/CustomSidebar';
55
import imagePath from '@/app/imagePath';
66
import BackButton from '@/components/BackButton/BackButton';
7+
import Integrations from "@/app/settings/SettingsOptions/Integrations";
78

89
export default function Settings() {
910
const options = [
@@ -13,7 +14,14 @@ export default function Settings() {
1314
selected: imagePath.modelsIconSelected,
1415
unselected: imagePath.modelsIconUnselected,
1516
icon_css: 'size-4',
16-
component: <Models />,
17+
component: <Models/>,
18+
}, {
19+
key: 'integrations',
20+
text: 'Integrations',
21+
selected: imagePath.modelsIconSelected,
22+
unselected: imagePath.modelsIconUnselected,
23+
icon_css: 'size-4',
24+
component: <Integrations/>,
1725
},
1826
];
1927

@@ -23,7 +31,7 @@ export default function Settings() {
2331

2432
return (
2533
<div className={'mx-[20vw] my-8 flex flex-col gap-3'}>
26-
<BackButton id={'settings'} url={'/board'} />
34+
<BackButton id={'settings'} url={'/board'}/>
2735

2836
<CustomSidebar
2937
id={'settings'}
+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.integration_container {
2+
background-color: #262628;
3+
}

gui/src/components/CustomSidebar/CustomSidebar.tsx

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
'use client';
2-
import React, { useState, useCallback } from 'react';
2+
import React, {useCallback, useState} from 'react';
33
import styles from './sidebar.module.css';
44
import CustomImage from '@/components/ImageComponents/CustomImage';
5-
import { CustomSidebarProps } from '../../../types/customComponentTypes';
5+
import {CustomSidebarProps} from '../../../types/customComponentTypes';
6+
import {useSearchParams} from 'next/navigation'
67

78
const CustomSidebar: React.FC<CustomSidebarProps> = ({
8-
id,
9-
title,
10-
options,
11-
onOptionSelect,
12-
}) => {
13-
const [selectedKey, setSelectedKey] = useState<string | null>(options[0].key);
9+
id,
10+
title,
11+
options,
12+
onOptionSelect,
13+
}) => {
14+
const searchParams = useSearchParams();
15+
const page = searchParams.get("page");
16+
const selectedPage = options?.find((option) => option.key === page) || options[0];
17+
18+
const [selectedKey, setSelectedKey] = useState<string | null>(selectedPage.key);
1419

1520
const handleOptionClick = useCallback(
1621
(key: string) => {

0 commit comments

Comments
 (0)