Merge remote-tracking branch 'origin/main' into feat/resource-metadata

This commit is contained in:
Sheen Capadngan
2024-12-20 14:23:14 +08:00
231 changed files with 11454 additions and 167 deletions
@@ -0,0 +1,134 @@
import { useEffect } from "react";
import { useRouter } from "next/router";
import queryString from "query-string";
import { createNotification } from "@app/components/notifications";
import { ContentLoader } from "@app/components/v2";
import {
GitHubConnectionMethod,
TAppConnection,
TGitHubConnection,
useCreateAppConnection,
useUpdateAppConnection
} from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
type FormData = Pick<TGitHubConnection, "name" | "method" | "description"> & {
returnUrl?: string;
connectionId?: string;
};
export default function GitHubOAuthCallbackPage() {
const router = useRouter();
const updateAppConnection = useUpdateAppConnection();
const createAppConnection = useCreateAppConnection();
// eslint-disable-next-line @typescript-eslint/naming-convention
const {
code,
state,
installation_id: installationId
} = queryString.parse(router.asPath.split("?")[1]);
useEffect(() => {
(async () => {
let formData: FormData;
try {
formData = JSON.parse(localStorage.getItem("githubConnectionFormData") ?? "{}") as FormData;
} catch (e) {
createNotification({
type: "error",
text: "Invalid form state, redirecting..."
});
router.push(window.location.origin);
return;
}
// validate state
if (state !== localStorage.getItem("latestCSRFToken")) {
createNotification({
type: "error",
text: "Invalid state, redirecting..."
});
router.push(window.location.origin);
return;
}
localStorage.removeItem("githubConnectionFormData");
localStorage.removeItem("latestCSRFToken");
const { connectionId, name, description, returnUrl } = formData;
let appConnection: TAppConnection;
try {
if (connectionId) {
appConnection = await updateAppConnection.mutateAsync({
app: AppConnection.GitHub,
...(installationId
? {
connectionId,
credentials: {
code: code as string,
installationId: installationId as string
}
}
: {
connectionId,
credentials: {
code: code as string
}
})
});
} else {
appConnection = await createAppConnection.mutateAsync({
app: AppConnection.GitHub,
name,
description,
...(installationId
? {
method: GitHubConnectionMethod.App,
credentials: {
code: code as string,
installationId: installationId as string
}
}
: {
method: GitHubConnectionMethod.OAuth,
credentials: {
code: code as string
}
})
});
}
} catch (e: any) {
createNotification({
title: `Failed to ${connectionId ? "update" : "add"} GitHub Connection`,
text: e.message,
type: "error"
});
router.push(
returnUrl ??
`/org/${localStorage.getItem("orgData.id")}/settings?selectedTab=app-connections`
);
return;
}
createNotification({
text: `Successfully ${connectionId ? "updated" : "added"} GitHub Connection`,
type: "success"
});
router.push(returnUrl ?? `/org/${appConnection.orgId}/settings?selectedTab=app-connections`);
})();
}, []);
return (
<div className="flex h-full w-full items-center justify-center">
<ContentLoader />
</div>
);
}
GitHubOAuthCallbackPage.requireAuth = true;
@@ -13,6 +13,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import queryString from "query-string";
import { useCreateIntegration } from "@app/hooks/api";
import { IntegrationSyncBehavior } from "@app/hooks/api/integrations/types";
import {
Button,
@@ -36,12 +37,26 @@ const vercelEnvironments = [
{ name: "Production", slug: "production" }
];
const initialSyncBehaviors = [
{
label: "No Import - Overwrite all values in Vercel",
value: IntegrationSyncBehavior.OVERWRITE_TARGET
},
{
label: "Import - Prefer values from Infisical",
value: IntegrationSyncBehavior.PREFER_SOURCE
}
];
export default function VercelCreateIntegrationPage() {
const router = useRouter();
const { mutateAsync } = useCreateIntegration();
const [selectedSourceEnvironment, setSelectedSourceEnvironment] = useState("");
const [secretPath, setSecretPath] = useState("/");
const [initialSyncBehavior, setInitialSyncBehavior] = useState<IntegrationSyncBehavior>(
IntegrationSyncBehavior.PREFER_SOURCE
);
const [targetAppId, setTargetAppId] = useState("");
const [targetEnvironment, setTargetEnvironment] = useState("");
const [targetBranch, setTargetBranch] = useState("");
@@ -104,7 +119,10 @@ export default function VercelCreateIntegrationPage() {
sourceEnvironment: selectedSourceEnvironment,
targetEnvironment,
path,
secretPath
secretPath,
metadata: {
initialSyncBehavior
}
});
setIsLoading(false);
@@ -231,6 +249,21 @@ export default function VercelCreateIntegrationPage() {
</Select>
</FormControl>
)}
<FormControl label="Initial Sync Behavior" className="px-6">
<Select
value={initialSyncBehavior}
onValueChange={(val) => setInitialSyncBehavior(val as IntegrationSyncBehavior)}
className="w-full border border-mineshaft-500 text-sm"
>
{initialSyncBehaviors.map((syncBehavior) => (
<SelectItem value={syncBehavior.value} key={`sync-behavior-${syncBehavior.value}`}>
{syncBehavior.label}
</SelectItem>
))}
</Select>
</FormControl>
<Button
onClick={handleButtonClick}
color="mineshaft"
@@ -62,7 +62,8 @@ enum ProjectOrderBy {
const formatTitle = (type: ProjectType) => {
if (type === ProjectType.SecretManager) return "Secret Management";
if (type === ProjectType.CertificateManager) return "Cert Management";
return "Key Management";
if (type === ProjectType.KMS) return "Key Management";
return "SSH";
};
const formatDescription = (type: ProjectType) => {
@@ -70,7 +71,9 @@ const formatDescription = (type: ProjectType) => {
return "Securely store, manage, and rotate various application secrets, such as database credentials, API keys, etc.";
if (type === ProjectType.CertificateManager)
return "Manage your PKI infrastructure and issue digital certificates for services, applications, and devices.";
return "Centralize the management of keys for cryptographic operations, such as encryption and decryption.";
if (type === ProjectType.KMS)
return "Centralize the management of keys for cryptographic operations, such as encryption and decryption.";
return "Generate SSH credentials to provide secure and centralized SSH access control for your infrastructure.";
};
type Props = {
@@ -0,0 +1,9 @@
import { ProjectType } from "@app/hooks/api/workspace/types";
import { ProductOverview } from "../secret-manager/overview";
const SshManagerOverviewPage = () => <ProductOverview type={ProjectType.SSH} />;
Object.assign(SshManagerOverviewPage, { requireAuth: true });
export default SshManagerOverviewPage;
@@ -0,0 +1,21 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { IPAllowlistPage } from "@app/views/Project/IPAllowListPage";
const ProjectAllowlist = () => {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<IPAllowlistPage />
</>
);
};
export default ProjectAllowlist;
ProjectAllowlist.requireAuth = true;
@@ -0,0 +1,18 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import Head from "next/head";
import { SshCaPage } from "@app/views/Project/SshCaPage";
export default function SshCa() {
return (
<>
<Head>
<title>SSH Certificate Authority</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<SshCaPage />
</>
);
}
SshCa.requireAuth = true;
@@ -0,0 +1,20 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { IdentityDetailsPage } from "@app/views/Project/IdentityDetailsPage";
export default function ProjectIdentityDetailsPage() {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.members.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<IdentityDetailsPage />
</>
);
}
ProjectIdentityDetailsPage.requireAuth = true;
@@ -0,0 +1,20 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { MemberDetailsPage } from "@app/views/Project/MemberDetailsPage";
export default function Page() {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.members.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<MemberDetailsPage />
</>
);
}
Page.requireAuth = true;
@@ -0,0 +1,21 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { MembersPage } from "@app/views/Project/MembersPage";
export default function WorkspaceMemberSettings() {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.members.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<MembersPage />
</>
);
}
WorkspaceMemberSettings.requireAuth = true;
@@ -0,0 +1,20 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { RolePage } from "@app/views/Project/RolePage";
export default function Role() {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: "Project Settings" })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<RolePage />
</>
);
}
Role.requireAuth = true;
@@ -0,0 +1,22 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { ProjectSettingsPage } from "@app/views/Settings/ProjectSettingsPage";
const ProjectSettings = () => {
const { t } = useTranslation();
return (
<>
<Head>
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
<link rel="icon" href="/infisical.ico" />
</Head>
<ProjectSettingsPage />
</>
);
};
export default ProjectSettings;
ProjectSettings.requireAuth = true;
+23
View File
@@ -0,0 +1,23 @@
import { useTranslation } from "react-i18next";
import Head from "next/head";
import { SshPage } from "@app/views/Project/SshPage";
const Ssh = () => {
const { t } = useTranslation();
return (
<div className="h-full bg-bunker-800">
<Head>
<title>{t("common.head-title", { title: "Certificates" })}</title>
<link rel="icon" href="/infisical.ico" />
<meta property="og:image" content="/images/message.png" />
</Head>
<SshPage />
</div>
);
};
export default Ssh;
Ssh.requireAuth = true;