Fix Typescript issues for frontend integrations

This commit is contained in:
Tuan Dang
2022-12-18 18:57:50 -05:00
parent 6ea26c135a
commit 91052df5f9
15 changed files with 161 additions and 129 deletions

View File

@ -9,7 +9,7 @@ services:
- 80:80
- 443:443
volumes:
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
- ./nginx/default.dev.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
- frontend
- backend

View File

@ -10,10 +10,10 @@ import { Listbox, Transition } from "@headlessui/react";
interface ListBoxProps {
selected: string;
onChange: () => void;
onChange: (arg: string) => void;
data: string[];
text: string;
buttonAction: () => void;
text?: string;
buttonAction?: () => void;
isFull?: boolean;
}

View File

@ -9,7 +9,7 @@ import {
const classNames = require("classnames");
type ButtonProps = {
text: string;
text?: string;
onButtonPressed: () => void;
loading?: boolean;
color?: string;

View File

@ -1,30 +1,32 @@
import React from "react";
import Image from "next/image";
import { useRouter } from "next/router";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faCheck,
faX,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import deleteIntegrationAuth from "../../pages/api/integrations/DeleteIntegrationAuth";
interface CloudIntegrationOption {
isAvailable: Boolean;
isAvailable: boolean;
name: string;
type: string;
clientId: string;
docsLink: string;
slug: string;
}
interface IntegrationAuth {
id: string;
_id: string;
integration: string;
}
interface Props {
cloudIntegrationOption: CloudIntegrationOption;
setSelectedIntegrationOption: () => void;
integrationOptionPress: () => void;
setSelectedIntegrationOption: (cloudIntegration: CloudIntegrationOption) => void;
integrationOptionPress: (cloudIntegrationOption: CloudIntegrationOption) => void;
integrationAuths: IntegrationAuth[];
}
@ -45,9 +47,7 @@ const CloudIntegration = ({
onClick={() => {
if (!cloudIntegrationOption.isAvailable) return;
setSelectedIntegrationOption(cloudIntegrationOption);
integrationOptionPress({
integrationOption: cloudIntegrationOption
});
integrationOptionPress(cloudIntegrationOption);
}}
key={cloudIntegrationOption.name}
>

View File

@ -1,11 +1,14 @@
import React from "react";
import CloudIntegration from "./CloudIntegration";
interface CloudIntegrationOption {
isAvailable: boolean;
name: string;
type: string;
clientId: string;
docsLink: string;
slug: string;
}
interface Props {

View File

@ -1,14 +1,17 @@
import React from "react";
import FrameworkIntegration from "./FrameworkIntegration";
interface Framework {
name: string;
image: string;
link: string;
slug: string;
docsLink: string;
}
interface Props {
framework: Framework
frameworks: [Framework]
}
const FrameworkIntegrationSection = ({ frameworks }: Props) => {

View File

@ -6,23 +6,30 @@ import {
faX,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
envMapping,
reverseEnvMapping,
reverseContextNetlifyMapping
} from "../../public/data/frequentConstants";
import updateIntegration from "../../pages/api/integrations/updateIntegration"
import deleteIntegration from "../../pages/api/integrations/DeleteIntegration"
import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps";
import Button from "~/components/basic/buttons/Button";
import ListBox from "~/components/basic/Listbox";
import deleteIntegration from "../../pages/api/integrations/DeleteIntegration"
import getIntegrationApps from "../../pages/api/integrations/GetIntegrationApps";
import updateIntegration from "../../pages/api/integrations/updateIntegration"
import {
envMapping,
reverseContextNetlifyMapping,
reverseEnvMapping} from "../../public/data/frequentConstants";
interface Integration {
_id: string;
app?: string;
environment: string;
integration: string;
integrationAuth: string;
isActive: Boolean;
isActive: boolean;
}
interface IntegrationApp {
name: string;
siteId: string;
}
const Integration = ({
@ -35,39 +42,44 @@ const Integration = ({
);
const [fileState, setFileState] = useState([]);
const router = useRouter();
const [apps, setApps] = useState([]); // integration app objects
const [integrationApp, setIntegrationApp] = useState(null); // integration app name
const [integrationTarget, setIntegrationTarget] = useState(null); // vercel-specific integration param
const [integrationContext, setIntegrationContext] = useState(null); // netlify-specific integration param
const [apps, setApps] = useState<IntegrationApp[]>([]); // integration app objects
const [integrationApp, setIntegrationApp] = useState(""); // integration app name
const [integrationTarget, setIntegrationTarget] = useState(""); // vercel-specific integration param
const [integrationContext, setIntegrationContext] = useState(""); // netlify-specific integration param
useEffect(async () => {
interface App {
name: string;
siteId?: string;
}
const tempApps = await getIntegrationApps({
integrationAuthId: integration.integrationAuth,
});
setApps(tempApps);
setIntegrationApp(
integration.app ? integration.app : tempApps[0].name
);
switch (integration.integration) {
case "vercel":
setIntegrationTarget("Development");
break;
case "netlify":
setIntegrationContext("All");
break;
default:
break;
useEffect(() => {
const loadIntegration = async () => {
interface App {
name: string;
siteId?: string;
}
const tempApps: [IntegrationApp] = await getIntegrationApps({
integrationAuthId: integration.integrationAuth,
});
setApps(tempApps);
setIntegrationApp(
integration.app ? integration.app : tempApps[0].name
);
switch (integration.integration) {
case "vercel":
setIntegrationTarget("Development");
break;
case "netlify":
setIntegrationContext("All");
break;
default:
break;
}
}
loadIntegration();
}, []);
const renderIntegrationSpecificParams = (integration) => {
const renderIntegrationSpecificParams = (integration: Integration) => {
try {
switch (integration.integration) {
case "vercel":
@ -77,11 +89,11 @@ const Integration = ({
ENVIRONMENT
</div>
<ListBox
data={!integration.isActive && [
data={!integration.isActive ? [
"Production",
"Preview",
"Development"
]}
] : []}
selected={"Production"}
onChange={setIntegrationTarget}
/>
@ -94,13 +106,13 @@ const Integration = ({
CONTEXT
</div>
<ListBox
data={!integration.isActive && [
data={!integration.isActive ? [
"All",
"Production",
"Deploy previews",
"Branch deploys",
"Local development"
]}
] : []}
selected={integrationContext}
onChange={setIntegrationContext}
/>
@ -126,9 +138,11 @@ const Integration = ({
"Staging",
"Testing",
"Production",
] : null}
] : []}
selected={integrationEnvironment}
onChange={setIntegrationEnvironment}
onChange={(environment) => {
setIntegrationEnvironment(environment);
}}
isFull={true}
/>
</div>
@ -152,9 +166,11 @@ const Integration = ({
APP
</div>
<ListBox
data={!integration.isActive && apps.map((app) => app.name)}
data={!integration.isActive ? apps.map((app) => app.name) : []}
selected={integrationApp}
onChange={setIntegrationApp}
onChange={(app) => {
setIntegrationApp(app);
}}
/>
</div>
{renderIntegrationSpecificParams(integration)}
@ -172,7 +188,9 @@ const Integration = ({
<Button
text="Start Integration"
onButtonPressed={async () => {
const siteId = apps.find((app) => app.name === integrationApp).siteId ? apps.find((app) => app.name === integrationApp).siteId : null;
const siteApp = apps.find((app) => app.name === integrationApp); // obj or undefined
const siteId = siteApp ? siteApp.siteId : null;
const result = await updateIntegration({
integrationId: integration._id,
environment: envMapping[integrationEnvironment],

View File

@ -1,15 +1,22 @@
import React from "react";
import Integration from "./Integration";
import guidGenerator from "~/utilities/randomId";
interface Integration {
}
import Integration from "./Integration";
interface Props {
integrations: any
}
interface IntegrationType {
_id: string;
app?: string;
environment: string;
integration: string;
integrationAuth: string;
isActive: boolean;
}
const ProjectIntegrationSection = ({
integrations
}: Props) => {
@ -21,12 +28,12 @@ const ProjectIntegrationSection = ({
Manage your integrations of Infisical with third-party services.
</p>
</div>
{integrations.map((integration => (
{integrations.map((integration: IntegrationType) => (
<Integration
key={guidGenerator()}
integration={integration}
/>
)))}
))}
</div>
) : <div></div>
}

View File

@ -4,15 +4,11 @@ const POSTHOG_HOST =
process.env.NEXT_PUBLIC_POSTHOG_HOST! || "https://app.posthog.com";
const STRIPE_PRODUCT_PRO = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_PRO!;
const STRIPE_PRODUCT_STARTER = process.env.NEXT_PUBLIC_STRIPE_PRODUCT_STARTER!;
const CLIENT_ID_HEROKU = process.env.NEXT_PUBLIC_CLIENT_ID_HEROKU!;
const CLIENT_ID_NETLIFY = process.env.NEXT_PUBLIC_CLIENT_ID_NETLIFY!;
export {
ENV,
POSTHOG_API_KEY,
POSTHOG_HOST,
STRIPE_PRODUCT_PRO,
STRIPE_PRODUCT_STARTER,
CLIENT_ID_HEROKU,
CLIENT_ID_NETLIFY
STRIPE_PRODUCT_STARTER
};

View File

@ -7,7 +7,7 @@ interface BotKey {
interface Props {
botId: string;
isActive: Boolean;
isActive: boolean;
botKey: BotKey;
}

View File

@ -22,6 +22,15 @@ const updateIntegration = ({
target,
context,
siteId
}: {
integrationId: string,
app: string,
environment: string,
isActive: boolean,
target: string | null,
context: string | null,
siteId: string | null
}) => {
return SecurityClient.fetchCall(
"/api/v1/integration/" + integrationId,
@ -40,7 +49,7 @@ const updateIntegration = ({
}),
}
).then(async (res) => {
if (res.status == 200) {
if (res && res.status == 200) {
return res;
} else {
console.log("Failed to start an integration");

View File

@ -2,20 +2,22 @@ import React, { useEffect, useState } from "react";
import Head from "next/head";
import Image from "next/image";
import { useRouter } from "next/router";
import NavHeader from "~/components/navigation/NavHeader";
import Integration from "~/components/integrations/Integration";
import FrameworkIntegrationSection from "~/components/integrations/FrameworkIntegrationSection";
import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection";
import IntegrationSection from "~/components/integrations/IntegrationSection";
import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json";
import getWorkspaceAuthorizations from "../api/integrations/getWorkspaceAuthorizations";
import getWorkspaceIntegrations from "../api/integrations/getWorkspaceIntegrations";
import getIntegrationOptions from "../api/integrations/GetIntegrationOptions";
import getBot from "../api/bot/getBot";
import setBotActiveStatus from "../api/bot/setBotActiveStatus";
import getLatestFileKey from "../api/workspace/getLatestFileKey";
import ActivateBotDialog from "~/components/basic/dialog/ActivateBotDialog";
import IntegrationAccessTokenDialog from "~/components/basic/dialog/IntegrationAccessTokenDialog";
import CloudIntegrationSection from "~/components/integrations/CloudIntegrationSection";
import FrameworkIntegrationSection from "~/components/integrations/FrameworkIntegrationSection";
import Integration from "~/components/integrations/Integration";
import IntegrationSection from "~/components/integrations/IntegrationSection";
import NavHeader from "~/components/navigation/NavHeader";
import frameworkIntegrationOptions from "../../public/json/frameworkIntegrations.json";
import getBot from "../api/bot/getBot";
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 getLatestFileKey from "../api/workspace/getLatestFileKey";
const {
decryptAssymmetric,
encryptAssymmetric
@ -150,14 +152,13 @@ export default function Integrations() {
/**
* Open dialog to activate bot if bot is not active.
* Otherwise, start integration [integrationOption]
* @param {Object} obj
* @param {Object} obj.integrationOption - an integration option
* @param {String} obj.name
* @param {String} obj.type
* @param {String} obj.docsLink
* @param {Object} integrationOption - an integration option
* @param {String} integrationOption.name
* @param {String} integrationOption.type
* @param {String} integrationOption.docsLink
* @returns
*/
const integrationOptionPress = ({ integrationOption }) => {
const integrationOptionPress = (integrationOption) => {
try {
if (bot.isActive) {
// case: bot is active -> proceed with integration

View File

@ -16,20 +16,18 @@ export default function Netlify() {
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "netlify"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
try {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "netlify"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
} catch (err) {
console.error('Netlify integration error: ', err);
}

View File

@ -15,20 +15,18 @@ export default function Vercel() {
*/
// eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(async () => {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "vercel"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
try {
if (state === localStorage.getItem('latestCSRFToken')) {
localStorage.removeItem('latestCSRFToken');
await AuthorizeIntegration({
workspaceId: localStorage.getItem('projectData.id'),
code,
integration: "vercel"
});
router.push("/integrations/" + localStorage.getItem("projectData.id"));
}
} catch (err) {
console.error('Vercel integration error: ', err);
}

View File

@ -1,22 +1,22 @@
const envMapping = {
interface Mapping {
[key: string]: string;
}
const envMapping: Mapping = {
Development: "dev",
Staging: "staging",
Production: "prod",
Testing: "test",
};
const reverseEnvMapping = {
const reverseEnvMapping: Mapping = {
dev: "Development",
staging: "Staging",
prod: "Production",
test: "Testing",
};
const vercelMapping = {
}
const reverseContextNetlifyMapping = {
const reverseContextNetlifyMapping: Mapping = {
"All": "all",
"Local development": "dev",
"Branch deploys": "branch-deploy",
@ -26,6 +26,5 @@ const reverseContextNetlifyMapping = {
export {
envMapping,
reverseEnvMapping,
reverseContextNetlifyMapping
};
reverseContextNetlifyMapping,
reverseEnvMapping};