mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 22:46:24 +00:00
Merge remote-tracking branch 'origin/main' into feat/resource-metadata
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user