mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 10:28:22 +00:00
feat(#31): added multi env support in integration
This commit is contained in:
@@ -34,12 +34,24 @@ interface IntegrationApp {
|
|||||||
siteId: string;
|
siteId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Integration = ({
|
type Props = {
|
||||||
integration
|
|
||||||
}: {
|
|
||||||
integration: Integration;
|
integration: Integration;
|
||||||
}) => {
|
environments: Array<{ name: string; slug: string }>;
|
||||||
const [integrationEnvironment, setIntegrationEnvironment] = useState(integration.environment);
|
};
|
||||||
|
|
||||||
|
const Integration = ({
|
||||||
|
integration,
|
||||||
|
environments = []
|
||||||
|
}:Props ) => {
|
||||||
|
// set initial environment. This find will only execute when component is mounting
|
||||||
|
const [integrationEnvironment, setIntegrationEnvironment] = useState<
|
||||||
|
Props['environments'][0]
|
||||||
|
>(
|
||||||
|
environments.find(({ slug }) => slug === integration.environment) || {
|
||||||
|
name: '',
|
||||||
|
slug: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
const [fileState, setFileState] = useState([]);
|
const [fileState, setFileState] = useState([]);
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
|
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
|
||||||
@@ -132,42 +144,47 @@ const Integration = ({
|
|||||||
if (!integrationApp || apps.length === 0) return <div></div>
|
if (!integrationApp || apps.length === 0) return <div></div>
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="max-w-5xl p-6 mx-6 mb-8 rounded-md bg-white/5 flex justify-between">
|
<div className='max-w-5xl p-6 mx-6 mb-8 rounded-md bg-white/5 flex justify-between'>
|
||||||
<div className="flex">
|
<div className='flex'>
|
||||||
<div>
|
<div>
|
||||||
<p className="text-gray-400 text-xs font-semibold mb-2">ENVIRONMENT</p>
|
<p className='text-gray-400 text-xs font-semibold mb-2'>
|
||||||
<ListBox data={!integration.isActive ? [
|
ENVIRONMENT
|
||||||
"Development",
|
</p>
|
||||||
"Staging",
|
<ListBox
|
||||||
"Testing",
|
data={
|
||||||
"Production",
|
!integration.isActive
|
||||||
] : null}
|
? environments.map(({ name }) => name)
|
||||||
selected={integrationEnvironment}
|
: null
|
||||||
onChange={(environment) => {
|
}
|
||||||
setIntegrationEnvironment(environment);
|
selected={integrationEnvironment.name}
|
||||||
}}
|
onChange={(envName) =>
|
||||||
|
setIntegrationEnvironment(
|
||||||
|
environments.find(({ name }) => envName === name) || {
|
||||||
|
name: 'unknown',
|
||||||
|
slug: 'unknown',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
isFull={true}
|
isFull={true}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-2">
|
<div className='pt-2'>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faArrowRight}
|
icon={faArrowRight}
|
||||||
className="mx-4 text-gray-400 mt-8"
|
className='mx-4 text-gray-400 mt-8'
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mr-2">
|
<div className='mr-2'>
|
||||||
<p className="text-gray-400 text-xs font-semibold mb-2">
|
<p className='text-gray-400 text-xs font-semibold mb-2'>
|
||||||
INTEGRATION
|
INTEGRATION
|
||||||
</p>
|
</p>
|
||||||
<div className="py-2.5 bg-white/[.07] rounded-md pl-4 pr-10 text-sm font-semibold text-gray-300">
|
<div className='py-2.5 bg-white/[.07] rounded-md pl-4 pr-10 text-sm font-semibold text-gray-300'>
|
||||||
{integration.integration.charAt(0).toUpperCase() +
|
{integration.integration.charAt(0).toUpperCase() +
|
||||||
integration.integration.slice(1)}
|
integration.integration.slice(1)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mr-2">
|
<div className='mr-2'>
|
||||||
<div className="text-gray-400 text-xs font-semibold mb-2">
|
<div className='text-gray-400 text-xs font-semibold mb-2'>APP</div>
|
||||||
APP
|
|
||||||
</div>
|
|
||||||
<ListBox
|
<ListBox
|
||||||
data={!integration.isActive ? apps.map((app) => app.name) : null}
|
data={!integration.isActive ? apps.map((app) => app.name) : null}
|
||||||
selected={integrationApp}
|
selected={integrationApp}
|
||||||
@@ -178,52 +195,55 @@ const Integration = ({
|
|||||||
</div>
|
</div>
|
||||||
{renderIntegrationSpecificParams(integration)}
|
{renderIntegrationSpecificParams(integration)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-end">
|
<div className='flex items-end'>
|
||||||
{integration.isActive ? (
|
{integration.isActive ? (
|
||||||
<div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
|
<div className='max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4'>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faRotate}
|
icon={faRotate}
|
||||||
className="text-lg mr-2.5 text-primary animate-spin"
|
className='text-lg mr-2.5 text-primary animate-spin'
|
||||||
/>
|
|
||||||
<div className="text-gray-300 font-semibold">In Sync</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
text="Start Integration"
|
|
||||||
onButtonPressed={async () => {
|
|
||||||
|
|
||||||
const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined
|
|
||||||
const siteId = siteApp?.siteId ? siteApp.siteId : null;
|
|
||||||
|
|
||||||
await updateIntegration({
|
|
||||||
integrationId: integration._id,
|
|
||||||
environment: integrationEnvironment,
|
|
||||||
app: integrationApp,
|
|
||||||
isActive: true,
|
|
||||||
target: integrationTarget ? integrationTarget.toLowerCase() : null,
|
|
||||||
context: integrationContext ? reverseContextNetlifyMapping[integrationContext] : null,
|
|
||||||
siteId
|
|
||||||
});
|
|
||||||
|
|
||||||
router.reload();
|
|
||||||
}}
|
|
||||||
color="mineshaft"
|
|
||||||
size="md"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<div className="opacity-50 hover:opacity-100 duration-200 ml-2">
|
|
||||||
<Button
|
|
||||||
onButtonPressed={async () => {
|
|
||||||
await deleteIntegration({
|
|
||||||
integrationId: integration._id,
|
|
||||||
});
|
|
||||||
router.reload();
|
|
||||||
}}
|
|
||||||
color="red"
|
|
||||||
size="icon-md"
|
|
||||||
icon={faX}
|
|
||||||
/>
|
/>
|
||||||
|
<div className='text-gray-300 font-semibold'>In Sync</div>
|
||||||
</div>
|
</div>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
text='Start Integration'
|
||||||
|
onButtonPressed={async () => {
|
||||||
|
const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined
|
||||||
|
const siteId = siteApp?.siteId ? siteApp.siteId : null;
|
||||||
|
|
||||||
|
await updateIntegration({
|
||||||
|
integrationId: integration._id,
|
||||||
|
environment: integrationEnvironment.slug,
|
||||||
|
app: integrationApp,
|
||||||
|
isActive: true,
|
||||||
|
target: integrationTarget
|
||||||
|
? integrationTarget.toLowerCase()
|
||||||
|
: null,
|
||||||
|
context: integrationContext
|
||||||
|
? reverseContextNetlifyMapping[integrationContext]
|
||||||
|
: null,
|
||||||
|
siteId,
|
||||||
|
});
|
||||||
|
|
||||||
|
router.reload();
|
||||||
|
}}
|
||||||
|
color='mineshaft'
|
||||||
|
size='md'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<div className='opacity-50 hover:opacity-100 duration-200 ml-2'>
|
||||||
|
<Button
|
||||||
|
onButtonPressed={async () => {
|
||||||
|
await deleteIntegration({
|
||||||
|
integrationId: integration._id,
|
||||||
|
});
|
||||||
|
router.reload();
|
||||||
|
}}
|
||||||
|
color='red'
|
||||||
|
size='icon-md'
|
||||||
|
icon={faX}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ import guidGenerator from "~/utilities/randomId";
|
|||||||
import Integration from "./Integration";
|
import Integration from "./Integration";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
integrations: any
|
integrations: any;
|
||||||
|
environments: Array<{ name: string; slug: string }>;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IntegrationType {
|
interface IntegrationType {
|
||||||
@@ -19,7 +20,8 @@ interface IntegrationType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ProjectIntegrationSection = ({
|
const ProjectIntegrationSection = ({
|
||||||
integrations
|
integrations,
|
||||||
|
environments = [],
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
return integrations.length > 0 ? (
|
return integrations.length > 0 ? (
|
||||||
<div className="mb-12">
|
<div className="mb-12">
|
||||||
@@ -33,6 +35,7 @@ const ProjectIntegrationSection = ({
|
|||||||
<Integration
|
<Integration
|
||||||
key={guidGenerator()}
|
key={guidGenerator()}
|
||||||
integration={integration}
|
integration={integration}
|
||||||
|
environments={environments}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
import SecurityClient from '~/utilities/SecurityClient';
|
||||||
|
|
||||||
|
interface Workspace {
|
||||||
|
__v: number;
|
||||||
|
_id: string;
|
||||||
|
name: string;
|
||||||
|
organization: string;
|
||||||
|
environments: Array<{ name: string; slug: string }>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This route lets us get the workspaces of a certain user
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const getAWorkspace = (workspaceID:string) => {
|
||||||
|
return SecurityClient.fetchCall(`/api/v1/workspace/${workspaceID}`, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
}).then(async (res) => {
|
||||||
|
if (res?.status == 200) {
|
||||||
|
const data = (await res.json()) as unknown as { workspace: Workspace };
|
||||||
|
return data.workspace;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Failed to get workspace');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export default getAWorkspace;
|
||||||
@@ -24,6 +24,7 @@ import setBotActiveStatus from "../api/bot/setBotActiveStatus";
|
|||||||
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
|
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
|
||||||
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
|
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
|
||||||
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
|
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
|
||||||
|
import getAWorkspace from "../api/workspace/getAWorkspace";
|
||||||
import getLatestFileKey from "../api/workspace/getLatestFileKey";
|
import getLatestFileKey from "../api/workspace/getLatestFileKey";
|
||||||
const {
|
const {
|
||||||
decryptAssymmetric,
|
decryptAssymmetric,
|
||||||
@@ -34,6 +35,7 @@ const crypto = require("crypto");
|
|||||||
export default function Integrations() {
|
export default function Integrations() {
|
||||||
const [cloudIntegrationOptions, setCloudIntegrationOptions] = useState([]);
|
const [cloudIntegrationOptions, setCloudIntegrationOptions] = useState([]);
|
||||||
const [integrationAuths, setIntegrationAuths] = useState([]);
|
const [integrationAuths, setIntegrationAuths] = useState([]);
|
||||||
|
const [environments,setEnvironments] = useState([])
|
||||||
const [integrations, setIntegrations] = useState([]);
|
const [integrations, setIntegrations] = useState([]);
|
||||||
const [bot, setBot] = useState(null);
|
const [bot, setBot] = useState(null);
|
||||||
const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false);
|
const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false);
|
||||||
@@ -41,11 +43,15 @@ export default function Integrations() {
|
|||||||
const [selectedIntegrationOption, setSelectedIntegrationOption] = useState(null);
|
const [selectedIntegrationOption, setSelectedIntegrationOption] = useState(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
const workspaceId = router.query.id;
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(async () => {
|
useEffect(async () => {
|
||||||
try {
|
try {
|
||||||
|
const workspace = await getAWorkspace(workspaceId);
|
||||||
|
setEnvironments(workspace.environments);
|
||||||
|
|
||||||
// get cloud integration options
|
// get cloud integration options
|
||||||
setCloudIntegrationOptions(
|
setCloudIntegrationOptions(
|
||||||
await getIntegrationOptions()
|
await getIntegrationOptions()
|
||||||
@@ -54,23 +60,19 @@ export default function Integrations() {
|
|||||||
// get project integration authorizations
|
// get project integration authorizations
|
||||||
setIntegrationAuths(
|
setIntegrationAuths(
|
||||||
await getWorkspaceAuthorizations({
|
await getWorkspaceAuthorizations({
|
||||||
workspaceId: router.query.id,
|
workspaceId
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// get project integrations
|
// get project integrations
|
||||||
setIntegrations(
|
setIntegrations(
|
||||||
await getWorkspaceIntegrations({
|
await getWorkspaceIntegrations({
|
||||||
workspaceId: router.query.id,
|
workspaceId,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
// get project bot
|
// get project bot
|
||||||
setBot(
|
setBot(await getBot({ workspaceId }));
|
||||||
await getBot({
|
|
||||||
workspaceId: router.query.id
|
|
||||||
}
|
|
||||||
));
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@@ -90,7 +92,7 @@ export default function Integrations() {
|
|||||||
|
|
||||||
if (bot) {
|
if (bot) {
|
||||||
// case: there is a bot
|
// case: there is a bot
|
||||||
const key = await getLatestFileKey({ workspaceId: router.query.id });
|
const key = await getLatestFileKey({ workspaceId });
|
||||||
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
|
const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
|
||||||
|
|
||||||
const WORKSPACE_KEY = decryptAssymmetric({
|
const WORKSPACE_KEY = decryptAssymmetric({
|
||||||
@@ -214,7 +216,7 @@ export default function Integrations() {
|
|||||||
handleBotActivate={handleBotActivate}
|
handleBotActivate={handleBotActivate}
|
||||||
handleIntegrationOption={handleIntegrationOption}
|
handleIntegrationOption={handleIntegrationOption}
|
||||||
/> */}
|
/> */}
|
||||||
<IntegrationSection integrations={integrations} />
|
<IntegrationSection integrations={integrations} environments={environments} />
|
||||||
{(cloudIntegrationOptions.length > 0 && bot) ? (
|
{(cloudIntegrationOptions.length > 0 && bot) ? (
|
||||||
<CloudIntegrationSection
|
<CloudIntegrationSection
|
||||||
cloudIntegrationOptions={cloudIntegrationOptions}
|
cloudIntegrationOptions={cloudIntegrationOptions}
|
||||||
|
|||||||
Reference in New Issue
Block a user