From 91052df5f9f91fd5bbb12e856795ff0702e86be6 Mon Sep 17 00:00:00 2001
From: Tuan Dang
Date: Sun, 18 Dec 2022 18:57:50 -0500
Subject: [PATCH] Fix Typescript issues for frontend integrations
---
docker-compose.yml | 2 +-
frontend/components/basic/Listbox.tsx | 6 +-
frontend/components/basic/buttons/Button.tsx | 2 +-
.../integrations/CloudIntegration.tsx | 16 +--
.../integrations/CloudIntegrationSection.tsx | 3 +
.../FrameworkIntegrationSection.tsx | 5 +-
.../components/integrations/Integration.tsx | 112 ++++++++++--------
.../integrations/IntegrationSection.tsx | 19 ++-
frontend/components/utilities/config/index.ts | 6 +-
frontend/pages/api/bot/setBotActiveStatus.ts | 2 +-
...ateIntegration.js => updateIntegration.ts} | 11 +-
frontend/pages/integrations/[id].js | 37 +++---
frontend/pages/netlify.js | 24 ++--
frontend/pages/vercel.js | 24 ++--
frontend/public/data/frequentConstants.ts | 21 ++--
15 files changed, 161 insertions(+), 129 deletions(-)
rename frontend/pages/api/integrations/{updateIntegration.js => updateIntegration.ts} (87%)
diff --git a/docker-compose.yml b/docker-compose.yml
index bd9022cef..206e7afa3 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -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
diff --git a/frontend/components/basic/Listbox.tsx b/frontend/components/basic/Listbox.tsx
index aa8c41f85..2ff0179dd 100644
--- a/frontend/components/basic/Listbox.tsx
+++ b/frontend/components/basic/Listbox.tsx
@@ -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;
}
diff --git a/frontend/components/basic/buttons/Button.tsx b/frontend/components/basic/buttons/Button.tsx
index 9f8d481b4..562a82a36 100644
--- a/frontend/components/basic/buttons/Button.tsx
+++ b/frontend/components/basic/buttons/Button.tsx
@@ -9,7 +9,7 @@ import {
const classNames = require("classnames");
type ButtonProps = {
- text: string;
+ text?: string;
onButtonPressed: () => void;
loading?: boolean;
color?: string;
diff --git a/frontend/components/integrations/CloudIntegration.tsx b/frontend/components/integrations/CloudIntegration.tsx
index f64268dba..75a8019a5 100644
--- a/frontend/components/integrations/CloudIntegration.tsx
+++ b/frontend/components/integrations/CloudIntegration.tsx
@@ -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}
>
diff --git a/frontend/components/integrations/CloudIntegrationSection.tsx b/frontend/components/integrations/CloudIntegrationSection.tsx
index 87ff74df1..58fb92cb2 100644
--- a/frontend/components/integrations/CloudIntegrationSection.tsx
+++ b/frontend/components/integrations/CloudIntegrationSection.tsx
@@ -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 {
diff --git a/frontend/components/integrations/FrameworkIntegrationSection.tsx b/frontend/components/integrations/FrameworkIntegrationSection.tsx
index c83599dc1..8535c595b 100644
--- a/frontend/components/integrations/FrameworkIntegrationSection.tsx
+++ b/frontend/components/integrations/FrameworkIntegrationSection.tsx
@@ -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) => {
diff --git a/frontend/components/integrations/Integration.tsx b/frontend/components/integrations/Integration.tsx
index a42fa5bcf..de0747409 100644
--- a/frontend/components/integrations/Integration.tsx
+++ b/frontend/components/integrations/Integration.tsx
@@ -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([]); // 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
@@ -94,13 +106,13 @@ const Integration = ({
CONTEXT
@@ -126,9 +138,11 @@ const Integration = ({
"Staging",
"Testing",
"Production",
- ] : null}
+ ] : []}
selected={integrationEnvironment}
- onChange={setIntegrationEnvironment}
+ onChange={(environment) => {
+ setIntegrationEnvironment(environment);
+ }}
isFull={true}
/>
@@ -152,9 +166,11 @@ const Integration = ({
APP
app.name)}
+ data={!integration.isActive ? apps.map((app) => app.name) : []}
selected={integrationApp}
- onChange={setIntegrationApp}
+ onChange={(app) => {
+ setIntegrationApp(app);
+ }}
/>
{renderIntegrationSpecificParams(integration)}
@@ -172,7 +188,9 @@ const Integration = ({
- {integrations.map((integration => (
+ {integrations.map((integration: IntegrationType) => (
- )))}
+ ))}
) :
}
diff --git a/frontend/components/utilities/config/index.ts b/frontend/components/utilities/config/index.ts
index 42dee5618..7570785ba 100644
--- a/frontend/components/utilities/config/index.ts
+++ b/frontend/components/utilities/config/index.ts
@@ -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
};
\ No newline at end of file
diff --git a/frontend/pages/api/bot/setBotActiveStatus.ts b/frontend/pages/api/bot/setBotActiveStatus.ts
index e85ed3c77..0a974a588 100644
--- a/frontend/pages/api/bot/setBotActiveStatus.ts
+++ b/frontend/pages/api/bot/setBotActiveStatus.ts
@@ -7,7 +7,7 @@ interface BotKey {
interface Props {
botId: string;
- isActive: Boolean;
+ isActive: boolean;
botKey: BotKey;
}
diff --git a/frontend/pages/api/integrations/updateIntegration.js b/frontend/pages/api/integrations/updateIntegration.ts
similarity index 87%
rename from frontend/pages/api/integrations/updateIntegration.js
rename to frontend/pages/api/integrations/updateIntegration.ts
index c77297e3a..8afcfc0a9 100644
--- a/frontend/pages/api/integrations/updateIntegration.js
+++ b/frontend/pages/api/integrations/updateIntegration.ts
@@ -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");
diff --git a/frontend/pages/integrations/[id].js b/frontend/pages/integrations/[id].js
index 494abee43..be0aff921 100644
--- a/frontend/pages/integrations/[id].js
+++ b/frontend/pages/integrations/[id].js
@@ -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
diff --git a/frontend/pages/netlify.js b/frontend/pages/netlify.js
index f25c6af83..6907d6db4 100644
--- a/frontend/pages/netlify.js
+++ b/frontend/pages/netlify.js
@@ -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);
}
diff --git a/frontend/pages/vercel.js b/frontend/pages/vercel.js
index a674c27d4..adfffe77e 100644
--- a/frontend/pages/vercel.js
+++ b/frontend/pages/vercel.js
@@ -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);
}
diff --git a/frontend/public/data/frequentConstants.ts b/frontend/public/data/frequentConstants.ts
index bbaa42ade..a447225d4 100644
--- a/frontend/public/data/frequentConstants.ts
+++ b/frontend/public/data/frequentConstants.ts
@@ -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};