Checkpoint GitLab integration group support

This commit is contained in:
Tuan Dang
2023-03-09 11:52:34 +07:00
parent 4edfc1e0be
commit 3f3516b7ba
21 changed files with 572 additions and 149 deletions

View File

@@ -8,7 +8,11 @@ import {
} from '../../models'; } from '../../models';
import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables'; import { INTEGRATION_SET, INTEGRATION_OPTIONS } from '../../variables';
import { IntegrationService } from '../../services'; import { IntegrationService } from '../../services';
import { getApps, revokeAccess } from '../../integrations'; import {
getApps,
getTeams,
revokeAccess
} from '../../integrations';
/*** /***
* Return integration authorization with id [integrationAuthId] * Return integration authorization with id [integrationAuthId]
@@ -154,25 +158,54 @@ export const saveIntegrationAccessToken = async (
* @returns * @returns
*/ */
export const getIntegrationAuthApps = async (req: Request, res: Response) => { export const getIntegrationAuthApps = async (req: Request, res: Response) => {
let apps; let apps;
try { try {
apps = await getApps({ const teamId = req.query.teamId as string;
integrationAuth: req.integrationAuth,
accessToken: req.accessToken,
});
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get integration authorization applications",
});
}
return res.status(200).send({ apps = await getApps({
apps, integrationAuth: req.integrationAuth,
}); accessToken: req.accessToken,
...teamId && { teamId }
});
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get integration authorization applications",
});
}
return res.status(200).send({
apps
});
}; };
/**
* Return list of teams allowed for integration with integration authorization id [integrationAuthId]
* @param req
* @param res
* @returns
*/
export const getIntegrationAuthTeams = async (req: Request, res: Response) => {
let teams;
try {
teams = await getTeams({
integrationAuth: req.integrationAuth,
accessToken: req.accessToken
});
} catch (err) {
Sentry.setUser({ email: req.user.email });
Sentry.captureException(err);
return res.status(400).send({
message: "Failed to get integration authorization teams"
});
}
return res.status(200).send({
teams
});
}
/** /**
* Delete integration authorization with id [integrationAuthId] * Delete integration authorization with id [integrationAuthId]
* @param req * @param req

View File

@@ -24,22 +24,27 @@ import {
INTEGRATION_CIRCLECI_API_URL, INTEGRATION_CIRCLECI_API_URL,
INTEGRATION_TRAVISCI_API_URL, INTEGRATION_TRAVISCI_API_URL,
} from "../variables"; } from "../variables";
import { requireIntegrationAuthorizationAuth } from "../middleware";
/** /**
* Return list of names of apps for integration named [integration] * Return list of names of apps for integration named [integration]
* @param {Object} obj * @param {Object} obj
* @param {String} obj.integration - name of integration * @param {String} obj.integration - name of integration
* @param {String} obj.accessToken - access token for integration * @param {String} obj.accessToken - access token for integration
* @param {String} obj.teamId - (optional) id of team for getting integration apps (used for integrations like GitLab)
* @returns {Object[]} apps - names of integration apps * @returns {Object[]} apps - names of integration apps
* @returns {String} apps.name - name of integration app * @returns {String} apps.name - name of integration app
*/ */
const getApps = async ({ const getApps = async ({
integrationAuth, integrationAuth,
accessToken, accessToken,
teamId
}: { }: {
integrationAuth: IIntegrationAuth; integrationAuth: IIntegrationAuth;
accessToken: string; accessToken: string;
teamId?: string;
}) => { }) => {
interface App { interface App {
name: string; name: string;
appId?: string; appId?: string;

View File

@@ -13,6 +13,7 @@ import {
INTEGRATION_NETLIFY_TOKEN_URL, INTEGRATION_NETLIFY_TOKEN_URL,
INTEGRATION_GITHUB_TOKEN_URL, INTEGRATION_GITHUB_TOKEN_URL,
INTEGRATION_GITLAB_TOKEN_URL, INTEGRATION_GITLAB_TOKEN_URL,
INTEGRATION_GITLAB_API_URL
} from '../variables'; } from '../variables';
import { import {
SITE_URL, SITE_URL,
@@ -73,7 +74,7 @@ interface ExchangeCodeGithubResponse {
interface ExchangeCodeGitlabResponse { interface ExchangeCodeGitlabResponse {
access_token: string; access_token: string;
token_type: string; token_type: string;
expires_in: string; expires_in: number;
refresh_token: string; refresh_token: string;
scope: string; scope: string;
created_at: number; created_at: number;
@@ -370,6 +371,7 @@ const exchangeCodeGithub = async ({ code }: { code: string }) => {
*/ */
const exchangeCodeGitlab = async ({ code }: { code: string }) => { const exchangeCodeGitlab = async ({ code }: { code: string }) => {
let res: ExchangeCodeGitlabResponse; let res: ExchangeCodeGitlabResponse;
const accessExpiresAt = new Date();
try { try {
res = ( res = (
@@ -389,6 +391,46 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
} }
) )
).data; ).data;
// 1. try getting groups
// https://gitlab.com/api/v4/groups
// const res2 = (await request.get(
// `${INTEGRATION_GITLAB_API_URL}/v4/groups`,
// {
// headers: {
// Authorization: `Bearer ${res.access_token}`,
// "Accept-Encoding": "application/json"
// }
// }
// )).data;
// 2. try getting projects of that group
// const res3 = (await request.get(
// `${INTEGRATION_GITLAB_API_URL}/v4/groups/${res2[0].id}`,
// {
// headers: {
// Authorization: `Bearer ${res.access_token}`,
// "Accept-Encoding": "application/json"
// }
// }
// )).data;
// const res = (
// await request.get(
// `${INTEGRATION_GITLAB_API_URL}/v4/users/${id}/projects`,
// {
// headers: {
// "Authorization": `Bearer ${accessToken}`,
// "Accept-Encoding": "application/json",
// },
// }
// )
// ).data;
accessExpiresAt.setSeconds(
accessExpiresAt.getSeconds() + res.expires_in
);
}catch (err) { }catch (err) {
Sentry.setUser(null); Sentry.setUser(null);
Sentry.captureException(err); Sentry.captureException(err);
@@ -397,8 +439,8 @@ const exchangeCodeGitlab = async ({ code }: { code: string }) => {
return { return {
accessToken: res.access_token, accessToken: res.access_token,
refreshToken: null, refreshToken: res.refresh_token,
accessExpiresAt: null accessExpiresAt
}; };
} }

View File

@@ -1,6 +1,7 @@
import { exchangeCode } from './exchange'; import { exchangeCode } from './exchange';
import { exchangeRefresh } from './refresh'; import { exchangeRefresh } from './refresh';
import { getApps } from './apps'; import { getApps } from './apps';
import { getTeams } from './teams';
import { syncSecrets } from './sync'; import { syncSecrets } from './sync';
import { revokeAccess } from './revoke'; import { revokeAccess } from './revoke';
@@ -8,6 +9,7 @@ export {
exchangeCode, exchangeCode,
exchangeRefresh, exchangeRefresh,
getApps, getApps,
getTeams,
syncSecrets, syncSecrets,
revokeAccess revokeAccess
} }

View File

@@ -0,0 +1,74 @@
import * as Sentry from "@sentry/node";
import {
IIntegrationAuth
} from '../models';
import {
INTEGRATION_GITLAB,
INTEGRATION_GITLAB_API_URL
} from '../variables';
import request from '../config/request';
const getTeams = async ({
integrationAuth,
accessToken
}: {
integrationAuth: IIntegrationAuth;
accessToken: string;
}) => {
interface Team {
name: string;
teamId: string;
}
let teams: Team[] = [];
try {
switch (integrationAuth.integration) {
case INTEGRATION_GITLAB:
teams = await getTeamsGitLab({
accessToken
});
break;
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to get integration teams');
}
return teams;
}
const getTeamsGitLab = async ({
accessToken
}: {
accessToken: string;
}) => {
let teams = [];
try {
const res = (await request.get(
`${INTEGRATION_GITLAB_API_URL}/v4/groups`,
{
headers: {
Authorization: `Bearer ${accessToken}`,
"Accept-Encoding": "application/json"
}
}
)).data;
teams = res.map((t: any) => ({
name: t.name,
teamId: t.id
}));
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error("Failed to get GitLab integration teams");
}
return teams;
}
export {
getTeams
}

View File

@@ -23,9 +23,9 @@ export interface IIntegrationAuth {
refreshCiphertext?: string; refreshCiphertext?: string;
refreshIV?: string; refreshIV?: string;
refreshTag?: string; refreshTag?: string;
accessIdCiphertext?: string; // new accessIdCiphertext?: string;
accessIdIV?: string; // new accessIdIV?: string;
accessIdTag?: string; // new accessIdTag?: string;
accessCiphertext?: string; accessCiphertext?: string;
accessIV?: string; accessIV?: string;
accessTag?: string; accessTag?: string;

View File

@@ -1,6 +1,6 @@
import express from 'express'; import express from 'express';
const router = express.Router(); const router = express.Router();
import { body, param } from 'express-validator'; import { body, param, query } from 'express-validator';
import { import {
requireAuth, requireAuth,
requireWorkspaceAuth, requireWorkspaceAuth,
@@ -64,6 +64,9 @@ router.post(
integrationAuthController.saveIntegrationAccessToken integrationAuthController.saveIntegrationAccessToken
); );
// this can optionally accept a teamId?
// IF teamId is passed in then it probably means that we want to get
// the apps for that team
router.get( router.get(
'/:integrationAuthId/apps', '/:integrationAuthId/apps',
requireAuth({ requireAuth({
@@ -73,10 +76,24 @@ router.get(
acceptedRoles: [ADMIN, MEMBER] acceptedRoles: [ADMIN, MEMBER]
}), }),
param('integrationAuthId'), param('integrationAuthId'),
query('entity'),
validateRequest, validateRequest,
integrationAuthController.getIntegrationAuthApps integrationAuthController.getIntegrationAuthApps
); );
router.get(
'/:integrationAuthId/teams',
requireAuth({
acceptedAuthModes: ['jwt']
}),
requireIntegrationAuthorizationAuth({
acceptedRoles: [ADMIN, MEMBER]
}),
param('integrationAuthId'),
validateRequest,
integrationAuthController.getIntegrationAuthTeams
);
router.delete( router.delete(
'/:integrationAuthId', '/:integrationAuthId',
requireAuth({ requireAuth({

View File

@@ -59,6 +59,7 @@ const INTEGRATION_FLYIO_API_URL = "https://api.fly.io/graphql";
const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api"; const INTEGRATION_CIRCLECI_API_URL = "https://circleci.com/api";
const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com"; const INTEGRATION_TRAVISCI_API_URL = "https://api.travis-ci.com";
// TODO: deprecate types?
const INTEGRATION_OPTIONS = [ const INTEGRATION_OPTIONS = [
{ {
name: 'Heroku', name: 'Heroku',
@@ -156,7 +157,7 @@ const INTEGRATION_OPTIONS = [
slug: 'gitlab', slug: 'gitlab',
image: 'GitLab.png', image: 'GitLab.png',
isAvailable: true, isAvailable: true,
type: 'oauth', type: 'custom',
clientId: CLIENT_ID_GITLAB, clientId: CLIENT_ID_GITLAB,
docsLink: '' docsLink: ''
}, },

View File

@@ -1,3 +1,4 @@
export { export {
useGetIntegrationAuthApps, useGetIntegrationAuthApps,
useGetIntegrationAuthById} from './queries'; useGetIntegrationAuthById,
useGetIntegrationAuthTeams} from './queries';

View File

@@ -4,11 +4,13 @@ import { apiRequest } from "@app/config/request";
import { import {
App, App,
IntegrationAuth} from './types'; IntegrationAuth,
Team} from './types';
const integrationAuthKeys = { const integrationAuthKeys = {
getIntegrationAuthById: (integrationAuthId: string) => [{ integrationAuthId }, 'integrationAuth'] as const, getIntegrationAuthById: (integrationAuthId: string) => [{ integrationAuthId }, 'integrationAuth'] as const,
getIntegrationAuthApps: (integrationAuthId: string) => [{ integrationAuthId }, 'integrationAuthApps'] as const, getIntegrationAuthApps: (integrationAuthId: string, teamId?: string) => [{ integrationAuthId, teamId }, 'integrationAuthApps'] as const,
getIntegrationAuthTeams: (integrationAuthId: string) => [{ integrationAuthId }, 'integrationAuthTeams'] as const
} }
const fetchIntegrationAuthById = async (integrationAuthId: string) => { const fetchIntegrationAuthById = async (integrationAuthId: string) => {
@@ -16,11 +18,27 @@ const fetchIntegrationAuthById = async (integrationAuthId: string) => {
return data.integrationAuth; return data.integrationAuth;
} }
const fetchIntegrationAuthApps = async (integrationAuthId: string) => { const fetchIntegrationAuthApps = async ({
const { data } = await apiRequest.get<{ apps: App[] }>(`/api/v1/integration-auth/${integrationAuthId}/apps`); integrationAuthId,
teamId
}: {
integrationAuthId: string;
teamId?: string;
}) => {
console.log('fetchIntegrationAuthApps: ', integrationAuthId);
const searchParams = new URLSearchParams(teamId ? { teamId } : undefined);
const { data } = await apiRequest.get<{ apps: App[] }>(
`/api/v1/integration-auth/${integrationAuthId}/apps`,
{ params: searchParams }
);
return data.apps; return data.apps;
} }
const fetchIntegrationAuthTeams = async (integrationAuthId: string) => {
const { data } = await apiRequest.get<{ teams: Team[] }>(`/api/v1/integration-auth/${integrationAuthId}/teams`);
return data.teams;
}
export const useGetIntegrationAuthById = (integrationAuthId: string) => { export const useGetIntegrationAuthById = (integrationAuthId: string) => {
return useQuery({ return useQuery({
queryKey: integrationAuthKeys.getIntegrationAuthById(integrationAuthId), queryKey: integrationAuthKeys.getIntegrationAuthById(integrationAuthId),
@@ -29,10 +47,28 @@ export const useGetIntegrationAuthById = (integrationAuthId: string) => {
}); });
} }
export const useGetIntegrationAuthApps = (integrationAuthId: string) => { // TODO: fix to teamId
export const useGetIntegrationAuthApps = ({
integrationAuthId,
teamId
}: {
integrationAuthId: string;
teamId?: string;
}) => {
return useQuery({ return useQuery({
queryKey: integrationAuthKeys.getIntegrationAuthApps(integrationAuthId), queryKey: integrationAuthKeys.getIntegrationAuthApps(integrationAuthId, teamId),
queryFn: () => fetchIntegrationAuthApps(integrationAuthId), queryFn: () => fetchIntegrationAuthApps({
integrationAuthId,
teamId
}),
enabled: true
});
}
export const useGetIntegrationAuthTeams = (integrationAuthId: string) => {
return useQuery({
queryKey: integrationAuthKeys.getIntegrationAuthTeams(integrationAuthId),
queryFn: () => fetchIntegrationAuthTeams(integrationAuthId),
enabled: true enabled: true
}); });
} }

View File

@@ -10,4 +10,9 @@ export type App = {
name: string; name: string;
appId?: string; appId?: string;
owner?: string; owner?: string;
}
export type Team = {
name: string;
teamId: string;
} }

View File

@@ -196,16 +196,16 @@ export default function Integrations() {
link = `https://gitlab.com/oauth/authorize?client_id=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`; link = `https://gitlab.com/oauth/authorize?client_id=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`;
break; break;
case 'render': case 'render':
link = `${window.location.origin}/integrations/render/authorize` link = `${window.location.origin}/integrations/render/authorize`;
break; break;
case 'flyio': case 'flyio':
link = `${window.location.origin}/integrations/flyio/authorize` link = `${window.location.origin}/integrations/flyio/authorize`;
break; break;
case 'circleci': case 'circleci':
link = `${window.location.origin}/integrations/circleci/authorize` link = `${window.location.origin}/integrations/circleci/authorize`;
break; break;
case 'travisci': case 'travisci':
link = `${window.location.origin}/integrations/travisci/authorize` link = `${window.location.origin}/integrations/travisci/authorize`;
break; break;
default: default:
break; break;

View File

@@ -22,7 +22,9 @@ export default function CircleCICreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -36,9 +38,12 @@ export default function CircleCICreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
setTargetApp(integrationAuthApps[0]?.name); if (integrationAuthApps.length > 0 ) {
setTargetApp(integrationAuthApps[0]?.name);
} else {
setTargetApp('none');
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -84,7 +89,7 @@ export default function CircleCICreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -98,19 +103,27 @@ export default function CircleCICreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`render-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -22,7 +22,9 @@ export default function FlyioCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -31,14 +33,18 @@ export default function FlyioCreateIntegrationPage() {
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
setSelectedSourceEnvironment(workspace.environments[0].slug); setSelectedSourceEnvironment(workspace.environments[0].slug);
} }
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty // TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); setTargetApp(integrationAuthApps[0].name);
} else {
setTargetApp('none');
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -84,7 +90,7 @@ export default function FlyioCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`flyio-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -98,12 +104,19 @@ export default function FlyioCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`render-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No apps found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
@@ -111,6 +124,7 @@ export default function FlyioCreateIntegrationPage() {
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -22,7 +22,9 @@ export default function GitHubCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [owner, setOwner] = useState<string | null>(null); const [owner, setOwner] = useState<string | null>(null);
@@ -37,10 +39,13 @@ export default function GitHubCreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); setTargetApp(integrationAuthApps[0].name);
setOwner(integrationAuthApps[0]?.owner ?? null); setOwner(integrationAuthApps[0]?.owner ?? null);
} else {
setTargetApp('none');
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -99,21 +104,29 @@ export default function GitHubCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`github-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`github-environment-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No repositories found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
</div> </div>

View File

@@ -11,10 +11,20 @@ import {
Select, Select,
SelectItem SelectItem
} from '../../../components/v2'; } from '../../../components/v2';
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth'; import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById,
useGetIntegrationAuthTeams} from '../../../hooks/api/integrationAuth';
import { useGetWorkspaceById } from '../../../hooks/api/workspace'; import { useGetWorkspaceById } from '../../../hooks/api/workspace';
import createIntegration from "../../api/integrations/createIntegration"; import createIntegration from "../../api/integrations/createIntegration";
const gitLabEntities = [
{ name: 'Individual', value: 'individual' },
{ name: 'Group', value: 'group' }
]
// TODO: flesh out the data flow...
export default function GitLabCreateIntegrationPage() { export default function GitLabCreateIntegrationPage() {
const router = useRouter(); const router = useRouter();
@@ -22,10 +32,18 @@ export default function GitLabCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? '');
const [targetEntity, setTargetEntity] = useState(gitLabEntities[0].value);
const [targetTeam, setTargetTeam] = useState('aa'); // ?
const [targetTeamId] = useState(undefined);
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? '',
...(targetTeamId ? { teamId: targetTeamId } : {})
});
const { data: integrationAuthTeams } = useGetIntegrationAuthTeams(integrationAuthId as string ?? '');
console.log('integrationAuthTeams: ', integrationAuthTeams);
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [owner, setOwner] = useState<string | null>(null);
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -38,12 +56,36 @@ export default function GitLabCreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty if (integrationAuthApps) {
if (integrationAuthApps) { if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); console.log('AA');
setOwner(integrationAuthApps[0]?.owner ?? null); setTargetApp(integrationAuthApps[0].name);
} else {
console.log('BB');
setTargetApp('none');
} }
}
}, [integrationAuthApps]); }, [integrationAuthApps]);
useEffect(() => {
// if (targetEntity === 'group' && integrationAuthTeams) {
// if (integrationAuthTeams.length > 0) {
// setTargetTeam(integrationAuthTeams[0].name);
// } else {
// setTargetTeam('none');
// }
// }
// if (targetEntity === 'group') {
// if (integrationAuthTeams && integrationAuthTeams.length > 0) {
// setTargetTeamId(integrationAuthTeams[0].teamId);
// } else {
// setTargetTeamId('');
// }
// } else {
// }
}, [integrationAuthTeams, integrationAuthApps, targetEntity]);
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { try {
@@ -57,7 +99,7 @@ export default function GitLabCreateIntegrationPage() {
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null, appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetEnvironment: null, targetEnvironment: null,
owner, owner: null,
path: null, path: null,
region: null region: null
}); });
@@ -71,7 +113,15 @@ export default function GitLabCreateIntegrationPage() {
} }
} }
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? ( console.log('A', (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && integrationAuthTeams && targetApp && targetTeam));
console.log('B', integrationAuth);
console.log('C', workspace);
console.log('D', selectedSourceEnvironment);
console.log('E', integrationAuthApps);
console.log('F', integrationAuthTeams);
console.log('G', targetApp);
console.log('H', targetTeam);
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && integrationAuthTeams && targetApp && targetTeam) ? (
<div className="h-full w-full flex justify-center items-center"> <div className="h-full w-full flex justify-center items-center">
<Card className="max-w-md p-8 rounded-md"> <Card className="max-w-md p-8 rounded-md">
<CardTitle className='text-center'>GitLab Integration</CardTitle> <CardTitle className='text-center'>GitLab Integration</CardTitle>
@@ -85,33 +135,83 @@ export default function GitLabCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<FormControl <FormControl
label="GitLab Repo" label="GitLab Integration Type"
className='mt-4'
>
<Select
value={targetEntity}
onValueChange={(val) => setTargetEntity(val)}
className='w-full border border-mineshaft-500'
>
{gitLabEntities.map((entity) => {
return (
<SelectItem value={entity.value} key={`target-entity-${entity.value}`}>
{entity.name}
</SelectItem>
);
})}
</Select>
</FormControl>
{targetEntity === 'group' && (
<FormControl
label="GitLab Group"
className='mt-4'
>
<Select
value={targetTeam}
onValueChange={(val) => setTargetTeam(val)}
className='w-full border border-mineshaft-500'
>
{integrationAuthTeams.length > 0 ? (
integrationAuthTeams.map((integrationAuthTeam) => (
<SelectItem value={integrationAuthTeam.name} key={`target-team-${integrationAuthTeam.name}`}>
{integrationAuthTeam.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-team-none">
No groups found
</SelectItem>
)}
</Select>
</FormControl>
)}
<FormControl
label="GitLab Project"
className='mt-4' className='mt-4'
> >
<Select <Select
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`gitlab-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -22,7 +22,9 @@ export default function HerokuCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -36,9 +38,12 @@ export default function HerokuCreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); setTargetApp(integrationAuthApps[0].name);
} else {
setTargetApp('none');
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -83,7 +88,7 @@ export default function HerokuCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -97,19 +102,27 @@ export default function HerokuCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`heroku-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No apps found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -29,7 +29,9 @@ export default function NetlifyCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -45,10 +47,13 @@ export default function NetlifyCreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty if (integrationAuthApps) {
if (integrationAuthApps) { if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); setTargetApp(integrationAuthApps[0].name);
} else {
setTargetApp('none');
} }
}
}, [integrationAuthApps]); }, [integrationAuthApps]);
const handleButtonClick = async () => { const handleButtonClick = async () => {
@@ -91,7 +96,7 @@ export default function NetlifyCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -104,12 +109,19 @@ export default function NetlifyCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`heroku-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No sites found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<FormControl <FormControl
@@ -121,17 +133,18 @@ export default function NetlifyCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{netlifyEnvironments.map((netlifyEnvironment) => ( {netlifyEnvironments.map((netlifyEnvironment) => (
<SelectItem value={netlifyEnvironment.slug} key={`netlify-environment-${netlifyEnvironment.slug}`}> <SelectItem value={netlifyEnvironment.slug} key={`target-environment-${netlifyEnvironment.slug}`}>
{netlifyEnvironment.name} {netlifyEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -22,7 +22,9 @@ export default function RenderCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -38,7 +40,11 @@ export default function RenderCreateIntegrationPage() {
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty // TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
setTargetApp(integrationAuthApps[0].name); if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name);
} else {
setTargetApp('none');
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -84,7 +90,7 @@ export default function RenderCreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -98,19 +104,27 @@ export default function RenderCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`render-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No services found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -22,7 +22,9 @@ export default function TravisCICreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
@@ -36,10 +38,13 @@ export default function TravisCICreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty if (integrationAuthApps) {
if (integrationAuthApps) { if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0]?.name); setTargetApp(integrationAuthApps[0].name);
} else {
setTargetApp('none');
} }
}
}, [integrationAuthApps]); }, [integrationAuthApps]);
const handleButtonClick = async () => { const handleButtonClick = async () => {
@@ -84,7 +89,7 @@ export default function TravisCICreateIntegrationPage() {
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{workspace?.environments.map((sourceEnvironment) => ( {workspace?.environments.map((sourceEnvironment) => (
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}> <SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
{sourceEnvironment.name} {sourceEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
@@ -98,19 +103,27 @@ export default function TravisCICreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`render-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-environment-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>

View File

@@ -28,11 +28,13 @@ export default function VercelCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? ''); const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? ''); const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
const { data: integrationAuthApps } = useGetIntegrationAuthApps(integrationAuthId as string ?? ''); const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: integrationAuthId as string ?? ''
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(''); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
const [targetApp, setTargetApp] = useState(''); const [targetApp, setTargetApp] = useState('');
const [targetEnvironment, setTargetEnvironemnt] = useState(''); const [targetEnvironment, setTargetEnvironment] = useState('');
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -43,10 +45,14 @@ export default function VercelCreateIntegrationPage() {
}, [workspace]); }, [workspace]);
useEffect(() => { useEffect(() => {
// TODO: handle case where apps can be empty
if (integrationAuthApps) { if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name); setTargetApp(integrationAuthApps[0].name);
setTargetEnvironemnt(vercelEnvironments[0].slug); setTargetEnvironment(vercelEnvironments[0].slug);
} else {
setTargetApp('none');
setTargetEnvironment(vercelEnvironments[0].slug);
}
} }
}, [integrationAuthApps]); }, [integrationAuthApps]);
@@ -103,12 +109,19 @@ export default function VercelCreateIntegrationPage() {
value={targetApp} value={targetApp}
onValueChange={(val) => setTargetApp(val)} onValueChange={(val) => setTargetApp(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
isDisabled={integrationAuthApps.length === 0}
> >
{integrationAuthApps.map((integrationAuthApp) => ( {integrationAuthApps.length > 0 ? (
<SelectItem value={integrationAuthApp.name} key={`heroku-environment-${integrationAuthApp.name}`}> integrationAuthApps.map((integrationAuthApp) => (
{integrationAuthApp.name} <SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem> </SelectItem>
))} )}
</Select> </Select>
</FormControl> </FormControl>
<FormControl <FormControl
@@ -116,21 +129,22 @@ export default function VercelCreateIntegrationPage() {
> >
<Select <Select
value={targetEnvironment} value={targetEnvironment}
onValueChange={(val) => setTargetEnvironemnt(val)} onValueChange={(val) => setTargetEnvironment(val)}
className='w-full border border-mineshaft-500' className='w-full border border-mineshaft-500'
> >
{vercelEnvironments.map((vercelEnvironment) => ( {vercelEnvironments.map((vercelEnvironment) => (
<SelectItem value={vercelEnvironment.slug} key={`vercel-environment-${vercelEnvironment.slug}`}> <SelectItem value={vercelEnvironment.slug} key={`target-environment-${vercelEnvironment.slug}`}>
{vercelEnvironment.name} {vercelEnvironment.name}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className='mt-4' className='mt-4'
isLoading={isLoading} isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
> >
Create Integration Create Integration
</Button> </Button>