mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 01:52:22 +00:00
refactor(ui): changed frontend to normal i18n without SSR
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
import { useEffect } from 'react';
|
||||
import { AppProps } from 'next/app';
|
||||
import { useRouter } from 'next/router';
|
||||
import { appWithTranslation } from 'next-i18next';
|
||||
import { config } from '@fortawesome/fontawesome-svg-core';
|
||||
import { QueryClientProvider } from '@tanstack/react-query';
|
||||
|
||||
@@ -23,6 +22,8 @@ import { queryClient } from '@app/reactQuery';
|
||||
import '@fortawesome/fontawesome-svg-core/styles.css';
|
||||
import '../styles/globals.css';
|
||||
|
||||
import '@app/i18n';
|
||||
|
||||
config.autoAddCss = false;
|
||||
|
||||
type NextAppProp = AppProps & {
|
||||
@@ -32,15 +33,6 @@ type NextAppProp = AppProps & {
|
||||
const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element => {
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
const storedLang = localStorage.getItem('lang');
|
||||
if (router.locale ?? storedLang !== 'en' ?? 'en') {
|
||||
router.push(router.asPath, router.asPath, {
|
||||
locale: storedLang ?? 'en'
|
||||
});
|
||||
}
|
||||
}, [router.locale, router.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
// Init for auto capturing
|
||||
const telemetry = new Telemetry().getInstance();
|
||||
@@ -95,7 +87,7 @@ const App = ({ Component, pageProps, ...appProps }: NextAppProp): JSX.Element =>
|
||||
);
|
||||
};
|
||||
|
||||
export default appWithTranslation(App);
|
||||
export default App;
|
||||
|
||||
/* <Script
|
||||
src="https://www.googletagmanager.com/gtag/js?id=G-DQ1XLJJGG1"
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import EventFilter from '@app/components/basic/EventFilter';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import ActivitySideBar from '@app/ee/components/ActivitySideBar';
|
||||
|
||||
import getProjectLogs from '../../ee/api/secrets/GetProjectLogs';
|
||||
@@ -154,9 +153,9 @@ export default function Activity() {
|
||||
)}
|
||||
<div className="flex flex-col justify-between items-start mx-4 mt-6 mb-4 text-xl max-w-5xl px-2">
|
||||
<div className="flex flex-row justify-start items-center text-3xl">
|
||||
<p className="font-semibold mr-4 text-bunker-100">{t('activity:title')}</p>
|
||||
<p className="font-semibold mr-4 text-bunker-100">{t('activity.title')}</p>
|
||||
</div>
|
||||
<p className="mr-4 text-base text-gray-400">{t('activity:subtitle')}</p>
|
||||
<p className="mr-4 text-base text-gray-400">{t('activity.subtitle')}</p>
|
||||
</div>
|
||||
<div className="px-6 h-8 mt-2">
|
||||
<EventFilter selected={eventChosen} select={setEventChosen} />
|
||||
@@ -165,8 +164,8 @@ export default function Activity() {
|
||||
<div className="flex justify-center w-full mb-6">
|
||||
<div className="items-center w-60">
|
||||
<Button
|
||||
text={String(t('common:view-more'))}
|
||||
textDisabled={String(t('common:end-of-history'))}
|
||||
text={String(t('common.view-more'))}
|
||||
textDisabled={String(t('common.end-of-history'))}
|
||||
active={logsData.length % 10 === 0}
|
||||
onButtonPressed={loadMoreLogs}
|
||||
size="md"
|
||||
@@ -180,4 +179,3 @@ export default function Activity() {
|
||||
|
||||
Activity.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['activity', 'common']);
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { DashboardPage } from '@app/views/DashboardPage';
|
||||
import { DashboardEnvOverview } from '@app/views/DashboardPage/DashboardEnvOverview';
|
||||
|
||||
@@ -23,11 +22,11 @@ const Dashboard = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('dashboard:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('dashboard.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={String(t('dashboard:og-title'))} />
|
||||
<meta name="og:description" content={String(t('dashboard:og-description'))} />
|
||||
<meta property="og:title" content={String(t('dashboard.og-title'))} />
|
||||
<meta name="og:description" content={String(t('dashboard.og-description'))} />
|
||||
</Head>
|
||||
<div className="h-full">
|
||||
{isOverviewMode ? (
|
||||
@@ -43,5 +42,3 @@ const Dashboard = () => {
|
||||
export default Dashboard;
|
||||
|
||||
Dashboard.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['dashboard']);
|
||||
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
import onboardingCheck from '@app/components/utilities/checks/OnboardingCheck';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { TabsObject } from '@app/components/v2/Tabs';
|
||||
|
||||
import registerUserAction from '../api/userActions/registerUserAction';
|
||||
@@ -45,7 +44,7 @@ const learningItem = ({
|
||||
<a
|
||||
target={`${link.includes('https') ? '_blank' : '_self'}`}
|
||||
rel="noopener noreferrer"
|
||||
className={`w-full ${complete && 'opacity-30 hover:opacity-100 duration-200'}`}
|
||||
className={`w-full ${complete && 'opacity-30 duration-200 hover:opacity-100'}`}
|
||||
href={link}
|
||||
>
|
||||
<div
|
||||
@@ -59,22 +58,22 @@ const learningItem = ({
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="relative group bg-bunker-500 hover:bg-mineshaft-700 shadow-xl duration-200 rounded-md border border-mineshaft-600 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden mb-3 cursor-pointer"
|
||||
className="group relative mb-3 flex h-[5.5rem] w-full cursor-pointer items-center justify-between overflow-hidden rounded-md border border-mineshaft-600 bg-bunker-500 py-2 pl-2 pr-6 shadow-xl duration-200 hover:bg-mineshaft-700"
|
||||
>
|
||||
<div className="flex flex-row items-center mr-4">
|
||||
<FontAwesomeIcon icon={icon} className="text-4xl mx-2 w-16" />
|
||||
<div className="mr-4 flex flex-row items-center">
|
||||
<FontAwesomeIcon icon={icon} className="mx-2 w-16 text-4xl" />
|
||||
{complete && (
|
||||
<div className="bg-bunker-500 group-hover:bg-mineshaft-700 w-7 h-7 rounded-full absolute left-12 top-10 p-2 flex items-center justify-center">
|
||||
<FontAwesomeIcon icon={faCheckCircle} className="text-4xl w-5 h-5 text-primary" />
|
||||
<div className="absolute left-12 top-10 flex h-7 w-7 items-center justify-center rounded-full bg-bunker-500 p-2 group-hover:bg-mineshaft-700">
|
||||
<FontAwesomeIcon icon={faCheckCircle} className="h-5 w-5 text-4xl text-primary" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col items-start">
|
||||
<div className="text-xl font-semibold mt-0.5">{text}</div>
|
||||
<div className="mt-0.5 text-xl font-semibold">{text}</div>
|
||||
<div className="text-sm font-normal">{subText}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`pr-4 font-semibold text-sm w-28 text-right ${complete && 'text-primary'}`}
|
||||
className={`w-28 pr-4 text-right text-sm font-semibold ${complete && 'text-primary'}`}
|
||||
>
|
||||
{complete ? 'Complete!' : `About ${time}`}
|
||||
</div>
|
||||
@@ -95,24 +94,24 @@ const learningItem = ({
|
||||
});
|
||||
}
|
||||
}}
|
||||
className="relative bg-bunker-700 hover:bg-bunker-500 shadow-xl duration-200 rounded-md border border-dashed border-bunker-400 pl-2 pr-6 py-2 h-[5.5rem] w-full flex items-center justify-between overflow-hidden my-1.5 cursor-pointer"
|
||||
className="relative my-1.5 flex h-[5.5rem] w-full cursor-pointer items-center justify-between overflow-hidden rounded-md border border-dashed border-bunker-400 bg-bunker-700 py-2 pl-2 pr-6 shadow-xl duration-200 hover:bg-bunker-500"
|
||||
>
|
||||
<div className="flex flex-row items-center mr-4">
|
||||
<FontAwesomeIcon icon={icon} className="text-4xl mx-2 w-16" />
|
||||
<div className="mr-4 flex flex-row items-center">
|
||||
<FontAwesomeIcon icon={icon} className="mx-2 w-16 text-4xl" />
|
||||
{complete && (
|
||||
<div className="bg-bunker-700 w-7 h-7 rounded-full absolute left-11 top-10">
|
||||
<div className="absolute left-11 top-10 h-7 w-7 rounded-full bg-bunker-700">
|
||||
<FontAwesomeIcon
|
||||
icon={faCheckCircle}
|
||||
className="absolute text-4xl left-12 top-16 w-5 h-5 text-primary"
|
||||
className="absolute left-12 top-16 h-5 w-5 text-4xl text-primary"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex flex-col items-start">
|
||||
<div className="text-xl font-semibold mt-0.5">{text}</div>
|
||||
<div className="text-sm font-normal mt-0.5">{subText}</div>
|
||||
<div className="mt-0.5 text-xl font-semibold">{text}</div>
|
||||
<div className="mt-0.5 text-sm font-normal">{subText}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`pr-4 font-semibold text-sm w-28 text-right ${complete && 'text-primary'}`}>
|
||||
<div className={`w-28 pr-4 text-right text-sm font-semibold ${complete && 'text-primary'}`}>
|
||||
{complete ? 'Complete!' : `About ${time}`}
|
||||
</div>
|
||||
{complete && <div className="absolute bottom-0 left-0 h-1 w-full bg-primary" />}
|
||||
@@ -144,17 +143,24 @@ export default function Home() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mx-6 lg:mx-0 w-full pt-4">
|
||||
<div className="mx-6 w-full pt-4 lg:mx-0">
|
||||
<Head>
|
||||
<title>Infisical Guide</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex relative flex-col items-center text-gray-300 text-lg mx-auto px-6 max-w-3xl lg:max-w-4xl xl:max-w-5xl py-6">
|
||||
<div className="text-5xl font-bold text-left w-full mt-12">Your quick start guide</div>
|
||||
<div className="text-lg text-left w-full pt-2 pb-4 mb-14 text-bunker-300">
|
||||
<div className="relative mx-auto flex max-w-3xl flex-col items-center px-6 py-6 text-lg text-gray-300 lg:max-w-4xl xl:max-w-5xl">
|
||||
<div className="mt-12 w-full text-left text-5xl font-bold">Your quick start guide</div>
|
||||
<div className="mb-14 w-full pt-2 pb-4 text-left text-lg text-bunker-300">
|
||||
Click on the items below and follow the instructions.
|
||||
</div>
|
||||
<div className='absolute h-min top-0 right-0 hidden lg:block'><Image src="/images/dragon-book.svg" height={250} width={400} alt="start guise dragon illustration" /></div>
|
||||
<div className="absolute top-0 right-0 hidden h-min lg:block">
|
||||
<Image
|
||||
src="/images/dragon-book.svg"
|
||||
height={250}
|
||||
width={400}
|
||||
alt="start guise dragon illustration"
|
||||
/>
|
||||
</div>
|
||||
{learningItem({
|
||||
text: 'Get to know Infisical',
|
||||
subText: '',
|
||||
@@ -173,27 +179,27 @@ export default function Home() {
|
||||
userAction: 'first_time_secrets_pushed',
|
||||
link: `/dashboard/${router.query.id}`
|
||||
})}
|
||||
<div className="relative group bg-bunker-500 shadow-xl duration-200 rounded-md border border-mineshaft-600 pl-2 pr-2 pt-4 pb-2 h-full w-full flex flex-col items-center justify-between overflow-hidden mb-3 cursor-default">
|
||||
<div className='w-full flex flex-row items-center mb-4 pr-4'>
|
||||
<div className="flex flex-row items-center mr-4 w-full">
|
||||
<FontAwesomeIcon icon={faNetworkWired} className="text-4xl mx-2 w-16" />
|
||||
<div className="group relative mb-3 flex h-full w-full cursor-default flex-col items-center justify-between overflow-hidden rounded-md border border-mineshaft-600 bg-bunker-500 pl-2 pr-2 pt-4 pb-2 shadow-xl duration-200">
|
||||
<div className="mb-4 flex w-full flex-row items-center pr-4">
|
||||
<div className="mr-4 flex w-full flex-row items-center">
|
||||
<FontAwesomeIcon icon={faNetworkWired} className="mx-2 w-16 text-4xl" />
|
||||
{false && (
|
||||
<div className="bg-bunker-500 group-hover:bg-mineshaft-700 w-7 h-7 rounded-full absolute left-12 top-10 p-2 flex items-center justify-center">
|
||||
<FontAwesomeIcon icon={faCheckCircle} className="text-4xl w-5 h-5 text-green" />
|
||||
<div className="absolute left-12 top-10 flex h-7 w-7 items-center justify-center rounded-full bg-bunker-500 p-2 group-hover:bg-mineshaft-700">
|
||||
<FontAwesomeIcon icon={faCheckCircle} className="h-5 w-5 text-4xl text-green" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex pl-0.5 flex-col items-start">
|
||||
<div className="text-xl font-semibold mt-0.5">Inject secrets locally</div>
|
||||
<div className="text-sm font-normal">Replace .env files with a more secure and efficient alternative.</div>
|
||||
<div className="flex flex-col items-start pl-0.5">
|
||||
<div className="mt-0.5 text-xl font-semibold">Inject secrets locally</div>
|
||||
<div className="text-sm font-normal">
|
||||
Replace .env files with a more secure and efficient alternative.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`pr-4 font-semibold text-sm w-28 text-right ${false && 'text-green'}`}
|
||||
>
|
||||
<div className={`w-28 pr-4 text-right text-sm font-semibold ${false && 'text-green'}`}>
|
||||
About 2 min
|
||||
</div>
|
||||
</div>
|
||||
<TabsObject/>
|
||||
<TabsObject />
|
||||
{false && <div className="absolute bottom-0 left-0 h-1 w-full bg-green" />}
|
||||
</div>
|
||||
{learningItem({
|
||||
@@ -236,5 +242,3 @@ export default function Home() {
|
||||
}
|
||||
|
||||
Home.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['home']);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import crypto from 'crypto';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import frameworkIntegrationOptions from 'public/json/frameworkIntegrations.json';
|
||||
|
||||
import ActivateBotDialog from '@app/components/basic/dialog/ActivateBotDialog';
|
||||
@@ -11,7 +11,6 @@ import CloudIntegrationSection from '@app/components/integrations/CloudIntegrati
|
||||
import FrameworkIntegrationSection from '@app/components/integrations/FrameworkIntegrationSection';
|
||||
import IntegrationSection from '@app/components/integrations/IntegrationSection';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
@@ -73,7 +72,8 @@ export default function Integrations() {
|
||||
// TODO: These will have its type when migratiing towards react-query
|
||||
const [bot, setBot] = useState<any>(null);
|
||||
const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false);
|
||||
const [selectedIntegrationOption, setSelectedIntegrationOption] = useState<IntegrationOption | null>(null);
|
||||
const [selectedIntegrationOption, setSelectedIntegrationOption] =
|
||||
useState<IntegrationOption | null>(null);
|
||||
|
||||
const router = useRouter();
|
||||
const workspaceId = router.query.id as string;
|
||||
@@ -162,7 +162,7 @@ export default function Integrations() {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const handleUnauthorizedIntegrationOptionPress = (integrationOption: IntegrationOption) => {
|
||||
try {
|
||||
// generate CSRF token for OAuth2 code-token exchange integrations
|
||||
@@ -223,8 +223,8 @@ export default function Integrations() {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const handleAuthorizedIntegrationOptionPress = (integrationAuth: IntegrationAuth) => {
|
||||
try {
|
||||
let link = '';
|
||||
@@ -281,8 +281,8 @@ export default function Integrations() {
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Open dialog to activate bot if bot is not active.
|
||||
* Otherwise, start integration [integrationOption]
|
||||
@@ -294,12 +294,14 @@ export default function Integrations() {
|
||||
*/
|
||||
const integrationOptionPress = async (integrationOption: IntegrationOption) => {
|
||||
try {
|
||||
const integrationAuthX = integrationAuths.find((integrationAuth) => integrationAuth.integration === integrationOption.slug);
|
||||
|
||||
const integrationAuthX = integrationAuths.find(
|
||||
(integrationAuth) => integrationAuth.integration === integrationOption.slug
|
||||
);
|
||||
|
||||
if (!bot.isActive) {
|
||||
await handleBotActivate();
|
||||
}
|
||||
|
||||
|
||||
if (!integrationAuthX) {
|
||||
// case: integration has not been authorized
|
||||
handleUnauthorizedIntegrationOptionPress(integrationOption);
|
||||
@@ -311,35 +313,45 @@ export default function Integrations() {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handle deleting integration authorization [integrationAuth] and corresponding integrations from state where applicable
|
||||
* @param {Object} obj
|
||||
* @param {IntegrationAuth} obj.integrationAuth - integrationAuth to delete
|
||||
*/
|
||||
const handleDeleteIntegrationAuth = async ({ integrationAuth: deletedIntegrationAuth }: { integrationAuth: IntegrationAuth }) => {
|
||||
const handleDeleteIntegrationAuth = async ({
|
||||
integrationAuth: deletedIntegrationAuth
|
||||
}: {
|
||||
integrationAuth: IntegrationAuth;
|
||||
}) => {
|
||||
try {
|
||||
const newIntegrations = integrations.filter((integration) => integration.integrationAuth !== deletedIntegrationAuth._id);
|
||||
setIntegrationAuths(integrationAuths.filter((integrationAuth) => integrationAuth._id !== deletedIntegrationAuth._id));
|
||||
const newIntegrations = integrations.filter(
|
||||
(integration) => integration.integrationAuth !== deletedIntegrationAuth._id
|
||||
);
|
||||
setIntegrationAuths(
|
||||
integrationAuths.filter(
|
||||
(integrationAuth) => integrationAuth._id !== deletedIntegrationAuth._id
|
||||
)
|
||||
);
|
||||
setIntegrations(newIntegrations);
|
||||
|
||||
|
||||
// handle updating bot
|
||||
if (newIntegrations.length < 1) {
|
||||
// case: no integrations left
|
||||
setBot(
|
||||
(
|
||||
await setBotActiveStatus({
|
||||
botId: bot._id,
|
||||
isActive: false
|
||||
})
|
||||
).bot
|
||||
);
|
||||
(
|
||||
await setBotActiveStatus({
|
||||
botId: bot._id,
|
||||
isActive: false
|
||||
})
|
||||
).bot
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle deleting integration [integration]
|
||||
* @param {Object} obj
|
||||
@@ -350,7 +362,7 @@ export default function Integrations() {
|
||||
const deletedIntegration = await deleteIntegration({
|
||||
integrationId: integration._id
|
||||
});
|
||||
|
||||
|
||||
const newIntegrations = integrations.filter((i) => i._id !== deletedIntegration._id);
|
||||
setIntegrations(newIntegrations);
|
||||
|
||||
@@ -358,42 +370,42 @@ export default function Integrations() {
|
||||
if (newIntegrations.length < 1) {
|
||||
// case: no integrations left
|
||||
setBot(
|
||||
(
|
||||
await setBotActiveStatus({
|
||||
botId: bot._id,
|
||||
isActive: false
|
||||
})
|
||||
).bot
|
||||
);
|
||||
(
|
||||
await setBotActiveStatus({
|
||||
botId: bot._id,
|
||||
isActive: false
|
||||
})
|
||||
).bot
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<div className="flex max-h-screen flex-col justify-between bg-bunker-800 text-white">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('integrations:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('integrations.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content="Manage your .env files in seconds" />
|
||||
<meta name="og:description" content={t('integrations:description') as string} />
|
||||
<meta name="og:description" content={t('integrations.description') as string} />
|
||||
</Head>
|
||||
<div className="w-full pb-2 h-screen max-h-[calc(100vh-10px)] overflow-y-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<NavHeader pageName={t('integrations:title')} isProjectRelated />
|
||||
<div className="no-scrollbar::-webkit-scrollbar h-screen max-h-[calc(100vh-10px)] w-full overflow-y-scroll pb-2 no-scrollbar">
|
||||
<NavHeader pageName={t('integrations.title')} isProjectRelated />
|
||||
<ActivateBotDialog
|
||||
isOpen={isActivateBotDialogOpen}
|
||||
closeModal={() => setIsActivateBotDialogOpen(false)}
|
||||
selectedIntegrationOption={selectedIntegrationOption}
|
||||
integrationOptionPress={integrationOptionPress}
|
||||
/>
|
||||
<IntegrationSection
|
||||
integrations={integrations}
|
||||
<IntegrationSection
|
||||
integrations={integrations}
|
||||
setIntegrations={setIntegrations}
|
||||
bot={bot}
|
||||
setBot={setBot}
|
||||
environments={environments}
|
||||
environments={environments}
|
||||
handleDeleteIntegration={handleDeleteIntegration}
|
||||
/>
|
||||
{cloudIntegrationOptions.length > 0 && bot ? (
|
||||
@@ -401,12 +413,12 @@ export default function Integrations() {
|
||||
cloudIntegrationOptions={cloudIntegrationOptions}
|
||||
setSelectedIntegrationOption={setSelectedIntegrationOption as any}
|
||||
integrationOptionPress={(integrationOption: IntegrationOption) => {
|
||||
if (!bot.isActive) {
|
||||
if (!bot.isActive) {
|
||||
// case: bot is not active -> open modal to activate bot
|
||||
setIsActivateBotDialogOpen(true);
|
||||
return;
|
||||
}
|
||||
integrationOptionPress(integrationOption)
|
||||
}
|
||||
integrationOptionPress(integrationOption);
|
||||
}}
|
||||
integrationAuths={integrationAuths}
|
||||
handleDeleteIntegrationAuth={handleDeleteIntegrationAuth}
|
||||
@@ -421,5 +433,3 @@ export default function Integrations() {
|
||||
}
|
||||
|
||||
Integrations.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
|
||||
@@ -1,75 +1,64 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function AWSParameterStoreAuthorizeIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [accessKey, setAccessKey] = useState('');
|
||||
const [accessKeyErrorText, setAccessKeyErrorText] = useState('');
|
||||
const [accessSecretKey, setAccessSecretKey] = useState('');
|
||||
const [accessSecretKeyErrorText, setAccessSecretKeyErrorText] = useState('');
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessKeyErrorText('');
|
||||
setAccessSecretKeyErrorText('');
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
if (accessKey.length === 0) {
|
||||
setAccessKeyErrorText('Access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const [accessKey, setAccessKey] = useState('');
|
||||
const [accessKeyErrorText, setAccessKeyErrorText] = useState('');
|
||||
const [accessSecretKey, setAccessSecretKey] = useState('');
|
||||
const [accessSecretKeyErrorText, setAccessSecretKeyErrorText] = useState('');
|
||||
|
||||
if (accessSecretKey.length === 0) {
|
||||
setAccessSecretKeyErrorText('Secret access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessKeyErrorText('');
|
||||
setAccessSecretKeyErrorText('');
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'aws-parameter-store',
|
||||
accessId: accessKey,
|
||||
accessToken: accessSecretKey
|
||||
});
|
||||
|
||||
setAccessKey('');
|
||||
setAccessSecretKey('');
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-parameter-store/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
if (accessKey.length === 0) {
|
||||
setAccessKeyErrorText('Access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessSecretKey.length === 0) {
|
||||
setAccessSecretKeyErrorText('Secret access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'aws-parameter-store',
|
||||
accessId: accessKey,
|
||||
accessToken: accessSecretKey
|
||||
});
|
||||
|
||||
setAccessKey('');
|
||||
setAccessSecretKey('');
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-parameter-store/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center mb-4'>AWS Parameter Store Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="mb-4 text-center">AWS Parameter Store Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Access Key ID"
|
||||
errorText={accessKeyErrorText}
|
||||
isError={accessKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={accessKey}
|
||||
onChange={(e) => setAccessKey(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Secret Access Key"
|
||||
@@ -77,24 +66,22 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
|
||||
isError={accessSecretKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
value={accessSecretKey}
|
||||
onChange={(e) => setAccessSecretKey(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to AWS Parameter Store
|
||||
Connect to AWS Parameter Store
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
AWSParameterStoreAuthorizeIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,148 +2,142 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
const awsRegions = [
|
||||
{ name: 'US East (Ohio)', slug: 'us-east-2' },
|
||||
{ name: 'US East (N. Virginia)', slug: 'us-east-1' },
|
||||
{ name: 'US West (N. California)', slug: 'us-west-1' },
|
||||
{ name: 'US West (Oregon)', slug: 'us-west-2' },
|
||||
{ name: 'Africa (Cape Town)', slug: 'af-south-1' },
|
||||
{ name: 'Asia Pacific (Hong Kong)', slug: 'ap-east-1' },
|
||||
{ name: 'Asia Pacific (Hyderabad)', slug: 'ap-south-2' },
|
||||
{ name: 'Asia Pacific (Jakarta)', slug: 'ap-southeast-3' },
|
||||
{ name: 'Asia Pacific (Melbourne)', slug: 'ap-southeast-4' },
|
||||
{ name: 'Asia Pacific (Mumbai)', slug: 'ap-south-1' },
|
||||
{ name: 'Asia Pacific (Osaka)', slug: 'ap-northeast-3' },
|
||||
{ name: 'Asia Pacific (Seoul)', slug: 'ap-northeast-2' },
|
||||
{ name: 'Asia Pacific (Singapore)', slug: 'ap-southeast-1' },
|
||||
{ name: 'Asia Pacific (Sydney)', slug: 'ap-southeast-2' },
|
||||
{ name: 'Asia Pacific (Tokyo)', slug: 'ap-northeast-1' },
|
||||
{ name: 'Canada (Central)', slug: 'ca-central-1' },
|
||||
{ name: 'Europe (Frankfurt)', slug: 'eu-central-1' },
|
||||
{ name: 'Europe (Ireland)', slug: 'eu-west-1' },
|
||||
{ name: 'Europe (London)', slug: 'eu-west-2' },
|
||||
{ name: 'Europe (Milan)', slug: 'eu-south-1' },
|
||||
{ name: 'Europe (Paris)', slug: 'eu-west-3' },
|
||||
{ name: 'Europe (Spain)', slug: 'eu-south-2' },
|
||||
{ name: 'Europe (Stockholm)', slug: 'eu-north-1' },
|
||||
{ name: 'Europe (Zurich)', slug: 'eu-central-2' },
|
||||
{ name: 'Middle East (Bahrain)', slug: 'me-south-1' },
|
||||
{ name: 'Middle East (UAE)', slug: 'me-central-1' },
|
||||
{ name: 'South America (Sao Paulo)', slug: 'sa-east-1' },
|
||||
{ name: 'AWS GovCloud (US-East)', slug: 'us-gov-east-1' },
|
||||
{ name: 'AWS GovCloud (US-West)', slug: 'us-gov-west-1' },
|
||||
]
|
||||
{ name: 'US East (Ohio)', slug: 'us-east-2' },
|
||||
{ name: 'US East (N. Virginia)', slug: 'us-east-1' },
|
||||
{ name: 'US West (N. California)', slug: 'us-west-1' },
|
||||
{ name: 'US West (Oregon)', slug: 'us-west-2' },
|
||||
{ name: 'Africa (Cape Town)', slug: 'af-south-1' },
|
||||
{ name: 'Asia Pacific (Hong Kong)', slug: 'ap-east-1' },
|
||||
{ name: 'Asia Pacific (Hyderabad)', slug: 'ap-south-2' },
|
||||
{ name: 'Asia Pacific (Jakarta)', slug: 'ap-southeast-3' },
|
||||
{ name: 'Asia Pacific (Melbourne)', slug: 'ap-southeast-4' },
|
||||
{ name: 'Asia Pacific (Mumbai)', slug: 'ap-south-1' },
|
||||
{ name: 'Asia Pacific (Osaka)', slug: 'ap-northeast-3' },
|
||||
{ name: 'Asia Pacific (Seoul)', slug: 'ap-northeast-2' },
|
||||
{ name: 'Asia Pacific (Singapore)', slug: 'ap-southeast-1' },
|
||||
{ name: 'Asia Pacific (Sydney)', slug: 'ap-southeast-2' },
|
||||
{ name: 'Asia Pacific (Tokyo)', slug: 'ap-northeast-1' },
|
||||
{ name: 'Canada (Central)', slug: 'ca-central-1' },
|
||||
{ name: 'Europe (Frankfurt)', slug: 'eu-central-1' },
|
||||
{ name: 'Europe (Ireland)', slug: 'eu-west-1' },
|
||||
{ name: 'Europe (London)', slug: 'eu-west-2' },
|
||||
{ name: 'Europe (Milan)', slug: 'eu-south-1' },
|
||||
{ name: 'Europe (Paris)', slug: 'eu-west-3' },
|
||||
{ name: 'Europe (Spain)', slug: 'eu-south-2' },
|
||||
{ name: 'Europe (Stockholm)', slug: 'eu-north-1' },
|
||||
{ name: 'Europe (Zurich)', slug: 'eu-central-2' },
|
||||
{ name: 'Middle East (Bahrain)', slug: 'me-south-1' },
|
||||
{ name: 'Middle East (UAE)', slug: 'me-central-1' },
|
||||
{ name: 'South America (Sao Paulo)', slug: 'sa-east-1' },
|
||||
{ name: 'AWS GovCloud (US-East)', slug: 'us-gov-east-1' },
|
||||
{ name: 'AWS GovCloud (US-West)', slug: 'us-gov-west-1' }
|
||||
];
|
||||
|
||||
export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [selectedAWSRegion, setSelectedAWSRegion] = useState('');
|
||||
const [path, setPath] = useState('');
|
||||
const [pathErrorText, setPathErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setSelectedAWSRegion(awsRegions[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
const isValidAWSParameterStorePath = (secretPath: string) => {
|
||||
const pattern = /^\/([\w-]+\/)*[\w-]+\/$/;
|
||||
return pattern.test(secretPath) && secretPath.length <= 2048;
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [selectedAWSRegion, setSelectedAWSRegion] = useState('');
|
||||
const [path, setPath] = useState('');
|
||||
const [pathErrorText, setPathErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setSelectedAWSRegion(awsRegions[0].slug);
|
||||
}
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
|
||||
if (path !== '') {
|
||||
// case: path is not empty
|
||||
if (!isValidAWSParameterStorePath(path)) {
|
||||
// case: path is not valid for aws parameter store
|
||||
setPathErrorText('Path must be a valid path for SSM like /project/env/');
|
||||
return;
|
||||
}
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
const isValidAWSParameterStorePath = (secretPath: string) => {
|
||||
const pattern = /^\/([\w-]+\/)*[\w-]+\/$/;
|
||||
return pattern.test(secretPath) && secretPath.length <= 2048;
|
||||
};
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: null,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: selectedAWSRegion
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setPathErrorText('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (path !== '') {
|
||||
// case: path is not empty
|
||||
if (!isValidAWSParameterStorePath(path)) {
|
||||
// case: path is not valid for aws parameter store
|
||||
setPathErrorText('Path must be a valid path for SSM like /project/env/');
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: null,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: selectedAWSRegion
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setPathErrorText('');
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>AWS Parameter Store Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
};
|
||||
|
||||
return integrationAuth && workspace && selectedSourceEnvironment ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">AWS Parameter Store Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`flyio-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`flyio-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="AWS Region"
|
||||
>
|
||||
<FormControl label="AWS Region">
|
||||
<Select
|
||||
value={selectedAWSRegion}
|
||||
onValueChange={(val) => setSelectedAWSRegion(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{awsRegions.map((awsRegion) => (
|
||||
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
|
||||
@@ -152,30 +146,28 @@ export default function AWSParameterStoreCreateIntegrationPage() {
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Path"
|
||||
errorText={pathErrorText}
|
||||
isError={pathErrorText !== '' ?? false}
|
||||
>
|
||||
<FormControl label="Path" errorText={pathErrorText} isError={pathErrorText !== '' ?? false}>
|
||||
<Input
|
||||
placeholder={`/${workspace.name.toLowerCase().replace(/ /g, "-")}/${selectedSourceEnvironment}/`}
|
||||
placeholder={`/${workspace.name
|
||||
.toLowerCase()
|
||||
.replace(/ /g, '-')}/${selectedSourceEnvironment}/`}
|
||||
value={path}
|
||||
onChange={(e) => setPath(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
AWSParameterStoreCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,75 +1,64 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const [accessKey, setAccessKey] = useState('');
|
||||
const [accessKeyErrorText, setAccessKeyErrorText] = useState('');
|
||||
const [accessSecretKey, setAccessSecretKey] = useState('');
|
||||
const [accessSecretKeyErrorText, setAccessSecretKeyErrorText] = useState('');
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessKeyErrorText('');
|
||||
setAccessSecretKeyErrorText('');
|
||||
const router = useRouter();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
if (accessKey.length === 0) {
|
||||
setAccessKeyErrorText('Access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const [accessKey, setAccessKey] = useState('');
|
||||
const [accessKeyErrorText, setAccessKeyErrorText] = useState('');
|
||||
const [accessSecretKey, setAccessSecretKey] = useState('');
|
||||
const [accessSecretKeyErrorText, setAccessSecretKeyErrorText] = useState('');
|
||||
|
||||
if (accessSecretKey.length === 0) {
|
||||
setAccessSecretKeyErrorText('Secret access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessKeyErrorText('');
|
||||
setAccessSecretKeyErrorText('');
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'aws-secret-manager',
|
||||
accessId: accessKey,
|
||||
accessToken: accessSecretKey
|
||||
});
|
||||
|
||||
setAccessKey('');
|
||||
setAccessSecretKey('');
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-secret-manager/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
if (accessKey.length === 0) {
|
||||
setAccessKeyErrorText('Access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessSecretKey.length === 0) {
|
||||
setAccessSecretKeyErrorText('Secret access key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'aws-secret-manager',
|
||||
accessId: accessKey,
|
||||
accessToken: accessSecretKey
|
||||
});
|
||||
|
||||
setAccessKey('');
|
||||
setAccessSecretKey('');
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/aws-secret-manager/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center mb-4'>AWS Secret Manager Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="mb-4 text-center">AWS Secret Manager Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Access Key ID"
|
||||
errorText={accessKeyErrorText}
|
||||
isError={accessKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={accessKey}
|
||||
onChange={(e) => setAccessKey(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Secret Access Key"
|
||||
@@ -77,18 +66,18 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
isError={accessSecretKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
value={accessSecretKey}
|
||||
onChange={(e) => setAccessSecretKey(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to AWS Secret Manager
|
||||
Connect to AWS Secret Manager
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
@@ -96,5 +85,3 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
}
|
||||
|
||||
AWSSecretManagerCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,147 +2,141 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
const awsRegions = [
|
||||
{ name: 'US East (Ohio)', slug: 'us-east-2' },
|
||||
{ name: 'US East (N. Virginia)', slug: 'us-east-1' },
|
||||
{ name: 'US West (N. California)', slug: 'us-west-1' },
|
||||
{ name: 'US West (Oregon)', slug: 'us-west-2' },
|
||||
{ name: 'Africa (Cape Town)', slug: 'af-south-1' },
|
||||
{ name: 'Asia Pacific (Hong Kong)', slug: 'ap-east-1' },
|
||||
{ name: 'Asia Pacific (Hyderabad)', slug: 'ap-south-2' },
|
||||
{ name: 'Asia Pacific (Jakarta)', slug: 'ap-southeast-3' },
|
||||
{ name: 'Asia Pacific (Melbourne)', slug: 'ap-southeast-4' },
|
||||
{ name: 'Asia Pacific (Mumbai)', slug: 'ap-south-1' },
|
||||
{ name: 'Asia Pacific (Osaka)', slug: 'ap-northeast-3' },
|
||||
{ name: 'Asia Pacific (Seoul)', slug: 'ap-northeast-2' },
|
||||
{ name: 'Asia Pacific (Singapore)', slug: 'ap-southeast-1' },
|
||||
{ name: 'Asia Pacific (Sydney)', slug: 'ap-southeast-2' },
|
||||
{ name: 'Asia Pacific (Tokyo)', slug: 'ap-northeast-1' },
|
||||
{ name: 'Canada (Central)', slug: 'ca-central-1' },
|
||||
{ name: 'Europe (Frankfurt)', slug: 'eu-central-1' },
|
||||
{ name: 'Europe (Ireland)', slug: 'eu-west-1' },
|
||||
{ name: 'Europe (London)', slug: 'eu-west-2' },
|
||||
{ name: 'Europe (Milan)', slug: 'eu-south-1' },
|
||||
{ name: 'Europe (Paris)', slug: 'eu-west-3' },
|
||||
{ name: 'Europe (Spain)', slug: 'eu-south-2' },
|
||||
{ name: 'Europe (Stockholm)', slug: 'eu-north-1' },
|
||||
{ name: 'Europe (Zurich)', slug: 'eu-central-2' },
|
||||
{ name: 'Middle East (Bahrain)', slug: 'me-south-1' },
|
||||
{ name: 'Middle East (UAE)', slug: 'me-central-1' },
|
||||
{ name: 'South America (Sao Paulo)', slug: 'sa-east-1' },
|
||||
{ name: 'AWS GovCloud (US-East)', slug: 'us-gov-east-1' },
|
||||
{ name: 'AWS GovCloud (US-West)', slug: 'us-gov-west-1' },
|
||||
]
|
||||
{ name: 'US East (Ohio)', slug: 'us-east-2' },
|
||||
{ name: 'US East (N. Virginia)', slug: 'us-east-1' },
|
||||
{ name: 'US West (N. California)', slug: 'us-west-1' },
|
||||
{ name: 'US West (Oregon)', slug: 'us-west-2' },
|
||||
{ name: 'Africa (Cape Town)', slug: 'af-south-1' },
|
||||
{ name: 'Asia Pacific (Hong Kong)', slug: 'ap-east-1' },
|
||||
{ name: 'Asia Pacific (Hyderabad)', slug: 'ap-south-2' },
|
||||
{ name: 'Asia Pacific (Jakarta)', slug: 'ap-southeast-3' },
|
||||
{ name: 'Asia Pacific (Melbourne)', slug: 'ap-southeast-4' },
|
||||
{ name: 'Asia Pacific (Mumbai)', slug: 'ap-south-1' },
|
||||
{ name: 'Asia Pacific (Osaka)', slug: 'ap-northeast-3' },
|
||||
{ name: 'Asia Pacific (Seoul)', slug: 'ap-northeast-2' },
|
||||
{ name: 'Asia Pacific (Singapore)', slug: 'ap-southeast-1' },
|
||||
{ name: 'Asia Pacific (Sydney)', slug: 'ap-southeast-2' },
|
||||
{ name: 'Asia Pacific (Tokyo)', slug: 'ap-northeast-1' },
|
||||
{ name: 'Canada (Central)', slug: 'ca-central-1' },
|
||||
{ name: 'Europe (Frankfurt)', slug: 'eu-central-1' },
|
||||
{ name: 'Europe (Ireland)', slug: 'eu-west-1' },
|
||||
{ name: 'Europe (London)', slug: 'eu-west-2' },
|
||||
{ name: 'Europe (Milan)', slug: 'eu-south-1' },
|
||||
{ name: 'Europe (Paris)', slug: 'eu-west-3' },
|
||||
{ name: 'Europe (Spain)', slug: 'eu-south-2' },
|
||||
{ name: 'Europe (Stockholm)', slug: 'eu-north-1' },
|
||||
{ name: 'Europe (Zurich)', slug: 'eu-central-2' },
|
||||
{ name: 'Middle East (Bahrain)', slug: 'me-south-1' },
|
||||
{ name: 'Middle East (UAE)', slug: 'me-central-1' },
|
||||
{ name: 'South America (Sao Paulo)', slug: 'sa-east-1' },
|
||||
{ name: 'AWS GovCloud (US-East)', slug: 'us-gov-east-1' },
|
||||
{ name: 'AWS GovCloud (US-West)', slug: 'us-gov-west-1' }
|
||||
];
|
||||
|
||||
export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [selectedAWSRegion, setSelectedAWSRegion] = useState('');
|
||||
const [targetSecretName, setTargetSecretName] = useState('');
|
||||
const [targetSecretNameErrorText, setTargetSecretNameErrorText] = useState('');
|
||||
|
||||
// const [path, setPath] = useState('');
|
||||
// const [pathErrorText, setPathErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setSelectedAWSRegion(awsRegions[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
// const isValidAWSPath = (path: string) => {
|
||||
// const pattern = /^\/[\w./]+\/$/;
|
||||
// return pattern.test(path) && path.length <= 2048;
|
||||
// }
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
|
||||
if (targetSecretName.trim() === '') {
|
||||
setTargetSecretName('Secret name cannot be blank');
|
||||
return;
|
||||
}
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetSecretName.trim(),
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: selectedAWSRegion
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setTargetSecretNameErrorText('');
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [selectedAWSRegion, setSelectedAWSRegion] = useState('');
|
||||
const [targetSecretName, setTargetSecretName] = useState('');
|
||||
const [targetSecretNameErrorText, setTargetSecretNameErrorText] = useState('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
// const [path, setPath] = useState('');
|
||||
// const [pathErrorText, setPathErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setSelectedAWSRegion(awsRegions[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>AWS Secret Manager Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
// const isValidAWSPath = (path: string) => {
|
||||
// const pattern = /^\/[\w./]+\/$/;
|
||||
// return pattern.test(path) && path.length <= 2048;
|
||||
// }
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (targetSecretName.trim() === '') {
|
||||
setTargetSecretName('Secret name cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetSecretName.trim(),
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: selectedAWSRegion
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
setTargetSecretNameErrorText('');
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth && workspace && selectedSourceEnvironment ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">AWS Secret Manager Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`flyio-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`flyio-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="AWS Region"
|
||||
>
|
||||
<FormControl label="AWS Region">
|
||||
<Select
|
||||
value={selectedAWSRegion}
|
||||
onValueChange={(val) => setSelectedAWSRegion(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{awsRegions.map((awsRegion) => (
|
||||
<SelectItem value={awsRegion.slug} key={`flyio-environment-${awsRegion.slug}`}>
|
||||
@@ -157,24 +151,26 @@ export default function AWSSecretManagerCreateIntegrationPage() {
|
||||
isError={targetSecretNameErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder={`${workspace.name.toLowerCase().replace(/ /g, "-")}/${selectedSourceEnvironment}`}
|
||||
placeholder={`${workspace.name
|
||||
.toLowerCase()
|
||||
.replace(/ /g, '-')}/${selectedSourceEnvironment}`}
|
||||
value={targetSecretName}
|
||||
onChange={(e) => setTargetSecretName(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
AWSSecretManagerCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,99 +2,92 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function AzureKeyVaultCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
|
||||
const [vaultBaseUrl, setVaultBaseUrl] = useState('');
|
||||
const [vaultBaseUrlErrorText, setVaultBaseUrlErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (vaultBaseUrl.length === 0) {
|
||||
setVaultBaseUrlErrorText('Vault URI cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!vaultBaseUrl.startsWith('https://')
|
||||
|| !vaultBaseUrl.endsWith('vault.azure.net')
|
||||
) {
|
||||
setVaultBaseUrlErrorText('Vault URI must be like https://<vault_name>.vault.azure.net');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: vaultBaseUrl,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
|
||||
const [vaultBaseUrl, setVaultBaseUrl] = useState('');
|
||||
const [vaultBaseUrlErrorText, setVaultBaseUrlErrorText] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Azure Key Vault Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (vaultBaseUrl.length === 0) {
|
||||
setVaultBaseUrlErrorText('Vault URI cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vaultBaseUrl.startsWith('https://') || !vaultBaseUrl.endsWith('vault.azure.net')) {
|
||||
setVaultBaseUrlErrorText('Vault URI must be like https://<vault_name>.vault.azure.net');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: vaultBaseUrl,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth && workspace && selectedSourceEnvironment ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Azure Key Vault Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`azure-key-vault-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
@@ -106,24 +99,24 @@ export default function AzureKeyVaultCreateIntegrationPage() {
|
||||
isError={vaultBaseUrlErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder='https://example.vault.azure.net'
|
||||
placeholder="https://example.vault.azure.net"
|
||||
value={vaultBaseUrl}
|
||||
onChange={(e) => setVaultBaseUrl(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
AzureKeyVaultCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,40 +2,36 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function AzureKeyVaultOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'azure-key-vault'
|
||||
});
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
router.push(
|
||||
`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'azure-key-vault'
|
||||
});
|
||||
|
||||
router.push(
|
||||
`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
AzureKeyVaultOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,77 +1,62 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function CircleCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
setIsLoading(true);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'circleci',
|
||||
accessToken: apiKey,
|
||||
accessId: null,
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/circleci/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'circleci',
|
||||
accessToken: apiKey,
|
||||
accessId: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/circleci/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>CircleCI Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">CircleCI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="CircleCI API Token"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to CircleCI
|
||||
Connect to CircleCI
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
CircleCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,115 +2,114 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function CircleCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0 ) {
|
||||
setTargetApp(integrationAuthApps[0]?.name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>CircleCI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0]?.name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId:
|
||||
integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)
|
||||
?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">CircleCI Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="CircleCI Project"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="CircleCI Project" className="mt-4">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-app-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -121,20 +120,20 @@ export default function CircleCICreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
CircleCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,77 +1,66 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function FlyioCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [accessToken, setAccessToken] = useState('');
|
||||
const [accessTokenErrorText, setAccessTokenErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessTokenErrorText('');
|
||||
if (accessToken.length === 0) {
|
||||
setAccessTokenErrorText('Access token cannot be blank');
|
||||
return;
|
||||
}
|
||||
const router = useRouter();
|
||||
const [accessToken, setAccessToken] = useState('');
|
||||
const [accessTokenErrorText, setAccessTokenErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
setIsLoading(true);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setAccessTokenErrorText('');
|
||||
if (accessToken.length === 0) {
|
||||
setAccessTokenErrorText('Access token cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'flyio',
|
||||
accessId: null,
|
||||
accessToken
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/flyio/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'flyio',
|
||||
accessId: null,
|
||||
accessToken
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/flyio/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Fly.io Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Fly.io Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Fly.io Access Token"
|
||||
errorText={accessTokenErrorText}
|
||||
isError={accessTokenErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
placeholder=""
|
||||
value={accessToken}
|
||||
onChange={(e) => setAccessToken(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Fly.io
|
||||
Connect to Fly.io
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
FlyioCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,116 +2,113 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function FlyioCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: handle case where apps can be empty
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Fly.io Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: handle case where apps can be empty
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Fly.io Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Fly.io App"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="Fly.io App" className="mt-4">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-app-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -122,20 +119,20 @@ export default function FlyioCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
FlyioCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,118 +2,117 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function GitHubCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
const targetApp = integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId);
|
||||
|
||||
if (!targetApp || !targetApp.owner) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: targetApp.owner,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetAppId) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>GitHub Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
const targetApp = integrationAuthApps?.find(
|
||||
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
|
||||
);
|
||||
|
||||
if (!targetApp || !targetApp.owner) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: targetApp.owner,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetAppId ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">GitHub Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`azure-key-vault-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="GitHub Repo"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="GitHub Repo" className="mt-4">
|
||||
<Select
|
||||
value={targetAppId}
|
||||
onValueChange={(val) => setTargetAppId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.appId as string} key={`github-repo-${integrationAuthApp.appId}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.appId as string}
|
||||
key={`github-repo-${integrationAuthApp.appId}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -124,10 +123,10 @@ export default function GitHubCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
@@ -135,9 +134,9 @@ export default function GitHubCreateIntegrationPage() {
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
GitHubCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,39 +2,33 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function GitHubOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'github'
|
||||
});
|
||||
const router = useRouter();
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
router.push(
|
||||
`/integrations/github/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'github'
|
||||
});
|
||||
|
||||
router.push(`/integrations/github/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
GitHubOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,136 +2,136 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthTeams} from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthTeams
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
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' }
|
||||
]
|
||||
];
|
||||
|
||||
export default function GitLabCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
|
||||
const [targetTeamId, setTargetTeamId] = useState<string | null>(null);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? '',
|
||||
...(targetTeamId ? { teamId: targetTeamId } : {})
|
||||
});
|
||||
const { data: integrationAuthTeams } = useGetIntegrationAuthTeams(integrationAuthId as string ?? '');
|
||||
|
||||
const [targetEntity, setTargetEntity] = useState(gitLabEntities[0].value);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (targetEntity === 'group' && integrationAuthTeams && integrationAuthTeams.length > 0) {
|
||||
if (integrationAuthTeams) {
|
||||
if (integrationAuthTeams.length > 0) {
|
||||
// case: user is part of at least 1 group in GitLab
|
||||
setTargetTeamId(integrationAuthTeams[0].teamId);
|
||||
} else {
|
||||
// case: user is not part of any groups in GitLab
|
||||
setTargetTeamId('none');
|
||||
}
|
||||
}
|
||||
} else if (targetEntity === 'individual') {
|
||||
setTargetTeamId(null);
|
||||
}
|
||||
}, [targetEntity, integrationAuthTeams]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId))?.name ?? null,
|
||||
appId: targetAppId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [targetTeamId, setTargetTeamId] = useState<string | null>(null);
|
||||
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? '',
|
||||
...(targetTeamId ? { teamId: targetTeamId } : {})
|
||||
});
|
||||
const { data: integrationAuthTeams } = useGetIntegrationAuthTeams(
|
||||
(integrationAuthId as string) ?? ''
|
||||
);
|
||||
|
||||
const [targetEntity, setTargetEntity] = useState(gitLabEntities[0].value);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && integrationAuthTeams && targetAppId) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>GitLab Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (targetEntity === 'group' && integrationAuthTeams && integrationAuthTeams.length > 0) {
|
||||
if (integrationAuthTeams) {
|
||||
if (integrationAuthTeams.length > 0) {
|
||||
// case: user is part of at least 1 group in GitLab
|
||||
setTargetTeamId(integrationAuthTeams[0].teamId);
|
||||
} else {
|
||||
// case: user is not part of any groups in GitLab
|
||||
setTargetTeamId('none');
|
||||
}
|
||||
}
|
||||
} else if (targetEntity === 'individual') {
|
||||
setTargetTeamId(null);
|
||||
}
|
||||
}, [targetEntity, integrationAuthTeams]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app:
|
||||
integrationAuthApps?.find(
|
||||
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
|
||||
)?.name ?? null,
|
||||
appId: targetAppId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
integrationAuthTeams &&
|
||||
targetAppId ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">GitLab Integration</CardTitle>
|
||||
<FormControl label="Project Environment">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="GitLab Integration Type"
|
||||
>
|
||||
<FormControl label="GitLab Integration Type">
|
||||
<Select
|
||||
value={targetEntity}
|
||||
onValueChange={(val) => setTargetEntity(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{gitLabEntities.map((entity) => {
|
||||
return (
|
||||
@@ -143,17 +143,18 @@ export default function GitLabCreateIntegrationPage() {
|
||||
</Select>
|
||||
</FormControl>
|
||||
{targetEntity === 'group' && targetTeamId && (
|
||||
<FormControl
|
||||
label="GitLab Group"
|
||||
>
|
||||
<FormControl label="GitLab Group">
|
||||
<Select
|
||||
value={targetTeamId}
|
||||
onValueChange={(val) => setTargetTeamId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{integrationAuthTeams.length > 0 ? (
|
||||
integrationAuthTeams.map((integrationAuthTeam) => (
|
||||
<SelectItem value={integrationAuthTeam.teamId} key={`target-team-${integrationAuthTeam.teamId}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthTeam.teamId}
|
||||
key={`target-team-${integrationAuthTeam.teamId}`}
|
||||
>
|
||||
{integrationAuthTeam.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -165,18 +166,19 @@ export default function GitLabCreateIntegrationPage() {
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
<FormControl
|
||||
label="GitLab Project"
|
||||
>
|
||||
<FormControl label="GitLab Project">
|
||||
<Select
|
||||
value={targetAppId}
|
||||
onValueChange={(val) => setTargetAppId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.appId as string} key={`target-app-${integrationAuthApp.appId}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.appId as string}
|
||||
key={`target-app-${integrationAuthApp.appId}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -187,20 +189,20 @@ export default function GitLabCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
GitLabCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,38 +2,32 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function GitLabOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'gitlab'
|
||||
});
|
||||
const router = useRouter();
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
router.push(
|
||||
`/integrations/gitlab/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'gitlab'
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
router.push(`/integrations/gitlab/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
GitLabOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,114 +2,111 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function HerokuCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Heroku Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Heroku Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Heroku App"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="Heroku App" className="mt-4">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-app-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -120,20 +117,20 @@ export default function HerokuCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
HerokuCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,39 +2,33 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function HerokuOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'heroku'
|
||||
});
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
router.push(
|
||||
`/integrations/heroku/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'heroku'
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
router.push(`/integrations/heroku/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
HerokuOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,121 +2,123 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
const netlifyEnvironments = [
|
||||
{ name: 'Local development', slug: 'dev' },
|
||||
{ name: 'Branch deploys', slug: 'branch-deploy' },
|
||||
{ name: 'Deploy previews', slug: 'deploy-preview' },
|
||||
{ name: 'Production', slug: 'production' }
|
||||
]
|
||||
{ name: 'Local development', slug: 'dev' },
|
||||
{ name: 'Branch deploys', slug: 'branch-deploy' },
|
||||
{ name: 'Deploy previews', slug: 'deploy-preview' },
|
||||
{ name: 'Production', slug: 'production' }
|
||||
];
|
||||
|
||||
export default function NetlifyCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
const [targetEnvironment, setTargetEnvironment] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setTargetEnvironment(netlifyEnvironments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
const [targetEnvironment, setTargetEnvironment] = useState('');
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
setTargetEnvironment(netlifyEnvironments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp && targetEnvironment) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Netlify Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId:
|
||||
integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)
|
||||
?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp &&
|
||||
targetEnvironment ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Netlify Integration</CardTitle>
|
||||
<FormControl label="Project Environment">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Netlify Site"
|
||||
>
|
||||
<FormControl label="Netlify Site">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-app-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -127,35 +129,36 @@ export default function NetlifyCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Netlify Context"
|
||||
>
|
||||
<FormControl label="Netlify Context">
|
||||
<Select
|
||||
value={targetEnvironment}
|
||||
onValueChange={(val) => setTargetEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{netlifyEnvironments.map((netlifyEnvironment) => (
|
||||
<SelectItem value={netlifyEnvironment.slug} key={`target-environment-${netlifyEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={netlifyEnvironment.slug}
|
||||
key={`target-environment-${netlifyEnvironment.slug}`}
|
||||
>
|
||||
{netlifyEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
NetlifyCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,40 +2,34 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function NetlifyOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'netlify'
|
||||
});
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
router.push(
|
||||
`/integrations/netlify/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'netlify'
|
||||
});
|
||||
|
||||
router.push(`/integrations/netlify/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
NetlifyOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,77 +1,62 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function RailwayAuthorizeIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
setIsLoading(true);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'railway',
|
||||
accessId: null,
|
||||
accessToken: apiKey
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/railway/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'railway',
|
||||
accessId: null,
|
||||
accessToken: apiKey
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/railway/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Railway Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Railway API Key"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Railway
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Railway Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Railway API Key"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Railway
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
RailwayAuthorizeIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,206 +2,213 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import {
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthRailwayEnvironments,
|
||||
useGetIntegrationAuthRailwayServices
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthRailwayEnvironments,
|
||||
useGetIntegrationAuthRailwayServices
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function RailwayCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
const [targetEnvironmentId, setTargetEnvironmentId] = useState('');
|
||||
const [targetServiceId, setTargetServiceId] = useState('');
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
const { data: targetEnvironments } = useGetIntegrationAuthRailwayEnvironments({
|
||||
integrationAuthId: integrationAuthId as string ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
const { data: targetServices } = useGetIntegrationAuthRailwayServices({
|
||||
integrationAuthId: integrationAuthId as string ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
const router = useRouter();
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (targetEnvironments) {
|
||||
if (targetEnvironments.length > 0) {
|
||||
setTargetEnvironmentId(targetEnvironments[0].environmentId);
|
||||
} else {
|
||||
setTargetEnvironmentId('none');
|
||||
}
|
||||
}
|
||||
}, [targetEnvironments]);
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
const [targetEnvironmentId, setTargetEnvironmentId] = useState('');
|
||||
const [targetServiceId, setTargetServiceId] = useState('');
|
||||
|
||||
const filteredServices = targetServices
|
||||
?.concat({
|
||||
name: '',
|
||||
serviceId: ''
|
||||
});
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const targetApp = integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId);
|
||||
const targetEnvironment = targetEnvironments?.find((environment) => environment.environmentId === targetEnvironmentId);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
const { data: targetEnvironments } = useGetIntegrationAuthRailwayEnvironments({
|
||||
integrationAuthId: (integrationAuthId as string) ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
const { data: targetServices } = useGetIntegrationAuthRailwayServices({
|
||||
integrationAuthId: (integrationAuthId as string) ?? '',
|
||||
appId: targetAppId
|
||||
});
|
||||
|
||||
if (!targetApp || !targetApp.appId || !targetEnvironment) return;
|
||||
|
||||
const targetService = targetServices?.find((service) => service.serviceId === targetServiceId);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: targetApp.appId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: targetEnvironment.name,
|
||||
targetEnvironmentId: targetEnvironment.environmentId,
|
||||
targetService: targetService ? targetService.name : null,
|
||||
targetServiceId: targetService ? targetService.serviceId : null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return workspace && selectedSourceEnvironment && integrationAuthApps && targetEnvironments && filteredServices ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className="text-center">Railway Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
useEffect(() => {
|
||||
if (targetEnvironments) {
|
||||
if (targetEnvironments.length > 0) {
|
||||
setTargetEnvironmentId(targetEnvironments[0].environmentId);
|
||||
} else {
|
||||
setTargetEnvironmentId('none');
|
||||
}
|
||||
}
|
||||
}, [targetEnvironments]);
|
||||
|
||||
const filteredServices = targetServices?.concat({
|
||||
name: '',
|
||||
serviceId: ''
|
||||
});
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
const targetApp = integrationAuthApps?.find(
|
||||
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
|
||||
);
|
||||
const targetEnvironment = targetEnvironments?.find(
|
||||
(environment) => environment.environmentId === targetEnvironmentId
|
||||
);
|
||||
|
||||
if (!targetApp || !targetApp.appId || !targetEnvironment) return;
|
||||
|
||||
const targetService = targetServices?.find(
|
||||
(service) => service.serviceId === targetServiceId
|
||||
);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: targetApp.appId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: targetEnvironment.name,
|
||||
targetEnvironmentId: targetEnvironment.environmentId,
|
||||
targetService: targetService ? targetService.name : null,
|
||||
targetServiceId: targetService ? targetService.serviceId : null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetEnvironments &&
|
||||
filteredServices ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Railway Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Project">
|
||||
<Select
|
||||
value={targetAppId}
|
||||
onValueChange={(val) => setTargetAppId(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem
|
||||
value={integrationAuthApp.appId as string}
|
||||
key={`target-app-${integrationAuthApp.appId as string}`}
|
||||
>
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value="none" key="target-app-none">
|
||||
No projects found
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Project Environment">
|
||||
<Select
|
||||
value={targetEnvironmentId}
|
||||
onValueChange={(val) => setTargetEnvironmentId(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{targetEnvironments.length > 0 ? (
|
||||
targetEnvironments.map((targetEnvironment) => (
|
||||
<SelectItem
|
||||
value={targetEnvironment.environmentId as string}
|
||||
key={`target-environment-${targetEnvironment.environmentId as string}`}
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Project">
|
||||
<Select
|
||||
value={targetAppId}
|
||||
onValueChange={(val) => setTargetAppId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.appId as string} key={`target-app-${integrationAuthApp.appId as string}`}>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value="none" key="target-app-none">
|
||||
No projects found
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Project Environment">
|
||||
<Select
|
||||
value={targetEnvironmentId}
|
||||
onValueChange={(val) => setTargetEnvironmentId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{targetEnvironments.length > 0 ? (
|
||||
targetEnvironments.map((targetEnvironment) => (
|
||||
<SelectItem value={targetEnvironment.environmentId as string} key={`target-environment-${targetEnvironment.environmentId as string}`}>
|
||||
{targetEnvironment.name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value="none" key="target-environment-none">
|
||||
No environments found
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Service (Optional)">
|
||||
<Select
|
||||
value={targetServiceId}
|
||||
onValueChange={(val) => setTargetServiceId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
>
|
||||
{filteredServices.map((targetService) => (
|
||||
<SelectItem value={targetService.serviceId as string} key={`target-service-${targetService.serviceId as string}`}>
|
||||
{targetService.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
{targetEnvironment.name}
|
||||
</SelectItem>
|
||||
))
|
||||
) : (
|
||||
<SelectItem value="none" key="target-environment-none">
|
||||
No environments found
|
||||
</SelectItem>
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl label="Railway Service (Optional)">
|
||||
<Select
|
||||
value={targetServiceId}
|
||||
onValueChange={(val) => setTargetServiceId(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{filteredServices.map((targetService) => (
|
||||
<SelectItem
|
||||
value={targetService.serviceId as string}
|
||||
key={`target-service-${targetService.serviceId as string}`}
|
||||
>
|
||||
{targetService.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
RailwayCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
|
||||
|
||||
@@ -1,77 +1,62 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function RenderCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
setIsLoading(true);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'render',
|
||||
accessId: null,
|
||||
accessToken: apiKey
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/render/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'render',
|
||||
accessId: null,
|
||||
accessToken: apiKey
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/render/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Render Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Render Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Render API Key"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder='rnd_xxx'
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="rnd_xxx" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Render
|
||||
Connect to Render
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
RenderCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,115 +2,114 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps, useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function RenderCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Render Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId:
|
||||
integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)
|
||||
?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Render Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Render Service"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="Render Service" className="mt-4">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-app-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-app-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -121,20 +120,20 @@ export default function RenderCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
RenderCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
@@ -61,5 +60,3 @@ export default function SupabaseCreateIntegrationPage() {
|
||||
}
|
||||
|
||||
SupabaseCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,7 +2,6 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
useGetIntegrationAuthApps,
|
||||
@@ -138,5 +137,3 @@ export default function SupabaseCreateIntegrationPage() {
|
||||
}
|
||||
|
||||
SupabaseCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,77 +1,62 @@
|
||||
import { useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Input,
|
||||
} from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from "../../api/integrations/saveIntegrationAccessToken";
|
||||
import { Button, Card, CardTitle, FormControl, Input } from '../../../components/v2';
|
||||
import saveIntegrationAccessToken from '../../api/integrations/saveIntegrationAccessToken';
|
||||
|
||||
export default function TravisCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
const router = useRouter();
|
||||
const [apiKey, setApiKey] = useState('');
|
||||
const [apiKeyErrorText, setApiKeyErrorText] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
setIsLoading(true);
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
setApiKeyErrorText('');
|
||||
if (apiKey.length === 0) {
|
||||
setApiKeyErrorText('API Key cannot be blank');
|
||||
return;
|
||||
}
|
||||
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'travisci',
|
||||
accessToken: apiKey,
|
||||
accessId: null,
|
||||
});
|
||||
setIsLoading(true);
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(
|
||||
`/integrations/travisci/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const integrationAuth = await saveIntegrationAccessToken({
|
||||
workspaceId: localStorage.getItem('projectData.id'),
|
||||
integration: 'travisci',
|
||||
accessToken: apiKey,
|
||||
accessId: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/travisci/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Travis CI Integration</CardTitle>
|
||||
<FormControl
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Travis CI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Travis CI API Token"
|
||||
errorText={apiKeyErrorText}
|
||||
isError={apiKeyErrorText !== '' ?? false}
|
||||
>
|
||||
<Input
|
||||
placeholder=''
|
||||
value={apiKey}
|
||||
onChange={(e) => setApiKey(e.target.value)}
|
||||
/>
|
||||
<Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
|
||||
</FormControl>
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
isLoading={isLoading}
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
>
|
||||
Connect to Travis CI
|
||||
Connect to Travis CI
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
TravisCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,115 +2,114 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { useGetIntegrationAuthApps,useGetIntegrationAuthById } from '../../../hooks/api/integrationAuth';
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
export default function TravisCICreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId: (integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp))?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null,
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetApp, setTargetApp] = useState('');
|
||||
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetApp) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Travis CI Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetApp(integrationAuthApps[0].name);
|
||||
} else {
|
||||
setTargetApp('none');
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp,
|
||||
appId:
|
||||
integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)
|
||||
?.appId ?? null,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment: null,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path: null,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetApp ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Travis CI Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`source-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`source-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Travis CI Project"
|
||||
className='mt-4'
|
||||
>
|
||||
<FormControl label="Travis CI Project" className="mt-4">
|
||||
<Select
|
||||
value={targetApp}
|
||||
onValueChange={(val) => setTargetApp(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.name} key={`target-environment-${integrationAuthApp.name}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.name}
|
||||
key={`target-environment-${integrationAuthApp.name}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -121,20 +120,20 @@ export default function TravisCICreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
TravisCICreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,140 +2,136 @@ import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../components/utilities/withTranslateProps';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardTitle,
|
||||
FormControl,
|
||||
Select,
|
||||
SelectItem
|
||||
} from '../../../components/v2';
|
||||
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from '../../../components/v2';
|
||||
import {
|
||||
useGetIntegrationAuthApps,
|
||||
useGetIntegrationAuthById,
|
||||
useGetIntegrationAuthVercelBranches
|
||||
} from '../../../hooks/api/integrationAuth';
|
||||
import { useGetWorkspaceById } from '../../../hooks/api/workspace';
|
||||
import createIntegration from "../../api/integrations/createIntegration";
|
||||
import createIntegration from '../../api/integrations/createIntegration';
|
||||
|
||||
const vercelEnvironments = [
|
||||
{ name: 'Development', slug: 'development' },
|
||||
{ name: 'Preview', slug: 'preview' },
|
||||
{ name: 'Production', slug: 'production' }
|
||||
]
|
||||
{ name: 'Development', slug: 'development' },
|
||||
{ name: 'Preview', slug: 'preview' },
|
||||
{ name: 'Production', slug: 'production' }
|
||||
];
|
||||
|
||||
export default function VercelCreateIntegrationPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
const [targetEnvironment, setTargetEnvironment] = useState('');
|
||||
const [targetBranch, setTargetBranch] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState('');
|
||||
const [targetAppId, setTargetAppId] = useState('');
|
||||
const [targetEnvironment, setTargetEnvironment] = useState('');
|
||||
const [targetBranch, setTargetBranch] = useState('');
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById(integrationAuthId as string ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: integrationAuthId as string ?? ''
|
||||
});
|
||||
|
||||
const { data: branches } = useGetIntegrationAuthVercelBranches({
|
||||
integrationAuthId: integrationAuthId as string,
|
||||
appId: targetAppId,
|
||||
});
|
||||
|
||||
const filteredBranches = branches
|
||||
?.filter((branchName) => branchName !== 'main')
|
||||
.concat('');
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
setTargetEnvironment(vercelEnvironments[0].slug);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
setTargetEnvironment(vercelEnvironments[0].slug);
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
const { integrationAuthId } = queryString.parse(router.asPath.split('?')[1]);
|
||||
const { data: workspace } = useGetWorkspaceById(localStorage.getItem('projectData.id') ?? '');
|
||||
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? '');
|
||||
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
|
||||
integrationAuthId: (integrationAuthId as string) ?? ''
|
||||
});
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const targetApp = integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId);
|
||||
|
||||
if (!targetApp || !targetApp.appId) return;
|
||||
|
||||
const path = (targetEnvironment === 'preview' && targetBranch !== '') ? targetBranch : null;
|
||||
const { data: branches } = useGetIntegrationAuthVercelBranches({
|
||||
integrationAuthId: integrationAuthId as string,
|
||||
appId: targetAppId
|
||||
});
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: targetApp.appId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(
|
||||
`/integrations/${localStorage.getItem('projectData.id')}`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
const filteredBranches = branches?.filter((branchName) => branchName !== 'main').concat('');
|
||||
|
||||
useEffect(() => {
|
||||
if (workspace) {
|
||||
setSelectedSourceEnvironment(workspace.environments[0].slug);
|
||||
}
|
||||
|
||||
return (integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps && targetAppId && targetEnvironment) ? (
|
||||
<div className="h-full w-full flex justify-center items-center">
|
||||
<Card className="max-w-md p-8 rounded-md">
|
||||
<CardTitle className='text-center'>Vercel Integration</CardTitle>
|
||||
<FormControl
|
||||
label="Project Environment"
|
||||
className='mt-4'
|
||||
>
|
||||
}, [workspace]);
|
||||
|
||||
useEffect(() => {
|
||||
if (integrationAuthApps) {
|
||||
if (integrationAuthApps.length > 0) {
|
||||
setTargetAppId(integrationAuthApps[0].appId as string);
|
||||
setTargetEnvironment(vercelEnvironments[0].slug);
|
||||
} else {
|
||||
setTargetAppId('none');
|
||||
setTargetEnvironment(vercelEnvironments[0].slug);
|
||||
}
|
||||
}
|
||||
}, [integrationAuthApps]);
|
||||
|
||||
const handleButtonClick = async () => {
|
||||
try {
|
||||
if (!integrationAuth?._id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
|
||||
const targetApp = integrationAuthApps?.find(
|
||||
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
|
||||
);
|
||||
|
||||
if (!targetApp || !targetApp.appId) return;
|
||||
|
||||
const path = targetEnvironment === 'preview' && targetBranch !== '' ? targetBranch : null;
|
||||
|
||||
await createIntegration({
|
||||
integrationAuthId: integrationAuth?._id,
|
||||
isActive: true,
|
||||
app: targetApp.name,
|
||||
appId: targetApp.appId,
|
||||
sourceEnvironment: selectedSourceEnvironment,
|
||||
targetEnvironment,
|
||||
targetEnvironmentId: null,
|
||||
targetService: null,
|
||||
targetServiceId: null,
|
||||
owner: null,
|
||||
path,
|
||||
region: null
|
||||
});
|
||||
|
||||
setIsLoading(false);
|
||||
router.push(`/integrations/${localStorage.getItem('projectData.id')}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
};
|
||||
|
||||
return integrationAuth &&
|
||||
workspace &&
|
||||
selectedSourceEnvironment &&
|
||||
integrationAuthApps &&
|
||||
targetAppId &&
|
||||
targetEnvironment ? (
|
||||
<div className="flex h-full w-full items-center justify-center">
|
||||
<Card className="max-w-md rounded-md p-8">
|
||||
<CardTitle className="text-center">Vercel Integration</CardTitle>
|
||||
<FormControl label="Project Environment" className="mt-4">
|
||||
<Select
|
||||
value={selectedSourceEnvironment}
|
||||
onValueChange={(val) => setSelectedSourceEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{workspace?.environments.map((sourceEnvironment) => (
|
||||
<SelectItem value={sourceEnvironment.slug} key={`azure-key-vault-environment-${sourceEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={sourceEnvironment.slug}
|
||||
key={`azure-key-vault-environment-${sourceEnvironment.slug}`}
|
||||
>
|
||||
{sourceEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Vercel App"
|
||||
>
|
||||
<FormControl label="Vercel App">
|
||||
<Select
|
||||
value={targetAppId}
|
||||
onValueChange={(val) => setTargetAppId(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
{integrationAuthApps.length > 0 ? (
|
||||
integrationAuthApps.map((integrationAuthApp) => (
|
||||
<SelectItem value={integrationAuthApp.appId as string} key={`target-app-${integrationAuthApp.appId as string}`}>
|
||||
<SelectItem
|
||||
value={integrationAuthApp.appId as string}
|
||||
key={`target-app-${integrationAuthApp.appId as string}`}
|
||||
>
|
||||
{integrationAuthApp.name}
|
||||
</SelectItem>
|
||||
))
|
||||
@@ -146,29 +142,28 @@ export default function VercelCreateIntegrationPage() {
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
<FormControl
|
||||
label="Vercel App Environment"
|
||||
>
|
||||
<FormControl label="Vercel App Environment">
|
||||
<Select
|
||||
value={targetEnvironment}
|
||||
onValueChange={(val) => setTargetEnvironment(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{vercelEnvironments.map((vercelEnvironment) => (
|
||||
<SelectItem value={vercelEnvironment.slug} key={`target-environment-${vercelEnvironment.slug}`}>
|
||||
<SelectItem
|
||||
value={vercelEnvironment.slug}
|
||||
key={`target-environment-${vercelEnvironment.slug}`}
|
||||
>
|
||||
{vercelEnvironment.name}
|
||||
</SelectItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
{targetEnvironment === 'preview' && filteredBranches && (
|
||||
<FormControl
|
||||
label="Vercel Preview Branch (Optional)"
|
||||
>
|
||||
<FormControl label="Vercel Preview Branch (Optional)">
|
||||
<Select
|
||||
value={targetBranch}
|
||||
onValueChange={(val) => setTargetBranch(val)}
|
||||
className='w-full border border-mineshaft-500'
|
||||
className="w-full border border-mineshaft-500"
|
||||
>
|
||||
{filteredBranches.map((branchName) => (
|
||||
<SelectItem value={branchName} key={`target-branch-${branchName}`}>
|
||||
@@ -178,20 +173,20 @@ export default function VercelCreateIntegrationPage() {
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
<Button
|
||||
<Button
|
||||
onClick={handleButtonClick}
|
||||
color="mineshaft"
|
||||
className='mt-4'
|
||||
color="mineshaft"
|
||||
className="mt-4"
|
||||
isLoading={isLoading}
|
||||
isDisabled={integrationAuthApps.length === 0}
|
||||
>
|
||||
Create Integration
|
||||
Create Integration
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
) : <div />
|
||||
) : (
|
||||
<div />
|
||||
);
|
||||
}
|
||||
|
||||
VercelCreateIntegrationPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -2,40 +2,34 @@ import { useEffect } from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { getTranslatedServerSideProps } from '../../../../components/utilities/withTranslateProps';
|
||||
import AuthorizeIntegration from "../../../api/integrations/authorizeIntegration";
|
||||
import AuthorizeIntegration from '../../../api/integrations/authorizeIntegration';
|
||||
|
||||
export default function VercelOAuth2CallbackPage() {
|
||||
const router = useRouter();
|
||||
const router = useRouter();
|
||||
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'vercel'
|
||||
});
|
||||
const { code, state } = queryString.parse(router.asPath.split('?')[1]);
|
||||
|
||||
router.push(
|
||||
`/integrations/vercel/create?integrationAuthId=${integrationAuth._id}`
|
||||
);
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
try {
|
||||
// validate state
|
||||
if (state !== localStorage.getItem('latestCSRFToken')) return;
|
||||
localStorage.removeItem('latestCSRFToken');
|
||||
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />
|
||||
const integrationAuth = await AuthorizeIntegration({
|
||||
workspaceId: localStorage.getItem('projectData.id') as string,
|
||||
code: code as string,
|
||||
integration: 'vercel'
|
||||
});
|
||||
|
||||
router.push(`/integrations/vercel/create?integrationAuthId=${integrationAuth._id}`);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
})();
|
||||
}, []);
|
||||
|
||||
return <div />;
|
||||
}
|
||||
|
||||
VercelOAuth2CallbackPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['integrations']);
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import ListBox from '@app/components/basic/Listbox';
|
||||
import LoginStep from '@app/components/login/LoginStep';
|
||||
import MFAStep from '@app/components/login/MFAStep';
|
||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { isLoggedIn } from '@app/reactQuery';
|
||||
|
||||
import getWorkspaces from './api/workspace/getWorkspaces';
|
||||
@@ -20,7 +19,6 @@ export default function Login() {
|
||||
const [step, setStep] = useState(1);
|
||||
const { t } = useTranslation();
|
||||
const lang = router.locale ?? 'en';
|
||||
|
||||
|
||||
const setLanguage = async (to: string) => {
|
||||
router.push('/login', '/login', { locale: to });
|
||||
@@ -43,7 +41,7 @@ export default function Login() {
|
||||
redirectToDashboard();
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
const renderStep = (loginStep: number) => {
|
||||
// TODO: add MFA step
|
||||
switch (loginStep) {
|
||||
@@ -59,45 +57,38 @@ export default function Login() {
|
||||
);
|
||||
case 2:
|
||||
// TODO: add MFA step
|
||||
return (
|
||||
<MFAStep
|
||||
email={email}
|
||||
password={password}
|
||||
/>
|
||||
);
|
||||
return <MFAStep email={email} password={password} />;
|
||||
default:
|
||||
return <div />
|
||||
return <div />;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
|
||||
<div className="flex h-screen flex-col justify-start bg-bunker-800 px-6">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('login:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('login.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={t('login:og-title') ?? ''} />
|
||||
<meta name="og:description" content={t('login:og-description') ?? ''} />
|
||||
<meta property="og:title" content={t('login.og-title') ?? ''} />
|
||||
<meta name="og:description" content={t('login.og-description') ?? ''} />
|
||||
</Head>
|
||||
<Link href="/">
|
||||
<div className="flex justify-center mb-8 mt-20 cursor-pointer">
|
||||
<div className="mb-8 mt-20 flex cursor-pointer justify-center">
|
||||
<Image src="/images/biglogo.png" height={90} width={120} alt="long logo" />
|
||||
</div>
|
||||
</Link>
|
||||
{renderStep(step)}
|
||||
<div className="absolute right-4 top-0 mt-4 flex items-center justify-center">
|
||||
<div className="w-48 mx-auto">
|
||||
<div className="mx-auto w-48">
|
||||
<ListBox
|
||||
isSelected={lang}
|
||||
onChange={setLanguage}
|
||||
data={['en', 'ko', 'fr', 'pt-BR']}
|
||||
isFull
|
||||
text={`${t('common:language')}: `}
|
||||
text={`${t('common.language')}: `}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = getTranslatedStaticProps(['auth', 'login', 'mfa']);
|
||||
|
||||
@@ -3,7 +3,6 @@ import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import getOrganizationUserProjects from './api/organization/GetOrgUserProjects';
|
||||
|
||||
@@ -11,7 +10,9 @@ export default function NoProjects() {
|
||||
const router = useRouter();
|
||||
|
||||
const redirectUser = async () => {
|
||||
const workspaces = await getOrganizationUserProjects({ orgId: String(localStorage.getItem("orgData.id")) });
|
||||
const workspaces = await getOrganizationUserProjects({
|
||||
orgId: String(localStorage.getItem('orgData.id'))
|
||||
});
|
||||
if (workspaces.length > 0) {
|
||||
router.push(`/dashboard/${workspaces[0]._id}`);
|
||||
}
|
||||
@@ -25,20 +26,19 @@ export default function NoProjects() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="h-full flex flex-col items-center justify-center text-gray-300 text-lg text-center w-11/12 mr-auto">
|
||||
<div className="mr-auto flex h-full w-11/12 flex-col items-center justify-center text-center text-lg text-gray-300">
|
||||
<div className="mb-6 mt-16 mr-16">
|
||||
<Image src="/images/dragon-cant-find.svg" height={270} width={436} alt="google logo" />
|
||||
</div>
|
||||
<div className="px-4 rounded-md bg-bunker-500 mb-8 text-bunker-300 shadow-xl py-6">
|
||||
<div className="mb-8 rounded-md bg-bunker-500 px-4 py-6 text-bunker-300 shadow-xl">
|
||||
<div className="max-w-md">
|
||||
You are not part of any projects in this organization yet. When you are, they will appear
|
||||
here.
|
||||
</div>
|
||||
<div className="max-w-md mt-4">
|
||||
Create a new project, or ask other organization members to give you neccessary
|
||||
permissions.
|
||||
<div className="mt-4 max-w-md">
|
||||
Create a new project, or ask other organization members to give you necessary permissions.
|
||||
</div>
|
||||
<div className="mt-6 mx-2">
|
||||
<div className="mx-2 mt-6">
|
||||
<Button text="Check again" onButtonPressed={redirectUser} size="md" color="mineshaft" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -47,5 +47,3 @@ export default function NoProjects() {
|
||||
}
|
||||
|
||||
NoProjects.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['noprojects']);
|
||||
|
||||
@@ -12,7 +12,6 @@ import Button from '@app/components/basic/buttons/Button';
|
||||
import InputField from '@app/components/basic/InputField';
|
||||
import passwordCheck from '@app/components/utilities/checks/PasswordCheck';
|
||||
import Aes256Gcm from '@app/components/utilities/cryptography/aes-256-gcm';
|
||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import { deriveArgonKey } from '../components/utilities/cryptography/crypto';
|
||||
import EmailVerifyOnPasswordReset from './api/auth/EmailVerifyOnPasswordReset';
|
||||
@@ -83,9 +82,9 @@ export default function PasswordReset() {
|
||||
parallelism: 1,
|
||||
hashLen: 32
|
||||
});
|
||||
|
||||
|
||||
if (!derivedKey) throw new Error('Failed to derive key from password');
|
||||
|
||||
|
||||
const key = crypto.randomBytes(32);
|
||||
|
||||
// create encrypted private key by encrypting the private
|
||||
@@ -98,7 +97,7 @@ export default function PasswordReset() {
|
||||
text: privateKey,
|
||||
secret: key
|
||||
});
|
||||
|
||||
|
||||
// create the protected key by encrypting the symmetric key
|
||||
// [key] with the derived key
|
||||
const {
|
||||
@@ -134,12 +133,12 @@ export default function PasswordReset() {
|
||||
|
||||
// Click a button to confirm email
|
||||
const stepConfirmEmail = (
|
||||
<div className="bg-bunker flex flex-col items-center w-full py-6 max-w-xs md:max-w-lg my-32 px-4 md:px-6 mx-1 rounded-xl drop-shadow-xl">
|
||||
<p className="text-4xl text-center font-semibold mb-8 flex justify-center text-transparent bg-clip-text bg-gradient-to-br from-sky-400 to-primary">
|
||||
<div className="my-32 mx-1 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker py-6 px-4 drop-shadow-xl md:max-w-lg md:px-6">
|
||||
<p className="mb-8 flex justify-center bg-gradient-to-br from-sky-400 to-primary bg-clip-text text-center text-4xl font-semibold text-transparent">
|
||||
Confirm your email
|
||||
</p>
|
||||
<Image src="/images/envelope.svg" height={262} width={410} alt="verify email" />
|
||||
<div className="flex flex-col items-center justify-center md:p-2 max-h-24 max-w-md mx-auto text-lg px-4 mt-4 mb-2">
|
||||
<div className="mx-auto mt-4 mb-2 flex max-h-24 max-w-md flex-col items-center justify-center px-4 text-lg md:p-2">
|
||||
<Button
|
||||
text="Confirm Email"
|
||||
onButtonPressed={async () => {
|
||||
@@ -163,16 +162,16 @@ export default function PasswordReset() {
|
||||
|
||||
// Input backup key
|
||||
const stepInputBackupKey = (
|
||||
<div className="bg-bunker flex flex-col items-center w-full pt-6 pb-3 max-w-xs md:max-w-lg my-32 px-4 md:px-6 mx-1 rounded-xl drop-shadow-xl">
|
||||
<p className="text-2xl md:text-3xl w-max mx-auto flex justify-center font-semibold text-bunker-100 mb-4">
|
||||
<div className="my-32 mx-1 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker px-4 pt-6 pb-3 drop-shadow-xl md:max-w-lg md:px-6">
|
||||
<p className="mx-auto mb-4 flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
|
||||
Enter your backup key
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center md:pb-4 mt-4 md:mx-2">
|
||||
<p className="text-sm flex justify-center text-gray-400 w-max max-w-md">
|
||||
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
|
||||
<p className="flex w-max max-w-md justify-center text-sm text-gray-400">
|
||||
You can find it in your emrgency kit. You had to download the enrgency kit during signup.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-full md:p-2 rounded-lg mt-4 md:mt-0 max-h-24 md:max-h-28">
|
||||
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
|
||||
<InputField
|
||||
label="Backup Key"
|
||||
onChangeHandler={setBackupKey}
|
||||
@@ -184,8 +183,8 @@ export default function PasswordReset() {
|
||||
errorText="Something is wrong with the backup key"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full md:p-2 max-h-20 max-w-md mt-4 mx-auto text-sm">
|
||||
<div className="text-l mt-6 m-8 px-8 py-3 text-lg">
|
||||
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
|
||||
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
|
||||
<Button
|
||||
text="Submit Backup Key"
|
||||
onButtonPressed={() => getEncryptedKeyHandler()}
|
||||
@@ -198,16 +197,16 @@ export default function PasswordReset() {
|
||||
|
||||
// Enter new password
|
||||
const stepEnterNewPassword = (
|
||||
<div className="bg-bunker flex flex-col items-center w-full pt-6 pb-3 max-w-xs md:max-w-lg my-32 px-4 md:px-6 mx-1 rounded-xl drop-shadow-xl">
|
||||
<p className="text-2xl md:text-3xl w-max mx-auto flex justify-center font-semibold text-bunker-100">
|
||||
<div className="my-32 mx-1 flex w-full max-w-xs flex-col items-center rounded-xl bg-bunker px-4 pt-6 pb-3 drop-shadow-xl md:max-w-lg md:px-6">
|
||||
<p className="mx-auto flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
|
||||
Enter new password
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center md:pb-4 mt-1 md:mx-2">
|
||||
<p className="text-sm flex justify-center text-gray-400 w-max max-w-md">
|
||||
<div className="mt-1 flex flex-row items-center justify-center md:mx-2 md:pb-4">
|
||||
<p className="flex w-max max-w-md justify-center text-sm text-gray-400">
|
||||
Make sure you save it somewhere save.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-full md:p-2 rounded-lg mt-4 md:mt-0 max-h-24 md:max-h-28">
|
||||
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
|
||||
<InputField
|
||||
label="New Password"
|
||||
onChangeHandler={(password) => {
|
||||
@@ -229,23 +228,23 @@ export default function PasswordReset() {
|
||||
/>
|
||||
</div>
|
||||
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 mx-2 flex flex-col items-start py-2 rounded-md max-w-md mb-2">
|
||||
<div className="text-gray-400 text-sm mb-1">Password should contain at least:</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="mx-2 mt-3 mb-2 flex w-full max-w-md flex-col items-start rounded-md bg-white/5 px-2 py-2">
|
||||
<div className="mb-1 text-sm text-gray-400">Password should contain at least:</div>
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div className={`${passwordErrorLength ? 'text-gray-400' : 'text-gray-600'} text-sm`}>
|
||||
14 characters
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div
|
||||
className={`${passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'} text-sm`}
|
||||
@@ -253,11 +252,11 @@ export default function PasswordReset() {
|
||||
1 lowercase character
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div className={`${passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'} text-sm`}>
|
||||
1 number
|
||||
@@ -267,8 +266,8 @@ export default function PasswordReset() {
|
||||
) : (
|
||||
<div className="py-2" />
|
||||
)}
|
||||
<div className="flex flex-col items-center justify-center w-full md:p-2 max-h-20 max-w-md mt-4 mx-auto text-sm">
|
||||
<div className="text-l mt-6 m-8 px-8 py-3 text-lg">
|
||||
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
|
||||
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
|
||||
<Button
|
||||
text="Submit New Password"
|
||||
onButtonPressed={() => resetPasswordHandler()}
|
||||
@@ -280,12 +279,10 @@ export default function PasswordReset() {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen w-full flex flex-col items-center justify-center">
|
||||
<div className="flex h-screen w-full flex-col items-center justify-center bg-bunker-800">
|
||||
{step === 1 && stepConfirmEmail}
|
||||
{step === 2 && stepInputBackupKey}
|
||||
{step === 3 && stepEnterNewPassword}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = getTranslatedStaticProps([]);
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { plans as plansConstant } from 'public/data/frequentConstants';
|
||||
|
||||
import Plan from '@app/components/billing/Plan';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import getOrganizationSubscriptions from '../../api/organization/GetOrgSubscription';
|
||||
import getOrganizationUsers from '../../api/organization/GetOrgUsers';
|
||||
@@ -19,43 +18,43 @@ export default function SettingsBilling() {
|
||||
const plans = [
|
||||
{
|
||||
key: 1,
|
||||
name: t('billing:starter.name')!,
|
||||
price: t('billing:free')!,
|
||||
priceExplanation: t('billing:starter.price-explanation')!,
|
||||
text: t('billing:starter.text')!,
|
||||
subtext: t('billing:starter.subtext')!,
|
||||
buttonTextMain: t('billing:downgrade')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
name: t('billing.starter.name')!,
|
||||
price: t('billing.free')!,
|
||||
priceExplanation: t('billing.starter.price-explanation')!,
|
||||
text: t('billing.starter.text')!,
|
||||
subtext: t('billing.starter.subtext')!,
|
||||
buttonTextMain: t('billing.downgrade')!,
|
||||
buttonTextSecondary: t('billing.learn-more')!,
|
||||
current: currentPlan === plansConstant.starter
|
||||
},
|
||||
{
|
||||
key: 2,
|
||||
name: 'Team',
|
||||
price: '$8',
|
||||
priceExplanation: t('billing:professional.price-explanation')!,
|
||||
priceExplanation: t('billing.professional.price-explanation')!,
|
||||
text: 'For teams that want to improve their efficiency and security.',
|
||||
buttonTextMain: t('billing:upgrade')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
buttonTextMain: t('billing.upgrade')!,
|
||||
buttonTextSecondary: t('billing.learn-more')!,
|
||||
current: currentPlan === plansConstant.team
|
||||
},
|
||||
{
|
||||
key: 3,
|
||||
name: t('billing:professional.name')!,
|
||||
name: t('billing.professional.name')!,
|
||||
price: '$18',
|
||||
priceExplanation: t('billing:professional.price-explanation')!,
|
||||
text: t('billing:enterprise.text')!,
|
||||
subtext: t('billing:professional.subtext')!,
|
||||
buttonTextMain: t('billing:upgrade')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
priceExplanation: t('billing.professional.price-explanation')!,
|
||||
text: t('billing.enterprise.text')!,
|
||||
subtext: t('billing.professional.subtext')!,
|
||||
buttonTextMain: t('billing.upgrade')!,
|
||||
buttonTextSecondary: t('billing.learn-more')!,
|
||||
current: currentPlan === plansConstant.professional
|
||||
},
|
||||
{
|
||||
key: 4,
|
||||
name: t('billing:enterprise.name')!,
|
||||
price: t('billing:custom-pricing')!,
|
||||
name: t('billing.enterprise.name')!,
|
||||
price: t('billing.custom-pricing')!,
|
||||
text: 'Boost the security and efficiency of your engineering teams.',
|
||||
buttonTextMain: t('billing:schedule-demo')!,
|
||||
buttonTextSecondary: t('billing:learn-more')!,
|
||||
buttonTextMain: t('billing.schedule-demo')!,
|
||||
buttonTextSecondary: t('billing.learn-more')!,
|
||||
current: false
|
||||
}
|
||||
];
|
||||
@@ -77,30 +76,30 @@ export default function SettingsBilling() {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 pb-4 flex flex-col justify-between text-white">
|
||||
<div className="flex flex-col justify-between bg-bunker-800 pb-4 text-white">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('billing:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('billing.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full pb-2">
|
||||
<NavHeader pageName={t('billing:title')} />
|
||||
<div className="flex flex-row justify-between items-center ml-6 my-8 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">{t('billing:title')}</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">{t('billing:description')}</p>
|
||||
<NavHeader pageName={t('billing.title')} />
|
||||
<div className="my-8 ml-6 flex max-w-5xl flex-row items-center justify-between text-xl">
|
||||
<div className="flex flex-col items-start justify-start text-3xl">
|
||||
<p className="mr-4 font-semibold text-gray-200">{t('billing.title')}</p>
|
||||
<p className="mr-4 text-base font-normal text-gray-400">{t('billing.description')}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50 w-max">
|
||||
<p className="text-xl font-semibold">{t('billing:subscription')}</p>
|
||||
<div className="grid grid-cols-2 grid-rows-2 gap-y-6 gap-x-3 mt-4 overflow-x-auto">
|
||||
<div className="ml-6 flex w-max flex-col text-mineshaft-50">
|
||||
<p className="text-xl font-semibold">{t('billing.subscription')}</p>
|
||||
<div className="mt-4 grid grid-cols-2 grid-rows-2 gap-y-6 gap-x-3 overflow-x-auto">
|
||||
{plans.map((plan) => (
|
||||
<Plan key={plan.name} plan={plan} />
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xl font-bold mt-12">{t('billing:current-usage')}</p>
|
||||
<p className="mt-12 text-xl font-bold">{t('billing.current-usage')}</p>
|
||||
<div className="flex flex-row">
|
||||
<div className="mr-4 mt-8 text-gray-300 w-60 pt-6 pb-10 rounded-md bg-white/5 justify-center items-center flex flex-col">
|
||||
<div className="mr-4 mt-8 flex w-60 flex-col items-center justify-center rounded-md bg-white/5 pt-6 pb-10 text-gray-300">
|
||||
<p className="text-6xl font-bold">{numUsers}</p>
|
||||
<p className="text-gray-300">
|
||||
{numUsers > 1 ? 'Organization members' : 'Organization member'}
|
||||
@@ -119,5 +118,3 @@ export default function SettingsBilling() {
|
||||
}
|
||||
|
||||
SettingsBilling.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps(['settings', 'billing']);
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { OrgSettingsPage } from '@app/views/Settings/OrgSettingsPage';
|
||||
|
||||
export default function SettingsOrg() {
|
||||
@@ -11,7 +10,7 @@ export default function SettingsOrg() {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('settings-org:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('settings.org.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<OrgSettingsPage />
|
||||
@@ -20,10 +19,3 @@ export default function SettingsOrg() {
|
||||
}
|
||||
|
||||
SettingsOrg.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-org',
|
||||
'section-incident',
|
||||
'section-members'
|
||||
]);
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import Head from 'next/head';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { CreateServiceAccountPage } from '@app/views/Settings/CreateServiceAccountPage';
|
||||
|
||||
export default function ServiceAccountPage() {
|
||||
@@ -18,10 +16,3 @@ export default function ServiceAccountPage() {
|
||||
}
|
||||
|
||||
ServiceAccountPage.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-org',
|
||||
'section-incident',
|
||||
'section-members'
|
||||
]);
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { faCheck, faPlus, faX } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
@@ -13,7 +13,6 @@ import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import passwordCheck from '@app/components/utilities/checks/PasswordCheck';
|
||||
import changePassword from '@app/components/utilities/cryptography/changePassword';
|
||||
import issueBackupKey from '@app/components/utilities/cryptography/issueBackupKey';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { SecuritySection } from '@app/views/Settings/PersonalSettingsPage/SecuritySection/SecuritySection';
|
||||
|
||||
import AddApiKeyDialog from '../../../components/basic/dialog/AddApiKeyDialog';
|
||||
@@ -36,13 +35,14 @@ export default function PersonalSettings() {
|
||||
const [isAddApiKeyDialogOpen, setIsAddApiKeyDialogOpen] = useState(false);
|
||||
const [apiKeys, setApiKeys] = useState<any[]>([]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const { t, i18n } = useTranslation();
|
||||
const router = useRouter();
|
||||
const lang = router.locale ?? 'en';
|
||||
|
||||
const setLanguage = async (to: string) => {
|
||||
router.push(router.asPath, router.asPath, { locale: to });
|
||||
localStorage.setItem('lang', to);
|
||||
i18n.changeLanguage(to);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -65,9 +65,9 @@ export default function PersonalSettings() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 max-h-screen flex flex-col justify-between text-white">
|
||||
<div className="flex max-h-screen flex-col justify-between bg-bunker-800 text-white">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('settings-personal:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('settings.personal.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<AddApiKeyDialog
|
||||
@@ -77,44 +77,44 @@ export default function PersonalSettings() {
|
||||
setApiKeys={setApiKeys}
|
||||
/>
|
||||
<div className="flex flex-row">
|
||||
<div className="w-full max-h-screen pb-2">
|
||||
<NavHeader pageName={t('settings-personal:title')} isProjectRelated={false} />
|
||||
<div className="flex flex-row justify-between items-center ml-6 mt-8 mb-6 text-xl max-w-5xl">
|
||||
<div className="flex flex-col justify-start items-start text-3xl">
|
||||
<p className="font-semibold mr-4 text-gray-200">{t('settings-personal:title')}</p>
|
||||
<p className="font-normal mr-4 text-gray-400 text-base">
|
||||
{t('settings-personal:description')}
|
||||
<div className="max-h-screen w-full pb-2">
|
||||
<NavHeader pageName={t('settings.personal.title')} isProjectRelated={false} />
|
||||
<div className="ml-6 mt-8 mb-6 flex max-w-5xl flex-row items-center justify-between text-xl">
|
||||
<div className="flex flex-col items-start justify-start text-3xl">
|
||||
<p className="mr-4 font-semibold text-gray-200">{t('settings.personal.title')}</p>
|
||||
<p className="mr-4 text-base font-normal text-gray-400">
|
||||
{t('settings.personal.description')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col ml-6 text-mineshaft-50 mr-6 max-w-5xl">
|
||||
<div className="bg-white/5 rounded-md px-6 pt-6 pb-6 flex flex-col items-start w-full mb-6 mt-4">
|
||||
<p className="text-xl font-semibold self-start">
|
||||
{t('settings-personal:change-language')}
|
||||
<div className="ml-6 mr-6 flex max-w-5xl flex-col text-mineshaft-50">
|
||||
<div className="mb-6 mt-4 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-6 pb-6">
|
||||
<p className="self-start text-xl font-semibold">
|
||||
{t('settings.personal.change-language')}
|
||||
</p>
|
||||
<div className="max-h-28 w-ful mt-4">
|
||||
<div className="w-ful mt-4 max-h-28">
|
||||
<ListBox
|
||||
isSelected={lang}
|
||||
onChange={setLanguage}
|
||||
data={['en', 'ko', 'fr', 'es']}
|
||||
text={`${t('common:language')}: `}
|
||||
text={`${t('common.language')}: `}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<SecuritySection />
|
||||
<div className="bg-white/5 rounded-md px-6 flex flex-col items-start w-full mt-2 mb-8 pt-4">
|
||||
<div className="flex flex-row justify-between w-full">
|
||||
<div className="flex flex-col w-full">
|
||||
<p className="text-xl font-semibold mb-3">
|
||||
{t('settings-personal:api-keys.title')}
|
||||
<div className="mt-2 mb-8 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-4">
|
||||
<div className="flex w-full flex-row justify-between">
|
||||
<div className="flex w-full flex-col">
|
||||
<p className="mb-3 text-xl font-semibold">
|
||||
{t('settings.personal.api-keys.title')}
|
||||
</p>
|
||||
<p className="text-sm text-gray-400">
|
||||
{t('settings-personal:api-keys.description')}
|
||||
{t('settings.personal.api-keys.description')}
|
||||
</p>
|
||||
</div>
|
||||
<div className="w-40 mt-2">
|
||||
<div className="mt-2 w-40">
|
||||
<Button
|
||||
text={String(t('settings-personal:api-keys.add-new'))}
|
||||
text={String(t('settings.personal.api-keys.add-new'))}
|
||||
onButtonPressed={() => {
|
||||
setIsAddApiKeyDialogOpen(true);
|
||||
}}
|
||||
@@ -127,17 +127,17 @@ export default function PersonalSettings() {
|
||||
<ApiKeyTable data={apiKeys} setApiKeys={setApiKeys as any} />
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 flex flex-col items-start w-full mb-6">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t('section-password:change')}
|
||||
<div className="mb-6 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-5 pb-6">
|
||||
<div className="flex w-full max-w-5xl flex-row items-center justify-between">
|
||||
<div className="flex w-full max-w-3xl flex-col justify-between">
|
||||
<p className="mb-3 min-w-max text-xl font-semibold">
|
||||
{t('section.password.change')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="max-w-xl w-full">
|
||||
<div className="w-full max-w-xl">
|
||||
<InputField
|
||||
label={t('section-password:current') as string}
|
||||
label={t('section.password.current') as string}
|
||||
onChangeHandler={(password) => {
|
||||
setCurrentPassword(password);
|
||||
}}
|
||||
@@ -145,13 +145,13 @@ export default function PersonalSettings() {
|
||||
value={currentPassword}
|
||||
isRequired
|
||||
error={currentPasswordError}
|
||||
errorText={t('section-password:current-wrong') as string}
|
||||
errorText={t('section.password.current-wrong') as string}
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
<div className="py-2" />
|
||||
<InputField
|
||||
label={t('section-password:new') as string}
|
||||
label={t('section.password.new') as string}
|
||||
onChangeHandler={(password) => {
|
||||
setNewPassword(password);
|
||||
passwordCheck({
|
||||
@@ -171,59 +171,59 @@ export default function PersonalSettings() {
|
||||
/>
|
||||
</div>
|
||||
{passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber ? (
|
||||
<div className="w-full mt-3 bg-white/5 px-2 flex flex-col items-start py-2 rounded-md max-w-xl mb-2">
|
||||
<div className="text-gray-400 text-sm mb-1">
|
||||
{t('section-password:validate-base')}
|
||||
<div className="mt-3 mb-2 flex w-full max-w-xl flex-col items-start rounded-md bg-white/5 px-2 py-2">
|
||||
<div className="mb-1 text-sm text-gray-400">
|
||||
{t('section.password.validate-base')}
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLength ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLength ? 'text-gray-400' : 'text-gray-600'
|
||||
} text-sm`}
|
||||
>
|
||||
{t('section-password:validate-length')}
|
||||
{t('section.password.validate-length')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorLowerCase ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorLowerCase ? 'text-gray-400' : 'text-gray-600'
|
||||
} text-sm`}
|
||||
>
|
||||
{t('section-password:validate-case')}
|
||||
{t('section.password.validate-case')}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-row justify-start items-center ml-1">
|
||||
<div className="ml-1 flex flex-row items-center justify-start">
|
||||
{passwordErrorNumber ? (
|
||||
<FontAwesomeIcon icon={faX} className="text-md text-red mr-2.5" />
|
||||
<FontAwesomeIcon icon={faX} className="text-md mr-2.5 text-red" />
|
||||
) : (
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md text-primary mr-2" />
|
||||
<FontAwesomeIcon icon={faCheck} className="text-md mr-2 text-primary" />
|
||||
)}
|
||||
<div
|
||||
className={`${
|
||||
passwordErrorNumber ? 'text-gray-400' : 'text-gray-600'
|
||||
} text-sm`}
|
||||
>
|
||||
{t('section-password:validate-number')}
|
||||
{t('section.password.validate-number')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="py-2" />
|
||||
)}
|
||||
<div className="flex flex-row items-center mt-3 w-52 pr-3">
|
||||
<div className="mt-3 flex w-52 flex-row items-center pr-3">
|
||||
<Button
|
||||
text={t('section-password:change') as string}
|
||||
text={t('section.password.change') as string}
|
||||
onButtonPressed={() => {
|
||||
if (!passwordErrorLength && !passwordErrorLowerCase && !passwordErrorNumber) {
|
||||
changePassword(
|
||||
@@ -244,47 +244,47 @@ export default function PersonalSettings() {
|
||||
currentPassword !== '' &&
|
||||
!(passwordErrorLength || passwordErrorLowerCase || passwordErrorNumber)
|
||||
}
|
||||
textDisabled={t('section-password:change') as string}
|
||||
textDisabled={t('section.password.change') as string}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className={`ml-4 text-primary text-3xl ${
|
||||
className={`ml-4 text-3xl text-primary ${
|
||||
passwordChanged ? 'opacity-100' : 'opacity-0'
|
||||
} duration-300`}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="bg-white/5 rounded-md px-6 pt-5 pb-6 mt-2 flex flex-col items-start w-full mb-6">
|
||||
<div className="flex flex-row max-w-5xl justify-between items-center w-full">
|
||||
<div className="flex flex-col justify-between w-full max-w-3xl">
|
||||
<p className="text-xl font-semibold mb-3 min-w-max">
|
||||
{t('settings-personal:emergency.name')}
|
||||
<div className="mt-2 mb-6 flex w-full flex-col items-start rounded-md bg-white/5 px-6 pt-5 pb-6">
|
||||
<div className="flex w-full max-w-5xl flex-row items-center justify-between">
|
||||
<div className="flex w-full max-w-3xl flex-col justify-between">
|
||||
<p className="mb-3 min-w-max text-xl font-semibold">
|
||||
{t('settings.personal.emergency.name')}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 min-w-max">
|
||||
{t('settings-personal:emergency.text1')}
|
||||
<p className="min-w-max text-sm text-mineshaft-300">
|
||||
{t('settings.personal.emergency.text1')}
|
||||
</p>
|
||||
<p className="text-sm text-mineshaft-300 mb-5 min-w-max">
|
||||
{t('settings-personal:emergency.text2')}
|
||||
<p className="mb-5 min-w-max text-sm text-mineshaft-300">
|
||||
{t('settings.personal.emergency.text2')}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-xl mb-4">
|
||||
<div className="mb-4 w-full max-w-xl">
|
||||
<InputField
|
||||
label={t('section-password:current') as string}
|
||||
label={t('section.password.current') as string}
|
||||
onChangeHandler={setBackupPassword}
|
||||
type="password"
|
||||
value={backupPassword}
|
||||
isRequired
|
||||
error={backupKeyError}
|
||||
errorText={t('section-password:current-wrong') as string}
|
||||
errorText={t('section.password.current-wrong') as string}
|
||||
autoComplete="current-password"
|
||||
id="current-password"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-row items-center mt-3 w-60">
|
||||
<div className="mt-3 flex w-60 flex-row items-center">
|
||||
<Button
|
||||
text={t('settings-personal:emergency.download') as string}
|
||||
text={t('settings.personal.emergency.download') as string}
|
||||
onButtonPressed={() => {
|
||||
issueBackupKey({
|
||||
email: personalEmail,
|
||||
@@ -297,11 +297,11 @@ export default function PersonalSettings() {
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
active={backupPassword !== ''}
|
||||
textDisabled={t('settings-personal:emergency.download') as string}
|
||||
textDisabled={t('settings.personal.emergency.download') as string}
|
||||
/>
|
||||
<FontAwesomeIcon
|
||||
icon={faCheck}
|
||||
className={`ml-4 text-primary text-3xl ${
|
||||
className={`ml-4 text-3xl text-primary ${
|
||||
backupKeyIssued ? 'opacity-100' : 'opacity-0'
|
||||
} duration-300`}
|
||||
/>
|
||||
@@ -315,10 +315,3 @@ export default function PersonalSettings() {
|
||||
}
|
||||
|
||||
PersonalSettings.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-personal',
|
||||
'section-password',
|
||||
'section-api-key'
|
||||
]);
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
|
||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { ProjectSettingsPage } from '@app/views/Settings/ProjectSettingsPage';
|
||||
|
||||
const ProjectSettings = () => {
|
||||
@@ -10,10 +9,9 @@ const ProjectSettings = () => {
|
||||
return (
|
||||
<>
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('settings-project:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('settings.project.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
|
||||
<ProjectSettingsPage />
|
||||
</>
|
||||
);
|
||||
@@ -22,9 +20,3 @@ const ProjectSettings = () => {
|
||||
export default ProjectSettings;
|
||||
|
||||
ProjectSettings.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedStaticProps([
|
||||
'settings',
|
||||
'settings-project',
|
||||
'section-token'
|
||||
]);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/* eslint-disable no-nested-ternary */
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
|
||||
import CodeInputStep from '@app/components/signup/CodeInputStep';
|
||||
import DownloadBackupPDF from '@app/components/signup/DonwloadBackupPDFStep';
|
||||
@@ -12,7 +12,6 @@ import EnterEmailStep from '@app/components/signup/EnterEmailStep';
|
||||
import TeamInviteStep from '@app/components/signup/TeamInviteStep';
|
||||
import UserInfoStep from '@app/components/signup/UserInfoStep';
|
||||
import SecurityClient from '@app/components/utilities/SecurityClient';
|
||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { useFetchServerStatus } from '@app/hooks/api/serverDetails';
|
||||
|
||||
import checkEmailVerificationCode from './api/auth/CheckEmailVerificationCode';
|
||||
@@ -30,8 +29,7 @@ export default function SignUp() {
|
||||
const [codeError, setCodeError] = useState(false);
|
||||
const [step, setStep] = useState(1);
|
||||
const router = useRouter();
|
||||
const {data: serverDetails } = useFetchServerStatus()
|
||||
|
||||
const { data: serverDetails } = useFetchServerStatus();
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -62,7 +60,7 @@ export default function SignUp() {
|
||||
// Checking if the code matches the email.
|
||||
const response = await checkEmailVerificationCode({ email, code });
|
||||
if (response.status === 200) {
|
||||
const {token} = await response.json();
|
||||
const { token } = await response.json();
|
||||
SecurityClient.setSignupToken(token);
|
||||
setStep(3);
|
||||
} else {
|
||||
@@ -73,29 +71,29 @@ export default function SignUp() {
|
||||
|
||||
// when email service is not configured, skip step 2 and 5
|
||||
useEffect(() => {
|
||||
if (!serverDetails?.emailConfigured && step === 2){
|
||||
incrementStep()
|
||||
if (!serverDetails?.emailConfigured && step === 2) {
|
||||
incrementStep();
|
||||
}
|
||||
|
||||
if (!serverDetails?.emailConfigured && step === 5){
|
||||
getWorkspaces().then((userWorkspaces)=>{
|
||||
if (!serverDetails?.emailConfigured && step === 5) {
|
||||
getWorkspaces().then((userWorkspaces) => {
|
||||
router.push(`/dashboard/${userWorkspaces[0]._id}`);
|
||||
});
|
||||
}
|
||||
}, [step]);
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col items-center justify-center">
|
||||
<div className="flex h-screen flex-col items-center justify-center bg-bunker-800">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('signup:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('signup.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
<meta property="og:image" content="/images/message.png" />
|
||||
<meta property="og:title" content={t('signup:og-title') as string} />
|
||||
<meta name="og:description" content={t('signup:og-description') as string} />
|
||||
<meta property="og:title" content={t('signup.og-title') as string} />
|
||||
<meta name="og:description" content={t('signup.og-description') as string} />
|
||||
</Head>
|
||||
<div className="flex flex-col justify-center items-center">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<Link href="/">
|
||||
<div className="flex justify-center mb-2 md:mb-8 cursor-pointer">
|
||||
<div className="mb-2 flex cursor-pointer justify-center md:mb-8">
|
||||
<Image src="/images/biglogo.png" height={90} width={120} alt="Infisical Wide Logo" />
|
||||
</div>
|
||||
</Link>
|
||||
@@ -127,11 +125,13 @@ export default function SignUp() {
|
||||
password={password}
|
||||
name={`${firstName} ${lastName}`}
|
||||
/>
|
||||
) : (serverDetails?.emailConfigured ? <TeamInviteStep /> : "")}
|
||||
) : serverDetails?.emailConfigured ? (
|
||||
<TeamInviteStep />
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getStaticProps = getTranslatedStaticProps(['auth', 'signup', 'section-password']);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Head from 'next/head';
|
||||
import Image from 'next/image';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslation } from 'next-i18next';
|
||||
import { faMagnifyingGlass, faPlus } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
|
||||
@@ -11,7 +11,6 @@ import AddProjectMemberDialog from '@app/components/basic/dialog/AddProjectMembe
|
||||
import ProjectUsersTable from '@app/components/basic/table/ProjectUsersTable';
|
||||
import NavHeader from '@app/components/navigation/NavHeader';
|
||||
import guidGenerator from '@app/components/utilities/randomId';
|
||||
import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps';
|
||||
|
||||
import {
|
||||
decryptAssymmetric,
|
||||
@@ -146,15 +145,15 @@ export default function Users() {
|
||||
};
|
||||
|
||||
return userList ? (
|
||||
<div className="bg-bunker-800 md:h-screen flex flex-col justify-start max-w-[calc(100vw-240px)]">
|
||||
<div className="flex max-w-[calc(100vw-240px)] flex-col justify-start bg-bunker-800 md:h-screen">
|
||||
<Head>
|
||||
<title>{t('common:head-title', { title: t('settings-members:title') })}</title>
|
||||
<title>{t('common.head-title', { title: t('settings.members.title') })}</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
</Head>
|
||||
<NavHeader pageName={t('settings-members:title')} isProjectRelated />
|
||||
<div className="flex flex-col justify-start items-start px-6 py-6 pb-4 text-3xl">
|
||||
<p className="font-semibold mr-4 text-white">{t('settings-members:title')}</p>
|
||||
<p className="mr-4 text-base text-gray-400">{t('settings-members:description')}</p>
|
||||
<NavHeader pageName={t('settings.members.title')} isProjectRelated />
|
||||
<div className="flex flex-col items-start justify-start px-6 py-6 pb-4 text-3xl">
|
||||
<p className="mr-4 font-semibold text-white">{t('settings.members.title')}</p>
|
||||
<p className="mr-4 text-base text-gray-400">{t('settings.members.description')}</p>
|
||||
</div>
|
||||
<AddProjectMemberDialog
|
||||
isOpen={isAddOpen}
|
||||
@@ -170,22 +169,22 @@ export default function Users() {
|
||||
setEmail={setEmail}
|
||||
/>
|
||||
{/* <DeleteUserDialog isOpen={isDeleteOpen} closeModal={closeDeleteModal} submitModal={deleteMembership} userIdToBeDeleted={userIdToBeDeleted}/> */}
|
||||
<div className="px-6 pb-1 w-full flex flex-row items-start">
|
||||
<div className="h-10 w-full bg-white/5 mt-2 rounded-md flex flex-row items-center">
|
||||
<div className="flex w-full flex-row items-start px-6 pb-1">
|
||||
<div className="mt-2 flex h-10 w-full flex-row items-center rounded-md bg-white/5">
|
||||
<FontAwesomeIcon
|
||||
className="bg-white/5 rounded-l-md py-3 pl-4 pr-2 text-gray-400"
|
||||
className="rounded-l-md bg-white/5 py-3 pl-4 pr-2 text-gray-400"
|
||||
icon={faMagnifyingGlass}
|
||||
/>
|
||||
<input
|
||||
className="pl-2 text-gray-400 rounded-r-md bg-white/5 w-full h-full outline-none"
|
||||
className="h-full w-full rounded-r-md bg-white/5 pl-2 text-gray-400 outline-none"
|
||||
value={searchUsers}
|
||||
onChange={(e) => setSearchUsers(e.target.value)}
|
||||
placeholder={String(t('section-members:search-members'))}
|
||||
placeholder={String(t('section.members.search-members'))}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 ml-2 min-w-max flex flex-row items-start justify-start">
|
||||
<div className="mt-2 ml-2 flex min-w-max flex-row items-start justify-start">
|
||||
<Button
|
||||
text={String(t('section-members:add-member'))}
|
||||
text={String(t('section.members.add-member'))}
|
||||
onButtonPressed={openAddModal}
|
||||
color="mineshaft"
|
||||
size="md"
|
||||
@@ -193,7 +192,7 @@ export default function Users() {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="block overflow-x-scroll px-6 pb-6 no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||
<div className="no-scrollbar::-webkit-scrollbar block overflow-x-scroll px-6 pb-6 no-scrollbar">
|
||||
<ProjectUsersTable
|
||||
userData={userList}
|
||||
changeData={setUserList}
|
||||
@@ -206,16 +205,10 @@ export default function Users() {
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="relative z-10 w-10/12 mr-auto h-full ml-2 bg-bunker-800 flex flex-col items-center justify-center">
|
||||
<div className="relative z-10 mr-auto ml-2 flex h-full w-10/12 flex-col items-center justify-center bg-bunker-800">
|
||||
<Image src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Users.requireAuth = true;
|
||||
|
||||
export const getServerSideProps = getTranslatedServerSideProps([
|
||||
'settings',
|
||||
'settings-members',
|
||||
'section-members'
|
||||
]);
|
||||
|
||||
@@ -5,7 +5,6 @@ import Link from 'next/link';
|
||||
|
||||
import Button from '@app/components/basic/buttons/Button';
|
||||
import InputField from '@app/components/basic/InputField';
|
||||
import { getTranslatedStaticProps } from '@app/components/utilities/withTranslateProps';
|
||||
import { EmailServiceSetupModal } from '@app/components/v2';
|
||||
import { usePopUp } from '@app/hooks';
|
||||
import { useFetchServerStatus } from '@app/hooks/api/serverDetails';
|
||||
@@ -15,10 +14,8 @@ import SendEmailOnPasswordReset from './api/auth/SendEmailOnPasswordReset';
|
||||
export default function VerifyEmail() {
|
||||
const [email, setEmail] = useState('');
|
||||
const [step, setStep] = useState(1);
|
||||
const {data: serverDetails } = useFetchServerStatus()
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp([
|
||||
'setUpEmail'
|
||||
] as const);
|
||||
const { data: serverDetails } = useFetchServerStatus();
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(['setUpEmail'] as const);
|
||||
|
||||
/**
|
||||
* This function sends the verification email and forwards a user to the next step.
|
||||
@@ -31,7 +28,7 @@ export default function VerifyEmail() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-bunker-800 h-screen flex flex-col justify-start px-6">
|
||||
<div className="flex h-screen flex-col justify-start bg-bunker-800 px-6">
|
||||
<Head>
|
||||
<title>Login</title>
|
||||
<link rel="icon" href="/infisical.ico" />
|
||||
@@ -43,21 +40,21 @@ export default function VerifyEmail() {
|
||||
/>
|
||||
</Head>
|
||||
<Link href="/">
|
||||
<div className="flex justify-center mb-8 mt-20 cursor-pointer">
|
||||
<div className="mb-8 mt-20 flex cursor-pointer justify-center">
|
||||
<Image src="/images/biglogo.png" height={90} width={120} alt="long logo" />
|
||||
</div>
|
||||
</Link>
|
||||
{step === 1 && (
|
||||
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-4 pt-8 px-6 rounded-xl drop-shadow-xl">
|
||||
<p className="text-2xl md:text-3xl w-max mx-auto flex justify-center font-semibold text-bunker-100 mb-6">
|
||||
<div className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker py-4 px-6 pt-8 drop-shadow-xl">
|
||||
<p className="mx-auto mb-6 flex w-max justify-center text-2xl font-semibold text-bunker-100 md:text-3xl">
|
||||
Forgot your password?
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center md:pb-4 mt-4 md:mx-2">
|
||||
<p className="text-sm flex justify-center text-gray-400 w-max">
|
||||
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
|
||||
<p className="flex w-max justify-center text-sm text-gray-400">
|
||||
You will need your emergency kit. Enter your email to start account recovery.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center justify-center w-full md:p-2 rounded-lg mt-4 md:mt-0 max-h-24 md:max-h-28">
|
||||
<div className="mt-4 flex max-h-24 w-full items-center justify-center rounded-lg md:mt-0 md:max-h-28 md:p-2">
|
||||
<InputField
|
||||
label="Email"
|
||||
onChangeHandler={setEmail}
|
||||
@@ -68,26 +65,30 @@ export default function VerifyEmail() {
|
||||
autoComplete="username"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col items-center justify-center w-full md:p-2 max-h-20 max-w-md mt-4 mx-auto text-sm">
|
||||
<div className="text-l mt-6 m-8 px-8 py-3 text-lg">
|
||||
<Button text="Continue" onButtonPressed={()=>{
|
||||
if (serverDetails?.emailConfigured){
|
||||
sendVerificationEmail()
|
||||
} else {
|
||||
handlePopUpOpen('setUpEmail');
|
||||
}
|
||||
}} size="lg" />
|
||||
<div className="mx-auto mt-4 flex max-h-20 w-full max-w-md flex-col items-center justify-center text-sm md:p-2">
|
||||
<div className="text-l m-8 mt-6 px-8 py-3 text-lg">
|
||||
<Button
|
||||
text="Continue"
|
||||
onButtonPressed={() => {
|
||||
if (serverDetails?.emailConfigured) {
|
||||
sendVerificationEmail();
|
||||
} else {
|
||||
handlePopUpOpen('setUpEmail');
|
||||
}
|
||||
}}
|
||||
size="lg"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{step === 2 && (
|
||||
<div className="bg-bunker w-full max-w-md mx-auto h-7/12 py-4 pt-8 px-6 rounded-xl drop-shadow-xl">
|
||||
<p className="text-xl md:text-2xl w-max mx-auto flex justify-center font-semibold text-bunker-100 mb-6">
|
||||
<div className="h-7/12 mx-auto w-full max-w-md rounded-xl bg-bunker py-4 px-6 pt-8 drop-shadow-xl">
|
||||
<p className="mx-auto mb-6 flex w-max justify-center text-xl font-semibold text-bunker-100 md:text-2xl">
|
||||
Look for an email in your inbox.
|
||||
</p>
|
||||
<div className="flex flex-row items-center justify-center md:pb-4 mt-4 md:mx-2">
|
||||
<p className="text-sm flex justify-center text-gray-400 w-max text-center">
|
||||
<div className="mt-4 flex flex-row items-center justify-center md:mx-2 md:pb-4">
|
||||
<p className="flex w-max justify-center text-center text-sm text-gray-400">
|
||||
An email with instructions has been sent to {email}.
|
||||
</p>
|
||||
</div>
|
||||
@@ -101,5 +102,3 @@ export default function VerifyEmail() {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const getServerSideProps = getTranslatedStaticProps([]);
|
||||
|
||||
Reference in New Issue
Block a user