mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge pull request #988 from Infisical/integrations-uiux-updates
improved ui/ux for checkly, gcp, and vault integrations
This commit is contained in:
@@ -608,6 +608,12 @@ const getAppsLaravelForge = async ({
|
||||
* @returns {String} apps.name - name of Fly.io apps
|
||||
*/
|
||||
const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
|
||||
interface FlyioApp {
|
||||
id: string;
|
||||
name: string;
|
||||
hostname: string;
|
||||
}
|
||||
|
||||
const query = `
|
||||
query($role: String) {
|
||||
apps(type: "container", first: 400, role: $role) {
|
||||
@@ -620,7 +626,7 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
|
||||
}
|
||||
`;
|
||||
|
||||
const res = (
|
||||
const res: FlyioApp[] = (
|
||||
await standardRequest.post(
|
||||
INTEGRATION_FLYIO_API_URL,
|
||||
{
|
||||
@@ -639,8 +645,9 @@ const getAppsFlyio = async ({ accessToken }: { accessToken: string }) => {
|
||||
)
|
||||
).data.data.apps.nodes;
|
||||
|
||||
const apps = res.map((a: any) => ({
|
||||
const apps = res.map((a: FlyioApp) => ({
|
||||
name: a.name,
|
||||
appId: a.id
|
||||
}));
|
||||
|
||||
return apps;
|
||||
|
||||
@@ -783,12 +783,12 @@ const syncSecretsAWSParameterStore = async ({
|
||||
};
|
||||
|
||||
/**
|
||||
* Sync/push [secrets] to AWS secret manager
|
||||
* Sync/push [secrets] to AWS Secrets Manager
|
||||
* @param {Object} obj
|
||||
* @param {IIntegration} obj.integration - integration details
|
||||
* @param {Object} obj.secrets - secrets to push to integration (object where keys are secret keys and values are secret values)
|
||||
* @param {String} obj.accessId - access id for AWS secret manager integration
|
||||
* @param {String} obj.accessToken - access token for AWS secret manager integration
|
||||
* @param {String} obj.accessId - access id for AWS Secrets Manager integration
|
||||
* @param {String} obj.accessToken - access token for AWS Secrets Manager integration
|
||||
*/
|
||||
const syncSecretsAWSSecretManager = async ({
|
||||
integration,
|
||||
|
||||
@@ -187,7 +187,8 @@ const integrationSchema = new Schema<IIntegration>(
|
||||
default: "/",
|
||||
},
|
||||
metadata: {
|
||||
type: Schema.Types.Mixed
|
||||
type: Schema.Types.Mixed,
|
||||
default: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -192,7 +192,7 @@ export const getIntegrationOptions = async () => {
|
||||
docsLink: "",
|
||||
},
|
||||
{
|
||||
name: "AWS Secret Manager",
|
||||
name: "AWS Secrets Manager",
|
||||
slug: "aws-secret-manager",
|
||||
image: "Amazon Web Services.png",
|
||||
isAvailable: true,
|
||||
|
||||
@@ -76,7 +76,7 @@ The changelog below reflects new product developments and updates on a monthly b
|
||||
- Added secret backups support for the CLI; it now fetches and caches secrets locally to be used in the event of future failed fetch.
|
||||
- Added support for comparing secret values across environments on each secret.
|
||||
- Added native AWS Parameter Store integration.
|
||||
- Added native AWS Secret Manager integration.
|
||||
- Added native AWS Secrets Manager integration.
|
||||
- Added native GitLab integration.
|
||||
- Added native CircleCI integration.
|
||||
- Added native Travis CI integration.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: "AWS Secret Manager"
|
||||
description: "How to sync secrets from Infisical to AWS Secret Manager"
|
||||
title: "AWS Secrets Manager"
|
||||
description: "How to sync secrets from Infisical to AWS Secrets Manager"
|
||||
---
|
||||
|
||||
Prerequisites:
|
||||
@@ -8,15 +8,15 @@ Prerequisites:
|
||||
- Set up and add envars to [Infisical Cloud](https://app.infisical.com)
|
||||
- Set up AWS and have/create an IAM user
|
||||
|
||||
## Grant the IAM user permissions to access AWS Secret Manager
|
||||
## Grant the IAM user permissions to access AWS Secrets Manager
|
||||
|
||||
Navigate to your IAM user permissions and add a permission policy to grant access to AWS Secret Manager.
|
||||
Navigate to your IAM user permissions and add a permission policy to grant access to AWS Secrets Manager.
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
For better security, here's a custom policy containing the minimum permissions required by Infisical to sync secrets to AWS Secret Manager for the IAM user that you can use:
|
||||
For better security, here's a custom policy containing the minimum permissions required by Infisical to sync secrets to AWS Secrets Manager for the IAM user that you can use:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -40,7 +40,7 @@ For better security, here's a custom policy containing the minimum permissions r
|
||||
|
||||

|
||||
|
||||
## Authorize Infisical for AWS Secret Manager
|
||||
## Authorize Infisical for AWS Secrets Manager
|
||||
|
||||
Obtain a AWS access key ID and secret access key for your IAM user in IAM > Users > User > Security credentials > Access keys
|
||||
|
||||
@@ -48,7 +48,7 @@ Obtain a AWS access key ID and secret access key for your IAM user in IAM > User
|
||||

|
||||

|
||||
|
||||
Press on the AWS Secret Manager tile and input your AWS access key ID and secret access key from the previous step.
|
||||
Press on the AWS Secrets Manager tile and input your AWS access key ID and secret access key from the previous step.
|
||||
|
||||

|
||||
|
||||
@@ -61,12 +61,12 @@ Press on the AWS Secret Manager tile and input your AWS access key ID and secret
|
||||
|
||||
## Start integration
|
||||
|
||||
Select which Infisical environment secrets you want to sync to which AWS Secret Manager region and under which secret name. Then, press create integration to start syncing secrets to AWS Secret Manager.
|
||||
Select which Infisical environment secrets you want to sync to which AWS Secrets Manager region and under which secret name. Then, press create integration to start syncing secrets to AWS Secrets Manager.
|
||||
|
||||

|
||||
|
||||
<Info>
|
||||
Infisical currently syncs environment variables to AWS Secret Manager as
|
||||
Infisical currently syncs environment variables to AWS Secrets Manager as
|
||||
key-value pairs under one secret. We're actively exploring ways to help users
|
||||
group environment variable key-pairs under multiple secrets for greater
|
||||
control.
|
||||
|
||||
@@ -29,7 +29,7 @@ Missing an integration? [Throw in a request](https://github.com/Infisical/infisi
|
||||
| [Checkly](/integrations/cloud/checkly) | Cloud | Available |
|
||||
| [HashiCorp Vault](/integrations/cloud/hashicorp-vault) | Cloud | Available |
|
||||
| [AWS Parameter Store](/integrations/cloud/aws-parameter-store) | Cloud | Available |
|
||||
| [AWS Secret Manager](/integrations/cloud/aws-secret-manager) | Cloud | Available |
|
||||
| [AWS Secrets Manager](/integrations/cloud/aws-secret-manager) | Cloud | Available |
|
||||
| [Azure Key Vault](/integrations/cloud/azure-key-vault) | Cloud | Available |
|
||||
| [GCP Secret Manager](/integrations/cloud/gcp-secret-manager) | Cloud | Available |
|
||||
| [Windmill](/integrations/cloud/windmill) | Cloud | Available |
|
||||
|
||||
@@ -5,7 +5,7 @@ interface Mapping {
|
||||
const integrationSlugNameMapping: Mapping = {
|
||||
"azure-key-vault": "Azure Key Vault",
|
||||
"aws-parameter-store": "AWS Parameter Store",
|
||||
"aws-secret-manager": "AWS Secret Manager",
|
||||
"aws-secret-manager": "AWS Secrets Manager",
|
||||
"heroku": "Heroku",
|
||||
"vercel": "Vercel",
|
||||
"netlify": "Netlify",
|
||||
|
||||
@@ -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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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'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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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>
|
||||
);
|
||||
|
||||
@@ -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'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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
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:support@infisical.com"
|
||||
>
|
||||
support@infisical.com
|
||||
</a> if the issue persists.
|
||||
</p>
|
||||
</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user