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.Title
as='h3'
className='text-xl font-medium leading-6 text-primary'
> >
<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 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,7 +218,8 @@ const ProjectUsersTable = ({ userData, changeData, myUser, filter, isUserListLoa
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{!isUserListLoading && userData?.filter( {!isUserListLoading &&
userData?.filter(
(user) => (user) =>
user.firstName?.toLowerCase().includes(filter) || user.firstName?.toLowerCase().includes(filter) ||
user.lastName?.toLowerCase().includes(filter) || user.lastName?.toLowerCase().includes(filter) ||
@@ -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) => {
return (
<Menu.Item key={tag.id}> <Menu.Item key={tag.id}>
<button <button
type="button" type="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`} className={`${
onClick={() => {if (!currentTags?.map(currentTag => currentTag.name).includes(tag.name)) {modifyTags(currentTags.concat([tag]), id)}}} currentTags?.map((currentTag) => currentTag.name).includes(tag.name)
? "cursor-default opacity-30"
: "hover:bg-mineshaft-700"
} 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="text-xs mr-2 text-primary"/> : <FontAwesomeIcon icon={faSquare} className="text-xs mr-2"/>} {tag.name} {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> </button>
</Menu.Item> </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>
+90 -48
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,27 +87,31 @@ const KeyPair = ({
togglePITSidebar, togglePITSidebar,
tags tags
}: KeyPairProps) => { }: KeyPairProps) => {
const tagData = (tags.map((tag, index) => {return { const tagData = tags.map((tag, index) => {
return {
...tag, ...tag,
color: colors[index%colors.length], color: colors[index % colors.length],
colorText: colorsText[index%colorsText.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}
</div>
<div className="flex max-h-16 w-full items-center">
<DashboardInputField <DashboardInputField
isCapitalized = {isCapitalized} isCapitalized={isCapitalized}
onChangeHandler={modifyKey} onChangeHandler={modifyKey}
type="varName" type="varName"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
value={keyPair.key} value={keyPair.key}
isDuplicate={isDuplicate} isDuplicate={isDuplicate}
overrideEnabled={keyPair.valueOverride !== undefined} overrideEnabled={keyPair.valueOverride !== undefined}
@@ -118,13 +121,13 @@ const KeyPair = ({
</div> </div>
</div> </div>
<div className="w-5/12 border-r border-mineshaft-600"> <div className="w-5/12 border-r border-mineshaft-600">
<div <div className="mt-4 flex max-h-10 items-center rounded-lg md:mt-0">
className='flex items-center rounded-lg mt-4 md:mt-0 max-h-10'
>
<DashboardInputField <DashboardInputField
onChangeHandler={keyPair.valueOverride !== undefined ? modifyValueOverride : modifyValue} onChangeHandler={
keyPair.valueOverride !== undefined ? modifyValueOverride : modifyValue
}
type="value" type="value"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
value={keyPair.valueOverride !== undefined ? keyPair.valueOverride : keyPair.value} value={keyPair.valueOverride !== undefined ? keyPair.valueOverride : keyPair.value}
blurred={isBlurred} blurred={isBlurred}
overrideEnabled={keyPair.valueOverride !== undefined} overrideEnabled={keyPair.valueOverride !== undefined}
@@ -133,28 +136,52 @@ const KeyPair = ({
</div> </div>
</div> </div>
<div className="w-[calc(10%)] border-r border-mineshaft-600"> <div className="w-[calc(10%)] border-r border-mineshaft-600">
<div className="flex items-center max-h-16"> <div className="flex max-h-16 items-center">
<DashboardInputField <DashboardInputField
onChangeHandler={modifyComment} onChangeHandler={modifyComment}
type="comment" type="comment"
id={keyPair.id ? keyPair.id : (keyPair.idOverride || "")} id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
value={keyPair.comment} value={keyPair.comment}
isDuplicate={isDuplicate} isDuplicate={isDuplicate}
isSideBarOpen={keyPair.id === sidebarSecretId} isSideBarOpen={keyPair.id === sidebarSecretId}
/> />
</div> </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> </div>
))} <div className="overflow-r-scroll no-scrollbar::-webkit-scrollbar flex h-10 w-2/12 items-center overflow-visible no-scrollbar">
<div className="flex max-h-16 items-center">
{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
</div> allTags={tags}
currentTags={keyPair.tags}
modifyTags={modifyTags}
id={keyPair.id ? keyPair.id : keyPair.idOverride || ""}
/>
</div> </div>
<div <div
onKeyDown={() => null} onKeyDown={() => null}
@@ -164,36 +191,51 @@ const KeyPair = ({
if (togglePITSidebar) { if (togglePITSidebar) {
togglePITSidebar(false); togglePITSidebar(false);
} }
toggleSidebar(keyPair.id) 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"}`} 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-primary text-lg" icon={faEllipsis} /> <FontAwesomeIcon
className="text-lg text-bunker-300 hover:text-primary"
icon={faEllipsis}
/>
</div> </div>
<div className={`group-hover:bg-mineshaft-700 z-50 ${isSnapshot ?? "invisible"}`}> <div className={`z-50 group-hover:bg-mineshaft-700 ${isSnapshot ?? "invisible"}`}>
{keyPair.key || keyPair.value {keyPair.key || keyPair.value ? (
? <DeleteActionButton <DeleteActionButton
onSubmit={() => { if (deleteRow) { onSubmit={() => {
deleteRow({ ids: [keyPair.id], secretName: keyPair?.key }) if (deleteRow) {
}}} deleteRow({ ids: [keyPair.id], secretName: keyPair?.key });
}
}}
isPlain isPlain
/> />
: <div className='cursor-pointer w-[1.5rem] h-[2.35rem] mr-2 flex items-center justfy-center'> ) : (
<div className="justfy-center mr-2 flex h-[2.35rem] w-[1.5rem] cursor-pointer items-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 (deleteRow) {
}}} deleteRow({ ids: [keyPair.id], secretName: keyPair?.key });
}
}}
className="invisible group-hover:visible" className="invisible group-hover:visible"
> >
<FontAwesomeIcon className="text-bunker-300 hover:text-red pl-2 pr-6 text-lg mt-0.5" icon={faXmark} /> <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,
+5 -5
View File
@@ -6,22 +6,22 @@ export type APIKeyDataV2 = {
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[];
+8 -9
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;
} };
+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");
@@ -171,7 +169,7 @@ export const Navbar = () => {
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 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"> <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="px-1 py-1">
<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.signed-in-as")} {t("nav.user.signed-in-as")}
@@ -318,7 +316,7 @@ export const Navbar = () => {
</div> </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;
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,10 +52,12 @@ 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 } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
const { data: integrationAuthGroups, isLoading: isintegrationAuthGroupsLoading } = useGetIntegrationAuthChecklyGroups({ const { data: integrationAuthGroups, isLoading: isintegrationAuthGroupsLoading } =
useGetIntegrationAuthChecklyGroups({
integrationAuthId: (integrationAuthId as string) ?? "", integrationAuthId: (integrationAuthId as string) ?? "",
accountId: targetAppId accountId: targetAppId
}); });
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,8 +36,11 @@ 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) ?? ""
);
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,29 +1,28 @@
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 [accountIdErrorText, setAccountIdErrorText] = useState("");
const [isLoading, setIsLoading] = useState(false); 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!");
if (accountId.length === 0) setAccountIdErrorText("Account ID cannot be blank!");
return; return;
} }
@@ -31,62 +30,73 @@ export default function CloudflarePagesIntegrationPage() {
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("");
setAccountId("");
setIsLoading(false); 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 <div className="flex flex-row items-center">
placeholder="" <div className="inline flex items-center pb-0.5">
value={accessKey} <Image
onChange={(e) => setAccessKey(e.target.value)} src="/images/integrations/Render.png"
height={30}
width={30}
alt="Render logo"
/> />
</FormControl> </div>
<span className="ml-2.5">Render Integration </span>
<Link href="https://infisical.com/docs/integrations/cloud/render" passHref>
<a target="_blank" rel="noopener noreferrer">
<div className="ml-2 mb-1 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" />
Docs
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="ml-1.5 mb-[0.07rem] text-xxs"
/>
</div>
</a>
</Link>
</div>
</CardTitle>
<FormControl <FormControl
label="Cloudflare Pages Account ID" label="Render API Key"
errorText={accountIdErrorText} errorText={apiKeyErrorText}
isError={accountIdErrorText !== "" ?? false} isError={apiKeyErrorText !== "" ?? false}
className="mx-6" className="px-6"
> >
<Input <Input placeholder="rnd_xxx" value={apiKey} onChange={(e) => setApiKey(e.target.value)} />
placeholder=""
value={accountId}
onChange={(e) => setAccountId(e.target.value)}
/>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
color="mineshaft" colorSchema="primary"
variant="outline_bg" variant="outline_bg"
className="mb-6 mt-2 ml-auto mr-6 w-min" className="mb-6 mt-2 ml-auto mr-6 w-min"
isFullWidth={false}
isLoading={isLoading} isLoading={isLoading}
> >
Connect to Cloudflare Pages Connect to Render
</Button> </Button>
</Card> </Card>
</div> </div>
); );
} }
CloudflarePagesIntegrationPage.requireAuth = true; RenderCreateIntegrationPage.requireAuth = true;
@@ -1,13 +1,14 @@
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" },
@@ -64,16 +65,16 @@ export default function CloudflarePagesIntegrationPage() {
appId: targetAppId, appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
targetEnvironment, targetEnvironment,
secretPath: "/", secretPath: "/"
}); });
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/${localStorage.getItem("projectData.id")}`); router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
} catch(err) { } catch (err) {
console.error(err); console.error(err);
} }
} };
return integrationAuth && return integrationAuth &&
workspace && workspace &&
@@ -82,8 +83,13 @@ export default function CloudflarePagesIntegrationPage() {
targetEnvironment && targetEnvironment &&
targetApp ? ( targetApp ? (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900"> <div className="flex 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 p-0 border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<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> <CardTitle
className="px-6 text-left"
subTitle="Choose which environment in Infisical you want to sync with your Cloudflare Pages project."
>
Cloudflare Pages Integration
</CardTitle>
<FormControl label="Infisical Project Environment" className="mt-2 px-6"> <FormControl label="Infisical Project Environment" className="mt-2 px-6">
<Select <Select
value={selectedSourceEnvironment} value={selectedSourceEnvironment}
@@ -1,11 +1,9 @@
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();
@@ -40,27 +38,30 @@ export default function CloudflareWorkersIntegrationPage() {
setAccountId(""); setAccountId("");
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/cloudflare-workers/create?integrationAuthId=${integrationAuth.id}`); router.push(
`/integrations/cloudflare-workers/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"> <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
className="px-6 text-left"
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>
<FormControl <FormControl
label="Cloudflare Workers API token" label="Cloudflare Workers API token"
errorText={accessKeyErrorText} errorText={accessKeyErrorText}
isError={accessKeyErrorText !== "" ?? false} isError={accessKeyErrorText !== "" ?? false}
className="mx-6" className="mx-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="Cloudflare Workers Account ID" label="Cloudflare Workers Account ID"
@@ -68,11 +69,7 @@ export default function CloudflareWorkersIntegrationPage() {
isError={accountIdErrorText !== "" ?? false} isError={accountIdErrorText !== "" ?? false}
className="mx-6" className="mx-6"
> >
<Input <Input placeholder="" value={accountId} onChange={(e) => setAccountId(e.target.value)} />
placeholder=""
value={accountId}
onChange={(e) => setAccountId(e.target.value)}
/>
</FormControl> </FormControl>
<Button <Button
onClick={handleButtonClick} onClick={handleButtonClick}
@@ -1,13 +1,14 @@
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();
@@ -45,26 +46,26 @@ export default function CloudflareWorkersIntegrationPage() {
const handleButtonClick = async () => { const handleButtonClick = async () => {
try { try {
if (!integrationAuth?.id) return; if (!integrationAuth?._id) return;
setIsLoading(true); setIsLoading(true);
await mutateAsync({ await mutateAsync({
integrationAuthId: integrationAuth?.id, integrationAuthId: integrationAuth?._id,
isActive: true, isActive: true,
app: targetApp, app: targetApp,
appId: targetAppId, appId: targetAppId,
sourceEnvironment: selectedSourceEnvironment, sourceEnvironment: selectedSourceEnvironment,
secretPath: "/", secretPath: "/"
}); });
setIsLoading(false); setIsLoading(false);
router.push(`/integrations/${localStorage.getItem("projectData.id")}`); router.push(`/integrations/${localStorage.getItem("projectData.id")}`);
} catch(err) { } catch (err) {
console.error(err); console.error(err);
} }
} };
return integrationAuth && return integrationAuth &&
workspace && workspace &&
@@ -72,8 +73,13 @@ export default function CloudflareWorkersIntegrationPage() {
integrationAuthApps && integrationAuthApps &&
targetApp ? ( targetApp ? (
<div className="flex h-full w-full items-center justify-center bg-gradient-to-tr from-mineshaft-900 to-bunker-900"> <div className="flex 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 p-0 border border-mineshaft-600"> <Card className="max-w-lg rounded-md border border-mineshaft-600 p-0">
<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> <CardTitle
className="px-6 text-left"
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"> <FormControl label="Infisical Project Environment" className="mt-2 px-6">
<Select <Select
value={selectedSourceEnvironment} value={selectedSourceEnvironment}
@@ -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,8 +37,11 @@ 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) ?? ""
);
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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>
@@ -111,20 +111,17 @@ export default function GCPSecretManagerAuthorizeIntegrationPage() {
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,7 +81,8 @@ 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 } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
@@ -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: { secretGCPLabel: {
labelName, labelName,
labelValue 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>
@@ -259,10 +258,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="/" />
{...field}
placeholder="/"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -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>
@@ -322,10 +318,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="INFISICAL_" />
{...field}
placeholder="INFISICAL_"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -338,10 +331,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="_INFISICAL" />
{...field}
placeholder="_INFISICAL"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -371,10 +361,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="managed-by" />
{...field}
placeholder="managed-by"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -387,10 +374,7 @@ export default function GCPSecretManagerCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="infisical" />
{...field}
placeholder="infisical"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -444,34 +428,44 @@ export default function GCPSecretManagerCreateIntegrationPage() {
</div> </div>
} }
> >
<p> <p>You&apos;re about to overwrite any existing secrets in GCP Secret Manager.</p>
You&apos;re about to overwrite any existing secrets in GCP Secret Manager.
</p>
<p className="mt-4"> <p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix or enabling labeling in the options tab. To avoid this behavior, you may consider adding a secret prefix/suffix or enabling
labeling in the options tab.
</p> </p>
</ModalContent> </ModalContent>
</Modal> </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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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 GCPSecretManagerOAuth2CallbackPage() { export default function GCPSecretManagerOAuth2CallbackPage() {
const router = useRouter(); const router = useRouter();
@@ -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);
} }
@@ -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,7 +53,8 @@ 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 } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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>
)} )}
/> />
@@ -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,12 +68,7 @@ export default function GitLabCreateIntegrationPage() {
"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: {
targetEntity: "individual", targetEntity: "individual",
@@ -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>
@@ -268,10 +268,7 @@ export default function GitLabCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="/" />
{...field}
placeholder="/"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -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,7 +357,8 @@ export default function GitLabCreateIntegrationPage() {
)} )}
</Select> </Select>
</FormControl> </FormControl>
)}} );
}}
/> />
<Controller <Controller
control={control} control={control}
@@ -381,10 +370,7 @@ export default function GitLabCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="*" />
{...field}
placeholder="*"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -408,10 +394,7 @@ export default function GitLabCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="INFISICAL_" />
{...field}
placeholder="INFISICAL_"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -424,10 +407,7 @@ export default function GitLabCreateIntegrationPage() {
isError={Boolean(error)} isError={Boolean(error)}
errorText={error?.message} errorText={error?.message}
> >
<Input <Input {...field} placeholder="_INFISICAL" />
{...field}
placeholder="_INFISICAL"
/>
</FormControl> </FormControl>
)} )}
/> />
@@ -472,34 +452,44 @@ export default function GitLabCreateIntegrationPage() {
</div> </div>
} }
> >
<p> <p>You&apos;re about to overwrite any existing secrets in GitLab.</p>
You&apos;re about to overwrite any existing secrets in GitLab.
</p>
<p className="mt-4"> <p className="mt-4">
To avoid this behavior, you may consider adding a secret prefix/suffix in the options tab. To avoid this behavior, you may consider adding a secret prefix/suffix in the options
tab.
</p> </p>
</ModalContent> </ModalContent>
</Modal> </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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,7 +22,9 @@ 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
}) })
}); });
@@ -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";
@@ -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>
@@ -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"
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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>
@@ -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,10 +84,11 @@ export default function QoveryCreateIntegrationPage() {
}); });
const [targetEnvironmentId, setTargetEnvironmentId] = useState(""); const [targetEnvironmentId, setTargetEnvironmentId] = useState("");
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } = useGetIntegrationAuthQoveryScopes({ const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthQoveryScopes({
integrationAuthId: (integrationAuthId as string) ?? "", integrationAuthId: (integrationAuthId as string) ?? "",
environmentId: targetEnvironmentId, environmentId: targetEnvironmentId,
scope: (scope as ("job" | "application" | "container")) scope: scope as "job" | "application" | "container"
}); });
const [targetAppId, setTargetAppId] = useState(""); const [targetAppId, setTargetAppId] = useState("");
@@ -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,16 +273,14 @@ 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 && (
<FormControl label="Qovery Organization">
<Select <Select
value={targetOrgId} value={targetOrgId}
onValueChange={(val) => setTargetOrgId(val)} onValueChange={(val) => setTargetOrgId(val)}
@@ -293,8 +302,10 @@ export default function QoveryCreateIntegrationPage() {
</SelectItem> </SelectItem>
)} )}
</Select> </Select>
</FormControl>} </FormControl>
{integrationAuthProjects && <FormControl label="Qovery Project"> )}
{integrationAuthProjects && (
<FormControl label="Qovery Project">
<Select <Select
value={targetProjectId} value={targetProjectId}
onValueChange={(val) => setTargetProjectId(val)} onValueChange={(val) => setTargetProjectId(val)}
@@ -316,8 +327,10 @@ export default function QoveryCreateIntegrationPage() {
</SelectItem> </SelectItem>
)} )}
</Select> </Select>
</FormControl>} </FormControl>
{integrationAuthEnvironments && <FormControl label="Qovery Environment"> )}
{integrationAuthEnvironments && (
<FormControl label="Qovery Environment">
<Select <Select
value={targetEnvironmentId} value={targetEnvironmentId}
onValueChange={(val) => setTargetEnvironmentId(val)} onValueChange={(val) => setTargetEnvironmentId(val)}
@@ -339,8 +352,10 @@ export default function QoveryCreateIntegrationPage() {
</SelectItem> </SelectItem>
)} )}
</Select> </Select>
</FormControl>} </FormControl>
{(scope && integrationAuthApps) && <FormControl label={`Qovery ${scope.charAt(0).toUpperCase() + scope.slice(1)}`}> )}
{scope && integrationAuthApps && (
<FormControl label={`Qovery ${scope.charAt(0).toUpperCase() + scope.slice(1)}`}>
<Select <Select
value={targetAppId} value={targetAppId}
onValueChange={(val) => setTargetAppId(val)} onValueChange={(val) => setTargetAppId(val)}
@@ -350,7 +365,7 @@ export default function QoveryCreateIntegrationPage() {
{integrationAuthApps.length > 0 ? ( {integrationAuthApps.length > 0 ? (
integrationAuthApps.map((integrationAuthApp) => ( integrationAuthApps.map((integrationAuthApp) => (
<SelectItem <SelectItem
value={(integrationAuthApp.appId as string)} value={integrationAuthApp.appId as string}
key={`target-app-${integrationAuthApp.appId}`} key={`target-app-${integrationAuthApp.appId}`}
> >
{integrationAuthApp.name} {integrationAuthApp.name}
@@ -362,7 +377,8 @@ export default function QoveryCreateIntegrationPage() {
</SelectItem> </SelectItem>
)} )}
</Select> </Select>
</FormControl>} </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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,8 +36,11 @@ 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) ?? ""
);
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
integrationAuthId: (integrationAuthId as string) ?? "" integrationAuthId: (integrationAuthId as string) ?? ""
}); });
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,8 +38,11 @@ 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) ?? ""
);
const { data: integrationAuthApps, isLoading: isIntegrationAuthAppsLoading } =
useGetIntegrationAuthApps({
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>
@@ -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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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,8 +62,8 @@ 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;
} }
@@ -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
value={variable.name}
key={`target-app-${variable.name}`}
>
{variable.name} {variable.name}
</SelectItem> </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,7 +50,8 @@ 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 } =
useGetIntegrationAuthApps({
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
src="/images/loading/loading.gif"
height={70}
width={120}
alt="infisical loading indicator"
/>
) : (
<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">
<FontAwesomeIcon icon={faBugs} className="inlineli my-2 text-6xl" />
<p> <p>
Something went wrong. Please contact <a Something went wrong. Please contact{" "}
className="inline underline underline-offset-4 decoration-primary-500 opacity-80 hover:opacity-100 text-mineshaft-100 duration-200 cursor-pointer" <a
className="inline cursor-pointer text-mineshaft-100 underline decoration-primary-500 underline-offset-4 opacity-80 duration-200 hover:opacity-100"
target="_blank" target="_blank"
rel="noopener noreferrer" rel="noopener noreferrer"
href="mailto:[email protected]" href="mailto:[email protected]"
> >
support@infisical.com support@infisical.com
</a> if the issue persists. </a>{" "}
if the issue persists.
</p> </p>
</div>} </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();
@@ -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">
+1 -1
View File
@@ -21,4 +21,4 @@ export const navigateUserToOrg = async (router: NextRouter, organizationId?: str
localStorage.removeItem("orgData.id"); localStorage.removeItem("orgData.id");
router.push("/org/none"); router.push("/org/none");
} }
} };
@@ -3,11 +3,7 @@ import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context"; import { OrgPermissionActions, OrgPermissionSubjects } from "@app/context";
import { withPermission } from "@app/hoc"; import { withPermission } from "@app/hoc";
import { import { OrgIdentityTab, OrgMembersTab, OrgRoleTabSection } from "./components";
OrgIdentityTab,
OrgMembersTab,
OrgRoleTabSection
} from "./components";
enum TabSections { enum TabSections {
Member = "members", Member = "members",
@@ -19,17 +15,15 @@ export const MembersPage = withPermission(
() => { () => {
return ( return (
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white"> <div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
<div className="mb-6 w-full py-6 px-6 max-w-7xl mx-auto"> <div className="mx-auto mb-6 w-full max-w-7xl py-6 px-6">
<p className="mr-4 mb-4 text-3xl font-semibold text-white"> <p className="mr-4 mb-4 text-3xl font-semibold text-white">Organization Access Control</p>
Organization Access Control
</p>
<Tabs defaultValue={TabSections.Member}> <Tabs defaultValue={TabSections.Member}>
<TabList> <TabList>
<Tab value={TabSections.Member}>People</Tab> <Tab value={TabSections.Member}>People</Tab>
<Tab value={TabSections.Identities}> <Tab value={TabSections.Identities}>
<div className="flex items-center"> <div className="flex items-center">
<p>Machine Identities</p> <p>Machine Identities</p>
<div className="ml-2 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 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">
New New
</div> </div>
</div> </div>
@@ -0,0 +1,577 @@
import { useCallback, useEffect, useMemo, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { useRouter } from "next/router";
import {
faCheck,
faCopy,
faMagnifyingGlass,
faPlus,
faTrash,
faUsers
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import { OrgPermissionCan } from "@app/components/permissions";
import {
decryptAssymmetric,
encryptAssymmetric
} from "@app/components/utilities/cryptography/crypto";
import {
Button,
DeleteActionModal,
EmailServiceSetupModal,
EmptyState,
FormControl,
IconButton,
Input,
Modal,
ModalContent,
Select,
SelectItem,
Table,
TableContainer,
TableSkeleton,
Tag,
TBody,
Td,
Th,
THead,
Tr,
UpgradePlanModal
} from "@app/components/v2";
import {
OrgPermissionActions,
OrgPermissionSubjects,
useOrganization,
useSubscription,
useUser,
useWorkspace
} from "@app/context";
import { usePopUp, useToggle } from "@app/hooks";
import {
useAddUserToOrg,
useDeleteOrgMembership,
useGetOrgUsers,
useGetSSOConfig,
useGetUserWorkspaceMemberships,
useGetUserWsKey,
useUpdateOrgUserRole,
useUploadWsKey
} from "@app/hooks/api";
import { TRole } from "@app/hooks/api/roles/types";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
type Props = {
roles?: TRole<undefined>[];
isRolesLoading?: boolean;
};
const addMemberFormSchema = yup.object({
email: yup.string().email().required().label("Email").trim().lowercase()
});
type TAddMemberForm = yup.InferType<typeof addMemberFormSchema>;
export const OrgMembersTable = ({ roles = [], isRolesLoading }: Props) => {
const router = useRouter();
const { createNotification } = useNotificationContext();
const { currentOrg } = useOrganization();
const { workspaces, currentWorkspace } = useWorkspace();
const { user } = useUser();
const userId = user?.id || "";
const orgId = currentOrg?.id || "";
const workspaceId = currentWorkspace?.id || "";
const { data: ssoConfig, isLoading: isLoadingSSOConfig } = useGetSSOConfig(orgId);
const [searchMemberFilter, setSearchMemberFilter] = useState("");
const { data: serverDetails } = useFetchServerStatus();
const [isInviteLinkCopied, setInviteLinkCopied] = useToggle(false);
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
"addMember",
"removeMember",
"upgradePlan",
"setUpEmail"
] as const);
const { subscription } = useSubscription();
const { data: members, isLoading: isMembersLoading } = useGetOrgUsers(orgId);
const { data: workspaceMemberships, isLoading: IsWsMembershipLoading } =
useGetUserWorkspaceMemberships(orgId);
const { data: wsKey } = useGetUserWsKey(workspaceId);
const removeUserOrgMembership = useDeleteOrgMembership();
const addUserToOrg = useAddUserToOrg();
const updateOrgUserRole = useUpdateOrgUserRole();
const uploadWsKey = useUploadWsKey();
const [completeInviteLink, setCompleteInviteLink] = useState<string | undefined>("");
const isMoreUsersNotAllowed = subscription?.memberLimit
? subscription.membersUsed >= subscription.memberLimit
: false;
useEffect(() => {
if (router.query.action === "invite") {
handlePopUpOpen("addMember");
}
}, []);
const {
control,
handleSubmit,
reset,
formState: { isSubmitting }
} = useForm<TAddMemberForm>({ resolver: yupResolver(addMemberFormSchema) });
const onAddMember = async ({ email }: TAddMemberForm) => {
if (!currentOrg?.id) return;
try {
const { data } = await addUserToOrg.mutateAsync({
organizationId: currentOrg?.id,
inviteeEmail: email
});
setCompleteInviteLink(data?.completeInviteLink);
// only show this notification when email is configured.
// A [completeInviteLink] will not be sent if smtp is configured
if (!data.completeInviteLink) {
createNotification({
text: "Successfully invited user to the organization.",
type: "success"
});
}
} catch (error) {
console.error(error);
createNotification({
text: "Failed to invite user to org",
type: "error"
});
}
if (serverDetails?.emailConfigured) {
handlePopUpClose("addMember");
}
reset();
};
const onAddUserToOrg = async (email: string) => {
if (!currentOrg?.id) return;
try {
const { data } = await addUserToOrg.mutateAsync({
organizationId: currentOrg?.id,
inviteeEmail: email
});
setCompleteInviteLink(data?.completeInviteLink);
// only show this notification when email is configured. A [completeInviteLink] will not be sent if smtp is configured
if (!data.completeInviteLink) {
createNotification({
text: "Successfully invited user to the organization.",
type: "success"
});
}
} catch (error) {
console.error(error);
createNotification({
text: "Failed to invite user to org",
type: "error"
});
}
};
const onRemoveOrgMemberApproved = async () => {
const membershipId = (popUp?.removeMember?.data as { id: string })?.id;
if (!currentOrg?.id) return;
try {
await removeUserOrgMembership.mutateAsync({ orgId: currentOrg?.id, membershipId });
createNotification({
text: "Successfully removed user from org",
type: "success"
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to remove user from the organization",
type: "error"
});
}
handlePopUpClose("removeMember");
};
const isIamOwner = useMemo(
() => members?.find(({ user: u }) => userId === u?.id)?.role === "owner",
[userId, members]
);
const findRoleFromId = useCallback(
(roleId: string) => {
return roles.find(({ id }) => id === roleId);
},
[roles]
);
const filterdUser = useMemo(
() =>
members?.filter(
({ user: u, inviteEmail }) =>
u?.firstName?.toLowerCase().includes(searchMemberFilter) ||
u?.lastName?.toLowerCase().includes(searchMemberFilter) ||
u?.email?.toLowerCase().includes(searchMemberFilter) ||
inviteEmail?.includes(searchMemberFilter)
),
[members, searchMemberFilter]
);
useEffect(() => {
let timer: NodeJS.Timeout;
if (isInviteLinkCopied) {
timer = setTimeout(() => setInviteLinkCopied.off(), 2000);
}
return () => clearTimeout(timer);
}, [isInviteLinkCopied]);
const onRoleChange = async (membershipId: string, role: string) => {
if (!currentOrg?.id) return;
try {
await updateOrgUserRole.mutateAsync({ organizationId: currentOrg?.id, membershipId, role });
createNotification({
text: "Successfully updated user role",
type: "success"
});
} catch (error) {
console.error(error);
createNotification({
text: "Failed to update user role",
type: "error"
});
}
};
const onGrantAccess = async (grantedUserId: string, publicKey: string) => {
try {
const PRIVATE_KEY = localStorage.getItem("PRIVATE_KEY") as string;
if (!PRIVATE_KEY || !wsKey) return;
// assymmetrically decrypt symmetric key with local private key
const key = decryptAssymmetric({
ciphertext: wsKey.encryptedKey,
nonce: wsKey.nonce,
publicKey: wsKey.sender.publicKey,
privateKey: PRIVATE_KEY
});
const { ciphertext, nonce } = encryptAssymmetric({
plaintext: key,
publicKey,
privateKey: PRIVATE_KEY
});
await uploadWsKey.mutateAsync({
userId: grantedUserId,
nonce,
encryptedKey: ciphertext,
workspaceId: currentWorkspace?.id || ""
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to grant access to user",
type: "error"
});
}
};
const copyTokenToClipboard = () => {
navigator.clipboard.writeText(completeInviteLink as string);
setInviteLinkCopied.on();
};
const isLoading = isMembersLoading || IsWsMembershipLoading || isRolesLoading;
return (
<div className="w-full">
<div className="mb-4 flex">
<div className="mr-4 flex-1">
<Input
value={searchMemberFilter}
onChange={(e) => setSearchMemberFilter(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..."
/>
</div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
{(isAllowed) => (
<Button
isDisabled={!isAllowed}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (!isLoadingSSOConfig && ssoConfig && ssoConfig.isActive) {
createNotification({
text: "You cannot invite users when SAML SSO is configured for your organization",
type: "error"
});
return;
}
if (isMoreUsersNotAllowed) {
handlePopUpOpen("upgradePlan");
} else {
handlePopUpOpen("addMember");
}
}}
>
Add Member
</Button>
)}
</OrgPermissionCan>
</div>
<div>
<TableContainer>
<Table>
<THead>
<Tr>
<Th>Name</Th>
<Th>Email</Th>
<Th>Role</Th>
<Th>Projects</Th>
<Th aria-label="actions" />
</Tr>
</THead>
<TBody>
{isLoading && <TableSkeleton columns={5} innerKey="org-members" />}
{!isLoading &&
filterdUser?.map(
({ user: u, inviteEmail, role, customRole, id: orgMembershipId, status }) => {
const name = u ? `${u.firstName} ${u.lastName}` : "-";
const email = u?.email || inviteEmail;
const userWs = workspaceMemberships?.[u?.id];
return (
<Tr key={`org-membership-${orgMembershipId}`} className="w-full">
<Td>{name}</Td>
<Td>{email}</Td>
<Td>
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.Member}
>
{(isAllowed) => (
<>
{status === "accepted" && (
<Select
defaultValue={
role === "custom" ? findRoleFromId(customRole)?.slug : role
}
isDisabled={userId === u?.id || !isAllowed}
className="w-40 bg-mineshaft-600"
dropdownContainerClassName="border border-mineshaft-600 bg-mineshaft-800"
onValueChange={(selectedRole) =>
onRoleChange(orgMembershipId, selectedRole)
}
>
{roles
.filter(({ slug }) =>
slug === "owner" ? isIamOwner || role === "owner" : true
)
.map(({ slug, name: roleName }) => (
<SelectItem value={slug} key={`owner-option-${slug}`}>
{roleName}
</SelectItem>
))}
</Select>
)}
{(status === "invited" || status === "verified") &&
serverDetails?.emailConfigured && (
<Button
isDisabled={!isAllowed}
className="w-40"
colorSchema="primary"
variant="outline_bg"
onClick={() => onAddUserToOrg(email)}
>
Resend Invite
</Button>
)}
{status === "completed" && (
<Button
colorSchema="secondary"
isDisabled={!isAllowed}
onClick={() => onGrantAccess(u?.id, u?.publicKey)}
>
Grant Access
</Button>
)}
</>
)}
</OrgPermissionCan>
</Td>
<Td>
{userWs ? (
userWs?.map(({ name: wsName, id }) => (
<Tag key={`user-${u.id}-workspace-${id}`} className="my-1">
{wsName}
</Tag>
))
) : (
<div className="flex flex-row">
{(status === "invited" || status === "verified") &&
serverDetails?.emailConfigured ? (
<Tag colorSchema="red">
This user hasn&apos;t accepted the invite yet
</Tag>
) : (
<Tag colorSchema="red">
This user isn&apos;t part of any projects yet
</Tag>
)}
{router.query.id !== "undefined" &&
!(
(status === "invited" || status === "verified") &&
serverDetails?.emailConfigured
) && (
<button
type="button"
onClick={() =>
router.push(`/project/${workspaces[0]?.id}/members`)
}
className="w-max cursor-pointer rounded-sm bg-mineshaft px-1.5 py-0.5 text-sm duration-200 hover:bg-primary hover:text-black"
>
<FontAwesomeIcon icon={faPlus} className="mr-1" />
Add to projects
</button>
)}
</div>
)}
</Td>
<Td>
{userId !== u?.id && (
<OrgPermissionCan
I={OrgPermissionActions.Delete}
a={OrgPermissionSubjects.Member}
>
{(isAllowed) => (
<IconButton
ariaLabel="delete"
colorSchema="danger"
isDisabled={userId === u?.id || !isAllowed}
onClick={() =>
handlePopUpOpen("removeMember", { id: orgMembershipId })
}
>
<FontAwesomeIcon icon={faTrash} />
</IconButton>
)}
</OrgPermissionCan>
)}
</Td>
</Tr>
);
}
)}
</TBody>
</Table>
{!isLoading && filterdUser?.length === 0 && (
<EmptyState title="No project members found" icon={faUsers} />
)}
</TableContainer>
</div>
<Modal
isOpen={popUp?.addMember?.isOpen}
onOpenChange={(isOpen) => {
handlePopUpToggle("addMember", isOpen);
setCompleteInviteLink(undefined);
}}
>
<ModalContent
title={`Invite others to ${currentOrg?.name}`}
subTitle={
<div>
{!completeInviteLink && (
<div>
An invite is specific to an email address and expires after 1 day.
<br />
For security reasons, you will need to separately add members to projects.
</div>
)}
{completeInviteLink &&
"This Infisical instance does not have a email provider setup. Please share this invite link with the invitee manually"}
</div>
}
>
{!completeInviteLink && (
<form onSubmit={handleSubmit(onAddMember)}>
<Controller
control={control}
defaultValue=""
name="email"
render={({ field, fieldState: { error } }) => (
<FormControl label="Email" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} />
</FormControl>
)}
/>
<div className="mt-8 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
Add Member
</Button>
<Button
colorSchema="secondary"
variant="plain"
onClick={() => handlePopUpClose("addMember")}
>
Cancel
</Button>
</div>
</form>
)}
{completeInviteLink && (
<div className="mt-2 mb-3 mr-2 flex items-center justify-end rounded-md bg-white/[0.07] p-2 text-base text-gray-400">
<p className="mr-4 break-all">{completeInviteLink}</p>
<IconButton
ariaLabel="copy icon"
colorSchema="secondary"
className="group relative"
onClick={copyTokenToClipboard}
>
<FontAwesomeIcon icon={isInviteLinkCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
click to copy
</span>
</IconButton>
</div>
)}
</ModalContent>
</Modal>
<DeleteActionModal
isOpen={popUp.removeMember.isOpen}
deleteKey="remove"
title="Do you want to remove this user from the org?"
onChange={(isOpen) => handlePopUpToggle("removeMember", isOpen)}
onDeleteApproved={onRemoveOrgMemberApproved}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can add custom environments if you switch to Infisical's Team plan."
/>
<EmailServiceSetupModal
isOpen={popUp.setUpEmail?.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("setUpEmail", isOpen)}
/>
</div>
);
};

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