feat(#31): added multi env support in integration

This commit is contained in:
akhilmhdh
2023-01-13 21:09:59 +05:30
parent b67abf94d4
commit 036d32aeba
4 changed files with 139 additions and 83 deletions

View File

@@ -34,12 +34,24 @@ interface IntegrationApp {
siteId: string;
}
const Integration = ({
integration
}: {
type Props = {
integration: Integration;
}) => {
const [integrationEnvironment, setIntegrationEnvironment] = useState(integration.environment);
environments: Array<{ name: string; slug: string }>;
};
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 router = useRouter();
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
@@ -132,42 +144,47 @@ const Integration = ({
if (!integrationApp || apps.length === 0) return <div></div>
return (
<div className="max-w-5xl p-6 mx-6 mb-8 rounded-md bg-white/5 flex justify-between">
<div className="flex">
<div className='max-w-5xl p-6 mx-6 mb-8 rounded-md bg-white/5 flex justify-between'>
<div className='flex'>
<div>
<p className="text-gray-400 text-xs font-semibold mb-2">ENVIRONMENT</p>
<ListBox data={!integration.isActive ? [
"Development",
"Staging",
"Testing",
"Production",
] : null}
selected={integrationEnvironment}
onChange={(environment) => {
setIntegrationEnvironment(environment);
}}
<p className='text-gray-400 text-xs font-semibold mb-2'>
ENVIRONMENT
</p>
<ListBox
data={
!integration.isActive
? environments.map(({ name }) => name)
: null
}
selected={integrationEnvironment.name}
onChange={(envName) =>
setIntegrationEnvironment(
environments.find(({ name }) => envName === name) || {
name: 'unknown',
slug: 'unknown',
}
)
}
isFull={true}
/>
</div>
<div className="pt-2">
<div className='pt-2'>
<FontAwesomeIcon
icon={faArrowRight}
className="mx-4 text-gray-400 mt-8"
/>
className='mx-4 text-gray-400 mt-8'
/>
</div>
<div className="mr-2">
<p className="text-gray-400 text-xs font-semibold mb-2">
<div className='mr-2'>
<p className='text-gray-400 text-xs font-semibold mb-2'>
INTEGRATION
</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.slice(1)}
</div>
</div>
<div className="mr-2">
<div className="text-gray-400 text-xs font-semibold mb-2">
APP
</div>
<div className='mr-2'>
<div className='text-gray-400 text-xs font-semibold mb-2'>APP</div>
<ListBox
data={!integration.isActive ? apps.map((app) => app.name) : null}
selected={integrationApp}
@@ -178,52 +195,55 @@ const Integration = ({
</div>
{renderIntegrationSpecificParams(integration)}
</div>
<div className="flex items-end">
{integration.isActive ? (
<div className="max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4">
<FontAwesomeIcon
icon={faRotate}
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='flex items-end'>
{integration.isActive ? (
<div className='max-w-5xl flex flex-row items-center bg-white/5 p-2 rounded-md px-4'>
<FontAwesomeIcon
icon={faRotate}
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.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>
);

View File

@@ -5,7 +5,8 @@ import guidGenerator from "~/utilities/randomId";
import Integration from "./Integration";
interface Props {
integrations: any
integrations: any;
environments: Array<{ name: string; slug: string }>;
}
interface IntegrationType {
@@ -19,7 +20,8 @@ interface IntegrationType {
}
const ProjectIntegrationSection = ({
integrations
integrations,
environments = [],
}: Props) => {
return integrations.length > 0 ? (
<div className="mb-12">
@@ -33,6 +35,7 @@ const ProjectIntegrationSection = ({
<Integration
key={guidGenerator()}
integration={integration}
environments={environments}
/>
))}
</div>

View File

@@ -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;

View File

@@ -24,6 +24,7 @@ import setBotActiveStatus from "../api/bot/setBotActiveStatus";
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import getAWorkspace from "../api/workspace/getAWorkspace";
import getLatestFileKey from "../api/workspace/getLatestFileKey";
const {
decryptAssymmetric,
@@ -34,6 +35,7 @@ const crypto = require("crypto");
export default function Integrations() {
const [cloudIntegrationOptions, setCloudIntegrationOptions] = useState([]);
const [integrationAuths, setIntegrationAuths] = useState([]);
const [environments,setEnvironments] = useState([])
const [integrations, setIntegrations] = useState([]);
const [bot, setBot] = useState(null);
const [isActivateBotDialogOpen, setIsActivateBotDialogOpen] = useState(false);
@@ -41,11 +43,15 @@ export default function Integrations() {
const [selectedIntegrationOption, setSelectedIntegrationOption] = useState(null);
const router = useRouter();
const workspaceId = router.query.id;
const { t } = useTranslation();
useEffect(async () => {
try {
const workspace = await getAWorkspace(workspaceId);
setEnvironments(workspace.environments);
// get cloud integration options
setCloudIntegrationOptions(
await getIntegrationOptions()
@@ -54,23 +60,19 @@ export default function Integrations() {
// get project integration authorizations
setIntegrationAuths(
await getWorkspaceAuthorizations({
workspaceId: router.query.id,
workspaceId
})
);
// get project integrations
setIntegrations(
await getWorkspaceIntegrations({
workspaceId: router.query.id,
workspaceId,
})
);
// get project bot
setBot(
await getBot({
workspaceId: router.query.id
}
));
setBot(await getBot({ workspaceId }));
} catch (err) {
console.log(err);
@@ -90,7 +92,7 @@ export default function Integrations() {
if (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 WORKSPACE_KEY = decryptAssymmetric({
@@ -214,7 +216,7 @@ export default function Integrations() {
handleBotActivate={handleBotActivate}
handleIntegrationOption={handleIntegrationOption}
/> */}
<IntegrationSection integrations={integrations} />
<IntegrationSection integrations={integrations} environments={environments} />
{(cloudIntegrationOptions.length > 0 && bot) ? (
<CloudIntegrationSection
cloudIntegrationOptions={cloudIntegrationOptions}