feat(infisical-pg): changed frontend api types _id to normal id

This commit is contained in:
Akhil Mohan
2024-01-27 12:38:22 +05:30
parent f3b37de3f3
commit aaba4a0895
161 changed files with 5358 additions and 4510 deletions
+1 -1
View File
@@ -8,7 +8,7 @@
"start:docker": "next build && next start", "start:docker": "next build && next start",
"lint": "eslint --ext js,ts,tsx ./src", "lint": "eslint --ext js,ts,tsx ./src",
"lint:fix": "eslint --fix --ext js,ts,tsx ./src", "lint:fix": "eslint --fix --ext js,ts,tsx ./src",
"type-check": "tsc --project tsconfig.json", "type:check": "tsc --project tsconfig.json --noEmit",
"storybook": "storybook dev -p 6006 -s ./public", "storybook": "storybook dev -p 6006 -s ./public",
"build-storybook": "storybook build" "build-storybook": "storybook build"
}, },
+1 -1
View File
@@ -1,5 +1,5 @@
export interface Tag { export interface Tag {
_id: string; id: string;
name: string; name: string;
slug: string; slug: string;
user: string; user: string;
@@ -31,18 +31,18 @@ const AddTagPopoverContent = ({
return ( return (
<PopoverContent <PopoverContent
side="left" side="left"
className="relative max-h-96 w-auto min-w-[200px] p-2 overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 text-bunker-200" className="relative max-h-96 w-auto min-w-[200px] overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 p-2 text-bunker-200"
hideCloseBtn hideCloseBtn
> >
<div className=" text-center text-sm font-medium text-bunker-200"> <div className=" text-center text-sm font-medium text-bunker-200">
Add tags to {secKey || "this secret"} Add tags to {secKey || "this secret"}
</div> </div>
<div className="absolute left-0 w-full border-mineshaft-600 border-t mt-2" /> <div className="absolute left-0 mt-2 w-full border-t border-mineshaft-600" />
<div className="flex flex-col space-y-1.5"> <div className="flex flex-col space-y-1.5">
{wsTags?.map((wsTag: WsTag) => ( {wsTags?.map((wsTag: WsTag) => (
<div <div
key={`tag-${wsTag.id}`} key={`tag-${wsTag.id}`}
className="mt-4 h-[32px] relative flex items-center justify-start hover:border-mineshaft-600 hover:border hover:bg-mineshaft-700 p-2 rounded-md hover:text-bunker-200 bg-none" className="relative mt-4 flex h-[32px] items-center justify-start rounded-md bg-none p-2 hover:border hover:border-mineshaft-600 hover:bg-mineshaft-700 hover:text-bunker-200"
onClick={() => handleSelectTag(wsTag)} onClick={() => handleSelectTag(wsTag)}
onMouseEnter={() => handleTagOnMouseEnter(wsTag)} onMouseEnter={() => handleTagOnMouseEnter(wsTag)}
onMouseLeave={() => handleTagOnMouseLeave()} onMouseLeave={() => handleTagOnMouseLeave()}
@@ -54,7 +54,7 @@ const AddTagPopoverContent = ({
<Checkbox <Checkbox
id="autoCapitalization" id="autoCapitalization"
isChecked={selectedTagIds?.[wsTag.slug]} isChecked={selectedTagIds?.[wsTag.slug]}
className="absolute top-[50%] translate-y-[-50%] left-[10px] " className="absolute top-[50%] left-[10px] translate-y-[-50%] "
checkIndicatorBg={`${ checkIndicatorBg={`${
!selectedTagIds?.[wsTag.slug] ? "text-transparent" : "text-mineshaft-800" !selectedTagIds?.[wsTag.slug] ? "text-transparent" : "text-mineshaft-800"
}`} }`}
@@ -62,7 +62,7 @@ const AddTagPopoverContent = ({
)} )}
<div className="ml-7 flex items-center gap-3"> <div className="ml-7 flex items-center gap-3">
<div <div
className="w-[10px] h-[10px] rounded-full" className="h-[10px] w-[10px] rounded-full"
style={{ background: wsTag?.tagColor ? wsTag.tagColor : "#bec2c8" }} style={{ background: wsTag?.tagColor ? wsTag.tagColor : "#bec2c8" }}
> >
{" "} {" "}
@@ -7,70 +7,61 @@ import { useOrganization } from "@app/context";
// REFACTOR: Move all these modals into one reusable one // REFACTOR: Move all these modals into one reusable one
type Props = { type Props = {
isOpen?: boolean; isOpen?: boolean;
onClose: ()=>void; onClose: () => void;
text: string; text: string;
} };
const UpgradePlanModal = ({ const UpgradePlanModal = ({ isOpen, onClose, text }: Props) => {
isOpen,
onClose,
text,
}:Props) => {
const router = useRouter(); const router = useRouter();
const { currentOrg } = useOrganization(); const { currentOrg } = useOrganization();
return ( return (
<div> <div>
<Transition appear show={isOpen} as={Fragment}> <Transition appear show={isOpen} as={Fragment}>
<Dialog as='div' className='relative z-10' onClose={onClose}> <Dialog as="div" className="relative z-10" onClose={onClose}>
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter='ease-out duration-300' enter="ease-out duration-300"
enterFrom='opacity-0' enterFrom="opacity-0"
enterTo='opacity-100' enterTo="opacity-100"
leave='ease-in duration-150' leave="ease-in duration-150"
leaveFrom='opacity-100' leaveFrom="opacity-100"
leaveTo='opacity-0' leaveTo="opacity-0"
> >
<div className='fixed inset-0 bg-black bg-opacity-50 drop-shadow-xl' /> <div className="fixed inset-0 bg-black bg-opacity-50 drop-shadow-xl" />
</Transition.Child> </Transition.Child>
<div className='fixed inset-0 overflow-y-auto'> <div className="fixed inset-0 overflow-y-auto">
<div className='flex min-h-full items-center justify-center p-4 text-center'> <div className="flex min-h-full items-center justify-center p-4 text-center">
<Transition.Child <Transition.Child
as={Fragment} as={Fragment}
enter='ease-out duration-300' enter="ease-out duration-300"
enterFrom='opacity-0 scale-95' enterFrom="opacity-0 scale-95"
enterTo='opacity-100 scale-100' enterTo="opacity-100 scale-100"
leave='ease-in duration-200' leave="ease-in duration-200"
leaveFrom='opacity-100 scale-100' leaveFrom="opacity-100 scale-100"
leaveTo='opacity-0 scale-95' leaveTo="opacity-0 scale-95"
> >
<Dialog.Panel className='w-full max-w-md transform overflow-hidden rounded-md bg-bunker border border-mineshaft-500 p-6 pt-5 text-left align-middle shadow-xl transition-all'> <Dialog.Panel className="w-full max-w-md transform overflow-hidden rounded-md border border-mineshaft-500 bg-bunker p-6 pt-5 text-left align-middle shadow-xl transition-all">
<Dialog.Title <Dialog.Title as="h3" className="text-xl font-medium leading-6 text-primary">
as='h3'
className='text-xl font-medium leading-6 text-primary'
>
Unleash Infisical&apos;s Full Power Unleash Infisical&apos;s Full Power
</Dialog.Title> </Dialog.Title>
<div className='mt-2'> <div className="mt-2">
<p className='text-sm text-bunker-300 mb-1'> <p className="mb-1 text-sm text-bunker-300">{text}</p>
{text} <p className="text-sm text-bunker-300">
</p>
<p className='text-sm text-bunker-300'>
Upgrade and get access to this, as well as to other powerful enhancements. Upgrade and get access to this, as well as to other powerful enhancements.
</p> </p>
</div> </div>
<div className='mt-4'> <div className="mt-4">
<button <button
type='button' type="button"
className='inline-flex justify-center rounded-md border border-transparent bg-primary opacity-80 hover:opacity-100 px-4 py-2 text-sm font-medium text-black hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2' className="hover:text-semibold inline-flex justify-center rounded-md border border-transparent bg-primary px-4 py-2 text-sm font-medium text-black opacity-80 duration-200 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={() => router.push(`/org/${currentOrg?.id}/billing`)} onClick={() => router.push(`/org/${currentOrg?.id}/billing`)}
> >
Upgrade Now Upgrade Now
</button> </button>
<button <button
type='button' type="button"
className='ml-2 inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-sm font-medium text-gray-400 hover:border-red hover:text-red hover:text-semibold duration-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2' className="hover:text-semibold ml-2 inline-flex justify-center rounded-md border border-transparent bg-gray-800 px-4 py-2 text-sm font-medium text-gray-400 duration-200 hover:border-red hover:text-red focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
onClick={onClose} onClick={onClose}
> >
Maybe Later Maybe Later
@@ -10,7 +10,8 @@ import {
useDeleteUserFromWorkspace, useDeleteUserFromWorkspace,
useGetUserWsKey, useGetUserWsKey,
useUpdateUserWorkspaceRole, useUpdateUserWorkspaceRole,
useUploadWsKey} from "@app/hooks/api"; useUploadWsKey
} from "@app/hooks/api";
import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto"; import { decryptAssymmetric, encryptAssymmetric } from "../../utilities/cryptography/crypto";
import guidGenerator from "../../utilities/randomId"; import guidGenerator from "../../utilities/randomId";
@@ -191,11 +192,15 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
<UpgradePlanModal <UpgradePlanModal
isOpen={isUpgradeModalOpen} isOpen={isUpgradeModalOpen}
onClose={closeUpgradeModal} onClose={closeUpgradeModal}
text={subscription.slug === null ? "You can use RBAC under an Enterprise license" : "You can use RBAC if you switch to Infisical's Team Plan."} text={
subscription.slug === null
? "You can use RBAC under an Enterprise license"
: "You can use RBAC if you switch to Infisical's Team Plan."
}
/> />
)} )}
<table className="my-0.5 w-full"> <table className="my-0.5 w-full">
<thead className="text-xs font-light text-gray-400 bg-mineshaft-800"> <thead className="bg-mineshaft-800 text-xs font-light text-gray-400">
<tr> <tr>
<th className="py-3.5 pl-4 text-left">NAME</th> <th className="py-3.5 pl-4 text-left">NAME</th>
<th className="py-3.5 pl-4 text-left">EMAIL</th> <th className="py-3.5 pl-4 text-left">EMAIL</th>
@@ -213,12 +218,13 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{!isUserListLoading && userData?.filter( {!isUserListLoading &&
(user) => userData?.filter(
user.firstName?.toLowerCase().includes(filter) || (user) =>
user.lastName?.toLowerCase().includes(filter) || user.firstName?.toLowerCase().includes(filter) ||
user.email?.toLowerCase().includes(filter) user.lastName?.toLowerCase().includes(filter) ||
).length > 0 && user.email?.toLowerCase().includes(filter)
).length > 0 &&
userData userData
?.filter( ?.filter(
(user) => (user) =>
@@ -373,10 +379,18 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
</td> </td>
</tr> </tr>
))} ))}
{isUserListLoading && <> {isUserListLoading && (
<tr key={guidGenerator()} className="bg-mineshaft-800 text-sm animate-pulse h-14 w-full"/> <>
<tr key={guidGenerator()} className="bg-mineshaft-800 text-sm animate-pulse h-14 w-full"/> <tr
</>} key={guidGenerator()}
className="h-14 w-full animate-pulse bg-mineshaft-800 text-sm"
/>
<tr
key={guidGenerator()}
className="h-14 w-full animate-pulse bg-mineshaft-800 text-sm"
/>
</>
)}
</tbody> </tbody>
</table> </table>
</div> </div>
@@ -13,17 +13,27 @@ import { Tag } from "public/data/frequentInterfaces";
* @param {function} obj.modifyTags - modify tags for a certain secret * @param {function} obj.modifyTags - modify tags for a certain secret
* @param {Tag[]} obj.position - currently selected tags for a certain secret * @param {Tag[]} obj.position - currently selected tags for a certain secret
*/ */
const AddTagsMenu = ({ allTags, currentTags, modifyTags, id }: { allTags: Tag[]; currentTags: Tag[]; modifyTags: (value: Tag[], id: string) => void; id: string; }) => { const AddTagsMenu = ({
allTags,
currentTags,
modifyTags,
id
}: {
allTags: Tag[];
currentTags: Tag[];
modifyTags: (value: Tag[], id: string) => void;
id: string;
}) => {
const router = useRouter(); const router = useRouter();
return ( return (
<Menu as="div" className="ml-2 relative inline-block text-left"> <Menu as="div" className="relative ml-2 inline-block text-left">
<Menu.Button <Menu.Button
as="div" as="div"
className="flex justify-center items-center font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75" className="flex items-center justify-center font-medium focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"
> >
<div className='bg-mineshaft/30 cursor-pointer rounded-sm text-sm text-mineshaft-200/50 hover:bg-mineshaft/70 duration-200 flex items-center'> <div className="flex cursor-pointer items-center rounded-sm bg-mineshaft/30 text-sm text-mineshaft-200/50 duration-200 hover:bg-mineshaft/70">
<FontAwesomeIcon icon={faPlus} className="p-[0.28rem]"/> <FontAwesomeIcon icon={faPlus} className="p-[0.28rem]" />
{currentTags?.length > 2 && <span className='pr-2'>{currentTags.length - 2}</span>} {currentTags?.length > 2 && <span className="pr-2">{currentTags.length - 2}</span>}
</div> </div>
</Menu.Button> </Menu.Button>
<Transition <Transition
@@ -35,24 +45,40 @@ const AddTagsMenu = ({ allTags, currentTags, modifyTags, id }: { allTags: Tag[];
leaveFrom="transform opacity-100 scale-100" leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95" leaveTo="transform opacity-0 scale-95"
> >
<Menu.Items className="absolute z-[90] text-sm drop-shadow-xl right-0 mt-0.5 w-[12rem] origin-top-right rounded-md bg-mineshaft-600 border border-mineshaft-500 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none p-1 space-y-1"> <Menu.Items className="absolute right-0 z-[90] mt-0.5 w-[12rem] origin-top-right space-y-1 rounded-md border border-mineshaft-500 bg-mineshaft-600 p-1 text-sm shadow-lg ring-1 ring-black ring-opacity-5 drop-shadow-xl focus:outline-none">
{allTags?.map((tag) => { return ( {allTags?.map((tag) => {
<Menu.Item key={tag.id}> return (
<button <Menu.Item key={tag.id}>
type="button" <button
className={`${currentTags?.map(currentTag => currentTag.name).includes(tag.name) ? "opacity-30 cursor-default" : "hover:bg-mineshaft-700"} w-full text-left bg-mineshaft-800 px-2 py-0.5 text-bunker-200 rounded-sm flex items-center`} type="button"
onClick={() => {if (!currentTags?.map(currentTag => currentTag.name).includes(tag.name)) {modifyTags(currentTags.concat([tag]), id)}}} className={`${
> currentTags?.map((currentTag) => currentTag.name).includes(tag.name)
{currentTags?.map(currentTag => currentTag.name).includes(tag.name) ? <FontAwesomeIcon icon={faCheckSquare} className="text-xs mr-2 text-primary"/> : <FontAwesomeIcon icon={faSquare} className="text-xs mr-2"/>} {tag.name} ? "cursor-default opacity-30"
</button> : "hover:bg-mineshaft-700"
</Menu.Item> } flex w-full items-center rounded-sm bg-mineshaft-800 px-2 py-0.5 text-left text-bunker-200`}
)})} onClick={() => {
if (!currentTags?.map((currentTag) => currentTag.name).includes(tag.name)) {
modifyTags(currentTags.concat([tag]), id);
}
}}
>
{currentTags?.map((currentTag) => currentTag.name).includes(tag.name) ? (
<FontAwesomeIcon icon={faCheckSquare} className="mr-2 text-xs text-primary" />
) : (
<FontAwesomeIcon icon={faSquare} className="mr-2 text-xs" />
)}{" "}
{tag.name}
</button>
</Menu.Item>
);
})}
<button <button
type="button" type="button"
className='w-full text-left bg-mineshaft-800 hover:bg-primary hover:text-black duration-200 px-2 py-0.5 text-bunker-200 rounded-sm' className="w-full rounded-sm bg-mineshaft-800 px-2 py-0.5 text-left text-bunker-200 duration-200 hover:bg-primary hover:text-black"
onClick={() => router.push(`/project/${String(router.query.id)}/settings`)} onClick={() => router.push(`/project/${String(router.query.id)}/settings`)}
> >
<FontAwesomeIcon icon={faPlus} className="mr-2 text-xs" />Add more tags <FontAwesomeIcon icon={faPlus} className="mr-2 text-xs" />
Add more tags
</button> </button>
</Menu.Items> </Menu.Items>
</Transition> </Transition>
+138 -96
View File
@@ -38,8 +38,7 @@ const colors = [
"bg-[#6F1AB6]/40", "bg-[#6F1AB6]/40",
"bg-[#C40B13]/40", "bg-[#C40B13]/40",
"bg-[#332FD0]/40" "bg-[#332FD0]/40"
] ];
const colorsText = [ const colorsText = [
"text-[#fcf0c3]/70", "text-[#fcf0c3]/70",
@@ -50,7 +49,7 @@ const colorsText = [
"text-[#FFE5F1]/70", "text-[#FFE5F1]/70",
"text-[#FFDEDE]/70", "text-[#FFDEDE]/70",
"text-[#DFF6FF]/70" "text-[#DFF6FF]/70"
] ];
/** /**
* This component represent a single row for an environemnt variable on the dashboard * This component represent a single row for an environemnt variable on the dashboard
@@ -88,112 +87,155 @@ const KeyPair = ({
togglePITSidebar, togglePITSidebar,
tags tags
}: KeyPairProps) => { }: KeyPairProps) => {
const tagData = (tags.map((tag, index) => {return { const tagData = tags.map((tag, index) => {
...tag, return {
color: colors[index%colors.length], ...tag,
colorText: colorsText[index%colorsText.length] color: colors[index % colors.length],
}})); colorText: colorsText[index % colorsText.length]
};
});
return ( return (
<div <div
className={`group flex flex-col items-center border-b border-mineshaft-500 hover:bg-white/[0.03] duration-100 ${isSnapshot && "pointer-events-none"} ${ className={`group flex flex-col items-center border-b border-mineshaft-500 duration-100 hover:bg-white/[0.03] ${
keyPair.id === sidebarSecretId && "bg-mineshaft-700 duration-200" isSnapshot && "pointer-events-none"
}`} } ${keyPair.id === sidebarSecretId && "bg-mineshaft-700 duration-200"}`}
> >
<div className="relative flex flex-row justify-between w-full mr-auto max-h-14 items-center"> <div className="relative mr-auto flex max-h-14 w-full flex-row items-center justify-between">
<div className="w-[23%] border-r border-mineshaft-600 flex flex-row items-center"> <div className="flex w-[23%] flex-row items-center border-r border-mineshaft-600">
<div className='text-bunker-400 text-xs flex items-center justify-center w-14 h-10 cursor-default'>{keyPair.pos + 1}</div> <div className="flex h-10 w-14 cursor-default items-center justify-center text-xs text-bunker-400">
<div className="flex items-center max-h-16 w-full"> {keyPair.pos + 1}
<DashboardInputField </div>
isCapitalized = {isCapitalized} <div className="flex max-h-16 w-full items-center">
onChangeHandler={modifyKey} <DashboardInputField
type="varName" isCapitalized={isCapitalized}
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} onChangeHandler={modifyKey}
value={keyPair.key} type="varName"
isDuplicate={isDuplicate} id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
overrideEnabled={keyPair.valueOverride !== undefined} value={keyPair.key}
modifyValueOverride={modifyValueOverride} isDuplicate={isDuplicate}
isSideBarOpen={keyPair.id === sidebarSecretId} overrideEnabled={keyPair.valueOverride !== undefined}
/> modifyValueOverride={modifyValueOverride}
isSideBarOpen={keyPair.id === sidebarSecretId}
/>
</div>
</div>
<div className="w-5/12 border-r border-mineshaft-600">
<div className="mt-4 flex max-h-10 items-center rounded-lg md:mt-0">
<DashboardInputField
onChangeHandler={
keyPair.valueOverride !== undefined ? modifyValueOverride : modifyValue
}
type="value"
id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
value={keyPair.valueOverride !== undefined ? keyPair.valueOverride : keyPair.value}
blurred={isBlurred}
overrideEnabled={keyPair.valueOverride !== undefined}
isSideBarOpen={keyPair.id === sidebarSecretId}
/>
</div>
</div>
<div className="w-[calc(10%)] border-r border-mineshaft-600">
<div className="flex max-h-16 items-center">
<DashboardInputField
onChangeHandler={modifyComment}
type="comment"
id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
value={keyPair.comment}
isDuplicate={isDuplicate}
isSideBarOpen={keyPair.id === sidebarSecretId}
/>
</div>
</div> </div>
</div> </div>
<div className="w-5/12 border-r border-mineshaft-600"> <div className="overflow-r-scroll no-scrollbar::-webkit-scrollbar flex h-10 w-2/12 items-center overflow-visible no-scrollbar">
<div <div className="flex max-h-16 items-center">
className='flex items-center rounded-lg mt-4 md:mt-0 max-h-10' {keyPair.tags?.map(
> (tag, index) =>
<DashboardInputField index < 2 && (
onChangeHandler={keyPair.valueOverride !== undefined ? modifyValueOverride : modifyValue} <div
type="value" key={keyPair.pos}
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} className={`ml-2 px-1.5 ${
value={keyPair.valueOverride !== undefined ? keyPair.valueOverride : keyPair.value} tagData.filter((tagDp) => tagDp.id === tag.id)[0]?.color
blurred={isBlurred} } rounded-sm text-sm ${
overrideEnabled={keyPair.valueOverride !== undefined} tagData.filter((tagDp) => tagDp.id === tag.id)[0]?.colorText
isSideBarOpen={keyPair.id === sidebarSecretId} } flex items-center`}
/> >
</div> <span className="mb-0.5 cursor-default">{tag.name}</span>
</div> <FontAwesomeIcon
<div className="w-[calc(10%)] border-r border-mineshaft-600"> icon={faXmark}
<div className="flex items-center max-h-16"> className="ml-1 cursor-pointer p-1"
<DashboardInputField onClick={() =>
onChangeHandler={modifyComment} modifyTags(
type="comment" keyPair.tags.filter((ttag) => ttag.id !== tag.id),
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} keyPair.id
value={keyPair.comment} )
isDuplicate={isDuplicate} }
isSideBarOpen={keyPair.id === sidebarSecretId} />
/> </div>
</div> )
</div> )}
<div className="w-2/12 h-10 flex items-center overflow-visible overflow-r-scroll no-scrollbar no-scrollbar::-webkit-scrollbar">
<div className="flex items-center max-h-16">
{keyPair.tags?.map((tag, index) => (
index < 2 && <div key={keyPair.pos} className={`ml-2 px-1.5 ${tagData.filter(tagDp => tagDp.id === tag.id)[0]?.color} rounded-sm text-sm ${tagData.filter(tagDp => tagDp.id === tag.id)[0]?.colorText} flex items-center`}>
<span className='mb-0.5 cursor-default'>{tag.name}</span>
<FontAwesomeIcon icon={faXmark} className="ml-1 cursor-pointer p-1" onClick={() => modifyTags(keyPair.tags.filter(ttag => ttag.id !== tag.id), keyPair.id)}/>
</div>
))}
<AddTagsMenu allTags={tags} currentTags={keyPair.tags} modifyTags={modifyTags} id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} /> <AddTagsMenu
allTags={tags}
currentTags={keyPair.tags}
modifyTags={modifyTags}
id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
/>
</div> </div>
</div>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => {
if (togglePITSidebar) {
togglePITSidebar(false);
}
toggleSidebar(keyPair.id)
}}
className={`cursor-pointer w-[1.5rem] h-[2.35rem] ml-auto group-hover:bg-mineshaft-700 z-50 rounded-md invisible group-hover:visible flex flex-row justify-center items-center ${isSnapshot ?? "invisible"}`}
>
<FontAwesomeIcon className="text-bunker-300 hover:text-primary text-lg" icon={faEllipsis} />
</div>
<div className={`group-hover:bg-mineshaft-700 z-50 ${isSnapshot ?? "invisible"}`}>
{keyPair.key || keyPair.value
? <DeleteActionButton
onSubmit={() => { if (deleteRow) {
deleteRow({ ids: [keyPair.id], secretName: keyPair?.key })
}}}
isPlain
/>
: <div className='cursor-pointer w-[1.5rem] h-[2.35rem] mr-2 flex items-center justfy-center'>
<div <div
onKeyDown={() => null} onKeyDown={() => null}
role="button" role="button"
tabIndex={0} tabIndex={0}
onClick={() => { if (deleteRow) { onClick={() => {
deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) if (togglePITSidebar) {
}}} togglePITSidebar(false);
className="invisible group-hover:visible" }
toggleSidebar(keyPair.id);
}}
className={`invisible z-50 ml-auto flex h-[2.35rem] w-[1.5rem] cursor-pointer flex-row items-center justify-center rounded-md group-hover:visible group-hover:bg-mineshaft-700 ${
isSnapshot ?? "invisible"
}`}
> >
<FontAwesomeIcon className="text-bunker-300 hover:text-red pl-2 pr-6 text-lg mt-0.5" icon={faXmark} /> <FontAwesomeIcon
className="text-lg text-bunker-300 hover:text-primary"
icon={faEllipsis}
/>
</div>
<div className={`z-50 group-hover:bg-mineshaft-700 ${isSnapshot ?? "invisible"}`}>
{keyPair.key || keyPair.value ? (
<DeleteActionButton
onSubmit={() => {
if (deleteRow) {
deleteRow({ ids: [keyPair.id], secretName: keyPair?.key });
}
}}
isPlain
/>
) : (
<div className="justfy-center mr-2 flex h-[2.35rem] w-[1.5rem] cursor-pointer items-center">
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => {
if (deleteRow) {
deleteRow({ ids: [keyPair.id], secretName: keyPair?.key });
}
}}
className="invisible group-hover:visible"
>
<FontAwesomeIcon
className="mt-0.5 pl-2 pr-6 text-lg text-bunker-300 hover:text-red"
icon={faXmark}
/>
</div>
</div>
)}
</div> </div>
</div>}
</div> </div>
</div> </div>
</div> );
)}; };
export default KeyPair; export default KeyPair;
@@ -157,7 +157,7 @@ export default function NavHeader({
})} })}
{isProtectedBranch && ( {isProtectedBranch && (
<Tooltip content={`Protected by policy ${protectionPolicyName}`}> <Tooltip content={`Protected by policy ${protectionPolicyName}`}>
<FontAwesomeIcon icon={faLock} className="text-primary ml-2" /> <FontAwesomeIcon icon={faLock} className="ml-2 text-primary" />
</Tooltip> </Tooltip>
)} )}
</div> </div>
@@ -119,9 +119,9 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
const [showHexInput, setShowHexInput] = useState<boolean>(false); const [showHexInput, setShowHexInput] = useState<boolean>(false);
const selectedTagColor = watch("color", secretTagsColors[0].hex); const selectedTagColor = watch("color", secretTagsColors[0].hex);
useEffect(()=>{ useEffect(() => {
if(!isOpen) reset(); if (!isOpen) reset();
},[isOpen]) }, [isOpen]);
const onFormSubmit = async ({ name, color }: FormData) => { const onFormSubmit = async ({ name, color }: FormData) => {
try { try {
@@ -168,21 +168,21 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
Tag Color Tag Color
</div> </div>
<div className="flex space-x-2"> <div className="flex space-x-2">
<div className="p-2 rounded flex items-center justify-center border border-mineshaft-500 bg-mineshaft-900 "> <div className="flex items-center justify-center rounded border border-mineshaft-500 bg-mineshaft-900 p-2 ">
<div <div
className="w-6 h-6 rounded-full" className="h-6 w-6 rounded-full"
style={{ background: `${selectedTagColor}` }} style={{ background: `${selectedTagColor}` }}
/> />
</div> </div>
<div className="flex-grow flex items-center rounded border-mineshaft-500 bg-mineshaft-900 px-1 pr-2"> <div className="flex flex-grow items-center rounded border-mineshaft-500 bg-mineshaft-900 px-1 pr-2">
{!showHexInput ? ( {!showHexInput ? (
<div className="inline-flex gap-3 items-center pl-3"> <div className="inline-flex items-center gap-3 pl-3">
{secretTagsColors.map(($tagColor: TagColor) => { {secretTagsColors.map(($tagColor: TagColor) => {
return ( return (
<div key={`tag-color-${$tagColor.id}`}> <div key={`tag-color-${$tagColor.id}`}>
<Tooltip content={`${$tagColor.name}`}> <Tooltip content={`${$tagColor.name}`}>
<div <div
className=" flex items-center justify-center w-[26px] h-[26px] hover:ring-offset-2 hover:ring-2 bg-[#bec2c8] border-2 p-2 hover:shadow-lg border-transparent hover:border-black rounded-full" className=" flex h-[26px] w-[26px] items-center justify-center rounded-full border-2 border-transparent bg-[#bec2c8] p-2 hover:border-black hover:shadow-lg hover:ring-2 hover:ring-offset-2"
key={`tag-${$tagColor.id}`} key={`tag-${$tagColor.id}`}
style={{ backgroundColor: `${$tagColor.hex}` }} style={{ backgroundColor: `${$tagColor.hex}` }}
onClick={() => setValue("color", $tagColor.hex)} onClick={() => setValue("color", $tagColor.hex)}
@@ -200,18 +200,18 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
})} })}
</div> </div>
) : ( ) : (
<div className="flex flex-grow items-center px-2 tags-hex-wrapper"> <div className="tags-hex-wrapper flex flex-grow items-center px-2">
<div className="flex items-center relative rounded-md "> <div className="relative flex items-center rounded-md ">
{isValidHexColor(selectedTagColor) && ( {isValidHexColor(selectedTagColor) && (
<div <div
className="w-7 h-7 rounded-full flex items-center justify-center" className="flex h-7 w-7 items-center justify-center rounded-full"
style={{ background: `${selectedTagColor}` }} style={{ background: `${selectedTagColor}` }}
> >
<FontAwesomeIcon icon={faCheck} style={{ color: "#00000070" }} /> <FontAwesomeIcon icon={faCheck} style={{ color: "#00000070" }} />
</div> </div>
)} )}
{!isValidHexColor(selectedTagColor) && ( {!isValidHexColor(selectedTagColor) && (
<div className="border-dashed border bg-blue rounded-full w-7 h-7 border-mineshaft-500" /> <div className="bg-blue h-7 w-7 rounded-full border border-dashed border-mineshaft-500" />
)} )}
</div> </div>
<div className="flex-grow"> <div className="flex-grow">
@@ -225,10 +225,10 @@ export const CreateTagModal = ({ isOpen, onToggle }: Props): JSX.Element => {
</div> </div>
</div> </div>
)} )}
<div className="border-mineshaft-500 border h-8 mx-4" /> <div className="mx-4 h-8 border border-mineshaft-500" />
<div className="w-7 h-7 flex items-center justify-center"> <div className="flex h-7 w-7 items-center justify-center">
<div <div
className={`flex items-center justify-center w-7 h-7 bg-transparent cursor-pointer hover:ring-offset-1 hover:ring-2 border-mineshaft-500 border bg-mineshaft-900 rounded-sm p-2 ${ className={`flex h-7 w-7 cursor-pointer items-center justify-center rounded-sm border border-mineshaft-500 bg-transparent bg-mineshaft-900 p-2 hover:ring-2 hover:ring-offset-1 ${
showHexInput ? "tags-conic-bg rounded-full" : "" showHexInput ? "tags-conic-bg rounded-full" : ""
}`} }`}
onClick={() => setShowHexInput((prev) => !prev)} onClick={() => setShowHexInput((prev) => !prev)}
@@ -1,12 +1,6 @@
const ENV = process.env.NEXT_PUBLIC_ENV! || "development"; // investigate const ENV = process.env.NEXT_PUBLIC_ENV! || "development"; // investigate
const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY!; const POSTHOG_API_KEY = process.env.NEXT_PUBLIC_POSTHOG_API_KEY!;
const POSTHOG_HOST = const POSTHOG_HOST = process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com";
process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com";
const INTERCOMid = process.env.NEXT_PUBLIC_INTERCOMid!; const INTERCOMid = process.env.NEXT_PUBLIC_INTERCOMid!;
export { export { ENV, INTERCOMid, POSTHOG_API_KEY, POSTHOG_HOST };
ENV,
INTERCOMid,
POSTHOG_API_KEY,
POSTHOG_HOST
};
@@ -54,9 +54,7 @@ export const load = () => {
// Initializes Intercom // Initializes Intercom
export const boot = (options = {}) => { export const boot = (options = {}) => {
window && window && window.Intercom && window.Intercom("boot", { appid: APPid, ...options });
window.Intercom &&
window.Intercom("boot", { appid: APPid, ...options });
}; };
export const update = () => { export const update = () => {
@@ -22,7 +22,7 @@ export const OrgPermissionProvider = ({ children }: Props): JSX.Element => {
if (isLoading) { if (isLoading) {
return ( return (
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800"> <div className="flex h-screen w-screen items-center justify-center bg-bunker-800">
<img <img
src="/images/loading/loading.gif" src="/images/loading/loading.gif"
height={70} height={70}
@@ -35,7 +35,7 @@ export const OrgPermissionProvider = ({ children }: Props): JSX.Element => {
if (!permission) { if (!permission) {
return ( return (
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800"> <div className="flex h-screen w-screen items-center justify-center bg-bunker-800">
Failed to load user permissions Failed to load user permissions
</div> </div>
); );
@@ -3,7 +3,6 @@ import { createContext, ReactNode, useContext, useMemo } from "react";
import { useGetOrganizations } from "@app/hooks/api"; import { useGetOrganizations } from "@app/hooks/api";
import { Organization } from "@app/hooks/api/types"; import { Organization } from "@app/hooks/api/types";
type TOrgContext = { type TOrgContext = {
orgs?: Organization[]; orgs?: Organization[];
currentOrg?: Organization; currentOrg?: Organization;
@@ -18,7 +18,7 @@ export const ProjectPermissionProvider = ({ children }: Props): JSX.Element => {
if ((isLoading && currentWorkspace) || isWsLoading) { if ((isLoading && currentWorkspace) || isWsLoading) {
return ( return (
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800"> <div className="flex h-screen w-screen items-center justify-center bg-bunker-800">
<img <img
src="/images/loading/loading.gif" src="/images/loading/loading.gif"
height={70} height={70}
@@ -31,7 +31,7 @@ export const ProjectPermissionProvider = ({ children }: Props): JSX.Element => {
if (!permission && currentWorkspace) { if (!permission && currentWorkspace) {
return ( return (
<div className="flex items-center justify-center w-screen h-screen bg-bunker-800"> <div className="flex h-screen w-screen items-center justify-center bg-bunker-800">
Failed to load user permissions Failed to load user permissions
</div> </div>
); );
@@ -72,9 +72,9 @@ export const ServerConfigProvider = ({ children }: Props): JSX.Element => {
export const useServerConfig = () => { export const useServerConfig = () => {
const ctx = useContext(ServerConfigContext); const ctx = useContext(ServerConfigContext);
// if (!ctx) { if (!ctx) {
// throw new Error("useServerConfig has to be used within <UserContext.Provider>"); throw new Error("useServerConfig has to be used within <UserContext.Provider>");
// } }
return ctx || { config: { allowSignUp: true } }; return ctx;
}; };
@@ -1,10 +1,10 @@
import { createContext, ReactNode, useContext, useMemo } from "react"; import { createContext, ReactNode, useContext, useMemo } from "react";
import { useGetUser } from "@app/hooks/api"; import { useGetUser } from "@app/hooks/api";
import { User } from "@app/hooks/api/types"; import { User, UserEnc } from "@app/hooks/api/types";
type TUserContext = { type TUserContext = {
user: User; user: User & UserEnc;
isLoading: boolean; isLoading: boolean;
}; };
@@ -26,7 +26,7 @@ export const WorkspaceProvider = ({ children }: Props): JSX.Element => {
const wsId = workspaceId || localStorage.getItem("projectData.id"); const wsId = workspaceId || localStorage.getItem("projectData.id");
return { return {
workspaces: ws || [], workspaces: ws || [],
currentWorkspace: (ws || []).find(({ id: id }) => id === wsId), currentWorkspace: (ws || []).find(({ id }) => id === wsId),
isLoading isLoading
}; };
}, [ws, workspaceId, isLoading]); }, [ws, workspaceId, isLoading]);
+4 -4
View File
@@ -112,8 +112,8 @@ const initProjectHelper = async ({
}); });
await uploadWsKey({ await uploadWsKey({
workspaceId: workspace._id, workspaceId: workspace.id,
userId: user._id, userId: user.id,
encryptedKey: ciphertext, encryptedKey: ciphertext,
nonce nonce
}); });
@@ -121,13 +121,13 @@ const initProjectHelper = async ({
// encrypt and upload secrets to new project // encrypt and upload secrets to new project
const secrets = await encryptSecrets({ const secrets = await encryptSecrets({
secretsToEncrypt: secretsToBeAdded, secretsToEncrypt: secretsToBeAdded,
workspaceId: workspace._id, workspaceId: workspace.id,
env: "dev" env: "dev"
}); });
secrets?.forEach((secret) => { secrets?.forEach((secret) => {
createSecret({ createSecret({
workspaceId: workspace._id, workspaceId: workspace.id,
environment: secret.environment, environment: secret.environment,
type: secret.type, type: secret.type,
secretKey: secret.secretName, secretKey: secret.secretName,
+18 -18
View File
@@ -1,27 +1,27 @@
export type APIKeyDataV2 = { export type APIKeyDataV2 = {
id: string; id: string;
name: string; name: string;
user: string; user: string;
lastUsed?: string; lastUsed?: string;
usageCount: number; usageCount: number;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
}; };
export type CreateAPIKeyDataV2DTO = { export type CreateAPIKeyDataV2DTO = {
name: string; name: string;
} };
export type CreateServiceTokenDataV3Res = { export type CreateServiceTokenDataV3Res = {
apiKeyData: APIKeyDataV2; apiKeyData: APIKeyDataV2;
apiKey: string; apiKey: string;
} };
export type UpdateAPIKeyDataV2DTO = { export type UpdateAPIKeyDataV2DTO = {
apiKeyDataId: string; apiKeyDataId: string;
name: string; name: string;
} };
export type DeleteAPIKeyDataV2DTO = { export type DeleteAPIKeyDataV2DTO = {
apiKeyDataId: string; apiKeyDataId: string;
} };
+6 -6
View File
@@ -194,7 +194,8 @@ interface DeleteServiceTokenEvent {
}; };
} }
interface CreateIdentityEvent { // note: currently not logging org-role interface CreateIdentityEvent {
// note: currently not logging org-role
type: EventType.CREATE_IDENTITY; type: EventType.CREATE_IDENTITY;
metadata: { metadata: {
identityId: string; identityId: string;
@@ -218,7 +219,7 @@ interface DeleteIdentityEvent {
} }
interface LoginIdentityUniversalAuthEvent { interface LoginIdentityUniversalAuthEvent {
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH ; type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH;
metadata: { metadata: {
identityId: string; identityId: string;
identityUniversalAuthId: string; identityUniversalAuthId: string;
@@ -259,7 +260,7 @@ interface GetIdentityUniversalAuthEvent {
} }
interface CreateIdentityUniversalAuthClientSecretEvent { interface CreateIdentityUniversalAuthClientSecretEvent {
type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ; type: EventType.CREATE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET;
metadata: { metadata: {
identityId: string; identityId: string;
clientSecretId: string; clientSecretId: string;
@@ -273,9 +274,8 @@ interface GetIdentityUniversalAuthClientSecretsEvent {
}; };
} }
interface RevokeIdentityUniversalAuthClientSecretEvent { interface RevokeIdentityUniversalAuthClientSecretEvent {
type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET ; type: EventType.REVOKE_IDENTITY_UNIVERSAL_AUTH_CLIENT_SECRET;
metadata: { metadata: {
identityId: string; identityId: string;
clientSecretId: string; clientSecretId: string;
@@ -507,7 +507,7 @@ export type Event =
| UpdateUserDeniedPermissions; | UpdateUserDeniedPermissions;
export type AuditLog = { export type AuditLog = {
_id: string; id: string;
actor: Actor; actor: Actor;
organization: string; organization: string;
workspace: string; workspace: string;
@@ -55,14 +55,14 @@ export type BitBucketWorkspace = {
uuid: string; uuid: string;
name: string; name: string;
slug: string; slug: string;
} };
export type NorthflankSecretGroup = { export type NorthflankSecretGroup = {
name: string; name: string;
groupId: string; groupId: string;
} };
export type TeamCityBuildConfig = { export type TeamCityBuildConfig = {
name: string; name: string;
buildConfigId: string; buildConfigId: string;
} };
+1 -1
View File
@@ -36,5 +36,5 @@ export type TIntegration = {
org: string; org: string;
project: string; project: string;
environment: string; environment: string;
} };
}; };
+12 -12
View File
@@ -13,7 +13,7 @@ export type RenameOrgDTO = {
export type BillingDetails = { export type BillingDetails = {
name: string; name: string;
email: string; email: string;
} };
export type PlanBillingInfo = { export type PlanBillingInfo = {
amount: number; amount: number;
@@ -22,7 +22,7 @@ export type PlanBillingInfo = {
interval: "month" | "year"; interval: "month" | "year";
intervalCount: number; intervalCount: number;
quantity: number; quantity: number;
} };
export type Invoice = { export type Invoice = {
id: string; id: string;
@@ -31,7 +31,7 @@ export type Invoice = {
number: string; number: string;
paid: boolean; paid: boolean;
total: number; total: number;
} };
export type PmtMethod = { export type PmtMethod = {
id: string; id: string;
@@ -40,14 +40,14 @@ export type PmtMethod = {
exp_year: number; exp_year: number;
funding: string; funding: string;
last4: string; last4: string;
} };
export type TaxID = { export type TaxID = {
id: string; id: string;
country: string; country: string;
type: string; type: string;
value: string; value: string;
} };
export type License = { export type License = {
id: string; id: string;
@@ -58,22 +58,22 @@ export type License = {
expiresAt: string; expiresAt: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
} };
export type OrgPlanTableHead = { export type OrgPlanTableHead = {
name: string; name: string;
} };
export type OrgPlanTableRow = { export type OrgPlanTableRow = {
name: string; name: string;
allowed: number | boolean | null; allowed: number | boolean | null;
used: string; used: string;
} };
export type OrgPlanTable = { export type OrgPlanTable = {
head: OrgPlanTableHead[]; head: OrgPlanTableHead[];
rows: OrgPlanTableRow[]; rows: OrgPlanTableRow[];
} };
export type ProductsTableHead = { export type ProductsTableHead = {
name: string; name: string;
@@ -82,7 +82,7 @@ export type ProductsTableHead = {
productId: string; productId: string;
slug: string; slug: string;
tier: number; tier: number;
} };
export type ProductsTableRow = { export type ProductsTableRow = {
name: string; name: string;
@@ -90,9 +90,9 @@ export type ProductsTableRow = {
team: number | boolean | null; team: number | boolean | null;
pro: number | boolean | null; pro: number | boolean | null;
enterprise: number | boolean | null; enterprise: number | boolean | null;
} };
export type ProductsTable = { export type ProductsTable = {
head: ProductsTableHead[]; head: ProductsTableHead[];
rows: ProductsTableRow[]; rows: ProductsTableRow[];
} };
@@ -4,7 +4,7 @@ export type ServiceTokenScope = {
}; };
export type ServiceToken = { export type ServiceToken = {
_id: string; id: string;
name: string; name: string;
workspace: string; workspace: string;
scopes: ServiceTokenScope[]; scopes: ServiceTokenScope[];
+9 -10
View File
@@ -9,7 +9,7 @@ export type WsTag = {
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
__v: number; __v: number;
} };
export type WorkspaceTag = { id: string; name: string; slug: string }; export type WorkspaceTag = { id: string; name: string; slug: string };
@@ -30,7 +30,7 @@ export type CreateTagRes = {
id: string; id: string;
}; };
export type DeleteTagDTO = { tagID: string; }; export type DeleteTagDTO = { tagID: string };
export type DeleteWsTagRes = { export type DeleteWsTagRes = {
name: string; name: string;
@@ -42,16 +42,15 @@ export type DeleteWsTagRes = {
}; };
export type SecretTags = { export type SecretTags = {
id: string;
id: string; id: string;
slug: string; slug: string;
tagColor: string; tagColor: string;
} };
export type TagColor = { export type TagColor = {
id: number; id: number;
hex: string hex: string;
rgba: string rgba: string;
name: string name: string;
selected: boolean selected: boolean;
} };
+7 -7
View File
@@ -1,9 +1,9 @@
export type TrustedIp = { export type TrustedIp = {
id: string; id: string;
workspace: string; workspace: string;
ipAddress: string; ipAddress: string;
type: "ipv4" | "ipv6"; type: "ipv4" | "ipv6";
isActive: boolean; isActive: boolean;
comment: string; comment: string;
prefix?: number; prefix?: number;
}; };
+1 -1
View File
@@ -23,7 +23,7 @@ export * from "./secrets/types";
export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types"; export type { CreateServiceTokenDTO, ServiceToken } from "./serviceTokens/types";
export type { SubscriptionPlan } from "./subscriptions/types"; export type { SubscriptionPlan } from "./subscriptions/types";
export type { WsTag } from "./tags/types"; export type { WsTag } from "./tags/types";
export type { AddUserToWsDTO, OrgUser, TWorkspaceUser, User } from "./users/types"; export type { AddUserToWsDTO, OrgUser, TWorkspaceUser, User, UserEnc } from "./users/types";
export type { TWebhook } from "./webhooks/types"; export type { TWebhook } from "./webhooks/types";
export type { export type {
CreateEnvironmentDTO, CreateEnvironmentDTO,
+3 -2
View File
@@ -14,7 +14,8 @@ import {
RenameUserDTO, RenameUserDTO,
TokenVersion, TokenVersion,
UpdateOrgUserRoleDTO, UpdateOrgUserRoleDTO,
User User,
UserEnc
} from "./types"; } from "./types";
export const userKeys = { export const userKeys = {
@@ -29,7 +30,7 @@ export const userKeys = {
}; };
export const fetchUserDetails = async () => { export const fetchUserDetails = async () => {
const { data } = await apiRequest.get<{ user: User }>("/api/v1/user"); const { data } = await apiRequest.get<{ user: User & UserEnc }>("/api/v1/user");
return data.user; return data.user;
}; };
+10 -8
View File
@@ -19,6 +19,12 @@ export type User = {
lastName?: string; lastName?: string;
authProvider?: AuthMethod; authProvider?: AuthMethod;
authMethods: AuthMethod[]; authMethods: AuthMethod[];
isMfaEnabled: boolean;
seenIps: string[];
id: string;
};
export type UserEnc = {
encryptionVersion?: number; encryptionVersion?: number;
protectedKey?: string; protectedKey?: string;
protectedKeyIV?: string; protectedKeyIV?: string;
@@ -27,19 +33,15 @@ export type User = {
encryptedPrivateKey?: string; encryptedPrivateKey?: string;
iv?: string; iv?: string;
tag?: string; tag?: string;
isMfaEnabled: boolean;
seenIps: string[];
_id: string;
__v: number;
}; };
export type OrgUser = { export type OrgUser = {
_id: string; id: string;
user: { user: {
email: string; email: string;
firstName: string; firstName: string;
lastName: string; lastName: string;
_id: string; id: string;
publicKey: string; publicKey: string;
}; };
inviteEmail: string; inviteEmail: string;
@@ -88,7 +90,7 @@ export type RenameUserDTO = {
}; };
export type APIKeyData = { export type APIKeyData = {
_id: string; id: string;
name: string; name: string;
user: string; user: string;
lastUsed: string; lastUsed: string;
@@ -97,7 +99,7 @@ export type APIKeyData = {
}; };
export type TokenVersion = { export type TokenVersion = {
_id: string; id: string;
user: string; user: string;
userAgent: string; userAgent: string;
ip: string; ip: string;
+1 -2
View File
@@ -22,7 +22,7 @@ export type NameWorkspaceSecretsDTO = {
secretName: string; secretName: string;
id: string; id: string;
}[]; }[];
} };
// mutation dto // mutation dto
export type CreateWorkspaceDTO = { export type CreateWorkspaceDTO = {
@@ -47,7 +47,6 @@ export type ReorderEnvironmentsDTO = {
environmentName: string; environmentName: string;
otherEnvironmentSlug: string; otherEnvironmentSlug: string;
otherEnvironmentName: string; otherEnvironmentName: string;
}; };
export type UpdateEnvironmentDTO = { export type UpdateEnvironmentDTO = {
@@ -100,7 +100,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
<nav className="items-between flex h-full flex-col justify-between overflow-y-auto dark:[color-scheme:dark]"> <nav className="items-between flex h-full flex-col justify-between overflow-y-auto dark:[color-scheme:dark]">
<div> <div>
{!router.asPath.includes("personal") && ( {!router.asPath.includes("personal") && (
<div className="flex h-12 cursor-default justify-between items-center px-3 pt-6"> <div className="flex h-12 cursor-default items-center justify-between px-3 pt-6">
<Link href={`/org/${currentOrg?.id}/overview`}> <Link href={`/org/${currentOrg?.id}/overview`}>
<div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100"> <div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100">
<FontAwesomeIcon icon={faArrowLeft} className="pr-3" /> <FontAwesomeIcon icon={faArrowLeft} className="pr-3" />
@@ -179,7 +179,7 @@ export const AdminLayout = ({ children }: LayoutProps) => {
<div <div
className={`${ className={`${
!updateClosed ? "block" : "hidden" !updateClosed ? "block" : "hidden"
} relative z-10 mb-6 flex pb-2 w-52 flex-col items-center justify-start rounded-md border border-mineshaft-600 bg-mineshaft-900 px-3`} } relative z-10 mb-6 flex w-52 flex-col items-center justify-start rounded-md border border-mineshaft-600 bg-mineshaft-900 px-3 pb-2`}
> >
<div className="text-md mt-2 w-full font-semibold text-mineshaft-100"> <div className="text-md mt-2 w-full font-semibold text-mineshaft-100">
Infisical December update Infisical December update
+47 -47
View File
@@ -120,7 +120,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
const { user } = useUser(); const { user } = useUser();
const { subscription } = useSubscription(); const { subscription } = useSubscription();
const workspaceId = currentWorkspace?._id || ""; const workspaceId = currentWorkspace?.id || "";
const { data: updateClosed } = useGetUserAction("december_update_closed"); const { data: updateClosed } = useGetUserAction("december_update_closed");
const { data: secretApprovalReqCount } = useGetSecretApprovalRequestCount({ workspaceId }); const { data: secretApprovalReqCount } = useGetSecretApprovalRequestCount({ workspaceId });
@@ -179,19 +179,19 @@ export const AppLayout = ({ children }: LayoutProps) => {
// Put a user in an org if they're not in one yet // Put a user in an org if they're not in one yet
const putUserInOrg = async () => { const putUserInOrg = async () => {
if (tempLocalStorage("orgData.id") === "") { if (tempLocalStorage("orgData.id") === "") {
localStorage.setItem("orgData.id", orgs[0]?._id); localStorage.setItem("orgData.id", orgs[0]?.id);
} }
if ( if (
currentOrg && currentOrg &&
((workspaces?.length === 0 && router.asPath.includes("project")) || ((workspaces?.length === 0 && router.asPath.includes("project")) ||
router.asPath.includes("/project/undefined") || router.asPath.includes("/project/undefined") ||
(!orgs?.map((org) => org._id)?.includes(router.query.id) && (!orgs?.map((org) => org.id)?.includes(router.query.id) &&
!router.asPath.includes("project") && !router.asPath.includes("project") &&
!router.asPath.includes("personal") && !router.asPath.includes("personal") &&
!router.asPath.includes("integration"))) !router.asPath.includes("integration")))
) { ) {
router.push(`/org/${currentOrg?._id}/overview`); router.push(`/org/${currentOrg?.id}/overview`);
} }
// else if (!router.asPath.includes("org") && !router.asPath.includes("project") && !router.asPath.includes("integrations") && !router.asPath.includes("personal-settings")) { // else if (!router.asPath.includes("org") && !router.asPath.includes("project") && !router.asPath.includes("integrations") && !router.asPath.includes("personal-settings")) {
@@ -221,14 +221,14 @@ export const AppLayout = ({ children }: LayoutProps) => {
const onCreateProject = async ({ name, addMembers }: TAddProjectFormData) => { const onCreateProject = async ({ name, addMembers }: TAddProjectFormData) => {
// type check // type check
if (!currentOrg?._id) return; if (!currentOrg?.id) return;
try { try {
const { const {
data: { data: {
workspace: { _id: newWorkspaceId } workspace: { id: newWorkspaceId }
} }
} = await createWs.mutateAsync({ } = await createWs.mutateAsync({
organizationId: currentOrg?._id, organizationId: currentOrg?.id,
workspaceName: name workspaceName: name
}); });
@@ -243,13 +243,13 @@ export const AppLayout = ({ children }: LayoutProps) => {
await uploadWsKey.mutateAsync({ await uploadWsKey.mutateAsync({
encryptedKey: ciphertext, encryptedKey: ciphertext,
nonce, nonce,
userId: user?._id, userId: user?.id,
workspaceId: newWorkspaceId workspaceId: newWorkspaceId
}); });
if (addMembers) { if (addMembers) {
// not using hooks because need at this point only // not using hooks because need at this point only
const orgUsers = await fetchOrgUsers(currentOrg._id); const orgUsers = await fetchOrgUsers(currentOrg.id);
const decryptKey = await fetchUserWsKey(newWorkspaceId); const decryptKey = await fetchUserWsKey(newWorkspaceId);
await addWsUser.mutateAsync({ await addWsUser.mutateAsync({
workspaceId: newWorkspaceId, workspaceId: newWorkspaceId,
@@ -259,7 +259,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
.filter( .filter(
({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email ({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email
) )
.map(({ user: orgUser, _id: orgMembershipId }) => ({ .map(({ user: orgUser, id: orgMembershipId }) => ({
userPublicKey: orgUser.publicKey, userPublicKey: orgUser.publicKey,
orgMembershipId orgMembershipId
})) }))
@@ -285,7 +285,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
<div className="flex h-12 cursor-default items-center px-3 pt-6"> <div className="flex h-12 cursor-default items-center px-3 pt-6">
{(router.asPath.includes("project") || {(router.asPath.includes("project") ||
router.asPath.includes("integrations")) && ( router.asPath.includes("integrations")) && (
<Link href={`/org/${currentOrg?._id}/overview`}> <Link href={`/org/${currentOrg?.id}/overview`}>
<div className="pl-1 pr-2 text-mineshaft-400 duration-200 hover:text-mineshaft-100"> <div className="pl-1 pr-2 text-mineshaft-400 duration-200 hover:text-mineshaft-100">
<FontAwesomeIcon icon={faArrowLeft} /> <FontAwesomeIcon icon={faArrowLeft} />
</div> </div>
@@ -298,7 +298,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
{currentOrg?.name.charAt(0)} {currentOrg?.name.charAt(0)}
</div> </div>
<div <div
className="pl-2 text-sm text-mineshaft-100 text-ellipsis overflow-hidden" className="overflow-hidden text-ellipsis pl-2 text-sm text-mineshaft-100"
style={{ maxWidth: "140px" }} style={{ maxWidth: "140px" }}
> >
{currentOrg?.name} {currentOrg?.name}
@@ -312,15 +312,15 @@ export const AppLayout = ({ children }: LayoutProps) => {
<DropdownMenuContent align="start" className="p-1"> <DropdownMenuContent align="start" className="p-1">
<div className="px-2 py-1 text-xs text-mineshaft-400">{user?.email}</div> <div className="px-2 py-1 text-xs text-mineshaft-400">{user?.email}</div>
{orgs?.map((org) => ( {orgs?.map((org) => (
<DropdownMenuItem key={org._id}> <DropdownMenuItem key={org.id}>
<Button <Button
onClick={() => changeOrg(org?._id)} onClick={() => changeOrg(org?.id)}
variant="plain" variant="plain"
colorSchema="secondary" colorSchema="secondary"
size="xs" size="xs"
className="flex w-full items-center justify-start p-0 font-normal" className="flex w-full items-center justify-start p-0 font-normal"
leftIcon={ leftIcon={
currentOrg._id === org._id && ( currentOrg.id === org.id && (
<FontAwesomeIcon icon={faCheck} className="mr-3 text-primary" /> <FontAwesomeIcon icon={faCheck} className="mr-3 text-primary" />
) )
} }
@@ -421,8 +421,8 @@ export const AppLayout = ({ children }: LayoutProps) => {
Project Project
</p> </p>
<Select <Select
defaultValue={currentWorkspace?._id} defaultValue={currentWorkspace?.id}
value={currentWorkspace?._id} value={currentWorkspace?.id}
className="w-full truncate bg-mineshaft-600 py-2.5 font-medium" className="w-full truncate bg-mineshaft-600 py-2.5 font-medium"
onValueChange={(value) => { onValueChange={(value) => {
router.push(`/project/${value}/secrets/overview`); router.push(`/project/${value}/secrets/overview`);
@@ -433,12 +433,12 @@ export const AppLayout = ({ children }: LayoutProps) => {
> >
<div className="no-scrollbar::-webkit-scrollbar h-full no-scrollbar"> <div className="no-scrollbar::-webkit-scrollbar h-full no-scrollbar">
{workspaces {workspaces
.filter((ws) => ws.organization === currentOrg?._id) .filter((ws) => ws.organization === currentOrg?.id)
.map(({ _id, name }) => ( .map(({ id, name }) => (
<SelectItem <SelectItem
key={`ws-layout-list-${_id}`} key={`ws-layout-list-${id}`}
value={_id} value={id}
className={`${currentWorkspace?._id === _id && "bg-mineshaft-600"}`} className={`${currentWorkspace?.id === id && "bg-mineshaft-600"}`}
> >
{name} {name}
</SelectItem> </SelectItem>
@@ -474,7 +474,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
</Select> </Select>
</div> </div>
) : ( ) : (
<Link href={`/org/${currentOrg?._id}/overview`}> <Link href={`/org/${currentOrg?.id}/overview`}>
<div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100"> <div className="my-6 flex cursor-default items-center justify-center pr-2 text-sm text-mineshaft-300 hover:text-mineshaft-100">
<FontAwesomeIcon icon={faArrowLeft} className="pr-3" /> <FontAwesomeIcon icon={faArrowLeft} className="pr-3" />
Back to organization Back to organization
@@ -485,11 +485,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
{(router.asPath.includes("project") || router.asPath.includes("integrations")) && {(router.asPath.includes("project") || router.asPath.includes("integrations")) &&
currentWorkspace ? ( currentWorkspace ? (
<Menu> <Menu>
<Link href={`/project/${currentWorkspace?._id}/secrets/overview`} passHref> <Link href={`/project/${currentWorkspace?.id}/secrets/overview`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath.includes( isSelected={router.asPath.includes(
`/project/${currentWorkspace?._id}/secrets` `/project/${currentWorkspace?.id}/secrets`
)} )}
icon="system-outline-90-lock-closed" icon="system-outline-90-lock-closed"
> >
@@ -497,11 +497,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/project/${currentWorkspace?._id}/members`} passHref> <Link href={`/project/${currentWorkspace?.id}/members`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={ isSelected={
router.asPath === `/project/${currentWorkspace?._id}/members` router.asPath === `/project/${currentWorkspace?.id}/members`
} }
icon="system-outline-96-groups" icon="system-outline-96-groups"
> >
@@ -509,7 +509,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/integrations/${currentWorkspace?._id}`} passHref> <Link href={`/integrations/${currentWorkspace?.id}`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath.includes("/integrations")} isSelected={router.asPath.includes("/integrations")}
@@ -519,11 +519,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/project/${currentWorkspace?._id}/secret-rotation`} passHref> <Link href={`/project/${currentWorkspace?.id}/secret-rotation`} passHref>
<a className="relative"> <a className="relative">
<MenuItem <MenuItem
isSelected={ isSelected={
router.asPath === `/project/${currentWorkspace?._id}/secret-rotation` router.asPath === `/project/${currentWorkspace?.id}/secret-rotation`
} }
icon="rotation" icon="rotation"
> >
@@ -531,11 +531,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/project/${currentWorkspace?._id}/approval`} passHref> <Link href={`/project/${currentWorkspace?.id}/approval`} passHref>
<a className="relative"> <a className="relative">
<MenuItem <MenuItem
isSelected={ isSelected={
router.asPath === `/project/${currentWorkspace?._id}/approval` router.asPath === `/project/${currentWorkspace?.id}/approval`
} }
icon="system-outline-189-domain-verification" icon="system-outline-189-domain-verification"
> >
@@ -548,11 +548,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/project/${currentWorkspace?._id}/audit-logs`} passHref> <Link href={`/project/${currentWorkspace?.id}/audit-logs`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={ isSelected={
router.asPath === `/project/${currentWorkspace?._id}/audit-logs` router.asPath === `/project/${currentWorkspace?.id}/audit-logs`
} }
icon="system-outline-168-view-headline" icon="system-outline-168-view-headline"
> >
@@ -560,11 +560,11 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/project/${currentWorkspace?._id}/settings`} passHref> <Link href={`/project/${currentWorkspace?.id}/settings`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={ isSelected={
router.asPath === `/project/${currentWorkspace?._id}/settings` router.asPath === `/project/${currentWorkspace?.id}/settings`
} }
icon="system-outline-109-slider-toggle-settings" icon="system-outline-109-slider-toggle-settings"
> >
@@ -575,7 +575,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
</Menu> </Menu>
) : ( ) : (
<Menu className="mt-4"> <Menu className="mt-4">
<Link href={`/org/${currentOrg?._id}/overview`} passHref> <Link href={`/org/${currentOrg?.id}/overview`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath.includes("/overview")} isSelected={router.asPath.includes("/overview")}
@@ -585,40 +585,40 @@ export const AppLayout = ({ children }: LayoutProps) => {
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/org/${currentOrg?._id}/members`} passHref> <Link href={`/org/${currentOrg?.id}/members`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath === `/org/${currentOrg?._id}/members`} isSelected={router.asPath === `/org/${currentOrg?.id}/members`}
icon="system-outline-96-groups" icon="system-outline-96-groups"
> >
Access Control Access Control
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/org/${currentOrg?._id}/secret-scanning`} passHref> <Link href={`/org/${currentOrg?.id}/secret-scanning`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath === `/org/${currentOrg?._id}/secret-scanning`} isSelected={router.asPath === `/org/${currentOrg?.id}/secret-scanning`}
icon="system-outline-69-document-scan" icon="system-outline-69-document-scan"
> >
Secret Scanning Secret Scanning
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/org/${currentOrg?._id}/billing`} passHref> <Link href={`/org/${currentOrg?.id}/billing`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath === `/org/${currentOrg?._id}/billing`} isSelected={router.asPath === `/org/${currentOrg?.id}/billing`}
icon="system-outline-103-coin-cash-monetization" icon="system-outline-103-coin-cash-monetization"
> >
Usage & Billing Usage & Billing
</MenuItem> </MenuItem>
</a> </a>
</Link> </Link>
<Link href={`/org/${currentOrg?._id}/settings`} passHref> <Link href={`/org/${currentOrg?.id}/settings`} passHref>
<a> <a>
<MenuItem <MenuItem
isSelected={router.asPath === `/org/${currentOrg?._id}/settings`} isSelected={router.asPath === `/org/${currentOrg?.id}/settings`}
icon="system-outline-109-slider-toggle-settings" icon="system-outline-109-slider-toggle-settings"
> >
Organization Settings Organization Settings
@@ -717,7 +717,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
</DropdownMenuItem> </DropdownMenuItem>
))} ))}
{infisicalPlatformVersion && ( {infisicalPlatformVersion && (
<div className="cursor-default mb-2 mt-2 w-full pl-5 duration-200 hover:text-mineshaft-200 text-sm"> <div className="mb-2 mt-2 w-full cursor-default pl-5 text-sm duration-200 hover:text-mineshaft-200">
<FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" /> <FontAwesomeIcon icon={faInfo} className="mr-4 px-[0.1rem]" />
Version: {infisicalPlatformVersion} Version: {infisicalPlatformVersion}
</div> </div>
@@ -734,7 +734,7 @@ export const AppLayout = ({ children }: LayoutProps) => {
// direct user to start pro trial // direct user to start pro trial
const url = await mutateAsync({ const url = await mutateAsync({
orgId: currentOrg._id, orgId: currentOrg.id,
success_url: window.location.href success_url: window.location.href
}); });
@@ -17,13 +17,11 @@ import {
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Menu, Transition } from "@headlessui/react"; import { Menu, Transition } from "@headlessui/react";
import {TFunction} from "i18next"; import { TFunction } from "i18next";
import guidGenerator from "@app/components/utilities/randomId"; import guidGenerator from "@app/components/utilities/randomId";
import { useOrganization, useSubscription,useUser } from "@app/context"; import { useOrganization, useSubscription, useUser } from "@app/context";
import { import { useGetOrgTrialUrl, useLogoutUser } from "@app/hooks/api";
useGetOrgTrialUrl,
useLogoutUser} from "@app/hooks/api";
const supportOptions = (t: TFunction) => [ const supportOptions = (t: TFunction) => [
[ [
@@ -80,7 +78,7 @@ export const Navbar = () => {
const closeApp = async () => { const closeApp = async () => {
try { try {
console.log("Logging out...") console.log("Logging out...");
await logout.mutateAsync(); await logout.mutateAsync();
localStorage.removeItem("protectedKey"); localStorage.removeItem("protectedKey");
localStorage.removeItem("protectedKeyIV"); localStorage.removeItem("protectedKeyIV");
@@ -101,224 +99,224 @@ export const Navbar = () => {
return ( return (
<div className="z-[70] border-b border-mineshaft-500 bg-mineshaft-900 text-white"> <div className="z-[70] border-b border-mineshaft-500 bg-mineshaft-900 text-white">
<div className="flex w-full justify-between px-4"> <div className="flex w-full justify-between px-4">
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<div className="flex justify-center py-4"> <div className="flex justify-center py-4">
<Image src="/images/logotransparent.png" height={23} width={57} alt="logo" /> <Image src="/images/logotransparent.png" height={23} width={57} alt="logo" />
</div>
<a href="#" className="mx-2 text-2xl font-semibold text-white">
Infisical
</a>
</div> </div>
<a href="#" className="mx-2 text-2xl font-semibold text-white"> <div className="relative z-40 mx-2 flex items-center justify-start">
Infisical <a
</a> href="https://infisical.com/docs/documentation/getting-started/introduction"
</div> target="_blank"
<div className="relative z-40 mx-2 flex items-center justify-start"> rel="noopener noreferrer"
<a className="mr-4 flex items-center rounded-md px-3 py-2 text-sm text-gray-200 duration-200 hover:bg-white/10"
href="https://infisical.com/docs/documentation/getting-started/introduction"
target="_blank"
rel="noopener noreferrer"
className="mr-4 flex items-center rounded-md px-3 py-2 text-sm text-gray-200 duration-200 hover:bg-white/10"
>
<FontAwesomeIcon icon={faBook} className="mr-2 text-xl" />
Docs
</a>
<Menu as="div" className="relative inline-block text-left">
<div className="mr-4">
<Menu.Button className="inline-flex w-full justify-center rounded-md px-2 py-2 text-sm font-medium text-gray-200 duration-200 hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
<FontAwesomeIcon className="text-xl" icon={faCircleQuestion} />
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
> >
<Menu.Items className="absolute right-0 z-20 mt-0.5 w-64 origin-top-right rounded-md border border-mineshaft-700 bg-bunker px-2 py-1.5 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"> <FontAwesomeIcon icon={faBook} className="mr-2 text-xl" />
{supportOptionsList.map(([icon, text, url]) => ( Docs
<a </a>
key={guidGenerator()} <Menu as="div" className="relative inline-block text-left">
target="_blank" <div className="mr-4">
rel="noopener noreferrer" <Menu.Button className="inline-flex w-full justify-center rounded-md px-2 py-2 text-sm font-medium text-gray-200 duration-200 hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
href={String(url)} <FontAwesomeIcon className="text-xl" icon={faCircleQuestion} />
className="flex w-full items-center rounded-md py-0.5 font-normal text-gray-300 duration-200" </Menu.Button>
> </div>
<div className="relative flex w-full cursor-pointer select-none items-center justify-start rounded-md py-2 px-2 text-gray-400 duration-200 hover:bg-white/10 hover:text-gray-200"> <Transition
{icon} as={Fragment}
<div className="text-sm">{text}</div> enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute right-0 z-20 mt-0.5 w-64 origin-top-right rounded-md border border-mineshaft-700 bg-bunker px-2 py-1.5 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
{supportOptionsList.map(([icon, text, url]) => (
<a
key={guidGenerator()}
target="_blank"
rel="noopener noreferrer"
href={String(url)}
className="flex w-full items-center rounded-md py-0.5 font-normal text-gray-300 duration-200"
>
<div className="relative flex w-full cursor-pointer select-none items-center justify-start rounded-md py-2 px-2 text-gray-400 duration-200 hover:bg-white/10 hover:text-gray-200">
{icon}
<div className="text-sm">{text}</div>
</div>
</a>
))}
</Menu.Items>
</Transition>
</Menu>
<Menu as="div" className="relative mr-4 inline-block text-left">
<div>
<Menu.Button className="inline-flex w-full justify-center rounded-md py-2 pr-2 pl-2 text-sm font-medium text-gray-200 duration-200 hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
{user?.firstName} {user?.lastName}
<FontAwesomeIcon
icon={faAngleDown}
className="ml-2 mt-1 text-sm text-gray-300 hover:text-lime-100"
/>
</Menu.Button>
</div>
<Transition
as={Fragment}
enter="transition ease-out duration-100"
enterFrom="transform opacity-0 scale-95"
enterTo="transform opacity-100 scale-100"
leave="transition ease-in duration-75"
leaveFrom="transform opacity-100 scale-100"
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="w-68 absolute right-0 z-[125] mt-0.5 origin-top-right divide-y divide-mineshaft-700 rounded-md border border-mineshaft-700 bg-mineshaft-900 shadow-lg ring-1 ring-black ring-opacity-5 drop-shadow-2xl focus:outline-none">
<div className="px-1 py-1">
<div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400">
{t("nav.user.signed-in-as")}
</div> </div>
</a> <div
))} onKeyDown={() => null}
</Menu.Items> role="button"
</Transition> tabIndex={0}
</Menu> onClick={() => router.push("/personal-settings")}
<Menu as="div" className="relative mr-4 inline-block text-left"> className="mx-1 my-1 flex cursor-pointer flex-row items-center rounded-md px-1 hover:bg-white/5"
<div> >
<Menu.Button className="inline-flex w-full justify-center rounded-md py-2 pr-2 pl-2 text-sm font-medium text-gray-200 duration-200 hover:bg-white/10 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75"> <div className="flex h-8 w-9 items-center justify-center rounded-full bg-white/10 text-gray-300">
{user?.firstName} {user?.lastName} {user?.firstName?.charAt(0)}
<FontAwesomeIcon </div>
icon={faAngleDown} <div className="flex w-full items-center justify-between">
className="ml-2 mt-1 text-sm text-gray-300 hover:text-lime-100" <div>
/> <p className="px-2 pt-1 text-sm text-gray-300">
</Menu.Button> {" "}
</div> {user?.firstName} {user?.lastName}
<Transition </p>
as={Fragment} <p className="px-2 pb-1 text-xs text-gray-400">{user?.email}</p>
enter="transition ease-out duration-100" </div>
enterFrom="transform opacity-0 scale-95" <FontAwesomeIcon
enterTo="transform opacity-100 scale-100" icon={faGear}
leave="transition ease-in duration-75" className="mr-1 cursor-pointer rounded-md p-2 text-lg text-gray-400 hover:bg-white/10"
leaveFrom="transform opacity-100 scale-100" />
leaveTo="transform opacity-0 scale-95"
>
<Menu.Items className="absolute right-0 z-[125] mt-0.5 w-68 origin-top-right divide-y divide-mineshaft-700 drop-shadow-2xl rounded-md border border-mineshaft-700 bg-mineshaft-900 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none">
<div className="px-1 py-1">
<div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400">
{t("nav.user.signed-in-as")}
</div>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => router.push("/personal-settings")}
className="mx-1 my-1 flex cursor-pointer flex-row items-center rounded-md px-1 hover:bg-white/5"
>
<div className="flex h-8 w-9 items-center justify-center rounded-full bg-white/10 text-gray-300">
{user?.firstName?.charAt(0)}
</div>
<div className="flex w-full items-center justify-between">
<div>
<p className="px-2 pt-1 text-sm text-gray-300">
{" "}
{user?.firstName} {user?.lastName}
</p>
<p className="px-2 pb-1 text-xs text-gray-400">{user?.email}</p>
</div> </div>
<FontAwesomeIcon
icon={faGear}
className="mr-1 cursor-pointer rounded-md p-2 text-lg text-gray-400 hover:bg-white/10"
/>
</div> </div>
</div> </div>
</div> <div className="px-2 pt-2">
<div className="px-2 pt-2"> <div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400">
<div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400"> {t("nav.user.current-organization")}
{t("nav.user.current-organization")}
</div>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => router.push(`/settings/org/${router.query.id}`)}
className="mt-2 flex cursor-pointer flex-row items-center rounded-md px-2 py-1 hover:bg-white/5"
>
<div className="flex h-7 w-8 items-center justify-center rounded-md bg-white/10 text-gray-300">
{currentOrg?.name?.charAt(0)}
</div> </div>
<div className="flex w-full items-center justify-between"> <div
<p className="px-2 text-sm text-gray-300">{currentOrg?.name}</p> onKeyDown={() => null}
<FontAwesomeIcon role="button"
icon={faGear} tabIndex={0}
className="cursor-pointer rounded-md p-2 text-lg text-gray-400 hover:bg-white/10" onClick={() => router.push(`/settings/org/${router.query.id}`)}
/> className="mt-2 flex cursor-pointer flex-row items-center rounded-md px-2 py-1 hover:bg-white/5"
>
<div className="flex h-7 w-8 items-center justify-center rounded-md bg-white/10 text-gray-300">
{currentOrg?.name?.charAt(0)}
</div>
<div className="flex w-full items-center justify-between">
<p className="px-2 text-sm text-gray-300">{currentOrg?.name}</p>
<FontAwesomeIcon
icon={faGear}
className="cursor-pointer rounded-md p-2 text-lg text-gray-400 hover:bg-white/10"
/>
</div>
</div> </div>
</div> {subscription && subscription.slug !== null && (
{subscription && subscription.slug !== null && ( <button
// onClick={buttonAction}
type="button"
className="w-full cursor-pointer"
>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => router.push(`/settings/billing/${router.query.id}`)}
className="relative mt-1 flex cursor-pointer select-none justify-start rounded-md py-2 px-2 text-gray-400 duration-200 hover:bg-white/5 hover:text-gray-200"
>
<FontAwesomeIcon className="pl-1.5 pr-3 text-lg" icon={faCoins} />
<div className="text-sm">{t("nav.user.usage-billing")}</div>
</div>
</button>
)}
<button <button
// onClick={buttonAction}
type="button" type="button"
className="w-full cursor-pointer" // onClick={buttonAction}
className="mb-2 w-full cursor-pointer"
> >
<div <div
onKeyDown={() => null} onKeyDown={() => null}
role="button" role="button"
tabIndex={0} tabIndex={0}
onClick={() => router.push(`/settings/billing/${router.query.id}`)} onClick={() => router.push(`/settings/org/${router.query.id}?invite`)}
className="relative mt-1 flex cursor-pointer select-none justify-start rounded-md py-2 px-2 text-gray-400 duration-200 hover:bg-white/5 hover:text-gray-200" className="relative mt-1 flex cursor-pointer select-none justify-start rounded-md py-2 pl-10 pr-4 text-gray-400 duration-200 hover:bg-primary/100 hover:font-semibold hover:text-black"
> >
<FontAwesomeIcon className="pl-1.5 pr-3 text-lg" icon={faCoins} /> <span className="absolute inset-y-0 left-0 flex items-center rounded-lg pl-3 pr-4">
<div className="text-sm">{t("nav.user.usage-billing")}</div> <FontAwesomeIcon icon={faPlus} className="ml-1" />
</span>
<div className="ml-1 text-sm">{t("nav.user.invite")}</div>
</div> </div>
</button> </button>
)}
<button
type="button"
// onClick={buttonAction}
className="mb-2 w-full cursor-pointer"
>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
onClick={() => router.push(`/settings/org/${router.query.id}?invite`)}
className="relative mt-1 flex cursor-pointer select-none justify-start rounded-md py-2 pl-10 pr-4 text-gray-400 duration-200 hover:bg-primary/100 hover:font-semibold hover:text-black"
>
<span className="absolute inset-y-0 left-0 flex items-center rounded-lg pl-3 pr-4">
<FontAwesomeIcon icon={faPlus} className="ml-1" />
</span>
<div className="ml-1 text-sm">{t("nav.user.invite")}</div>
</div>
</button>
</div>
{orgs && orgs?.length > 1 && (
<div className="px-1 pt-1">
<div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400">
{t("nav.user.other-organizations")}
</div>
<div className="mt-3 mb-2 flex flex-col items-start px-1">
{orgs
?.filter((org: { id: string }) => org.id !== currentOrg?.id)
.map((org: { id: string; name: string }) => (
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
key={guidGenerator()}
onClick={() => {
localStorage.setItem("orgData.id", org.id);
router.reload();
}}
className="flex w-full cursor-pointer flex-row items-center justify-start rounded-md p-1.5 hover:bg-white/5"
>
<div className="flex h-7 w-8 items-center justify-center rounded-md bg-white/10 text-gray-300">
{org.name.charAt(0)}
</div>
<div className="flex w-full items-center justify-between">
<p className="px-2 text-sm text-gray-300">{org.name}</p>
</div>
</div>
))}
</div>
</div> </div>
)} {orgs && orgs?.length > 1 && (
<div className="px-1 py-1"> <div className="px-1 pt-1">
<Menu.Item> <div className="ml-2 mt-2 self-start text-xs font-semibold tracking-wide text-gray-400">
{({ active }) => ( {t("nav.user.other-organizations")}
<button </div>
type="button" <div className="mt-3 mb-2 flex flex-col items-start px-1">
onClick={closeApp} {orgs
className={`${ ?.filter((org: { id: string }) => org.id !== currentOrg?.id)
active ? "bg-red font-semibold text-white" : "text-gray-400" .map((org: { id: string; name: string }) => (
} group flex w-full items-center rounded-md px-2 py-2 text-sm`} <div
> onKeyDown={() => null}
<div className="relative flex cursor-pointer select-none items-center justify-start"> role="button"
<FontAwesomeIcon tabIndex={0}
className="ml-1.5 mr-3 text-lg" key={guidGenerator()}
icon={faRightFromBracket} onClick={() => {
/> localStorage.setItem("orgData.id", org.id);
{t("common.logout")} router.reload();
</div> }}
</button> className="flex w-full cursor-pointer flex-row items-center justify-start rounded-md p-1.5 hover:bg-white/5"
)} >
</Menu.Item> <div className="flex h-7 w-8 items-center justify-center rounded-md bg-white/10 text-gray-300">
</div> {org.name.charAt(0)}
</Menu.Items> </div>
</Transition> <div className="flex w-full items-center justify-between">
</Menu> <p className="px-2 text-sm text-gray-300">{org.name}</p>
</div> </div>
</div>
))}
</div>
</div>
)}
<div className="px-1 py-1">
<Menu.Item>
{({ active }) => (
<button
type="button"
onClick={closeApp}
className={`${
active ? "bg-red font-semibold text-white" : "text-gray-400"
} group flex w-full items-center rounded-md px-2 py-2 text-sm`}
>
<div className="relative flex cursor-pointer select-none items-center justify-start">
<FontAwesomeIcon
className="ml-1.5 mr-3 text-lg"
icon={faRightFromBracket}
/>
{t("common.logout")}
</div>
</button>
)}
</Menu.Item>
</div>
</Menu.Items>
</Transition>
</Menu>
</div>
</div> </div>
{subscription && subscription.slug === "starter" && !subscription.has_used_trial && ( {subscription && subscription.slug === "starter" && !subscription.has_used_trial && (
<div className="w-full mx-auto border-t border-mineshaft-500 text-center"> <div className="mx-auto w-full border-t border-mineshaft-500 text-center">
<button <button
type="button" type="button"
onClick={async () => { onClick={async () => {
@@ -326,15 +324,17 @@ export const Navbar = () => {
// direct user to start pro trial // direct user to start pro trial
const url = await mutateAsync({ const url = await mutateAsync({
orgId: currentOrg.id, orgId: currentOrg._id,
success_url: window.location.href success_url: window.location.href
}); });
window.location.href = url; window.location.href = url;
}} }}
className="text-center py-4 text-sm mx-auto" className="mx-auto py-4 text-center text-sm"
> >
You are currently on the <span className="font-semibold">Starter</span> plan. Unlock the full power of Infisical on the <span className="font-semibold">Pro Free Trial &rarr;</span> You are currently on the <span className="font-semibold">Starter</span> plan. Unlock the
full power of Infisical on the{" "}
<span className="font-semibold">Pro Free Trial &rarr;</span>
</button> </button>
</div> </div>
)} )}
@@ -25,17 +25,17 @@ export type IGitRisks = {
isFalsePositive: boolean; // New field for marking risks as false positives isFalsePositive: boolean; // New field for marking risks as false positives
isResolved: boolean; // New field for marking risks as resolved isResolved: boolean; // New field for marking risks as resolved
riskOwner: string | null; // New field for setting a risk owner (nullable string) riskOwner: string | null; // New field for setting a risk owner (nullable string)
installationId: string, installationId: string;
repositoryId: string, repositoryId: string;
repositoryLink: string repositoryLink: string;
repositoryFullName: string repositoryFullName: string;
pusher: { pusher: {
name: string, name: string;
email: string email: string;
}, };
createdAt: string, createdAt: string;
organization: string, organization: string;
} };
/** /**
* Will create a new integration session and return it for the given org * Will create a new integration session and return it for the given org
@@ -46,7 +46,7 @@ const getRisksByOrganization = (oranizationId: string): Promise<IGitRisks[]> =>
method: "GET", method: "GET",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
}, }
}).then(async (res) => { }).then(async (res) => {
if (res && res.status === 200) { if (res && res.status === 200) {
return (await res.json()).risks; return (await res.json()).risks;
+3 -3
View File
@@ -18,9 +18,9 @@ export default function DashboardRedirect() {
if (localStorage.getItem("orgData.id")) { if (localStorage.getItem("orgData.id")) {
router.push(`/org/${localStorage.getItem("orgData.id")}/overview`); router.push(`/org/${localStorage.getItem("orgData.id")}/overview`);
} else if (userOrgs) { } else if (userOrgs) {
userOrg = userOrgs[0].id; userOrg = userOrgs[0].id;
router.push(`/org/${userOrg}/overview`); router.push(`/org/${userOrg}/overview`);
} }
} catch (error) { } catch (error) {
console.log("Error - Not logged in yet"); console.log("Error - Not logged in yet");
} }
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -63,11 +61,11 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize AWS Parameter Integration</title> <title>Authorize AWS Parameter Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -82,10 +80,13 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
<span className="ml-1.5">AWS Parameter Store Integration </span> <span className="ml-1.5">AWS Parameter Store Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref> <Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -97,11 +98,7 @@ export default function AWSParameterStoreAuthorizeIntegrationPage() {
isError={accessKeyErrorText !== "" ?? false} isError={accessKeyErrorText !== "" ?? false}
className="px-6" className="px-6"
> >
<Input <Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
placeholder=""
value={accessKey}
onChange={(e) => setAccessKey(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl <FormControl
label="Secret Access Key" label="Secret Access Key"
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -62,7 +65,9 @@ export default function AWSParameterStoreCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById(
(integrationAuthId as string) ?? ""
);
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
@@ -118,14 +123,14 @@ export default function AWSParameterStoreCreateIntegrationPage() {
}; };
return integrationAuth && workspace && selectedSourceEnvironment ? ( return integrationAuth && workspace && selectedSourceEnvironment ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up AWS Parameter Integration</title> <title>Set Up AWS Parameter Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment in Infisical you want to sync to secerts in AWS Parameter Store." 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="flex flex-row items-center">
@@ -140,10 +145,13 @@ export default function AWSParameterStoreCreateIntegrationPage() {
<span className="ml-1.5">AWS Parameter Store Integration </span> <span className="ml-1.5">AWS Parameter Store Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref> <Link href="https://infisical.com/docs/integrations/cloud/aws-parameter-store" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -185,7 +193,12 @@ export default function AWSParameterStoreCreateIntegrationPage() {
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<FormControl label="Path" errorText={pathErrorText} isError={pathErrorText !== "" ?? false} className="px-6"> <FormControl
label="Path"
errorText={pathErrorText}
isError={pathErrorText !== "" ?? false}
className="px-6"
>
<Input <Input
placeholder={`/${workspace.name placeholder={`/${workspace.name
.toLowerCase() .toLowerCase()
@@ -204,31 +217,49 @@ export default function AWSParameterStoreCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up AWS Parameter Store Integration</title> <title>Set Up AWS Parameter Store Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isintegrationAuthLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -61,11 +61,11 @@ export default function AWSSecretManagerCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize AWS Secrets Manager Integration</title> <title>Authorize AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -80,10 +80,13 @@ export default function AWSSecretManagerCreateIntegrationPage() {
<span className="ml-1.5">AWS Secrets Manager Integration </span> <span className="ml-1.5">AWS Secrets Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref> <Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -62,7 +65,9 @@ export default function AWSSecretManagerCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById(
(integrationAuthId as string) ?? ""
);
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
@@ -117,14 +122,14 @@ export default function AWSSecretManagerCreateIntegrationPage() {
}; };
return integrationAuth && workspace && selectedSourceEnvironment ? ( return integrationAuth && workspace && selectedSourceEnvironment ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up AWS Secrets Manager Integration</title> <title>Set Up AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment in Infisical you want to sync to secerts in AWS Secrets Manager." 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="flex flex-row items-center">
@@ -139,10 +144,13 @@ export default function AWSSecretManagerCreateIntegrationPage() {
<span className="ml-1.5">AWS Secrets Manager Integration </span> <span className="ml-1.5">AWS Secrets Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref> <Link href="https://infisical.com/docs/integrations/cloud/aws-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -208,31 +216,49 @@ export default function AWSSecretManagerCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up AWS Secrets Manager Integration</title> <title>Set Up AWS Secrets Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isintegrationAuthLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function AzureKeyVaultOAuth2CallbackPage() { export default function AzureKeyVaultOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -25,9 +23,7 @@ export default function AzureKeyVaultOAuth2CallbackPage() {
integration: "azure-key-vault" integration: "azure-key-vault"
}); });
router.push( router.push(`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth.id}`);
`/integrations/azure-key-vault/create?integrationAuthId=${integrationAuth.id}`
);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -18,7 +16,7 @@ import {
import { import {
useGetIntegrationAuthApps, useGetIntegrationAuthApps,
useGetIntegrationAuthBitBucketWorkspaces, useGetIntegrationAuthBitBucketWorkspaces,
useGetIntegrationAuthById, useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth"; } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace"; import { useGetWorkspaceById } from "../../../hooks/api/workspace";
@@ -36,7 +34,9 @@ export default function BitBucketCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: targetEnvironments } = useGetIntegrationAuthBitBucketWorkspaces((integrationAuthId as string) ?? ""); const { data: targetEnvironments } = useGetIntegrationAuthBitBucketWorkspaces(
(integrationAuthId as string) ?? ""
);
const { data: integrationAuthApps } = useGetIntegrationAuthApps({ const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "", integrationAuthId: (integrationAuthId as string) ?? "",
workspaceSlug: targetEnvironmentId workspaceSlug: targetEnvironmentId
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function BitBucketOAuth2CallbackPage() { export default function BitBucketOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -48,11 +46,11 @@ export default function ChecklyCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize Checkly Integration</title> <title>Authorize Checkly Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -67,10 +65,13 @@ export default function ChecklyCreateIntegrationPage() {
<span className="ml-2.5">Checkly Integration </span> <span className="ml-2.5">Checkly Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref> <Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -21,9 +21,7 @@ import {
TabPanel, TabPanel,
Tabs Tabs
} from "@app/components/v2"; } from "@app/components/v2";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
useGetIntegrationAuthApps, useGetIntegrationAuthApps,
@@ -54,13 +52,15 @@ export default function ChecklyCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
integrationAuthId: (integrationAuthId as string) ?? "" useGetIntegrationAuthApps({
}); integrationAuthId: (integrationAuthId as string) ?? ""
const { data: integrationAuthGroups, isLoading: isintegrationAuthGroupsLoading } = useGetIntegrationAuthChecklyGroups({ });
integrationAuthId: (integrationAuthId as string) ?? "", const { data: integrationAuthGroups, isLoading: isintegrationAuthGroupsLoading } =
accountId: targetAppId useGetIntegrationAuthChecklyGroups({
}); integrationAuthId: (integrationAuthId as string) ?? "",
accountId: targetAppId
});
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
@@ -121,14 +121,14 @@ export default function ChecklyCreateIntegrationPage() {
integrationAuthApps && integrationAuthApps &&
integrationAuthGroups && integrationAuthGroups &&
targetAppId ? ( targetAppId ? (
<div className="flex h-full flex-col w-full py-6 items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900"> <div className="flex h-full w-full flex-col items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900 py-6">
<Head> <Head>
<title>Set Up Checkly Integration</title> <title>Set Up Checkly Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment in Infisical you want to sync to Checkly environment variables." subTitle="Choose which environment in Infisical you want to sync to Checkly environment variables."
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
@@ -143,10 +143,13 @@ export default function ChecklyCreateIntegrationPage() {
<span className="ml-2.5">Checkly Integration </span> <span className="ml-2.5">Checkly Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref> <Link href="https://infisical.com/docs/integrations/cloud/checkly" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -154,7 +157,7 @@ export default function ChecklyCreateIntegrationPage() {
</CardTitle> </CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList> <TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full"> <div className="flex w-full flex-row border-b border-mineshaft-600">
<Tab value={TabSections.Connection}>Connection</Tab> <Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab> <Tab value={TabSections.Options}>Options</Tab>
</div> </div>
@@ -268,24 +271,35 @@ export default function ChecklyCreateIntegrationPage() {
</Card> </Card>
</div> </div>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Checkly Integration</title> <title>Set Up Checkly Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
{isIntegrationAuthAppsLoading || isintegrationAuthGroupsLoading ? <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"> {isIntegrationAuthAppsLoading || isintegrationAuthGroupsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -48,11 +46,11 @@ export default function CircleCICreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize CircleCI Integration</title> <title>Authorize CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding your API Token, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -67,10 +65,13 @@ export default function CircleCICreateIntegrationPage() {
<span className="ml-1.5">CircleCI Integration </span> <span className="ml-1.5">CircleCI Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref> <Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -33,10 +36,13 @@ export default function CircleCICreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById(
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ (integrationAuthId as string) ?? ""
integrationAuthId: (integrationAuthId as string) ?? "" );
}); const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
@@ -71,7 +77,9 @@ export default function CircleCICreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -89,14 +97,14 @@ export default function CircleCICreateIntegrationPage() {
selectedSourceEnvironment && selectedSourceEnvironment &&
integrationAuthApps && integrationAuthApps &&
targetApp ? ( targetApp ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up CircleCI Integration</title> <title>Set Up CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to CircleCI environment variables." 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="flex flex-row items-center">
@@ -111,10 +119,13 @@ export default function CircleCICreateIntegrationPage() {
<span className="ml-1.5">CircleCI Integration </span> <span className="ml-1.5">CircleCI Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref> <Link href="https://infisical.com/docs/integrations/cicd/circleci" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -177,31 +188,48 @@ export default function CircleCICreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up CircleCI Integration</title> <title>Set Up CircleCI Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading || isintegrationAuthLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -17,7 +15,7 @@ import {
} from "../../../components/v2"; } from "../../../components/v2";
import { import {
useGetIntegrationAuthApps, useGetIntegrationAuthApps,
useGetIntegrationAuthById, useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth"; } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace"; import { useGetWorkspaceById } from "../../../hooks/api/workspace";
@@ -64,7 +62,9 @@ export default function Cloud66CreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -1,92 +1,102 @@
import { useState } from "react"; 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 { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button,Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
export default function CloudflarePagesIntegrationPage() { export default function RenderCreateIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useSaveIntegrationAccessToken(); const { mutateAsync } = useSaveIntegrationAccessToken();
const [accessKey, setAccessKey] = useState(""); const [apiKey, setApiKey] = useState("");
const [accessKeyErrorText, setAccessKeyErrorText] = useState(""); const [apiKeyErrorText, setApiKeyErrorText] = useState("");
const [accountId, setAccountId] = useState(""); const [isLoading, setIsLoading] = useState(false);
const [accountIdErrorText, setAccountIdErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false);
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { try {
setAccessKeyErrorText(""); setApiKeyErrorText("");
setAccountIdErrorText(""); if (apiKey.length === 0) {
if (accessKey.length === 0 || accountId.length === 0) { setApiKeyErrorText("API Key cannot be blank");
if (accessKey.length === 0) setAccessKeyErrorText("API token cannot be blank!"); return;
if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!"); }
return;
}
setIsLoading(true); setIsLoading(true);
const integrationAuth = await mutateAsync({ const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"), workspaceId: localStorage.getItem("projectData.id"),
integration: "cloudflare-pages", integration: "render",
accessId: accountId, accessToken: apiKey
accessToken: accessKey });
});
setAccessKey(""); setIsLoading(false);
setAccountId("");
setIsLoading(false);
router.push(`/integrations/cloudflare-pages/create?integrationAuthId=${integrationAuth.id}`); router.push(`/integrations/render/create?integrationAuthId=${integrationAuth._id}`);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
}
} }
};
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Head>
<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.">Cloudflare Pages Integration</CardTitle> <title>Authorize Render Integration</title>
<FormControl <link rel="icon" href="/infisical.ico" />
label="Cloudflare Pages API token" </Head>
errorText={accessKeyErrorText} <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
isError={accessKeyErrorText !== "" ?? false} <CardTitle
className="mx-6" className="px-6 text-left text-xl"
> subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment."
<Input >
placeholder="" <div className="flex flex-row items-center">
value={accessKey} <div className="inline flex items-center pb-0.5">
onChange={(e) => setAccessKey(e.target.value)} <Image
/> src="/images/integrations/Render.png"
</FormControl> height={30}
<FormControl width={30}
label="Cloudflare Pages Account ID" alt="Render logo"
errorText={accountIdErrorText} />
isError={accountIdErrorText !== "" ?? false} </div>
className="mx-6" <span className="ml-2.5">Render Integration </span>
> <Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<Input <a target="_blank" rel="noopener noreferrer">
placeholder="" <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
value={accountId} <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
onChange={(e) => setAccountId(e.target.value)} Docs
/> <FontAwesomeIcon
</FormControl> icon={faArrowUpRightFromSquare}
<Button className="ml-1.5 mb-[0.07rem] text-xxs"
onClick={handleButtonClick} />
color="mineshaft" </div>
variant="outline_bg" </a>
className="mb-6 mt-2 ml-auto mr-6 w-min" </Link>
isFullWidth={false} </div>
isLoading={isLoading} </CardTitle>
> <FormControl
Connect to Cloudflare Pages label="Render API Key"
</Button> errorText={apiKeyErrorText}
</Card> isError={apiKeyErrorText !== "" ?? false}
</div> className="px-6"
); >
<Input placeholder="rnd_xxx" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
</FormControl>
<Button
onClick={handleButtonClick}
colorSchema="primary"
variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min"
isLoading={isLoading}
>
Connect to Render
</Button>
</Card>
</div>
);
} }
CloudflarePagesIntegrationPage.requireAuth = true; RenderCreateIntegrationPage.requireAuth = true;
@@ -1,159 +1,165 @@
import { useEffect,useState } from "react"; import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration, useGetWorkspaceById } from "@app/hooks/api";
useCreateIntegration
, useGetWorkspaceById } from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "../../../components/v2";
import { useGetIntegrationAuthApps, useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth"; import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth";
const cloudflareEnvironments = [ const cloudflareEnvironments = [
{ name: "Production", slug: "production" }, { name: "Production", slug: "production" },
{ name: "Preview", slug: "preview" } { name: "Preview", slug: "preview" }
]; ];
export default function CloudflarePagesIntegrationPage() { export default function CloudflarePagesIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useCreateIntegration(); const { mutateAsync } = useCreateIntegration();
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({ const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [targetApp, setTargetApp] = useState(""); const [targetApp, setTargetApp] = useState("");
const [targetAppId, setTargetAppId] = useState(""); const [targetAppId, setTargetAppId] = useState("");
const [targetEnvironment, setTargetEnvironment] = useState(""); const [targetEnvironment, setTargetEnvironment] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
setSelectedSourceEnvironment(workspace.environments[0].slug); setSelectedSourceEnvironment(workspace.environments[0].slug);
}
}, [workspace]);
useEffect(() => {
if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name);
setTargetAppId(String(integrationAuthApps[0].appId));
setTargetEnvironment(cloudflareEnvironments[0].slug);
} else {
setTargetApp("none");
setTargetEnvironment(cloudflareEnvironments[0].slug);
}
}
}, [integrationAuthApps]);
const handleButtonClick = async () => {
try {
if (!integrationAuth?.id) return;
setIsLoading(true);
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: targetApp,
appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment,
targetEnvironment,
secretPath: "/",
});
setIsLoading(false);
router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
} catch(err) {
console.error(err);
}
} }
}, [workspace]);
return integrationAuth && useEffect(() => {
workspace && if (integrationAuthApps) {
selectedSourceEnvironment && if (integrationAuthApps.length > 0) {
integrationAuthApps && setTargetApp(integrationAuthApps[0].name);
targetEnvironment && setTargetAppId(String(integrationAuthApps[0].appId));
targetApp ? ( setTargetEnvironment(cloudflareEnvironments[0].slug);
<div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900"> } else {
<Card className="max-w-lg rounded-md p-0 border border-mineshaft-600"> setTargetApp("none");
<CardTitle className="text-left px-6" subTitle="Choose which environment in Infisical you want to sync with your Cloudflare Pages project.">Cloudflare Pages Integration</CardTitle> setTargetEnvironment(cloudflareEnvironments[0].slug);
<FormControl label="Infisical Project Environment" className="mt-2 px-6"> }
<Select }
value={selectedSourceEnvironment} }, [integrationAuthApps]);
onValueChange={(val) => setSelectedSourceEnvironment(val)}
className="w-full border border-mineshaft-500" const handleButtonClick = async () => {
> try {
{workspace?.environments.map((sourceEnvironment) => ( if (!integrationAuth?.id) return;
<SelectItem
value={sourceEnvironment.slug} setIsLoading(true);
key={`source-environment-${sourceEnvironment.slug}`}
> await mutateAsync({
{sourceEnvironment.name} integrationAuthId: integrationAuth?.id,
</SelectItem> isActive: true,
))} app: targetApp,
</Select> appId: targetAppId,
</FormControl> sourceEnvironment: selectedSourceEnvironment,
<FormControl label="Cloudflare Pages Project" className="mt-4 px-6"> targetEnvironment,
<Select secretPath: "/"
value={targetApp} });
onValueChange={(val) => setTargetApp(val)}
className="w-full border border-mineshaft-500" setIsLoading(false);
isDisabled={integrationAuthApps.length === 0}
> router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
{integrationAuthApps.length > 0 ? ( } catch (err) {
integrationAuthApps.map((integrationAuthApp) => ( console.error(err);
<SelectItem }
value={integrationAuthApp.name} };
key={`target-app-${integrationAuthApp.name}`}
> return integrationAuth &&
{integrationAuthApp.name} workspace &&
</SelectItem> selectedSourceEnvironment &&
)) integrationAuthApps &&
) : ( targetEnvironment &&
<SelectItem value="none" key="target-app-none"> targetApp ? (
No apps found <div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
</SelectItem> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
)} <CardTitle
</Select> className="px-6 text-left"
</FormControl> subTitle="Choose which environment in Infisical you want to sync with your Cloudflare Pages project."
<FormControl label="Cloudflare Pages Environment" className="mt-4 px-6"> >
<Select Cloudflare Pages Integration
value={targetEnvironment} </CardTitle>
onValueChange={(val) => setTargetEnvironment(val)} <FormControl label="Infisical Project Environment" className="mt-2 px-6">
className="w-full border border-mineshaft-500" <Select
> value={selectedSourceEnvironment}
{cloudflareEnvironments.map((cloudflareEnvironment) => ( onValueChange={(val) => setSelectedSourceEnvironment(val)}
<SelectItem className="w-full border border-mineshaft-500"
value={cloudflareEnvironment.slug} >
key={`target-environment-${cloudflareEnvironment.slug}`} {workspace?.environments.map((sourceEnvironment) => (
> <SelectItem
{cloudflareEnvironment.name} value={sourceEnvironment.slug}
</SelectItem> key={`source-environment-${sourceEnvironment.slug}`}
))} >
</Select> {sourceEnvironment.name}
</FormControl> </SelectItem>
<Button ))}
onClick={handleButtonClick} </Select>
color="mineshaft" </FormControl>
variant="outline_bg" <FormControl label="Cloudflare Pages Project" className="mt-4 px-6">
className="mt-2 mb-6 ml-auto mr-6" <Select
isFullWidth={false} value={targetApp}
isLoading={isLoading} 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}`}
> >
Create Integration {integrationAuthApp.name}
</Button> </SelectItem>
</Card> ))
</div> ) : (
) : ( <SelectItem value="none" key="target-app-none">
<div /> No apps found
); </SelectItem>
)}
</Select>
</FormControl>
<FormControl label="Cloudflare Pages Environment" className="mt-4 px-6">
<Select
value={targetEnvironment}
onValueChange={(val) => setTargetEnvironment(val)}
className="w-full border border-mineshaft-500"
>
{cloudflareEnvironments.map((cloudflareEnvironment) => (
<SelectItem
value={cloudflareEnvironment.slug}
key={`target-environment-${cloudflareEnvironment.slug}`}
>
{cloudflareEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
variant="outline_bg"
className="mt-2 mb-6 ml-auto mr-6"
isFullWidth={false}
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
</div>
) : (
<div />
);
} }
CloudflarePagesIntegrationPage.requireAuth = true; CloudflarePagesIntegrationPage.requireAuth = true;
@@ -1,92 +1,89 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button,Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
export default function CloudflareWorkersIntegrationPage() { export default function CloudflareWorkersIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useSaveIntegrationAccessToken(); const { mutateAsync } = useSaveIntegrationAccessToken();
const [accessKey, setAccessKey] = useState(""); const [accessKey, setAccessKey] = useState("");
const [accessKeyErrorText, setAccessKeyErrorText] = useState(""); const [accessKeyErrorText, setAccessKeyErrorText] = useState("");
const [accountId, setAccountId] = useState(""); const [accountId, setAccountId] = useState("");
const [accountIdErrorText, setAccountIdErrorText] = useState(""); const [accountIdErrorText, setAccountIdErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { try {
setAccessKeyErrorText(""); setAccessKeyErrorText("");
setAccountIdErrorText(""); setAccountIdErrorText("");
if (accessKey.length === 0 || accountId.length === 0) { if (accessKey.length === 0 || accountId.length === 0) {
if (accessKey.length === 0) setAccessKeyErrorText("API token cannot be blank!"); if (accessKey.length === 0) setAccessKeyErrorText("API token cannot be blank!");
if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!"); if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!");
return; return;
} }
setIsLoading(true); setIsLoading(true);
const integrationAuth = await mutateAsync({ const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"), workspaceId: localStorage.getItem("projectData.id"),
integration: "cloudflare-workers", integration: "cloudflare-workers",
accessId: accountId, accessId: accountId,
accessToken: accessKey accessToken: accessKey
}); });
setAccessKey(""); setAccessKey("");
setAccountId(""); setAccountId("");
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/cloudflare-workers/create?integrationAuthId=${integrationAuth.id}`); router.push(
} catch (err) { `/integrations/cloudflare-workers/create?integrationAuthId=${integrationAuth.id}`
console.error(err); );
} } catch (err) {
console.error(err);
} }
};
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<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.">Cloudflare Workers Integration</CardTitle> <CardTitle
<FormControl className="px-6 text-left"
label="Cloudflare Workers API token" subTitle="After adding your API-key, you will be prompted to set up an integration for a particular Infisical project and environment."
errorText={accessKeyErrorText} >
isError={accessKeyErrorText !== "" ?? false} Cloudflare Workers Integration
className="mx-6" </CardTitle>
> <FormControl
<Input label="Cloudflare Workers API token"
placeholder="" errorText={accessKeyErrorText}
value={accessKey} isError={accessKeyErrorText !== "" ?? false}
onChange={(e) => setAccessKey(e.target.value)} className="mx-6"
/> >
</FormControl> <Input placeholder="" value={accessKey} onChange={(e) => setAccessKey(e.target.value)} />
<FormControl </FormControl>
label="Cloudflare Workers Account ID" <FormControl
errorText={accountIdErrorText} label="Cloudflare Workers Account ID"
isError={accountIdErrorText !== "" ?? false} errorText={accountIdErrorText}
className="mx-6" isError={accountIdErrorText !== "" ?? false}
> className="mx-6"
<Input >
placeholder="" <Input placeholder="" value={accountId} onChange={(e) => setAccountId(e.target.value)} />
value={accountId} </FormControl>
onChange={(e) => setAccountId(e.target.value)} <Button
/> onClick={handleButtonClick}
</FormControl> color="mineshaft"
<Button variant="outline_bg"
onClick={handleButtonClick} className="mb-6 mt-2 ml-auto mr-6 w-min"
color="mineshaft" isFullWidth={false}
variant="outline_bg" isLoading={isLoading}
className="mb-6 mt-2 ml-auto mr-6 w-min" >
isFullWidth={false} Connect to Cloudflare Workers
isLoading={isLoading} </Button>
> </Card>
Connect to Cloudflare Workers </div>
</Button> );
</Card>
</div>
);
} }
CloudflareWorkersIntegrationPage.requireAuth = true; CloudflareWorkersIntegrationPage.requireAuth = true;
@@ -1,133 +1,139 @@
import { useEffect,useState } from "react"; import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration, useGetWorkspaceById } from "@app/hooks/api";
useCreateIntegration
, useGetWorkspaceById } from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Select, SelectItem } from "../../../components/v2";
import { useGetIntegrationAuthApps, useGetIntegrationAuthById } from "../../../hooks/api/integrationAuth"; import {
useGetIntegrationAuthApps,
useGetIntegrationAuthById
} from "../../../hooks/api/integrationAuth";
export default function CloudflareWorkersIntegrationPage() { export default function CloudflareWorkersIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useCreateIntegration(); const { mutateAsync } = useCreateIntegration();
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps } = useGetIntegrationAuthApps({ const { data: integrationAuthApps } = useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [targetApp, setTargetApp] = useState(""); const [targetApp, setTargetApp] = useState("");
const [targetAppId, setTargetAppId] = useState(""); const [targetAppId, setTargetAppId] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
useEffect(() => { useEffect(() => {
if (workspace) { if (workspace) {
setSelectedSourceEnvironment(workspace.environments[0].slug); setSelectedSourceEnvironment(workspace.environments[0].slug);
}
}, [workspace]);
useEffect(() => {
if (integrationAuthApps) {
if (integrationAuthApps.length > 0) {
setTargetApp(integrationAuthApps[0].name);
setTargetAppId(String(integrationAuthApps[0].appId));
} else {
setTargetApp("none");
}
}
}, [integrationAuthApps]);
const handleButtonClick = async () => {
try {
if (!integrationAuth?.id) return;
setIsLoading(true);
await mutateAsync({
integrationAuthId: integrationAuth?.id,
isActive: true,
app: targetApp,
appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment,
secretPath: "/",
});
setIsLoading(false);
router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
} catch(err) {
console.error(err);
}
} }
}, [workspace]);
return integrationAuth && useEffect(() => {
workspace && if (integrationAuthApps) {
selectedSourceEnvironment && if (integrationAuthApps.length > 0) {
integrationAuthApps && setTargetApp(integrationAuthApps[0].name);
targetApp ? ( setTargetAppId(String(integrationAuthApps[0].appId));
<div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900"> } else {
<Card className="max-w-lg rounded-md p-0 border border-mineshaft-600"> setTargetApp("none");
<CardTitle className="text-left px-6" subTitle="Choose which environment in Infisical you want to sync with your Cloudflare Workers project.">Cloudflare Workers Integration</CardTitle> }
<FormControl label="Infisical Project Environment" className="mt-2 px-6"> }
<Select }, [integrationAuthApps]);
value={selectedSourceEnvironment}
onValueChange={(val) => setSelectedSourceEnvironment(val)} const handleButtonClick = async () => {
className="w-full border border-mineshaft-500" try {
> if (!integrationAuth?._id) return;
{workspace?.environments.map((sourceEnvironment) => (
<SelectItem setIsLoading(true);
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`} await mutateAsync({
> integrationAuthId: integrationAuth?._id,
{sourceEnvironment.name} isActive: true,
</SelectItem> app: targetApp,
))} appId: targetAppId,
</Select> sourceEnvironment: selectedSourceEnvironment,
</FormControl> secretPath: "/"
<FormControl label="Cloudflare Workers Project" className="mt-4 px-6"> });
<Select
value={targetApp} setIsLoading(false);
onValueChange={(val) => setTargetApp(val)}
className="w-full border border-mineshaft-500" router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
isDisabled={integrationAuthApps.length === 0} } catch (err) {
> console.error(err);
{integrationAuthApps.length > 0 ? ( }
integrationAuthApps.map((integrationAuthApp) => ( };
<SelectItem
value={integrationAuthApp.name} return integrationAuth &&
key={`target-app-${integrationAuthApp.name}`} workspace &&
> selectedSourceEnvironment &&
{integrationAuthApp.name} integrationAuthApps &&
</SelectItem> targetApp ? (
)) <div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
) : ( <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<SelectItem value="none" key="target-app-none"> <CardTitle
No apps found className="px-6 text-left"
</SelectItem> subTitle="Choose which environment in Infisical you want to sync with your Cloudflare Workers project."
)} >
</Select> Cloudflare Workers Integration
</FormControl> </CardTitle>
<Button <FormControl label="Infisical Project Environment" className="mt-2 px-6">
onClick={handleButtonClick} <Select
color="mineshaft" value={selectedSourceEnvironment}
variant="outline_bg" onValueChange={(val) => setSelectedSourceEnvironment(val)}
className="mt-2 mb-6 ml-auto mr-6" className="w-full border border-mineshaft-500"
isFullWidth={false} >
isLoading={isLoading} {workspace?.environments.map((sourceEnvironment) => (
<SelectItem
value={sourceEnvironment.slug}
key={`source-environment-${sourceEnvironment.slug}`}
>
{sourceEnvironment.name}
</SelectItem>
))}
</Select>
</FormControl>
<FormControl label="Cloudflare Workers Project" 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}`}
> >
Create Integration {integrationAuthApp.name}
</Button> </SelectItem>
</Card> ))
</div> ) : (
) : ( <SelectItem value="none" key="target-app-none">
<div /> No apps found
); </SelectItem>
)}
</Select>
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
variant="outline_bg"
className="mt-2 mb-6 ml-auto mr-6"
isFullWidth={false}
isLoading={isLoading}
>
Create Integration
</Button>
</Card>
</div>
) : (
<div />
);
} }
CloudflareWorkersIntegrationPage.requireAuth = true; CloudflareWorkersIntegrationPage.requireAuth = true;
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -64,7 +62,9 @@ export default function CodefreshCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -33,7 +31,9 @@ export default function DigitalOceanAppPlatformCreateIntegrationPage() {
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/digital-ocean-app-platform/create?integrationAuthId=${integrationAuth.id}`); router.push(
`/integrations/digital-ocean-app-platform/create?integrationAuthId=${integrationAuth.id}`
);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -64,7 +62,9 @@ export default function DigitalOceanAppPlatformCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -9,9 +9,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -24,10 +22,7 @@ type FormData = yup.InferType<typeof schema>;
export default function FlyioAuthorizeIntegrationPage() { export default function FlyioAuthorizeIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { const { control, handleSubmit } = useForm<FormData>({
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema),
defaultValues: { defaultValues: {
accessToken: "" accessToken: ""
@@ -38,9 +33,7 @@ export default function FlyioAuthorizeIntegrationPage() {
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const onFormSubmit = async ({ const onFormSubmit = async ({ accessToken }: FormData) => {
accessToken
}: FormData) => {
try { try {
setIsLoading(true); setIsLoading(true);
@@ -56,17 +49,17 @@ export default function FlyioAuthorizeIntegrationPage() {
setIsLoading(false); setIsLoading(false);
console.error(err); console.error(err);
} }
} };
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize Fly.io Integration</title> <title>Authorize Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding your access token, you will be prompted to set up an integration for a particular Infisical project and environment." subTitle="After adding your access 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="flex flex-row items-center">
@@ -81,19 +74,19 @@ export default function FlyioAuthorizeIntegrationPage() {
<span className="ml-2.5">Fly.io Integration </span> <span className="ml-2.5">Fly.io Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref> <Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
</div> </div>
</CardTitle> </CardTitle>
<form <form onSubmit={handleSubmit(onFormSubmit)} className="px-6 pb-8 text-right">
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<Controller <Controller
control={control} control={control}
name="accessToken" name="accessToken"
@@ -103,10 +96,7 @@ export default function FlyioAuthorizeIntegrationPage() {
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
> >
<Input <Input {...field} placeholder="" />
{...field}
placeholder=""
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -34,10 +37,13 @@ export default function FlyioCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById(
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ (integrationAuthId as string) ?? ""
integrationAuthId: (integrationAuthId as string) ?? "" );
}); const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
@@ -90,14 +96,14 @@ export default function FlyioCreateIntegrationPage() {
selectedSourceEnvironment && selectedSourceEnvironment &&
integrationAuthApps && integrationAuthApps &&
targetApp ? ( targetApp ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up Fly.io Integration</title> <title>Set Up Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to Fly.io environment variables." 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="flex flex-row items-center">
@@ -112,10 +118,13 @@ export default function FlyioCreateIntegrationPage() {
<span className="ml-2.5">Fly.io Integration </span> <span className="ml-2.5">Fly.io Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref> <Link href="https://infisical.com/docs/integrations/cloud/flyio" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -178,31 +187,48 @@ export default function FlyioCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Fly.io Integration</title> <title>Set Up Fly.io Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -12,9 +12,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup"; import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup"; import * as yup from "yup";
import { import { useGetCloudIntegrations, useSaveIntegrationAccessToken } from "@app/hooks/api";
useGetCloudIntegrations,
useSaveIntegrationAccessToken} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, TextArea } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, TextArea } from "../../../components/v2";
@@ -27,10 +25,7 @@ type FormData = yup.InferType<typeof schema>;
export default function GCPSecretManagerAuthorizeIntegrationPage() { export default function GCPSecretManagerAuthorizeIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { const { control, handleSubmit } = useForm<FormData>({
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema) resolver: yupResolver(schema)
}); });
@@ -42,7 +37,9 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
const handleIntegrateWithOAuth = () => { const handleIntegrateWithOAuth = () => {
if (!cloudIntegrations) return; if (!cloudIntegrations) return;
const integrationOption = cloudIntegrations.find((integration) => integration.slug === "gcp-secret-manager"); const integrationOption = cloudIntegrations.find(
(integration) => integration.slug === "gcp-secret-manager"
);
if (!integrationOption) return; if (!integrationOption) return;
@@ -51,11 +48,9 @@ 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&clientid=${integrationOption.clientId}`; 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&clientid=${integrationOption.clientId}`;
window.location.assign(link); window.location.assign(link);
} };
const onFormSubmit = async ({ const onFormSubmit = async ({ accessToken }: FormData) => {
accessToken
}: FormData) => {
try { try {
setIsLoading(true); setIsLoading(true);
@@ -66,22 +61,24 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
}); });
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth.id}`); router.push(
`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth.id}`
);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
setIsLoading(false); setIsLoading(false);
} }
} };
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize GCP Secret Manager Integration</title> <title>Authorize GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Connect Infisical to GCP Secret Manager to sync secrets." subTitle="Connect Infisical to GCP Secret Manager to sync secrets."
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
@@ -96,10 +93,13 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
<span className="ml-1.5">GCP Secret Manager Integration </span> <span className="ml-1.5">GCP Secret Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref> <Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -107,24 +107,21 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
</CardTitle> </CardTitle>
<div className="px-6"> <div className="px-6">
<Button <Button
colorSchema="primary" colorSchema="primary"
variant="outline_bg" variant="outline_bg"
onClick={handleIntegrateWithOAuth} onClick={handleIntegrateWithOAuth}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />} leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />}
className="h-11 w-full mx-0 mt-4" className="mx-0 mt-4 h-11 w-full"
> >
Continue with OAuth Continue with OAuth
</Button> </Button>
<div className='w-full flex flex-row items-center my-4 py-2'> <div className="my-4 flex w-full flex-row items-center py-2">
<div className='w-full border-t border-mineshaft-400/40' /> <div className="w-full border-t border-mineshaft-400/40" />
<span className="mx-2 text-mineshaft-400 text-xs">or</span> <span className="mx-2 text-xs text-mineshaft-400">or</span>
<div className='w-full border-t border-mineshaft-400/40' /> <div className="w-full border-t border-mineshaft-400/40" />
</div> </div>
</div> </div>
<form <form onSubmit={handleSubmit(onFormSubmit)} className="px-6 pb-8 text-right">
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<Controller <Controller
control={control} control={control}
name="accessToken" name="accessToken"
@@ -12,9 +12,7 @@ import queryString from "query-string";
import * as yup from "yup"; import * as yup from "yup";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -30,7 +28,8 @@ import {
Tab, Tab,
TabList, TabList,
TabPanel, TabPanel,
Tabs} from "../../../components/v2"; Tabs
} from "../../../components/v2";
import { import {
useGetIntegrationAuthApps, useGetIntegrationAuthApps,
useGetIntegrationAuthById useGetIntegrationAuthById
@@ -61,12 +60,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
"confirmIntegration" "confirmIntegration"
] as const); ] as const);
const { const { control, handleSubmit, setValue, watch } = useForm<FormData>({
control,
handleSubmit,
setValue,
watch
} = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema),
defaultValues: { defaultValues: {
secretPath: "/", secretPath: "/",
@@ -87,9 +81,10 @@ export default function GCPSecretManagerCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
integrationAuthId: (integrationAuthId as string) ?? "" useGetIntegrationAuthApps({
}); integrationAuthId: (integrationAuthId as string) ?? ""
});
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -138,19 +133,23 @@ export default function GCPSecretManagerCreateIntegrationPage() {
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId)?.name, app: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
)?.name,
appId: targetAppId, appId: targetAppId,
sourceEnvironment: sce, sourceEnvironment: sce,
secretPath, secretPath,
metadata: { metadata: {
...(secretPrefix ? { secretPrefix } : {}), ...(secretPrefix ? { secretPrefix } : {}),
...(secretSuffix ? { secretSuffix } : {}), ...(secretSuffix ? { secretSuffix } : {}),
...(sl ? { ...(sl
secretGCPLabel: { ? {
labelName, secretGCPLabel: {
labelValue labelName,
} labelValue
} : {}) }
}
: {})
} }
}); });
@@ -160,12 +159,9 @@ export default function GCPSecretManagerCreateIntegrationPage() {
console.error(err); console.error(err);
setIsLoading(false); setIsLoading(false);
} }
} };
return integrationAuth && return integrationAuth && workspace && selectedSourceEnvironment && integrationAuthApps ? (
workspace &&
selectedSourceEnvironment &&
integrationAuthApps ? (
<form <form
onSubmit={handleSubmit((data: FormData) => { onSubmit={handleSubmit((data: FormData) => {
if (!data.secretPrefix && !data.secretSuffix && !data.shouldLabel) { if (!data.secretPrefix && !data.secretSuffix && !data.shouldLabel) {
@@ -175,15 +171,15 @@ export default function GCPSecretManagerCreateIntegrationPage() {
onFormSubmit(data); onFormSubmit(data);
})} })}
className="flex flex-col h-full w-full items-center justify-center" className="flex h-full w-full flex-col items-center justify-center"
> >
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<Head> <Head>
<title>Set Up GCP Secret Manager Integration</title> <title>Set Up GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<CardTitle <CardTitle
className="text-left px-6 text-xl mb-2" className="mb-2 px-6 text-left text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to GCP Secret Manager." 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="flex flex-row items-center">
@@ -198,10 +194,13 @@ export default function GCPSecretManagerCreateIntegrationPage() {
<span className="ml-1.5">GCP Secret Manager Integration </span> <span className="ml-1.5">GCP Secret Manager Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref> <Link href="https://infisical.com/docs/integrations/cloud/gcp-secret-manager" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -209,7 +208,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
</CardTitle> </CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList> <TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full"> <div className="flex w-full flex-row border-b border-mineshaft-600">
<Tab value={TabSections.Connection}>Connection</Tab> <Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab> <Tab value={TabSections.Options}>Options</Tab>
</div> </div>
@@ -250,26 +249,23 @@ export default function GCPSecretManagerCreateIntegrationPage() {
)} )}
/> />
<Controller <Controller
control={control} control={control}
defaultValue="" defaultValue=""
name="secretPath" name="secretPath"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secrets Path" label="Secrets Path"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="/" />
{...field} </FormControl>
placeholder="/" )}
/>
</FormControl>
)}
/> />
<Controller <Controller
control={control} control={control}
name="targetAppId" name="targetAppId"
render={({ field: { onChange, ...field }, fieldState: { error } }) => { render={({ field: { onChange, ...field }, fieldState: { error } }) => {
return ( return (
<FormControl <FormControl
label="GCP Project" label="GCP Project"
@@ -280,7 +276,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
{...field} {...field}
onValueChange={(e) => { onValueChange={(e) => {
if (e === "") return; if (e === "") return;
onChange(e) onChange(e);
}} }}
className="w-full" className="w-full"
> >
@@ -300,7 +296,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
)} )}
</Select> </Select>
</FormControl> </FormControl>
) );
}} }}
/> />
</motion.div> </motion.div>
@@ -317,32 +313,26 @@ export default function GCPSecretManagerCreateIntegrationPage() {
control={control} control={control}
name="secretPrefix" name="secretPrefix"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secret Prefix" label="Secret Prefix"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="INFISICAL_" />
{...field} </FormControl>
placeholder="INFISICAL_"
/>
</FormControl>
)} )}
/> />
<Controller <Controller
control={control} control={control}
name="secretSuffix" name="secretSuffix"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secret Suffix" label="Secret Suffix"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="_INFISICAL" />
{...field} </FormControl>
placeholder="_INFISICAL"
/>
</FormControl>
)} )}
/> />
<div className="mt-8 mb-[2.36rem]"> <div className="mt-8 mb-[2.36rem]">
@@ -366,32 +356,26 @@ export default function GCPSecretManagerCreateIntegrationPage() {
control={control} control={control}
name="labelName" name="labelName"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Label Name" label="Label Name"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="managed-by" />
{...field} </FormControl>
placeholder="managed-by"
/>
</FormControl>
)} )}
/> />
<Controller <Controller
control={control} control={control}
name="labelValue" name="labelValue"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Label Name" label="Label Name"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="infisical" />
{...field} </FormControl>
placeholder="infisical"
/>
</FormControl>
)} )}
/> />
</div> </div>
@@ -424,54 +408,64 @@ export default function GCPSecretManagerCreateIntegrationPage() {
</span> </span>
</div> */} </div> */}
<Modal <Modal
isOpen={popUp.confirmIntegration?.isOpen} isOpen={popUp.confirmIntegration?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("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>
}
> >
<ModalContent <p>You&apos;re about to overwrite any existing secrets in GCP Secret Manager.</p>
title="Heads Up" <p className="mt-4">
footerContent={ To avoid this behavior, you may consider adding a secret prefix/suffix or enabling
<div className="flex items-center space-x-2"> labeling in the options tab.
<Button onClick={() => onFormSubmit(popUp.confirmIntegration?.data as FormData)}> </p>
Continue Anyway </ModalContent>
</Button> </Modal>
<Button
onClick={() => handlePopUpClose("confirmIntegration")}
variant="outline_bg"
colorSchema="secondary"
>
Cancel
</Button>
</div>
}
>
<p>
You&apos;re about to overwrite any existing secrets in GCP Secret Manager.
</p>
<p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix or enabling labeling in the options tab.
</p>
</ModalContent>
</Modal>
</form> </form>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up GCP Secret Manager Integration</title> <title>Set Up GCP Secret Manager Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,15 +2,13 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function GCPSecretManagerOAuth2CallbackPage() { export default function GCPSecretManagerOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useAuthorizeIntegration(); const { mutateAsync } = useAuthorizeIntegration();
const { code, state } = queryString.parse(router.asPath.split("?")[1]); const { code, state } = queryString.parse(router.asPath.split("?")[1]);
useEffect(() => { useEffect(() => {
(async () => { (async () => {
@@ -25,7 +23,9 @@ export default function GCPSecretManagerOAuth2CallbackPage() {
integration: "gcp-secret-manager" integration: "gcp-secret-manager"
}); });
router.push(`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth.id}`); router.push(
`/integrations/gcp-secret-manager/create?integrationAuthId=${integrationAuth.id}`
);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
+105 -50
View File
@@ -3,14 +3,19 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faAngleDown, faArrowUpRightFromSquare, faBookOpen, faBugs, faCheckCircle, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faAngleDown,
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCheckCircle,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { motion } from "framer-motion"; import { motion } from "framer-motion";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -48,9 +53,10 @@ export default function GitHubCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
integrationAuthId: (integrationAuthId as string) ?? "" useGetIntegrationAuthApps({
}); integrationAuthId: (integrationAuthId as string) ?? ""
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
@@ -81,8 +87,8 @@ export default function GitHubCreateIntegrationPage() {
if (!integrationAuth?.id) return; if (!integrationAuth?.id) return;
const targetApps = integrationAuthApps?.filter( const targetApps = integrationAuthApps?.filter((integrationAuthApp) =>
(integrationAuthApp) => targetAppIds.includes(String(integrationAuthApp.appId)) targetAppIds.includes(String(integrationAuthApp.appId))
); );
if (!targetApps) return; if (!targetApps) return;
@@ -99,7 +105,7 @@ export default function GitHubCreateIntegrationPage() {
metadata: { metadata: {
secretSuffix secretSuffix
} }
}) });
}) })
); );
@@ -115,18 +121,18 @@ export default function GitHubCreateIntegrationPage() {
selectedSourceEnvironment && selectedSourceEnvironment &&
integrationAuthApps && integrationAuthApps &&
targetAppIds ? ( targetAppIds ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up GitHub Integration</title> <title>Set Up GitHub Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment in Infisical you want to sync to environment variables in GitHub." subTitle="Choose which environment in Infisical you want to sync to environment variables in GitHub."
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
<div className="inline flex items-center bg-mineshaft-200 rounded-full"> <div className="inline flex items-center rounded-full bg-mineshaft-200">
<Image <Image
src="/images/integrations/GitHub.png" src="/images/integrations/GitHub.png"
height={30} height={30}
@@ -137,10 +143,13 @@ export default function GitHubCreateIntegrationPage() {
<span className="ml-2.5">GitHub Integration </span> <span className="ml-2.5">GitHub Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/githubactions" passHref> <Link href="https://infisical.com/docs/integrations/cicd/githubactions" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -148,7 +157,7 @@ export default function GitHubCreateIntegrationPage() {
</CardTitle> </CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList> <TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full"> <div className="flex w-full flex-row border-b border-mineshaft-600">
<Tab value={TabSections.Connection}>Connection</Tab> <Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab> <Tab value={TabSections.Options}>Options</Tab>
</div> </div>
@@ -187,17 +196,27 @@ export default function GitHubCreateIntegrationPage() {
<FormControl label="GitHub Repo"> <FormControl label="GitHub Repo">
<DropdownMenu> <DropdownMenu>
<DropdownMenuTrigger asChild> <DropdownMenuTrigger asChild>
{(integrationAuthApps.length > 0) ? <div className="w-full cursor-pointer border border-mineshaft-600 inline-flex items-center justify-between rounded-md bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-mineshaft-200"> {integrationAuthApps.length > 0 ? (
{targetAppIds.length === 1 ? integrationAuthApps?.find( <div className="inline-flex w-full cursor-pointer items-center justify-between rounded-md border border-mineshaft-600 bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-mineshaft-200">
(integrationAuthApp) => targetAppIds[0] === String(integrationAuthApp.appId) {targetAppIds.length === 1
)?.name : `${targetAppIds.length} repositories selected`} ? integrationAuthApps?.find(
(integrationAuthApp) =>
targetAppIds[0] === String(integrationAuthApp.appId)
)?.name
: `${targetAppIds.length} repositories selected`}
<FontAwesomeIcon icon={faAngleDown} className="text-xs" /> <FontAwesomeIcon icon={faAngleDown} className="text-xs" />
</div> : <div className="w-full cursor-default border border-mineshaft-600 inline-flex items-center justify-between rounded-md bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-mineshaft-200"> </div>
) : (
<div className="inline-flex w-full cursor-default items-center justify-between rounded-md border border-mineshaft-600 bg-mineshaft-900 px-3 py-2 font-inter text-sm font-normal text-bunker-200 outline-none data-[placeholder]:text-mineshaft-200">
No repositories found No repositories found
</div>} </div>
)}
</DropdownMenuTrigger> </DropdownMenuTrigger>
<DropdownMenuContent align="start" className="z-[100] max-h-80 overflow-y-scroll thin-scrollbar"> <DropdownMenuContent
{(integrationAuthApps.length > 0) ? ( align="start"
className="thin-scrollbar z-[100] max-h-80 overflow-y-scroll"
>
{integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => { integrationAuthApps.map((integrationAuthApp) => {
const isSelected = targetAppIds.includes(String(integrationAuthApp.appId)); const isSelected = targetAppIds.includes(String(integrationAuthApp.appId));
@@ -205,20 +224,39 @@ export default function GitHubCreateIntegrationPage() {
<DropdownMenuItem <DropdownMenuItem
onClick={() => { onClick={() => {
if (targetAppIds.includes(String(integrationAuthApp.appId))) { if (targetAppIds.includes(String(integrationAuthApp.appId))) {
setTargetAppIds(targetAppIds.filter((appId) => appId !== String(integrationAuthApp.appId))); setTargetAppIds(
targetAppIds.filter(
(appId) => appId !== String(integrationAuthApp.appId)
)
);
} else { } else {
setTargetAppIds([...targetAppIds, String(integrationAuthApp.appId)]); setTargetAppIds([
...targetAppIds,
String(integrationAuthApp.appId)
]);
} }
}} }}
key={integrationAuthApp.appId} key={integrationAuthApp.appId}
icon={isSelected ? <FontAwesomeIcon icon={faCheckCircle} className="text-primary pr-0.5" /> : <div className="pl-[1.01rem]"/>} icon={
isSelected ? (
<FontAwesomeIcon
icon={faCheckCircle}
className="pr-0.5 text-primary"
/>
) : (
<div className="pl-[1.01rem]" />
)
}
iconPos="left" iconPos="left"
className="w-[28.4rem] text-sm" className="w-[28.4rem] text-sm"
> >
{integrationAuthApp.name} {integrationAuthApp.name}
</DropdownMenuItem> </DropdownMenuItem>
)}) );
) : <div/>} })
) : (
<div />
)}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
</FormControl> </FormControl>
@@ -253,31 +291,48 @@ export default function GitHubCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up GitHub Integration</title> <title>Set Up GitHub Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function GitHubOAuth2CallbackPage() { export default function GitHubOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -20,10 +20,7 @@ const schema = yup.object({
type FormData = yup.InferType<typeof schema>; type FormData = yup.InferType<typeof schema>;
export default function GitLabAuthorizeIntegrationPage() { export default function GitLabAuthorizeIntegrationPage() {
const { const { control, handleSubmit } = useForm<FormData>({
control,
handleSubmit
} = useForm<FormData>({
resolver: yupResolver(schema), resolver: yupResolver(schema),
defaultValues: { defaultValues: {
gitLabURL: "" gitLabURL: ""
@@ -32,34 +29,37 @@ export default function GitLabAuthorizeIntegrationPage() {
const { data: cloudIntegrations } = useGetCloudIntegrations(); const { data: cloudIntegrations } = useGetCloudIntegrations();
const onFormSubmit = ({ const onFormSubmit = ({ gitLabURL }: FormData) => {
gitLabURL
}: FormData) => {
if (!cloudIntegrations) return; if (!cloudIntegrations) return;
const integrationOption = cloudIntegrations.find((integration) => integration.slug === "gitlab"); const integrationOption = cloudIntegrations.find(
(integration) => integration.slug === "gitlab"
);
if (!integrationOption) return; if (!integrationOption) return;
const baseURL = (gitLabURL as string).trim() === "" ? "https://gitlab.com" : (gitLabURL as string).trim(); const baseURL =
(gitLabURL as string).trim() === "" ? "https://gitlab.com" : (gitLabURL as string).trim();
const csrfToken = crypto.randomBytes(16).toString("hex"); const csrfToken = crypto.randomBytes(16).toString("hex");
localStorage.setItem("latestCSRFToken", csrfToken); localStorage.setItem("latestCSRFToken", csrfToken);
const state = `${csrfToken}|${(gitLabURL as string).trim() === "" ? "" : (gitLabURL as string).trim()}`; const state = `${csrfToken}|${
(gitLabURL as string).trim() === "" ? "" : (gitLabURL as string).trim()
}`;
const link = `${baseURL}/oauth/authorize?clientid=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`; const link = `${baseURL}/oauth/authorize?clientid=${integrationOption.clientId}&redirect_uri=${window.location.origin}/integrations/gitlab/oauth2/callback&response_type=code&state=${state}`;
window.location.assign(link); window.location.assign(link);
} };
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize GitLab Integration</title> <title>Authorize GitLab Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left 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." 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="flex flex-row items-center">
@@ -74,19 +74,19 @@ export default function GitLabAuthorizeIntegrationPage() {
<span className="ml-2.5">GitLab Integration </span> <span className="ml-2.5">GitLab Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref> <Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
</div> </div>
</CardTitle> </CardTitle>
<form <form onSubmit={handleSubmit(onFormSubmit)} className="px-6 pb-8 text-right">
onSubmit={handleSubmit(onFormSubmit)}
className="px-6 text-right pb-8"
>
<Controller <Controller
control={control} control={control}
name="gitLabURL" name="gitLabURL"
@@ -96,10 +96,7 @@ export default function GitLabAuthorizeIntegrationPage() {
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
> >
<Input <Input {...field} placeholder="https://self-hosted-gitlab.com" />
{...field}
placeholder="https://self-hosted-gitlab.com"
/>
</FormControl> </FormControl>
)} )}
/> />
+132 -142
View File
@@ -12,9 +12,7 @@ import queryString from "query-string";
import * as yup from "yup"; import * as yup from "yup";
import { usePopUp } from "@app/hooks"; import { usePopUp } from "@app/hooks";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -49,7 +47,10 @@ enum TabSections {
} }
const schema = yup.object({ const schema = yup.object({
targetEntity: yup.string().oneOf(gitLabEntities.map(entity => entity.value), "Invalid entity type"), targetEntity: yup.string().oneOf(
gitLabEntities.map((entity) => entity.value),
"Invalid entity type"
),
targetTeamId: yup.string(), targetTeamId: yup.string(),
selectedSourceEnvironment: yup.string().required("Source environment is required"), selectedSourceEnvironment: yup.string().required("Source environment is required"),
secretPath: yup.string().required("Secret path is required"), secretPath: yup.string().required("Secret path is required"),
@@ -67,19 +68,14 @@ export default function GitLabCreateIntegrationPage() {
"confirmIntegration" "confirmIntegration"
] as const); ] as const);
const { const { control, handleSubmit, setValue, watch } = useForm<FormData>({
control, resolver: yupResolver(schema),
handleSubmit, defaultValues: {
setValue, targetEntity: "individual",
watch secretPath: "/",
} = useForm<FormData>({ secretPrefix: "",
resolver: yupResolver(schema), secretSuffix: ""
defaultValues: { }
targetEntity: "individual",
secretPath: "/",
secretPrefix: "",
secretSuffix: ""
}
}); });
const selectedSourceEnvironment = watch("selectedSourceEnvironment"); const selectedSourceEnvironment = watch("selectedSourceEnvironment");
const targetEntity = watch("targetEntity"); const targetEntity = watch("targetEntity");
@@ -93,14 +89,13 @@ export default function GitLabCreateIntegrationPage() {
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "", integrationAuthId: (integrationAuthId as string) ?? "",
...(targetTeamId ? { teamId: targetTeamId } : {}) ...(targetTeamId ? { teamId: targetTeamId } : {})
}); });
const { data: integrationAuthTeams, isLoading: isintegrationAuthTeamsLoading } = useGetIntegrationAuthTeams( const { data: integrationAuthTeams, isLoading: isintegrationAuthTeamsLoading } =
(integrationAuthId as string) ?? "" useGetIntegrationAuthTeams((integrationAuthId as string) ?? "");
);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -151,7 +146,9 @@ export default function GitLabCreateIntegrationPage() {
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: integrationAuthApps?.find((integrationAuthApp) => String(integrationAuthApp.appId) === targetAppId)?.name, app: integrationAuthApps?.find(
(integrationAuthApp) => String(integrationAuthApp.appId) === targetAppId
)?.name,
appId: String(targetAppId), appId: String(targetAppId),
sourceEnvironment: sse, sourceEnvironment: sse,
targetEnvironment: targetEnvironment === "" ? "*" : targetEnvironment, targetEnvironment: targetEnvironment === "" ? "*" : targetEnvironment,
@@ -168,7 +165,7 @@ export default function GitLabCreateIntegrationPage() {
console.error(err); console.error(err);
setIsLoading(false); setIsLoading(false);
} }
} };
return integrationAuth && return integrationAuth &&
workspace && workspace &&
@@ -184,15 +181,15 @@ export default function GitLabCreateIntegrationPage() {
onFormSubmit(data); onFormSubmit(data);
})} })}
className="flex flex-col h-full w-full items-center justify-center" className="flex h-full w-full flex-col items-center justify-center"
> >
<Head> <Head>
<title>Set Up GitLab Integration</title> <title>Set Up GitLab Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to GitLab's environment variables." 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="flex flex-row items-center">
@@ -207,10 +204,13 @@ export default function GitLabCreateIntegrationPage() {
<span className="ml-2.5">GitLab Integration </span> <span className="ml-2.5">GitLab Integration </span>
<Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref> <Link href="https://infisical.com/docs/integrations/cicd/gitlab" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -218,7 +218,7 @@ export default function GitLabCreateIntegrationPage() {
</CardTitle> </CardTitle>
<Tabs defaultValue={TabSections.Connection} className="px-6"> <Tabs defaultValue={TabSections.Connection} className="px-6">
<TabList> <TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full"> <div className="flex w-full flex-row border-b border-mineshaft-600">
<Tab value={TabSections.Connection}>Connection</Tab> <Tab value={TabSections.Connection}>Connection</Tab>
<Tab value={TabSections.Options}>Options</Tab> <Tab value={TabSections.Options}>Options</Tab>
</div> </div>
@@ -259,21 +259,18 @@ export default function GitLabCreateIntegrationPage() {
)} )}
/> />
<Controller <Controller
control={control} control={control}
defaultValue="" defaultValue=""
name="secretPath" name="secretPath"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secrets Path" label="Secrets Path"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="/" />
{...field} </FormControl>
placeholder="/" )}
/>
</FormControl>
)}
/> />
<Controller <Controller
control={control} control={control}
@@ -284,11 +281,7 @@ export default function GitLabCreateIntegrationPage() {
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
> >
<Select <Select {...field} onValueChange={(e) => onChange(e)} className="w-full">
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{gitLabEntities.map((entity) => { {gitLabEntities.map((entity) => {
return ( return (
<SelectItem value={entity.value} key={`target-entity-${entity.value}`}> <SelectItem value={entity.value} key={`target-entity-${entity.value}`}>
@@ -310,14 +303,9 @@ export default function GitLabCreateIntegrationPage() {
errorText={error?.message} errorText={error?.message}
isError={Boolean(error)} isError={Boolean(error)}
> >
<Select <Select {...field} onValueChange={(e) => onChange(e)} className="w-full">
{...field}
onValueChange={(e) => onChange(e)}
className="w-full"
>
{integrationAuthTeams.length > 0 ? ( {integrationAuthTeams.length > 0 ? (
integrationAuthTeams.map((integrationAuthTeam) => integrationAuthTeams.map((integrationAuthTeam) => (
(
<SelectItem <SelectItem
value={String(integrationAuthTeam.teamId as string)} value={String(integrationAuthTeam.teamId as string)}
key={`target-team-${String(integrationAuthTeam.teamId)}`} key={`target-team-${String(integrationAuthTeam.teamId)}`}
@@ -349,7 +337,7 @@ export default function GitLabCreateIntegrationPage() {
{...field} {...field}
onValueChange={(e) => { onValueChange={(e) => {
if (e === "") return; if (e === "") return;
onChange(e) onChange(e);
}} }}
className="w-full" className="w-full"
> >
@@ -369,24 +357,22 @@ export default function GitLabCreateIntegrationPage() {
)} )}
</Select> </Select>
</FormControl> </FormControl>
)}} );
/> }}
<Controller />
control={control} <Controller
defaultValue="" control={control}
name="targetEnvironment" defaultValue=""
render={({ field, fieldState: { error } }) => ( name="targetEnvironment"
<FormControl render={({ field, fieldState: { error } }) => (
label="GitLab Environment Scope (Optional)" <FormControl
isError={Boolean(error)} label="GitLab Environment Scope (Optional)"
errorText={error?.message} isError={Boolean(error)}
> errorText={error?.message}
<Input >
{...field} <Input {...field} placeholder="*" />
placeholder="*" </FormControl>
/> )}
</FormControl>
)}
/> />
</motion.div> </motion.div>
</TabPanel> </TabPanel>
@@ -403,32 +389,26 @@ export default function GitLabCreateIntegrationPage() {
control={control} control={control}
name="secretPrefix" name="secretPrefix"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secret Prefix" label="Secret Prefix"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="INFISICAL_" />
{...field} </FormControl>
placeholder="INFISICAL_"
/>
</FormControl>
)} )}
/> />
<Controller <Controller
control={control} control={control}
name="secretSuffix" name="secretSuffix"
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<FormControl <FormControl
label="Secret Suffix" label="Secret Suffix"
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="_INFISICAL" />
{...field} </FormControl>
placeholder="_INFISICAL"
/>
</FormControl>
)} )}
/> />
</motion.div> </motion.div>
@@ -452,54 +432,64 @@ export default function GitLabCreateIntegrationPage() {
<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> <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> */} </div> */}
<Modal <Modal
isOpen={popUp.confirmIntegration?.isOpen} isOpen={popUp.confirmIntegration?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("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>
}
> >
<ModalContent <p>You&apos;re about to overwrite any existing secrets in GitLab.</p>
title="Heads Up" <p className="mt-4">
footerContent={ To avoid this behavior, you may consider adding a secret prefix/suffix in the options
<div className="flex items-center space-x-2"> tab.
<Button onClick={() => onFormSubmit(popUp.confirmIntegration?.data as FormData)}> </p>
Continue Anyway </ModalContent>
</Button> </Modal>
<Button
onClick={() => handlePopUpClose("confirmIntegration")}
variant="outline_bg"
colorSchema="secondary"
>
Cancel
</Button>
</div>
}
>
<p>
You&apos;re about to overwrite any existing secrets in GitLab.
</p>
<p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix in the options tab.
</p>
</ModalContent>
</Modal>
</form> </form>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up GitLab Integration</title> <title>Set Up GitLab Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading || isintegrationAuthTeamsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function GitLabOAuth2CallbackPage() { export default function GitLabOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -24,9 +22,11 @@ export default function GitLabOAuth2CallbackPage() {
workspaceId: localStorage.getItem("projectData.id") as string, workspaceId: localStorage.getItem("projectData.id") as string,
code: code as string, code: code as string,
integration: "gitlab", integration: "gitlab",
...(url === "" ? {} : { ...(url === ""
url ? {}
}) : {
url
})
}); });
router.push(`/integrations/gitlab/create?integrationAuthId=${integrationAuth.id}`); router.push(`/integrations/gitlab/create?integrationAuthId=${integrationAuth.id}`);
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -56,23 +54,23 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
setVaultSecretIDErrorText(""); setVaultSecretIDErrorText("");
} }
if ( if (
vaultURL.length === 0 || vaultURL.length === 0 ||
vaultNamespace.length === 0 || vaultNamespace.length === 0 ||
vaultRoleID.length === 0 || vaultRoleID.length === 0 ||
vaultSecretID.length === 0 vaultSecretID.length === 0
) { ) {
return; return;
} }
setIsLoading(true); setIsLoading(true);
const integrationAuth = await mutateAsync({ const integrationAuth = await mutateAsync({
workspaceId: localStorage.getItem("projectData.id"), workspaceId: localStorage.getItem("projectData.id"),
integration: "hashicorp-vault", integration: "hashicorp-vault",
accessId: vaultRoleID, accessId: vaultRoleID,
accessToken: vaultSecretID, accessToken: vaultSecretID,
url: vaultURL, url: vaultURL,
namespace: vaultNamespace namespace: vaultNamespace
}); });
setIsLoading(false); setIsLoading(false);
@@ -87,11 +85,11 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize Vault Integration</title> <title>Authorize Vault Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After connecting to Vault, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -106,10 +104,13 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
<span className="ml-2.5">HashiCorp Vault Integration</span> <span className="ml-2.5">HashiCorp Vault Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref> <Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -130,10 +131,10 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
className="px-6" className="px-6"
> >
<Input <Input
placeholder="admin/education" placeholder="admin/education"
value={vaultNamespace} value={vaultNamespace}
onChange={(e) => setVaultNamespace(e.target.value)} onChange={(e) => setVaultNamespace(e.target.value)}
/> />
</FormControl> </FormControl>
<FormControl <FormControl
label="Vault RoleID" label="Vault RoleID"
@@ -141,7 +142,11 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
isError={vaultRoleIDErrorText !== "" ?? false} isError={vaultRoleIDErrorText !== "" ?? false}
className="px-6" className="px-6"
> >
<Input placeholder="" value={vaultRoleID} onChange={(e) => setVaultRoleID(e.target.value)} /> <Input
placeholder=""
value={vaultRoleID}
onChange={(e) => setVaultRoleID(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl <FormControl
label="Vault SecretID" label="Vault SecretID"
@@ -150,10 +155,10 @@ export default function HashiCorpVaultAuthorizeIntegrationPage() {
className="px-6" className="px-6"
> >
<Input <Input
placeholder="" placeholder=""
value={vaultSecretID} value={vaultSecretID}
onChange={(e) => setVaultSecretID(e.target.value)} onChange={(e) => setVaultSecretID(e.target.value)}
/> />
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -30,7 +33,9 @@ export default function HashiCorpVaultCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isintegrationAuthLoading } = useGetIntegrationAuthById(
(integrationAuthId as string) ?? ""
);
const [vaultEnginePath, setVaultEnginePath] = useState(""); const [vaultEnginePath, setVaultEnginePath] = useState("");
const [vaultEnginePathErrorText, setVaultEnginePathErrorText] = useState(""); const [vaultEnginePathErrorText, setVaultEnginePathErrorText] = useState("");
@@ -84,14 +89,14 @@ export default function HashiCorpVaultCreateIntegrationPage() {
}; };
return integrationAuth && workspace ? ( return integrationAuth && workspace ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up Vault Integration</title> <title>Set Up Vault Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to which path in HashiCorp Vault." 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="flex flex-row items-center">
@@ -106,10 +111,13 @@ export default function HashiCorpVaultCreateIntegrationPage() {
<span className="ml-2.5">HashiCorp Vault Integration</span> <span className="ml-2.5">HashiCorp Vault Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref> <Link href="https://infisical.com/docs/integrations/cloud/hashicorp-vault" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -173,31 +181,48 @@ export default function HashiCorpVaultCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Vault Integration</title> <title>Set Up Vault Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isintegrationAuthLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function HerokuOAuth2CallbackPage() { export default function HerokuOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -58,14 +56,22 @@ export default function LaravelForgeCreateIntegrationPage() {
errorText={apiKeyErrorText} errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false} isError={apiKeyErrorText !== "" ?? false}
> >
<Input placeholder="Access Token" value={apiKey} onChange={(e) => setApiKey(e.target.value)} /> <Input
placeholder="Access Token"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl <FormControl
label="Laravel Forge Server ID" label="Laravel Forge Server ID"
errorText={serverIdErrorText} errorText={serverIdErrorText}
isError={serverIdErrorText !== "" ?? false} isError={serverIdErrorText !== "" ?? false}
> >
<Input placeholder="123456" value={serverId} onChange={(e) => setServerId(e.target.value)} /> <Input
placeholder="123456"
value={serverId}
onChange={(e) => setServerId(e.target.value)}
/>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -64,7 +62,10 @@ export default function LaravelForgeCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: String(integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId), appId: String(
integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)
?.appId
),
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -73,7 +71,9 @@ export default function NetlifyCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetEnvironment, targetEnvironment,
secretPath secretPath
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function NetlifyOAuth2CallbackPage() { export default function NetlifyOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -73,7 +71,6 @@ export default function NorthflankCreateIntegrationPage() {
setTargetSecretGroupId("none"); setTargetSecretGroupId("none");
} }
} }
}, [integrationAuthSecretGroups]); }, [integrationAuthSecretGroups]);
const handleButtonClick = async () => { const handleButtonClick = async () => {
@@ -85,7 +82,9 @@ export default function NorthflankCreateIntegrationPage() {
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId)?.name, app: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
)?.name,
appId: targetAppId, appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetServiceId: targetSecretGroupId, targetServiceId: targetSecretGroupId,
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -48,11 +46,11 @@ export default function QoveryCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize Qovery Integration</title> <title>Authorize Qovery Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -67,10 +65,13 @@ export default function QoveryCreateIntegrationPage() {
<span className="ml-2.5">Qovery Integration </span> <span className="ml-2.5">Qovery Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/qovery" passHref> <Link href="https://infisical.com/docs/integrations/cloud/qovery" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
+157 -130
View File
@@ -21,9 +21,7 @@ import {
TabPanel, TabPanel,
Tabs Tabs
} from "@app/components/v2"; } from "@app/components/v2";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
useGetIntegrationAuthQoveryEnvironments, useGetIntegrationAuthQoveryEnvironments,
useGetIntegrationAuthQoveryOrgs, useGetIntegrationAuthQoveryOrgs,
@@ -69,7 +67,9 @@ export default function QoveryCreateIntegrationPage() {
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/"); const [secretPath, setSecretPath] = useState("/");
const { data: integrationAuthOrgs } = useGetIntegrationAuthQoveryOrgs((integrationAuthId as string) ?? ""); const { data: integrationAuthOrgs } = useGetIntegrationAuthQoveryOrgs(
(integrationAuthId as string) ?? ""
);
const [targetOrgId, setTargetOrgId] = useState(""); const [targetOrgId, setTargetOrgId] = useState("");
const { data: integrationAuthProjects } = useGetIntegrationAuthQoveryProjects({ const { data: integrationAuthProjects } = useGetIntegrationAuthQoveryProjects({
@@ -84,11 +84,12 @@ export default function QoveryCreateIntegrationPage() {
}); });
const [targetEnvironmentId, setTargetEnvironmentId] = useState(""); const [targetEnvironmentId, setTargetEnvironmentId] = useState("");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthQoveryScopes({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
integrationAuthId: (integrationAuthId as string) ?? "", useGetIntegrationAuthQoveryScopes({
environmentId: targetEnvironmentId, integrationAuthId: (integrationAuthId as string) ?? "",
scope: (scope as ("job" | "application" | "container")) environmentId: targetEnvironmentId,
}); scope: scope as "job" | "application" | "container"
});
const [targetAppId, setTargetAppId] = useState(""); const [targetAppId, setTargetAppId] = useState("");
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
@@ -145,10 +146,19 @@ export default function QoveryCreateIntegrationPage() {
setIsLoading(true); setIsLoading(true);
const targetOrg = integrationAuthOrgs?.find((integrationAuthOrg) => integrationAuthOrg.orgId === targetOrgId)?.name; const targetOrg = integrationAuthOrgs?.find(
const targetProject = integrationAuthProjects?.find((integrationAuthProject) => integrationAuthProject.projectId === targetProjectId)?.name; (integrationAuthOrg) => integrationAuthOrg.orgId === targetOrgId
const targetEnvironment = integrationAuthEnvironments?.find((integrationAuthEnvironment) => integrationAuthEnvironment.environmentId === targetEnvironmentId)?.name; )?.name;
const targetApp = integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId)?.name; const targetProject = integrationAuthProjects?.find(
(integrationAuthProject) => integrationAuthProject.projectId === targetProjectId
)?.name;
const targetEnvironment = integrationAuthEnvironments?.find(
(integrationAuthEnvironment) =>
integrationAuthEnvironment.environmentId === targetEnvironmentId
)?.name;
const targetApp = integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
)?.name;
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
@@ -173,17 +183,15 @@ export default function QoveryCreateIntegrationPage() {
} }
}; };
return integrationAuth && return integrationAuth && workspace && selectedSourceEnvironment ? (
workspace && <div className="flex h-full w-full flex-col items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
selectedSourceEnvironment ? (
<div className="flex flex-col h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900">
<Head> <Head>
<title>Set Up Qovery Integration</title> <title>Set Up Qovery Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment in Infisical you want to sync to Checkly environment variables." subTitle="Choose which environment in Infisical you want to sync to Checkly environment variables."
> >
<div className="flex flex-row items-center"> <div className="flex flex-row items-center">
@@ -198,10 +206,13 @@ export default function QoveryCreateIntegrationPage() {
<span className="ml-2.5">Qovery Integration </span> <span className="ml-2.5">Qovery Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/qovery" passHref> <Link href="https://infisical.com/docs/integrations/cloud/qovery" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -209,7 +220,7 @@ export default function QoveryCreateIntegrationPage() {
</CardTitle> </CardTitle>
<Tabs defaultValue={TabSections.InfisicalSettings} className="px-6"> <Tabs defaultValue={TabSections.InfisicalSettings} className="px-6">
<TabList> <TabList>
<div className="flex flex-row border-b border-mineshaft-600 w-full"> <div className="flex w-full flex-row border-b border-mineshaft-600">
<Tab value={TabSections.InfisicalSettings}>Infisical Settings</Tab> <Tab value={TabSections.InfisicalSettings}>Infisical Settings</Tab>
<Tab value={TabSections.QoverySettings}>Qovery Settings</Tab> <Tab value={TabSections.QoverySettings}>Qovery Settings</Tab>
</div> </div>
@@ -262,107 +273,112 @@ export default function QoveryCreateIntegrationPage() {
className="w-full border border-mineshaft-500" className="w-full border border-mineshaft-500"
> >
{qoveryScopes.map((qoveryScope) => ( {qoveryScopes.map((qoveryScope) => (
<SelectItem <SelectItem value={qoveryScope.value} key={`target-app-${qoveryScope.value}`}>
value={qoveryScope.value}
key={`target-app-${qoveryScope.value}`}
>
{qoveryScope.label} {qoveryScope.label}
</SelectItem> </SelectItem>
))} ))}
</Select> </Select>
</FormControl> </FormControl>
{integrationAuthOrgs && <FormControl label="Qovery Organization"> {integrationAuthOrgs && (
<Select <FormControl label="Qovery Organization">
value={targetOrgId} <Select
onValueChange={(val) => setTargetOrgId(val)} value={targetOrgId}
className="w-full border border-mineshaft-500" onValueChange={(val) => setTargetOrgId(val)}
isDisabled={integrationAuthOrgs.length === 0} className="w-full border border-mineshaft-500"
> isDisabled={integrationAuthOrgs.length === 0}
{integrationAuthOrgs.length > 0 ? ( >
integrationAuthOrgs.map((integrationAuthOrg) => ( {integrationAuthOrgs.length > 0 ? (
<SelectItem integrationAuthOrgs.map((integrationAuthOrg) => (
value={integrationAuthOrg.orgId} <SelectItem
key={`target-app-${integrationAuthOrg.orgId}`} value={integrationAuthOrg.orgId}
> key={`target-app-${integrationAuthOrg.orgId}`}
{integrationAuthOrg.name} >
{integrationAuthOrg.name}
</SelectItem>
))
) : (
<SelectItem value="none" key="target-app-none">
No organizaztions found
</SelectItem> </SelectItem>
)) )}
) : ( </Select>
<SelectItem value="none" key="target-app-none"> </FormControl>
No organizaztions found )}
</SelectItem> {integrationAuthProjects && (
)} <FormControl label="Qovery Project">
</Select> <Select
</FormControl>} value={targetProjectId}
{integrationAuthProjects && <FormControl label="Qovery Project"> onValueChange={(val) => setTargetProjectId(val)}
<Select className="w-full border border-mineshaft-500"
value={targetProjectId} isDisabled={integrationAuthProjects.length === 0}
onValueChange={(val) => setTargetProjectId(val)} >
className="w-full border border-mineshaft-500" {integrationAuthProjects.length > 0 ? (
isDisabled={integrationAuthProjects.length === 0} integrationAuthProjects.map((integrationAuthProject) => (
> <SelectItem
{integrationAuthProjects.length > 0 ? ( value={integrationAuthProject.projectId}
integrationAuthProjects.map((integrationAuthProject) => ( key={`target-app-${integrationAuthProject.projectId}`}
<SelectItem >
value={integrationAuthProject.projectId} {integrationAuthProject.name}
key={`target-app-${integrationAuthProject.projectId}`} </SelectItem>
> ))
{integrationAuthProject.name} ) : (
<SelectItem value="none" key="target-app-none">
No projects found
</SelectItem> </SelectItem>
)) )}
) : ( </Select>
<SelectItem value="none" key="target-app-none"> </FormControl>
No projects found )}
</SelectItem> {integrationAuthEnvironments && (
)} <FormControl label="Qovery Environment">
</Select> <Select
</FormControl>} value={targetEnvironmentId}
{integrationAuthEnvironments && <FormControl label="Qovery Environment"> onValueChange={(val) => setTargetEnvironmentId(val)}
<Select className="w-full border border-mineshaft-500"
value={targetEnvironmentId} isDisabled={integrationAuthEnvironments.length === 0}
onValueChange={(val) => setTargetEnvironmentId(val)} >
className="w-full border border-mineshaft-500" {integrationAuthEnvironments.length > 0 ? (
isDisabled={integrationAuthEnvironments.length === 0} integrationAuthEnvironments.map((integrationAuthEnvironment) => (
> <SelectItem
{integrationAuthEnvironments.length > 0 ? ( value={integrationAuthEnvironment.environmentId}
integrationAuthEnvironments.map((integrationAuthEnvironment) => ( key={`target-app-${integrationAuthEnvironment.environmentId}`}
<SelectItem >
value={integrationAuthEnvironment.environmentId} {integrationAuthEnvironment.name}
key={`target-app-${integrationAuthEnvironment.environmentId}`} </SelectItem>
> ))
{integrationAuthEnvironment.name} ) : (
<SelectItem value="none" key="target-app-none">
No environments found
</SelectItem> </SelectItem>
)) )}
) : ( </Select>
<SelectItem value="none" key="target-app-none"> </FormControl>
No environments found )}
</SelectItem> {scope && integrationAuthApps && (
)} <FormControl label={`Qovery ${scope.charAt(0).toUpperCase() + scope.slice(1)}`}>
</Select> <Select
</FormControl>} value={targetAppId}
{(scope && integrationAuthApps) && <FormControl label={`Qovery ${scope.charAt(0).toUpperCase() + scope.slice(1)}`}> onValueChange={(val) => setTargetAppId(val)}
<Select className="w-full border border-mineshaft-500"
value={targetAppId} isDisabled={integrationAuthApps.length === 0}
onValueChange={(val) => setTargetAppId(val)} >
className="w-full border border-mineshaft-500" {integrationAuthApps.length > 0 ? (
isDisabled={integrationAuthApps.length === 0} integrationAuthApps.map((integrationAuthApp) => (
> <SelectItem
{integrationAuthApps.length > 0 ? ( value={integrationAuthApp.appId as string}
integrationAuthApps.map((integrationAuthApp) => ( key={`target-app-${integrationAuthApp.appId}`}
<SelectItem >
value={(integrationAuthApp.appId as string)} {integrationAuthApp.name}
key={`target-app-${integrationAuthApp.appId}`} </SelectItem>
> ))
{integrationAuthApp.name} ) : (
<SelectItem value="none" key="target-app-none">
No {scope}s found
</SelectItem> </SelectItem>
)) )}
) : ( </Select>
<SelectItem value="none" key="target-app-none"> </FormControl>
No {scope}s found )}
</SelectItem>
)}
</Select>
</FormControl>}
</motion.div> </motion.div>
</TabPanel> </TabPanel>
</Tabs> </Tabs>
@@ -384,24 +400,35 @@ export default function QoveryCreateIntegrationPage() {
</div> */} </div> */}
</div> </div>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Qovery Integration</title> <title>Set Up Qovery Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -6,7 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useSaveIntegrationAccessToken} from "@app/hooks/api"; import { useSaveIntegrationAccessToken } from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -46,11 +46,11 @@ export default function RenderCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize Render Integration</title> <title>Authorize Render Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding your API key, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -65,10 +65,13 @@ export default function RenderCreateIntegrationPage() {
<span className="ml-2.5">Render Integration </span> <span className="ml-2.5">Render Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/render" passHref> <Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -33,10 +36,13 @@ export default function RenderCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById(
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ (integrationAuthId as string) ?? ""
integrationAuthId: (integrationAuthId as string) ?? "" );
}); const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState(""); const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [targetApp, setTargetApp] = useState(""); const [targetApp, setTargetApp] = useState("");
@@ -69,7 +75,9 @@ export default function RenderCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -87,14 +95,14 @@ export default function RenderCreateIntegrationPage() {
selectedSourceEnvironment && selectedSourceEnvironment &&
integrationAuthApps && integrationAuthApps &&
targetApp ? ( targetApp ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up Render Integration</title> <title>Set Up Render Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment or folder in Infisical you want to sync to Render environment variables." 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="flex flex-row items-center">
@@ -109,10 +117,13 @@ export default function RenderCreateIntegrationPage() {
<span className="ml-2.5">Render Integration </span> <span className="ml-2.5">Render Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/render" passHref> <Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -175,31 +186,48 @@ export default function RenderCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Render Integration</title> <title>Set Up Render Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -65,7 +63,9 @@ export default function SupabaseCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -6,9 +6,7 @@ import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons"; import { faArrowUpRightFromSquare, faBookOpen } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -43,7 +41,7 @@ export default function TeamCityCreateIntegrationPage() {
workspaceId: localStorage.getItem("projectData.id"), workspaceId: localStorage.getItem("projectData.id"),
integration: "teamcity", integration: "teamcity",
accessToken: apiKey, accessToken: apiKey,
url: serverUrl, url: serverUrl
}); });
setIsLoading(false); setIsLoading(false);
@@ -58,11 +56,11 @@ export default function TeamCityCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Authorize TeamCity Integration</title> <title>Authorize TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="After adding the details below, you will be prompted to set up an integration for a particular Infisical project and environment." 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="flex flex-row items-center">
@@ -77,10 +75,13 @@ export default function TeamCityCreateIntegrationPage() {
<span className="ml-2">TeamCity Integration</span> <span className="ml-2">TeamCity Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref> <Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -7,9 +7,7 @@ import { faArrowUpRightFromSquare, faBookOpen, faBugs } from "@fortawesome/free-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -40,10 +38,13 @@ export default function TeamCityCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth, isLoading: isIntegrationAuthLoading } = useGetIntegrationAuthById(
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ (integrationAuthId as string) ?? ""
integrationAuthId: (integrationAuthId as string) ?? "" );
}); const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? ""
});
const { data: targetBuildConfigs } = useGetIntegrationAuthTeamCityBuildConfigs({ const { data: targetBuildConfigs } = useGetIntegrationAuthTeamCityBuildConfigs({
integrationAuthId: (integrationAuthId as string) ?? "", integrationAuthId: (integrationAuthId as string) ?? "",
@@ -79,7 +80,9 @@ export default function TeamCityCreateIntegrationPage() {
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.appId === targetAppId)?.name, app: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.appId === targetAppId
)?.name,
appId: targetAppId, appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetEnvironment: targetEnvironment?.name, targetEnvironment: targetEnvironment?.name,
@@ -109,11 +112,11 @@ export default function TeamCityCreateIntegrationPage() {
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up TeamCity Integration</title> <title>Set Up TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 mb-12"> <Card className="mb-12 max-w-lg rounded-md border border-mineshaft-600">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Choose which environment or folders in Infisical you want to sync to which project in TeamCity." 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="flex flex-row items-center">
@@ -128,10 +131,13 @@ export default function TeamCityCreateIntegrationPage() {
<span className="ml-2">TeamCity Integration</span> <span className="ml-2">TeamCity Integration</span>
<Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref> <Link href="https://infisical.com/docs/integrations/cloud/teamcity" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -183,7 +189,7 @@ export default function TeamCityCreateIntegrationPage() {
)} )}
</Select> </Select>
</FormControl> </FormControl>
<FormControl label="Team City Build Config (Optional)" className="px-6"> <FormControl label="Team City Build Config (Optional)" className="px-6">
<Select <Select
value={targetBuildConfigId} value={targetBuildConfigId}
onValueChange={(val) => setTargetBuildConfigId(val)} onValueChange={(val) => setTargetBuildConfigId(val)}
@@ -212,24 +218,35 @@ export default function TeamCityCreateIntegrationPage() {
</Card> </Card>
</div> </div>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up TeamCity Integration</title> <title>Set Up TeamCity Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthLoading || isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -58,14 +56,22 @@ export default function TerraformCloudCreateIntegrationPage() {
errorText={apiKeyErrorText} errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false} isError={apiKeyErrorText !== "" ?? false}
> >
<Input placeholder="API Token" value={apiKey} onChange={(e) => setApiKey(e.target.value)} /> <Input
placeholder="API Token"
value={apiKey}
onChange={(e) => setApiKey(e.target.value)}
/>
</FormControl> </FormControl>
<FormControl <FormControl
label="Terraform Cloud Workspace ID" label="Terraform Cloud Workspace ID"
errorText={workspacesIdErrorText} errorText={workspacesIdErrorText}
isError={workspacesIdErrorText !== "" ?? false} isError={workspacesIdErrorText !== "" ?? false}
> >
<Input placeholder="Workspace Id" value={workspacesId} onChange={(e) => setWorkSpacesId(e.target.value)} /> <Input
placeholder="Workspace Id"
value={workspacesId}
onChange={(e) => setWorkSpacesId(e.target.value)}
/>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
@@ -19,10 +19,7 @@ import {
} from "../../../hooks/api/integrationAuth"; } from "../../../hooks/api/integrationAuth";
import { useGetWorkspaceById } from "../../../hooks/api/workspace"; import { useGetWorkspaceById } from "../../../hooks/api/workspace";
const variableTypes = [ const variableTypes = [{ name: "env" }, { name: "terraform" }];
{ name: "env" },
{ name: "terraform" }
];
export default function TerraformCloudCreateIntegrationPage() { export default function TerraformCloudCreateIntegrationPage() {
const router = useRouter(); const router = useRouter();
@@ -65,9 +62,9 @@ export default function TerraformCloudCreateIntegrationPage() {
if (!integrationAuth?.id) return; if (!integrationAuth?.id) return;
setVariableTypeErrorText(""); setVariableTypeErrorText("");
if (variableType.length === 0 ) { if (variableType.length === 0) {
setVariableTypeErrorText("Variable Type cannot be blank!") setVariableTypeErrorText("Variable Type cannot be blank!");
return; return;
} }
setIsLoading(true); setIsLoading(true);
@@ -76,7 +73,9 @@ export default function TerraformCloudCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetService: variableType, targetService: variableType,
secretPath secretPath
@@ -90,7 +89,6 @@ export default function TerraformCloudCreateIntegrationPage() {
} }
}; };
return integrationAuth && return integrationAuth &&
workspace && workspace &&
selectedSourceEnvironment && selectedSourceEnvironment &&
@@ -122,23 +120,22 @@ export default function TerraformCloudCreateIntegrationPage() {
placeholder="Provide a path, default is /" placeholder="Provide a path, default is /"
/> />
</FormControl> </FormControl>
<FormControl label="Category" className="mt-4" errorText={variableTypeErrorText} <FormControl
isError={variableTypeErrorText !== "" ?? false}> label="Category"
className="mt-4"
errorText={variableTypeErrorText}
isError={variableTypeErrorText !== "" ?? false}
>
<Select <Select
value={variableType} value={variableType}
onValueChange={(val) => setVariableType(val)} onValueChange={(val) => setVariableType(val)}
className="w-full border border-mineshaft-500" className="w-full border border-mineshaft-500"
> >
{ {variableTypes.map((variable) => (
variableTypes.map((variable) => ( <SelectItem value={variable.name} key={`target-app-${variable.name}`}>
<SelectItem {variable.name}
value={variable.name} </SelectItem>
key={`target-app-${variable.name}`} ))}
>
{variable.name}
</SelectItem>
))
}
</Select> </Select>
</FormControl> </FormControl>
<FormControl label="Terraform Cloud Project" className="mt-4"> <FormControl label="Terraform Cloud Project" className="mt-4">
@@ -1,9 +1,7 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -64,7 +62,9 @@ export default function TravisCICreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -3,13 +3,16 @@ import Head from "next/head";
import Image from "next/image"; import Image from "next/image";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faArrowUpRightFromSquare, faBookOpen, faBugs, faCircleInfo } from "@fortawesome/free-solid-svg-icons"; import {
faArrowUpRightFromSquare,
faBookOpen,
faBugs,
faCircleInfo
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -47,9 +50,10 @@ export default function VercelCreateIntegrationPage() {
const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]); const { integrationAuthId } = queryString.parse(router.asPath.split("?")[1]);
const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? ""); const { data: workspace } = useGetWorkspaceById(localStorage.getItem("projectData.id") ?? "");
const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? ""); const { data: integrationAuth } = useGetIntegrationAuthById((integrationAuthId as string) ?? "");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthApps({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
integrationAuthId: (integrationAuthId as string) ?? "" useGetIntegrationAuthApps({
}); integrationAuthId: (integrationAuthId as string) ?? ""
});
const { data: branches } = useGetIntegrationAuthVercelBranches({ const { data: branches } = useGetIntegrationAuthVercelBranches({
integrationAuthId: integrationAuthId as string, integrationAuthId: integrationAuthId as string,
@@ -88,7 +92,8 @@ export default function VercelCreateIntegrationPage() {
if (!targetApp || !targetApp.appId) return; if (!targetApp || !targetApp.appId) return;
const path = targetEnvironment === "preview" && targetBranch !== "" ? targetBranch : undefined; const path =
targetEnvironment === "preview" && targetBranch !== "" ? targetBranch : undefined;
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
@@ -114,14 +119,14 @@ export default function VercelCreateIntegrationPage() {
integrationAuthApps && integrationAuthApps &&
targetAppId && targetAppId &&
targetEnvironment ? ( targetEnvironment ? (
<div className="flex flex-col h-full w-full items-center justify-center"> <div className="flex h-full w-full flex-col items-center justify-center">
<Head> <Head>
<title>Set Up Vercel Integration</title> <title>Set Up Vercel Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </Head>
<Card className="max-w-lg rounded-md border border-mineshaft-600 p-0"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<CardTitle <CardTitle
className="text-left px-6 text-xl" className="px-6 text-left text-xl"
subTitle="Select which environment or folder in Infisical you want to sync to Vercel's environment variables." 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="flex flex-row items-center">
@@ -136,10 +141,13 @@ export default function VercelCreateIntegrationPage() {
<span className="ml-2">Vercel Integration </span> <span className="ml-2">Vercel Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/vercel" passHref> <Link href="https://infisical.com/docs/integrations/cloud/vercel" passHref>
<a target="_blank" rel="noopener noreferrer"> <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"> <div className="ml-2 mb-1 inline-block cursor-default rounded-md bg-yellow/20 px-1.5 pb-[0.03rem] pt-[0.04rem] text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5"/> <FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
Docs Docs
<FontAwesomeIcon icon={faArrowUpRightFromSquare} className="ml-1.5 text-xxs mb-[0.07rem]"/> <FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div> </div>
</a> </a>
</Link> </Link>
@@ -233,31 +241,48 @@ export default function VercelCreateIntegrationPage() {
Create Integration Create Integration
</Button> </Button>
</Card> </Card>
<div className="border-t border-mineshaft-800 w-full max-w-md mt-6"/> <div className="mt-6 w-full max-w-md border-t border-mineshaft-800" />
<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="mt-6 flex w-full max-w-lg flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4">
<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> <div className="flex flex-row items-center">
<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> <FontAwesomeIcon icon={faCircleInfo} className="text-xl text-mineshaft-200" />{" "}
<span className="text-md ml-3 text-mineshaft-100">Pro Tips</span>
</div>
<span className="mt-4 text-sm text-mineshaft-300">
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>
) : ( ) : (
<div className="flex justify-center items-center w-full h-full"> <div className="flex h-full w-full items-center justify-center">
<Head> <Head>
<title>Set Up Vercel Integration</title> <title>Set Up Vercel Integration</title>
<link rel='icon' href='/infisical.ico' /> <link rel="icon" href="/infisical.ico" />
</Head> </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"> {isIntegrationAuthAppsLoading ? (
<FontAwesomeIcon icon={faBugs} className="text-6xl my-2 inlineli"/> <img
<p> src="/images/loading/loading.gif"
Something went wrong. Please contact <a height={70}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" width={120}
target="_blank" alt="infisical loading indicator"
rel="noopener noreferrer" />
href="mailto:[email protected]" ) : (
> <div className="flex h-max max-w-md flex-col rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6 text-center text-mineshaft-200">
support@infisical.com <FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
</a> if the issue persists. <p>
</p> Something went wrong. Please contact{" "}
</div>} <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank"
rel="noopener noreferrer"
href="mailto:[email protected]"
>
support@infisical.com
</a>{" "}
if the issue persists.
</p>
</div>
)}
</div> </div>
); );
} }
@@ -2,9 +2,7 @@ import { useEffect } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useAuthorizeIntegration } from "@app/hooks/api";
useAuthorizeIntegration
} from "@app/hooks/api";
export default function VercelOAuth2CallbackPage() { export default function VercelOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -1,13 +1,10 @@
import { useState } from "react"; import { useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { import { useSaveIntegrationAccessToken } from "@app/hooks/api";
useSaveIntegrationAccessToken
} from "@app/hooks/api";
import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2"; import { Button, Card, CardTitle, FormControl, Input } from "../../../components/v2";
export default function WindmillCreateIntegrationPage() { export default function WindmillCreateIntegrationPage() {
const router = useRouter(); const router = useRouter();
const { mutateAsync } = useSaveIntegrationAccessToken(); const { mutateAsync } = useSaveIntegrationAccessToken();
@@ -41,27 +38,27 @@ export default function WindmillCreateIntegrationPage() {
}; };
return ( return (
<div className="flex h-full w-full items-center justify-center"> <div className="flex h-full w-full items-center justify-center">
<Card className="max-w-md rounded-md p-8"> <Card className="max-w-md rounded-md p-8">
<CardTitle className="text-center">Windmill Integration</CardTitle> <CardTitle className="text-center">Windmill Integration</CardTitle>
<FormControl <FormControl
label="Windmill Access Token" label="Windmill Access Token"
errorText={apiKeyErrorText} errorText={apiKeyErrorText}
isError={apiKeyErrorText !== "" ?? false} isError={apiKeyErrorText !== "" ?? false}
> >
<Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} /> <Input placeholder="" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" color="mineshaft"
className="mt-4" className="mt-4"
isLoading={isLoading} isLoading={isLoading}
> >
Connect to Windmill Connect to Windmill
</Button> </Button>
</Card> </Card>
</div> </div>
); );
} }
WindmillCreateIntegrationPage.requireAuth = true; WindmillCreateIntegrationPage.requireAuth = true;
@@ -2,9 +2,7 @@ import { useEffect, useState } from "react";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import queryString from "query-string"; import queryString from "query-string";
import { import { useCreateIntegration } from "@app/hooks/api";
useCreateIntegration
} from "@app/hooks/api";
import { import {
Button, Button,
@@ -65,7 +63,9 @@ export default function WindmillCreateIntegrationPage() {
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?.id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: integrationAuthApps?.find((integrationAuthApp) => integrationAuthApp.name === targetApp)?.appId, appId: integrationAuthApps?.find(
(integrationAuthApp) => integrationAuthApp.name === targetApp
)?.appId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath secretPath
}); });
@@ -68,7 +68,7 @@ import { usePopUp } from "@app/hooks/usePopUp";
const features = [ const features = [
{ {
_id: 0, id: 0,
name: "Kubernetes Operator", name: "Kubernetes Operator",
link: "https://infisical.com/docs/documentation/getting-started/kubernetes", link: "https://infisical.com/docs/documentation/getting-started/kubernetes",
description: description:
@@ -519,7 +519,7 @@ const OrganizationPage = withPermission(
try { try {
const { const {
data: { data: {
workspace: { _id: newWorkspaceId } workspace: { id: newWorkspaceId }
} }
} = await createWs.mutateAsync({ } = await createWs.mutateAsync({
organizationId: currentOrg, organizationId: currentOrg,
@@ -537,7 +537,7 @@ const OrganizationPage = withPermission(
await uploadWsKey.mutateAsync({ await uploadWsKey.mutateAsync({
encryptedKey: ciphertext, encryptedKey: ciphertext,
nonce, nonce,
userId: user?._id, userId: user?.id,
workspaceId: newWorkspaceId workspaceId: newWorkspaceId
}); });
@@ -553,7 +553,7 @@ const OrganizationPage = withPermission(
.filter( .filter(
({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email ({ status, user: orgUser }) => status === "accepted" && user.email !== orgUser.email
) )
.map(({ user: orgUser, _id: orgMembershipId }) => ({ .map(({ user: orgUser, id: orgMembershipId }) => ({
userPublicKey: orgUser.publicKey, userPublicKey: orgUser.publicKey,
orgMembershipId orgMembershipId
})) }))
@@ -682,7 +682,7 @@ const OrganizationPage = withPermission(
.filter((ws) => ws?.name?.toLowerCase().includes(searchFilter.toLowerCase())) .filter((ws) => ws?.name?.toLowerCase().includes(searchFilter.toLowerCase()))
.map((workspace) => ( .map((workspace) => (
<div <div
key={workspace._id} key={workspace.id}
className="min-w-72 flex h-40 flex-col justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4" className="min-w-72 flex h-40 flex-col justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4"
> >
<div className="mt-0 text-lg text-mineshaft-100">{workspace.name}</div> <div className="mt-0 text-lg text-mineshaft-100">{workspace.name}</div>
@@ -692,8 +692,8 @@ const OrganizationPage = withPermission(
<button <button
type="button" type="button"
onClick={() => { onClick={() => {
router.push(`/project/${workspace._id}/secrets/overview`); router.push(`/project/${workspace.id}/secrets/overview`);
localStorage.setItem("projectData.id", workspace._id); localStorage.setItem("projectData.id", workspace.id);
}} }}
> >
<div className="group ml-auto w-max cursor-pointer rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200"> <div className="group ml-auto w-max cursor-pointer rounded-full border border-mineshaft-600 bg-mineshaft-900 py-2 px-4 text-sm text-mineshaft-300 hover:border-primary-500/80 hover:bg-primary-800/20 hover:text-mineshaft-200">
@@ -782,7 +782,7 @@ const OrganizationPage = withPermission(
icon={faPlus} icon={faPlus}
time="1 min" time="1 min"
userAction="first_time_secrets_pushed" userAction="first_time_secrets_pushed"
link={`/project/${orgWorkspaces[0]?._id}/secrets/overview`} link={`/project/${orgWorkspaces[0]?.id}/secrets/overview`}
/> />
<LearningItemSquare <LearningItemSquare
text="Invite your teammates" text="Invite your teammates"
@@ -63,20 +63,20 @@ const SecretScanning = withPermission(
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" /> <meta property="og:image" content="/images/message.png" />
</Head> </Head>
<div className="flex justify-center bg-bunker-800 text-white w-full h-full"> <div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<div className="max-w-7xl px-6 w-full"> <div className="w-full max-w-7xl px-6">
<div className="mt-6 text-3xl font-semibold text-gray-200">Secret Scanning</div> <div className="mt-6 text-3xl font-semibold text-gray-200">Secret Scanning</div>
<div className="mb-6 text-lg text-mineshaft-300"> <div className="mb-6 text-lg text-mineshaft-300">
Automatically monitor your GitHub activity and prevent secret leaks Automatically monitor your GitHub activity and prevent secret leaks
</div> </div>
<div className="relative flex justify-between bg-mineshaft-800 border border-mineshaft-600 rounded-md p-6 mb-6"> <div className="relative mb-6 flex justify-between rounded-md border border-mineshaft-600 bg-mineshaft-800 p-6">
<div className="flex flex-col items-start"> <div className="flex flex-col items-start">
<div className="flex flex-row mb-1"> <div className="mb-1 flex flex-row">
Secret Scanning Status:{" "} Secret Scanning Status:{" "}
{integrationEnabled ? ( {integrationEnabled ? (
<p className="text-green ml-1.5 font-semibold">Enabled</p> <p className="ml-1.5 font-semibold text-green">Enabled</p>
) : ( ) : (
<p className="text-red ml-1.5 font-semibold">Not enabled</p> <p className="ml-1.5 font-semibold text-red">Not enabled</p>
)} )}
</div> </div>
<div> <div>
@@ -94,12 +94,12 @@ const SecretScanning = withPermission(
</div> </div>
{integrationEnabled ? ( {integrationEnabled ? (
<div> <div>
<div className="absolute right-[2.5rem] top-[2.5rem] animate-ping rounded-full h-6 w-6 bg-green flex items-center justify-center" /> <div className="absolute right-[2.5rem] top-[2.5rem] flex h-6 w-6 animate-ping items-center justify-center rounded-full bg-green" />
<div className="absolute right-[2.63rem] top-[2.63rem] animate-ping rounded-full h-5 w-5 bg-green flex items-center justify-center" /> <div className="absolute right-[2.63rem] top-[2.63rem] flex h-5 w-5 animate-ping items-center justify-center rounded-full bg-green" />
<div className="absolute right-[2.82rem] top-[2.82rem] animate-ping rounded-full h-3.5 w-3.5 bg-green flex items-center justify-center" /> <div className="absolute right-[2.82rem] top-[2.82rem] flex h-3.5 w-3.5 animate-ping items-center justify-center rounded-full bg-green" />
</div> </div>
) : ( ) : (
<div className="flex items-center h-[3.25rem]"> <div className="flex h-[3.25rem] items-center">
<OrgPermissionCan <OrgPermissionCan
I={OrgPermissionActions.Create} I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.SecretScanning} a={OrgPermissionSubjects.SecretScanning}
@@ -109,7 +109,7 @@ const SecretScanning = withPermission(
variant="solid" variant="solid"
colorSchema="primary" colorSchema="primary"
onClick={generateNewIntegrationSession} onClick={generateNewIntegrationSession}
className="py-2 h-min" className="h-min py-2"
isDisabled={!isAllowed} isDisabled={!isAllowed}
> >
Integrate with GitHub Integrate with GitHub
+1 -1
View File
@@ -153,7 +153,7 @@ export default function SignUp() {
}; };
return ( return (
<div className="flex min-h-screen max-h-screen overflow-y-auto flex-col justify-center bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 "> <div className="flex max-h-screen min-h-screen flex-col justify-center overflow-y-auto bg-gradient-to-tr from-mineshaft-600 via-mineshaft-800 to-bunker-700 px-6 pb-28 ">
<Head> <Head>
<title>{t("common.head-title", { title: t("signup.title") })}</title> <title>{t("common.head-title", { title: t("signup.title") })}</title>
<link rel="icon" href="/infisical.ico" /> <link rel="icon" href="/infisical.ico" />
@@ -162,7 +162,8 @@ export const IntegrationsSection = ({
</div> </div>
</div> </div>
)} )}
{((integration.integration === "checkly") || (integration.integration === "github")) && ( {(integration.integration === "checkly" ||
integration.integration === "github") && (
<> <>
{integration.targetService && ( {integration.targetService && (
<div className="ml-2"> <div className="ml-2">
+17 -17
View File
@@ -3,22 +3,22 @@ import { NextRouter } from "next/router";
import { fetchOrganizations } from "@app/hooks/api/organization/queries"; import { fetchOrganizations } from "@app/hooks/api/organization/queries";
export const navigateUserToOrg = async (router: NextRouter, organizationId?: string) => { export const navigateUserToOrg = async (router: NextRouter, organizationId?: string) => {
const userOrgs = await fetchOrganizations(); const userOrgs = await fetchOrganizations();
if (organizationId) { if (organizationId) {
localStorage.setItem("orgData.id", organizationId); localStorage.setItem("orgData.id", organizationId);
router.push(`/org/${organizationId}/overview`); router.push(`/org/${organizationId}/overview`);
return; return;
} }
if (userOrgs.length > 0) { if (userOrgs.length > 0) {
// user is part of at least 1 org // user is part of at least 1 org
const userOrg = userOrgs[0] && userOrgs[0].id; const userOrg = userOrgs[0] && userOrgs[0].id;
localStorage.setItem("orgData.id", userOrg); localStorage.setItem("orgData.id", userOrg);
router.push(`/org/${userOrg}/overview`); router.push(`/org/${userOrg}/overview`);
} else { } else {
// user is not part of any org // user is not part of any org
localStorage.removeItem("orgData.id"); localStorage.removeItem("orgData.id");
router.push("/org/none"); router.push("/org/none");
} }
} };

Some files were not shown because too many files have changed in this diff Show More