Merge pull request #988 from Infisical/integrations-uiux-updates

improved ui/ux for checkly, gcp, and vault integrations
This commit is contained in:
BlackMagiq
2023-09-16 18:40:00 +01:00
committed by GitHub
31 changed files with 1951 additions and 683 deletions
+2 -2
View File
@@ -445,7 +445,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
<a>
<MenuItem
isSelected={router.asPath.includes(
`/project/${currentWorkspace?._id}/secrets/overview`
`/project/${currentWorkspace?._id}/secrets`
)}
icon="system-outline-90-lock-closed"
>
@@ -468,7 +468,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
<Link href={`/integrations/${currentWorkspace?._id}`} passHref>
<a>
<MenuItem
isSelected={router.asPath === `/integrations/${currentWorkspace?._id}`}
isSelected={router.asPath.includes("/integrations")}
icon="system-outline-82-extension"
>
{t("nav.menu.integrations")}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
useSaveIntegrationAccessToken
@@ -56,12 +61,41 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
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>
<Head>
<title>Authorize AWS Parameter Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Amazon Web Services.png"
height={35}
width={35}
alt="AWS logo"
/>
</div>
<span className="ml-1.5">AWS Parameter Store Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="Access Key ID"
errorText={accessKeyErrorText}
isError={accessKeyErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder=""
@@ -73,6 +107,7 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
label="Secret Access Key"
errorText={accessSecretKeyErrorText}
isError={accessSecretKeyErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder=""
@@ -82,8 +117,9 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to AWS Parameter Store
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -57,7 +62,7 @@ export default function AWSParameterStoreCreateIntegrationPage() {
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: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/");
@@ -113,10 +118,38 @@ export default function AWSParameterStoreCreateIntegrationPage() {
};
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up AWS Parameter Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment in Infisical you want to sync to secerts in AWS Parameter Store."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Amazon Web Services.png"
height={35}
width={35}
alt="AWS logo"
/>
</div>
<span className="ml-1.5">AWS Parameter Store Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -132,14 +165,14 @@ export default function AWSParameterStoreCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="AWS Region">
<FormControl label="AWS Region" className="px-6">
<Select
value={selectedAWSRegion}
onValueChange={(val) => setSelectedAWSRegion(val)}
@@ -152,7 +185,7 @@ export default function AWSParameterStoreCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Path" errorText={pathErrorText} isError={pathErrorText !== "" ?? false}>
<FormControl label="Path" errorText={pathErrorText} isError={pathErrorText !== "" ?? false} className="px-6">
<Input
placeholder={`/${workspace.name
.toLowerCase()
@@ -164,15 +197,39 @@ export default function AWSParameterStoreCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6"
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in AWS Parameter Store with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up AWS Parameter Store Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isintegrationAuthLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useSaveIntegrationAccessToken } from "@app/hooks/api";
@@ -54,12 +59,41 @@ export default function AWSSecretManagerCreateIntegrationPage() {
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>
<Head>
<title>Authorize AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Amazon Web Services.png"
height={35}
width={35}
alt="AWS logo"
/>
</div>
<span className="ml-1.5">AWS Secrets Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="Access Key ID"
errorText={accessKeyErrorText}
isError={accessKeyErrorText !== "" ?? false}
className="px-6"
>
<Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
</FormControl>
@@ -67,6 +101,7 @@ export default function AWSSecretManagerCreateIntegrationPage() {
label="Secret Access Key"
errorText={accessSecretKeyErrorText}
isError={accessSecretKeyErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder=""
@@ -76,11 +111,12 @@ export default function AWSSecretManagerCreateIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to AWS Secret Manager
Connect to AWS Secrets Manager
</Button>
</Card>
</div>
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -57,7 +62,7 @@ export default function AWSSecretManagerCreateIntegrationPage() {
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: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/");
@@ -112,10 +117,38 @@ export default function AWSSecretManagerCreateIntegrationPage() {
};
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment in Infisical you want to sync to secerts in AWS Secrets Manager."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Amazon Web Services.png"
height={35}
width={35}
alt="AWS logo"
/>
</div>
<span className="ml-1.5">AWS Secrets Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -131,14 +164,14 @@ export default function AWSSecretManagerCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="AWS Region">
<FormControl label="AWS Region" className="px-6">
<Select
value={selectedAWSRegion}
onValueChange={(val) => setSelectedAWSRegion(val)}
@@ -155,6 +188,7 @@ export default function AWSSecretManagerCreateIntegrationPage() {
label="AWS SM Secret Name"
errorText={targetSecretNameErrorText}
isError={targetSecretNameErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder={`${workspace.name
@@ -167,15 +201,39 @@ export default function AWSSecretManagerCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6"
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in AWS Secrets Manager with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isintegrationAuthLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
useSaveIntegrationAccessToken
@@ -41,8 +46,36 @@ export default function ChecklyCreateIntegrationPage() {
return (
<div className="flex h-full w-full items-center justify-center">
<Head>
<title>Authorize Checkly Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle className="text-left px-6" subTitle="After adding your API-key, you will be prompted to set up an integration for a particular Infisical project and environment.">Checkly Integration</CardTitle>
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Checkly.png"
height={30}
width={30}
alt="Checkly logo"
/>
</div>
<span className="ml-2.5">Checkly Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="Checkly API key"
errorText={accessTokenErrorText}
@@ -57,7 +90,7 @@ export default function ChecklyCreateIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isFullWidth={false}
@@ -1,5 +1,11 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { motion } from "framer-motion";
import queryString from "query-string";
import {
@@ -9,7 +15,11 @@ import {
FormControl,
Input,
Select,
SelectItem
SelectItem,
Tab,
TabList,
TabPanel,
Tabs
} from "@app/components/v2";
import {
useCreateIntegration
@@ -21,6 +31,11 @@ import {
} from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace";
enum TabSections {
Connection = "connection",
Options = "options"
}
export default function ChecklyCreateIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
@@ -29,7 +44,7 @@ export default function ChecklyCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -91,81 +106,156 @@ export default function ChecklyCreateIntegrationPage() {
selectedSourceEnvironment &&
integrationAuthApps &&
targetApp ? (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
<div className="flex flex-col h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
<Head>
<title>Set Up Checkly Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle
className="px-6 text-left"
subTitle="Choose which environment in Infisical you want to sync with your Checkly account."
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment in Infisical you want to sync to Checkly environment variables."
>
Checkly Integration
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Checkly.png"
height={30}
width={30}
alt="Checkly logo"
/>
</div>
<span className="ml-2.5">Checkly Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Infisical Project Environment" className="mt-4 px-6">
<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="Secrets Path" className="mt-4 px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="Checkly Account" className="mt-4 px-6">
<Select
value={targetApp}
onValueChange={(val) => setTargetApp(val)}
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}`}
<Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full">
<Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab>
</div>
</TabList>
<TabPanel value={TabSections.Connection}>
<motion.div
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<FormControl label="Infisical Project Environment">
<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 apps found
</SelectItem>
)}
</Select>
</FormControl>
<FormControl label="Append the Secret Name with..." className="mt-4 px-6">
<Input
value={secretSuffix}
onChange={(evt) => setSecretSuffix(evt.target.value)}
placeholder="Provide a suffix for secret names, default is no suffix"
/>
</FormControl>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="Checkly Account">
<Select
value={targetApp}
onValueChange={(val) => setTargetApp(val)}
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}`}
>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No apps found
</SelectItem>
)}
</Select>
</FormControl>
</motion.div>
</TabPanel>
<TabPanel value={TabSections.Options}>
<motion.div
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: -30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<FormControl label="Append Secret Names with..." className="pb-[9.75rem]">
<Input
value={secretSuffix}
onChange={(evt) => setSecretSuffix(evt.target.value)}
placeholder="Provide a suffix for secret names, default is no suffix"
/>
</FormControl>
</motion.div>
</TabPanel>
</Tabs>
<Button
onClick={handleButtonClick}
color="mineshaft"
variant="outline_bg"
className="mt-2 mb-6 ml-auto mr-6"
className="mb-6 ml-auto mr-6"
isFullWidth={false}
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in Checkly with secrets from Infisical.</span>
<span className="text-mineshaft-300 text-sm mt-4">If you have multiple Checkly integrations and are using suffixes for at least one of them, you will have to add suffixes for all the active Checkly integrations – otherwise you might run into rare unexpected behavior.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up Checkly Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
useSaveIntegrationAccessToken
@@ -41,19 +46,49 @@ export default function CircleCICreateIntegrationPage() {
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>
<Head>
<title>Authorize CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding your API Token, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Circle CI.png"
height={30}
width={30}
alt="CircleCI logo"
/>
</div>
<span className="ml-1.5">CircleCI Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="CircleCI API Token"
errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false}
className="px-6"
>
<Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to CircleCI
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -28,8 +33,8 @@ export default function CircleCICreateIntegrationPage() {
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({
const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -84,10 +89,38 @@ export default function CircleCICreateIntegrationPage() {
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to CircleCI environment variables."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Circle CI.png"
height={30}
width={30}
alt="CircleCI logo"
/>
</div>
<span className="ml-1.5">CircleCI Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -103,14 +136,14 @@ export default function CircleCICreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="CircleCI Project" className="mt-4">
<FormControl label="CircleCI Project" className="px-6">
<Select
value={targetApp}
onValueChange={(val) => setTargetApp(val)}
@@ -135,17 +168,41 @@ export default function CircleCICreateIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in CircleCI with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading || isintegrationAuthLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,13 @@
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import {
useSaveIntegrationAccessToken
@@ -7,64 +15,116 @@ import {
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
export default function FlyioCreateIntegrationPage() {
const schema = yup.object({
accessToken: yup.string().trim().required("Fly.io Access Token is required")
});
type FormData = yup.InferType<typeof schema>;
export default function FlyioAuthorizeIntegrationPage() {
const router = useRouter();
const {
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
accessToken: ""
}
});
const { mutateAsync } = useSaveIntegrationAccessToken();
const [accessToken, setAccessToken] = useState("");
const [accessTokenErrorText, setAccessTokenErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleButtonClick = async () => {
const onFormSubmit = async ({
accessToken
}: FormData) => {
console.log("onFormSubmit accessToken: ", accessToken);
try {
setAccessTokenErrorText("");
if (accessToken.length === 0) {
setAccessTokenErrorText("Access token cannot be blank");
return;
}
setIsLoading(true);
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "flyio",
accessToken
});
setIsLoading(false);
router.push(`/integrations/flyio/create?integrationAuthId=${integrationAuth._id}`);
} catch (err) {
setIsLoading(false);
console.error(err);
}
};
}
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}
<Head>
<title>Authorize Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding your access token, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<Input
placeholder=""
value={accessToken}
onChange={(e) => setAccessToken(e.target.value)}
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Flyio.svg"
height={30}
width={30}
alt="Fly.io logo"
/>
</div>
<span className="ml-2.5">Fly.io Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<form
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<Controller
control={control}
name="accessToken"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Fly.io Access Token"
errorText={error?.message}
isError={Boolean(error)}
>
<Input
{...field}
placeholder=""
/>
</FormControl>
)}
/>
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
isLoading={isLoading}
>
Connect to Fly.io
</Button>
<Button
colorSchema="primary"
variant="outline_bg"
className="mt-2 w-min"
size="sm"
type="submit"
isLoading={isLoading}
>
Connect to Fly.io
</Button>
</form>
</Card>
</div>
);
}
FlyioCreateIntegrationPage.requireAuth = true;
FlyioAuthorizeIntegrationPage.requireAuth = true;
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -23,13 +28,14 @@ import { useGetWorkspaceById } from "../../../hooks/api/workspace";
export default function FlyioCreateIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
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({
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -84,10 +90,38 @@ export default function FlyioCreateIntegrationPage() {
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to Fly.io environment variables."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Flyio.svg"
height={30}
width={30}
alt="Fly.io logo"
/>
</div>
<span className="ml-2.5">Fly.io Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -103,14 +137,14 @@ export default function FlyioCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="Fly.io App" className="mt-4">
<FormControl label="Fly.io App" className="px-6">
<Select
value={targetApp}
onValueChange={(val) => setTargetApp(val)}
@@ -136,16 +170,40 @@ export default function FlyioCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in Fly.io with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,9 +1,16 @@
import crypto from "crypto";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faGoogle } from "@fortawesome/free-brands-svg-icons";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import {
useGetCloudIntegrations,
@@ -11,39 +18,27 @@ import {
import { Button, Card, CardTitle, FormControl, TextArea } from "../../../components/v2";
const schema = yup.object({
accessToken: yup.string().required("Service Account JSON cannot be empty")
});
type FormData = yup.InferType<typeof schema>;
export default function GCPSecretManagerAuthorizeIntegrationPage() {
const router = useRouter();
const {
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema)
});
const { data: cloudIntegrations } = useGetCloudIntegrations();
const { mutateAsync } = useSaveIntegrationAccessToken();
const [accessToken, setAccessToken] = useState("");
const [accessTokenErrorText, setAccessTokenErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleIntegrateWithPAT = async () => {
try {
setAccessTokenErrorText("");
if (accessToken.length === 0) {
setAccessTokenErrorText("Service account JSON cannot be blank");
return;
}
setIsLoading(true);
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "gcp-secret-manager",
refreshToken: accessToken
});
setIsLoading(false);
router.push(`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth._id}`);
} catch (err) {
console.error(err);
}
};
const handleIntegrateWithOAuth = () => {
if (!cloudIntegrations) return;
@@ -57,46 +52,106 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
const link = `https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/cloud-platform&response_type=code&access_type=offline&state=${state}&redirect_uri=${window.location.origin}/integrations/gcp-secret-manager/oauth2/callback&client_id=${integrationOption.clientId}`;
window.location.assign(link);
}
const onFormSubmit = async ({
accessToken
}: FormData) => {
try {
setIsLoading(true);
const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"),
integration: "gcp-secret-manager",
refreshToken: accessToken
});
setIsLoading(false);
router.push(`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth._id}`);
} catch (err) {
console.error(err);
setIsLoading(false);
}
}
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">GCP Secret Manager Integration</CardTitle>
<Button
colorSchema="primary"
variant="outline_bg"
onClick={handleIntegrateWithOAuth}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />}
className="h-11 w-full mx-0 mt-4"
>
Continue with OAuth
</Button>
<div className='w-full flex flex-row items-center my-4 py-2'>
<div className='w-full border-t border-mineshaft-400/60' />
<span className="mx-2 text-mineshaft-200 text-xs">or</span>
<div className='w-full border-t border-mineshaft-400/60' />
<Head>
<title>Authorize GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Connect Infisical to GCP Secret Manager to sync secrets."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Google Cloud Platform.png"
height={30}
width={30}
alt="GCP logo"
/>
</div>
<span className="ml-1.5">GCP Secret Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<div className="px-6">
<Button
colorSchema="primary"
variant="outline_bg"
onClick={handleIntegrateWithOAuth}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />}
className="h-11 w-full mx-0 mt-4"
>
Continue with OAuth
</Button>
<div className='w-full flex flex-row items-center my-4 py-2'>
<div className='w-full border-t border-mineshaft-400/40' />
<span className="mx-2 text-mineshaft-400 text-xs">or</span>
<div className='w-full border-t border-mineshaft-400/40' />
</div>
</div>
<FormControl
label="GCP Service Account JSON"
errorText={accessTokenErrorText}
isError={accessTokenErrorText !== "" ?? false}
<form
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<TextArea
value={accessToken}
onChange={(e) => setAccessToken(e.target.value)}
placeholder=""
className="h-48"
/>
</FormControl>
<Button
onClick={handleIntegrateWithPAT}
color="mineshaft"
className="mt-4"
isLoading={isLoading}
>
Connect to GCP Secret Manager
</Button>
<Controller
control={control}
name="accessToken"
render={({ field, fieldState: { error } }) => (
<FormControl
label="GCP Service Account JSON"
errorText={error?.message}
isError={Boolean(error)}
>
<TextArea
{...field}
className="h-48 border border-mineshaft-600 bg-bunker-900/80"
/>
</FormControl>
)}
/>
<Button
colorSchema="primary"
variant="outline_bg"
className="mt-2 w-min"
size="sm"
type="submit"
isLoading={isLoading}
>
Connect to GCP Secret Manager
</Button>
</form>
</Card>
</div>
);
@@ -1,11 +1,17 @@
import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import { motion } from "framer-motion";
import queryString from "query-string";
import * as yup from "yup";
import { usePopUp } from "@app/hooks";
import {
useCreateIntegration
} from "@app/hooks/api";
@@ -16,14 +22,15 @@ import {
CardTitle,
FormControl,
Input,
Modal,
ModalContent,
Select,
SelectItem,
Switch,
Tab,
TabList,
TabPanel,
Tabs
} from "../../../components/v2";
Tabs} from "../../../components/v2";
import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById
@@ -39,30 +46,36 @@ const schema = yup.object({
selectedSourceEnvironment: yup.string().required("Source environment is required"),
secretPath: yup.string().required("Secret path is required"),
targetAppId: yup.string().required("GCP project is required"),
secretPrefix: yup.string(),
secretSuffix: yup.string(),
secretPrefix: yup.string().trim(),
secretSuffix: yup.string().trim(),
shouldLabel: yup.boolean(),
labelName: yup.string(),
labelValue: yup.string()
labelName: yup.string().trim(),
labelValue: yup.string().trim()
});
type FormData = yup.InferType<typeof schema>;
export default function GCPSecretManagerCreateIntegrationPage() {
const router = useRouter();
const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([
"confirmIntegration"
] as const);
const {
control,
handleSubmit,
setValue,
watch
} = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
secretPath: "/",
shouldLabel: false,
labelName: "managed-by",
labelValue: "infisical"
}
resolver: yupResolver(schema),
defaultValues: {
secretPath: "/",
secretPrefix: "",
secretSuffix: "",
shouldLabel: false,
labelName: "managed-by",
labelValue: "infisical"
}
});
const shouldLabel = watch("shouldLabel");
@@ -74,7 +87,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -87,8 +100,8 @@ export default function GCPSecretManagerCreateIntegrationPage() {
return;
}
setValue("labelName", undefined);
setValue("labelValue", undefined);
setValue("labelName", "");
setValue("labelValue", "");
}, [shouldLabel]);
useEffect(() => {
@@ -130,8 +143,8 @@ export default function GCPSecretManagerCreateIntegrationPage() {
sourceEnvironment: sce,
secretPath,
metadata: {
secretPrefix,
secretSuffix,
...(secretPrefix ? { secretPrefix } : {}),
...(secretSuffix ? { secretSuffix } : {}),
...(sl ? {
secretGCPLabel: {
labelName,
@@ -154,15 +167,52 @@ export default function GCPSecretManagerCreateIntegrationPage() {
selectedSourceEnvironment &&
integrationAuthApps ? (
<form
onSubmit={handleSubmit(onFormSubmit)}
className="flex h-full w-full items-center justify-center"
onSubmit={handleSubmit((data: FormData) => {
if (!data.secretPrefix && !data.secretSuffix && !data.shouldLabel) {
handlePopUpOpen("confirmIntegration", data);
return;
}
onFormSubmit(data);
})}
className="flex flex-col h-full w-full items-center justify-center"
>
<Card className="max-w-md rounded-md p-8">
<CardTitle className="text-center">GCP Secret Manager Integration</CardTitle>
<Tabs defaultValue={TabSections.Connection}>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<Head>
<title>Set Up GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<CardTitle
className="text-left px-6 text-xl mb-2"
subTitle="Select which environment or folder in Infisical you want to sync to GCP Secret Manager."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Google Cloud Platform.png"
height={30}
width={30}
alt="GCP logo"
/>
</div>
<span className="ml-1.5">GCP Secret Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList>
<Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab>
<div className="flex flex-row border-b border-mineshaft-600 w-full">
<Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab>
</div>
</TabList>
<TabPanel value={TabSections.Connection}>
<motion.div
@@ -172,190 +222,258 @@ export default function GCPSecretManagerCreateIntegrationPage() {
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<div>
<Controller
<Controller
control={control}
name="selectedSourceEnvironment"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
control={control}
name="selectedSourceEnvironment"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
defaultValue=""
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secrets Path"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="/"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="targetAppId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return (
<FormControl
label="Project Environment"
label="GCP Project"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
onValueChange={(e) => {
if (e === "") return;
onChange(e)
}}
className="w-full"
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
{integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => (
<SelectItem
value={String(integrationAuthApp.appId as string)}
key={`target-app-${String(integrationAuthApp.appId)}`}
>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem>
))}
)}
</Select>
</FormControl>
)
}}
/>
</motion.div>
</TabPanel>
<TabPanel value={TabSections.Options}>
<motion.div
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: -30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<Controller
control={control}
name="secretPrefix"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secret Prefix"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="INFISICAL_"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="secretSuffix"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secret Suffix"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="_INFISICAL"
/>
</FormControl>
)}
/>
<div className="mt-8 mb-[2.36rem]">
<Controller
control={control}
name="shouldLabel"
render={({ field: { onChange, value } }) => (
<Switch
id="label-gcp"
onCheckedChange={(isChecked) => onChange(isChecked)}
isChecked={value}
>
Label in GCP Secret Manager
</Switch>
)}
/>
<Controller
</div>
{shouldLabel && (
<div className="mt-8">
<Controller
control={control}
defaultValue=""
name="secretPath"
name="labelName"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secrets Path"
label="Label Name"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="/"
placeholder="managed-by"
/>
</FormControl>
)}
/>
<Controller
/>
<Controller
control={control}
name="targetAppId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return (
<FormControl
label="GCP Project"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => {
if (e === "") return;
onChange(e)
}}
className="w-full"
name="labelValue"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Label Name"
isError={Boolean(error)}
errorText={error?.message}
>
{integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => (
<SelectItem
value={String(integrationAuthApp.appId as string)}
key={`target-app-${String(integrationAuthApp.appId)}`}
>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem>
)}
</Select>
</FormControl>
)
}}
/>
<Button
className="mt-4"
size="sm"
type="submit"
isLoading={isLoading}
>
Create Integration
</Button>
<Input
{...field}
placeholder="infisical"
/>
</FormControl>
)}
/>
</div>
)}
</motion.div>
</TabPanel>
<TabPanel value={TabSections.Options}>
<Controller
control={control}
name="secretPrefix"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secret Prefix"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="INFISICAL_"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="secretSuffix"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secret Suffix"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="_INFISICAL"
/>
</FormControl>
)}
/>
<div className="mt-8">
<Controller
control={control}
name="shouldLabel"
render={({ field: { onChange, value } }) => (
<Switch
id="label-gcp"
onCheckedChange={(isChecked) => onChange(isChecked)}
isChecked={value}
>
Label in GCP Secret Manager
</Switch>
)}
/>
</div>
{shouldLabel && (
<div className="mt-8">
<Controller
control={control}
name="labelName"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Label Name"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="managed-by"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="labelValue"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Label Name"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="infisical"
/>
</FormControl>
)}
/>
</div>
)}
</TabPanel>
</Tabs>
<Button
colorSchema="primary"
variant="outline_bg"
className="mb-8 ml-auto mr-6 w-min"
size="sm"
type="submit"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
{/* <div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center">
<FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/>
<span className="ml-3 text-md text-mineshaft-100">Pro Tip</span>
</div>
<span className="text-mineshaft-300 text-sm mt-4">
After creating an integration, your secrets will start syncing immediately.
To avoid overwriting existing secrets in GCP Secret Manager, you may consider adding a secret prefix/suffix and/or enabling labeling in the options tab.
</span>
</div> */}
<Modal
isOpen={popUp.confirmIntegration?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("confirmIntegration", isOpen)}
>
<ModalContent
title="Heads Up"
footerContent={
<div className="flex items-center space-x-2">
<Button onClick={() => onFormSubmit(popUp.confirmIntegration?.data as FormData)}>
Continue Anyway
</Button>
<Button
onClick={() => handlePopUpClose("confirmIntegration")}
variant="outline_bg"
colorSchema="secondary"
>
Cancel
</Button>
</div>
}
>
<p>
You&apos;re about to overwrite any existing secrets in GCP Secret Manager.
</p>
<p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix or enabling labeling in the options tab.
</p>
</ModalContent>
</Modal>
</form>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
GCPSecretManagerCreateIntegrationPage.requireAuth = true;
GCPSecretManagerCreateIntegrationPage.requireAuth = true;
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -29,7 +34,7 @@ export default function GitHubCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -88,10 +93,38 @@ export default function GitHubCreateIntegrationPage() {
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up GitHub Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment in Infisical you want to sync to environment variables in GitHub."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center bg-mineshaft-200 rounded-full">
<Image
src="/images/integrations/GitHub.png"
height={30}
width={30}
alt="GitHub logo"
/>
</div>
<span className="ml-2.5">GitHub Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/githubactions" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -107,14 +140,14 @@ export default function GitHubCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="GitHub Repo" className="mt-4">
<FormControl label="GitHub Repo" className="px-6">
<Select
value={targetAppId}
onValueChange={(val) => setTargetAppId(val)}
@@ -140,16 +173,40 @@ export default function GitHubCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mt-2 mb-6 ml-auto mr-6"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in GitHub with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up GitHub Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,52 +1,118 @@
import crypto from "crypto";
import { useState } from "react";
import { faGoogle } from "@fortawesome/free-brands-svg-icons";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useGetCloudIntegrations } from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
const schema = yup.object({
gitLabURL: yup.string()
});
type FormData = yup.InferType<typeof schema>;
export default function GitLabAuthorizeIntegrationPage() {
const { data: cloudIntegrations } = useGetCloudIntegrations();
const [gitLabURL, setGitLabURL] = useState("");
const handleIntegrateWithOAuth = () => {
if (!cloudIntegrations) return;
const integrationOption = cloudIntegrations.find((integration) => integration.slug === "gitlab");
if (!integrationOption) return;
const baseURL = gitLabURL.trim() === "" ? "https://gitlab.com" : gitLabURL.trim();
const csrfToken = crypto.randomBytes(16).toString("hex");
localStorage.setItem("latestCSRFToken", csrfToken);
const state = `${csrfToken}|${gitLabURL.trim() === "" ? "" : gitLabURL.trim()}`;
const link = `${baseURL}/oauth/authorize?client_id=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`;
window.location.assign(link);
const {
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema),
defaultValues: {
gitLabURL: ""
}
});
const { data: cloudIntegrations } = useGetCloudIntegrations();
const onFormSubmit = ({
gitLabURL
}: FormData) => {
if (!cloudIntegrations) return;
const integrationOption = cloudIntegrations.find((integration) => integration.slug === "gitlab");
if (!integrationOption) return;
const baseURL = (gitLabURL as string).trim() === "" ? "https://gitlab.com" : (gitLabURL as string).trim();
const csrfToken = crypto.randomBytes(16).toString("hex");
localStorage.setItem("latestCSRFToken", csrfToken);
const state = `${csrfToken}|${(gitLabURL as string).trim() === "" ? "" : (gitLabURL as string).trim()}`;
const link = `${baseURL}/oauth/authorize?client_id=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`;
window.location.assign(link);
}
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">GitLab Integration</CardTitle>
<FormControl label="Self-hosted URL (optional)">
<Input
placeholder="https://self-hosted-gitlab.com"
value={gitLabURL} onChange={(e) => setGitLabURL(e.target.value)}
/>
</FormControl>
<Button
onClick={handleIntegrateWithOAuth}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />}
className="h-11 w-full mx-0 mt-4"
>
<Head>
<title>Authorize GitLab Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Authorize this integration to sync secrets from Infisical to GitLab. If no self-hosted GitLab URL is specified, then Infisical will connect you to GitLab Cloud."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Gitlab.png"
height={28}
width={28}
alt="Gitlab logo"
/>
</div>
<span className="ml-2.5">GitLab Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<form
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<Controller
control={control}
name="gitLabURL"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Self-hosted URL (optional)"
errorText={error?.message}
isError={Boolean(error)}
>
<Input
{...field}
placeholder="https://self-hosted-gitlab.com"
/>
</FormControl>
)}
/>
<Button
colorSchema="primary"
variant="outline_bg"
className="mt-2 w-min"
size="sm"
type="submit"
>
Continue with OAuth
</Button>
</Button>
</form>
</Card>
</div>
);
+289 -179
View File
@@ -1,11 +1,17 @@
import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import { motion } from "framer-motion";
import queryString from "query-string";
import * as yup from "yup";
import { usePopUp } from "@app/hooks";
import {
useCreateIntegration
} from "@app/hooks/api";
@@ -16,6 +22,8 @@ import {
CardTitle,
FormControl,
Input,
Modal,
ModalContent,
Select,
SelectItem,
Tab,
@@ -55,6 +63,9 @@ type FormData = yup.InferType<typeof schema>;
export default function GitLabCreateIntegrationPage() {
const router = useRouter();
const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([
"confirmIntegration"
] as const);
const {
control,
@@ -65,7 +76,9 @@ export default function GitLabCreateIntegrationPage() {
resolver: yupResolver(schema),
defaultValues: {
targetEntity: "individual",
secretPath: "/"
secretPath: "/",
secretPrefix: "",
secretSuffix: ""
}
});
const selectedSourceEnvironment = watch("selectedSourceEnvironment");
@@ -79,11 +92,12 @@ export default function GitLabCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "",
...(targetTeamId ? { teamId: targetTeamId } : {})
});
const { data: integrationAuthTeams } = useGetIntegrationAuthTeams(
const { data: integrationAuthTeams, isLoading: isintegrationAuthTeamsLoading } = useGetIntegrationAuthTeams(
(integrationAuthId as string) ?? ""
);
@@ -161,195 +175,229 @@ export default function GitLabCreateIntegrationPage() {
integrationAuthApps &&
integrationAuthTeams ? (
<form
onSubmit={handleSubmit(onFormSubmit)}
className="flex h-full w-full items-center justify-center"
onSubmit={handleSubmit((data: FormData) => {
if (!data.secretPrefix && !data.secretSuffix) {
handlePopUpOpen("confirmIntegration", data);
return;
}
onFormSubmit(data);
})}
className="flex flex-col h-full w-full items-center justify-center"
>
<Card className="max-w-md rounded-md p-8">
<CardTitle className="text-center">GitLab Integration</CardTitle>
<Tabs defaultValue={TabSections.Connection}>
<Head>
<title>Set Up GitLab Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to GitLab's environment variables."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Gitlab.png"
height={28}
width={28}
alt="Gitlab logo"
/>
</div>
<span className="ml-2.5">GitLab Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList>
<Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab>
<div className="flex flex-row border-b border-mineshaft-600 w-full">
<Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab>
</div>
</TabList>
<TabPanel value={TabSections.Connection}>
<motion.div
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
>
<div>
<Controller
control={control}
name="selectedSourceEnvironment"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
<Controller
control={control}
name="selectedSourceEnvironment"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="Project Environment"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
<Select
defaultValue={field.value}
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
/>
<Controller
control={control}
defaultValue=""
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Secrets Path"
isError={Boolean(error)}
errorText={error?.message}
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
<Input
{...field}
placeholder="/"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="targetEntity"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="GitLab Integration Type"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{gitLabEntities.map((entity) => {
return (
<SelectItem value={entity.value} key={`target-entity-${entity.value}`}>
{entity.name}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
{targetEntity === "group" && targetTeamId && (
<Controller
control={control}
name="targetTeamId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="GitLab Group"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{integrationAuthTeams.length > 0 ? (
integrationAuthTeams.map((integrationAuthTeam) =>
(
<SelectItem
value={String(integrationAuthTeam.teamId as string)}
key={`target-team-${String(integrationAuthTeam.teamId)}`}
>
{integrationAuthTeam.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-team-none">
No groups found
</SelectItem>
)}
</Select>
</FormControl>
)}
/>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
<Controller
control={control}
name="targetAppId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return (
/>
<Controller
control={control}
defaultValue=""
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl
label="GitLab Project"
errorText={error?.message}
isError={Boolean(error)}
label="Secrets Path"
isError={Boolean(error)}
errorText={error?.message}
>
<Select
{...field}
onValueChange={(e) => {
if (e === "") return;
onChange(e)
}}
className="w-full"
>
{integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => (
<SelectItem
value={String(integrationAuthApp.appId as string)}
key={`target-app-${String(integrationAuthApp.appId)}`}
>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem>
)}
</Select>
<Input
{...field}
placeholder="/"
/>
</FormControl>
)}}
/>
<Controller
control={control}
defaultValue=""
name="targetEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="GitLab Environment Scope (Optional)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="*"
/>
</FormControl>
)}
)}
/>
<Controller
control={control}
name="targetEntity"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="GitLab Integration Type"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{gitLabEntities.map((entity) => {
return (
<SelectItem value={entity.value} key={`target-entity-${entity.value}`}>
{entity.name}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
{targetEntity === "group" && targetTeamId && (
<Controller
control={control}
name="targetTeamId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => (
<FormControl
label="GitLab Group"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{integrationAuthTeams.length > 0 ? (
integrationAuthTeams.map((integrationAuthTeam) =>
(
<SelectItem
value={String(integrationAuthTeam.teamId as string)}
key={`target-team-${String(integrationAuthTeam.teamId)}`}
>
{integrationAuthTeam.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-team-none">
No groups found
</SelectItem>
)}
</Select>
</FormControl>
)}
/>
</div>
<Button
className="mt-4"
size="sm"
type="submit"
isLoading={isLoading}
>
Create Integration
</Button>
)}
<Controller
control={control}
name="targetAppId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return (
<FormControl
label="GitLab Project"
errorText={error?.message}
isError={Boolean(error)}
>
<Select
{...field}
onValueChange={(e) => {
if (e === "") return;
onChange(e)
}}
className="w-full"
>
{integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => (
<SelectItem
value={String(integrationAuthApp.appId as string)}
key={`target-app-${String(integrationAuthApp.appId)}`}
>
{integrationAuthApp.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem>
)}
</Select>
</FormControl>
)}}
/>
<Controller
control={control}
defaultValue=""
name="targetEnvironment"
render={({ field, fieldState: { error } }) => (
<FormControl
label="GitLab Environment Scope (Optional)"
isError={Boolean(error)}
errorText={error?.message}
>
<Input
{...field}
placeholder="*"
/>
</FormControl>
)}
/>
</motion.div>
</TabPanel>
<TabPanel value={TabSections.Options}>
<div>
<motion.div
key="panel-1"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: -30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
className="pb-[14.25rem]"
>
<Controller
control={control}
name="secretPrefix"
@@ -382,13 +430,75 @@ export default function GitLabCreateIntegrationPage() {
</FormControl>
)}
/>
</div>
</motion.div>
</TabPanel>
</Tabs>
</Card>
<Button
colorSchema="primary"
variant="outline_bg"
className="mb-8 ml-auto mr-6 w-min"
size="sm"
type="submit"
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
{/* <div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in GitLab with secrets from Infisical.</span>
</div> */}
<Modal
isOpen={popUp.confirmIntegration?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("confirmIntegration", isOpen)}
>
<ModalContent
title="Heads Up"
footerContent={
<div className="flex items-center space-x-2">
<Button onClick={() => onFormSubmit(popUp.confirmIntegration?.data as FormData)}>
Continue Anyway
</Button>
<Button
onClick={() => handlePopUpClose("confirmIntegration")}
variant="outline_bg"
colorSchema="secondary"
>
Cancel
</Button>
</div>
}
>
<p>
You&apos;re about to overwrite any existing secrets in GitLab.
</p>
<p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix in the options tab.
</p>
</ModalContent>
</Modal>
</form>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up GitLab Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading || isintegrationAuthTeamsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
useSaveIntegrationAccessToken
@@ -80,12 +85,41 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
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">Vault Integration</CardTitle>
<Head>
<title>Authorize Vault Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After connecting to Vault, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Vault.png"
height={30}
width={30}
alt="HCP Vault logo"
/>
</div>
<span className="ml-2.5">HashiCorp Vault Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="Vault Cluster URL"
errorText={vaultURLErrorText}
isError={vaultURLErrorText !== "" ?? false}
className="px-6"
>
<Input placeholder="" value={vaultURL} onChange={(e) => setVaultURL(e.target.value)} />
</FormControl>
@@ -93,6 +127,7 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
label="Vault Namespace"
errorText={vaultNamespaceErrorText}
isError={vaultNamespaceErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder="admin/education"
@@ -104,6 +139,7 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
label="Vault RoleID"
errorText={vaultRoleIDErrorText}
isError={vaultRoleIDErrorText !== "" ?? false}
className="px-6"
>
<Input placeholder="" value={vaultRoleID} onChange={(e) => setVaultRoleID(e.target.value)} />
</FormControl>
@@ -111,6 +147,7 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
label="Vault SecretID"
errorText={vaultSecretIDErrorText}
isError={vaultSecretIDErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder=""
@@ -120,8 +157,9 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to Vault
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -25,7 +30,7 @@ export default function HashiCorpVaultCreateIntegrationPage() {
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: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const [vaultEnginePath, setVaultEnginePath] = useState("");
const [vaultEnginePathErrorText, setVaultEnginePathErrorText] = useState("");
@@ -79,10 +84,38 @@ export default function HashiCorpVaultCreateIntegrationPage() {
};
return integrationAuth && workspace ? (
<div className="flex h-full w-full items-center justify-center">
<Card className="max-w-md rounded-md p-8">
<CardTitle className="text-center">Vault Integration</CardTitle>
<FormControl label="Project Environment" className="mt-4">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up Vault Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to which path in HashiCorp Vault."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Vault.png"
height={30}
width={30}
alt="HCP Vault logo"
/>
</div>
<span className="ml-2.5">HashiCorp Vault Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -98,7 +131,7 @@ export default function HashiCorpVaultCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
@@ -109,6 +142,7 @@ export default function HashiCorpVaultCreateIntegrationPage() {
label="Vault KV Secrets Engine Path"
errorText={vaultEnginePathErrorText}
isError={vaultEnginePathErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder="kv"
@@ -120,6 +154,7 @@ export default function HashiCorpVaultCreateIntegrationPage() {
label="Vault Secret(s) Path"
errorText={vaultSecretPathErrorText}
isError={vaultSecretPathErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder="machine/dev"
@@ -129,17 +164,41 @@ export default function HashiCorpVaultCreateIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
isDisabled={!(isValidVaultPath(vaultEnginePath) && isValidVaultPath(vaultSecretPath))}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in Vault with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up Vault Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isintegrationAuthLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useSaveIntegrationAccessToken} from "@app/hooks/api";
@@ -39,19 +44,49 @@ export default function RenderCreateIntegrationPage() {
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>
<Head>
<title>Authorize Render Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Render.png"
height={30}
width={30}
alt="Render logo"
/>
</div>
<span className="ml-2.5">Render Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="Render API Key"
errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false}
className="px-6"
>
<Input placeholder="rnd_xxx" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to Render
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -28,8 +33,8 @@ export default function RenderCreateIntegrationPage() {
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({
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -82,10 +87,38 @@ export default function RenderCreateIntegrationPage() {
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up Render Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to Render environment variables."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/Render.png"
height={30}
width={30}
alt="Render logo"
/>
</div>
<span className="ml-2.5">Render Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -101,14 +134,14 @@ export default function RenderCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="Render Service" className="mt-4">
<FormControl label="Render Service" className="px-6">
<Select
value={targetApp}
onValueChange={(val) => setTargetApp(val)}
@@ -134,16 +167,40 @@ export default function RenderCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in Render with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up Render Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
useSaveIntegrationAccessToken
@@ -51,12 +56,41 @@ export default function TeamCityCreateIntegrationPage() {
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">TeamCity Integration</CardTitle>
<Head>
<title>Authorize TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/TeamCity.png"
height={28}
width={28}
alt="TeamCity logo"
/>
</div>
<span className="ml-2">TeamCity Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl
label="TeamCity Access Token"
errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder="Access Token"
@@ -68,6 +102,7 @@ export default function TeamCityCreateIntegrationPage() {
label="TeamCity Server URL"
errorText={serverUrlErrorText}
isError={serverUrlErrorText !== "" ?? false}
className="px-6"
>
<Input
placeholder="https://example.teamcity.com"
@@ -77,8 +112,9 @@ export default function TeamCityCreateIntegrationPage() {
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to TeamCity
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -35,8 +40,8 @@ export default function TeamCityCreateIntegrationPage() {
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({
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -102,9 +107,37 @@ export default function TeamCityCreateIntegrationPage() {
filteredBuildConfigs &&
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">TeamCity Integration</CardTitle>
<FormControl label="Project Environment" className="mt-4">
<Head>
<title>Set Up TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Choose which environment or folders in Infisical you want to sync to which project in TeamCity."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center pb-0.5">
<Image
src="/images/integrations/TeamCity.png"
height={28}
width={28}
alt="TeamCity logo"
/>
</div>
<span className="ml-2">TeamCity Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -120,14 +153,14 @@ export default function TeamCityCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="TeamCity Project" className="mt-4">
<FormControl label="TeamCity Project" className="px-6">
<Select
value={targetAppId}
onValueChange={(val) => setTargetAppId(val)}
@@ -150,7 +183,7 @@ export default function TeamCityCreateIntegrationPage() {
)}
</Select>
</FormControl>
<FormControl label="Team City Build Config (Optional)" className="mt-4">
<FormControl label="Team City Build Config (Optional)" className="px-6">
<Select
value={targetBuildConfigId}
onValueChange={(val) => setTargetBuildConfigId(val)}
@@ -169,7 +202,8 @@ export default function TeamCityCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
@@ -178,7 +212,25 @@ export default function TeamCityCreateIntegrationPage() {
</Card>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}
@@ -1,5 +1,10 @@
import { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import Link from "next/link";
import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import {
@@ -42,7 +47,7 @@ export default function VercelCreateIntegrationPage() {
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({
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
@@ -109,10 +114,38 @@ export default function VercelCreateIntegrationPage() {
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">
<div className="flex flex-col h-full w-full items-center justify-center">
<Head>
<title>Set Up Vercel Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle
className="text-left px-6 text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to Vercel's environment variables."
>
<div className="flex flex-row items-center">
<div className="inline flex items-center">
<Image
src="/images/integrations/Vercel.png"
height={30}
width={30}
alt="Vercel logo"
/>
</div>
<span className="ml-2">Vercel Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/vercel" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 rounded-md text-yellow text-sm inline-block bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] opacity-80 hover:opacity-100 cursor-default">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/>
Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl label="Infisical Project Environment" className="px-6">
<Select
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)}
@@ -128,14 +161,14 @@ export default function VercelCreateIntegrationPage() {
))}
</Select>
</FormControl>
<FormControl label="Secrets Path">
<FormControl label="Secrets Path" className="px-6">
<Input
value={secretPath}
onChange={(evt) => setSecretPath(evt.target.value)}
placeholder="Provide a path, default is /"
/>
</FormControl>
<FormControl label="Vercel App">
<FormControl label="Vercel App" className="px-6">
<Select
value={targetAppId}
onValueChange={(val) => setTargetAppId(val)}
@@ -158,7 +191,7 @@ export default function VercelCreateIntegrationPage() {
)}
</Select>
</FormControl>
<FormControl label="Vercel App Environment">
<FormControl label="Vercel App Environment" className="px-6">
<Select
value={targetEnvironment}
onValueChange={(val) => setTargetEnvironment(val)}
@@ -175,7 +208,7 @@ export default function VercelCreateIntegrationPage() {
</Select>
</FormControl>
{targetEnvironment === "preview" && filteredBranches && (
<FormControl label="Vercel Preview Branch (Optional)">
<FormControl label="Vercel Preview Branch (Optional)" className="px-6">
<Select
value={targetBranch}
onValueChange={(val) => setTargetBranch(val)}
@@ -192,16 +225,40 @@ export default function VercelCreateIntegrationPage() {
<Button
onClick={handleButtonClick}
color="mineshaft"
className="mt-4"
variant="outline_bg"
className="mt-2 mb-6 ml-auto mr-6"
isLoading={isLoading}
isDisabled={integrationAuthApps.length === 0}
>
Create Integration
</Button>
</Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/>
<div className="flex flex-col bg-mineshaft-800 border border-mineshaft-600 w-full p-4 max-w-lg mt-6 rounded-md">
<div className="flex flex-row items-center"><FontAwesomeIcon icon={faCircleInfo} className="text-mineshaft-200 text-xl"/> <span className="ml-3 text-md text-mineshaft-100">Pro Tips</span></div>
<span className="text-mineshaft-300 text-sm mt-4">After creating an integration, your secrets will start syncing immediately. This might cause an unexpected override of current secrets in Vercel with secrets from Infisical.</span>
</div>
</div>
) : (
<div />
<div className="flex justify-center items-center w-full h-full">
<Head>
<title>Set Up Vercel Integration</title>
<link rel='icon' href='/infisical.ico' />
</Head>
{isIntegrationAuthAppsLoading ? <img src="/images/loading/loading.gif" height={70} width={120} alt="infisical loading indicator" /> : <div className="max-w-md h-max p-6 border border-mineshaft-600 rounded-md bg-mineshaft-800 text-mineshaft-200 flex flex-col text-center">
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/>
<p>
Something went wrong. Please contact <a
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a> if the issue persists.
</p>
</div>}
</div>
);
}