mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 08:29:55 +00:00
feat(secret-sync): add Gitlab PR comments suggestions
This commit is contained in:
+24
-26
@@ -1,6 +1,6 @@
|
||||
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||
import { SingleValue } from "react-select";
|
||||
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faCircleInfo, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
|
||||
@@ -40,26 +40,24 @@ const SecretProtectionOption = ({
|
||||
tooltip?: string;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex items-start justify-between rounded-lg border border-mineshaft-600 bg-mineshaft-800/50 p-4 transition-all duration-200 hover:border-mineshaft-500">
|
||||
<div className="flex flex-1 items-start space-x-3">
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="mb-1 flex items-center gap-2">
|
||||
<h4 className="text-sm font-medium text-bunker-100">{title}</h4>
|
||||
{tooltip && (
|
||||
<Tooltip className="max-w-sm" content={tooltip}>
|
||||
<FontAwesomeIcon
|
||||
icon={faCircleInfo}
|
||||
className="cursor-help text-xs text-mineshaft-400 hover:text-mineshaft-300"
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ml-4 flex-shrink-0">
|
||||
<Switch id={id} onCheckedChange={onChange} isChecked={isEnabled} isDisabled={isDisabled} />
|
||||
</div>
|
||||
</div>
|
||||
<Switch
|
||||
className="bg-mineshaft-400/80 shadow-inner data-[state=checked]:bg-green/80"
|
||||
id={id}
|
||||
thumbClassName="bg-mineshaft-800"
|
||||
onCheckedChange={onChange}
|
||||
isChecked={isEnabled}
|
||||
isDisabled={isDisabled}
|
||||
containerClassName="w-full"
|
||||
>
|
||||
<p>
|
||||
{title}{" "}
|
||||
{tooltip && (
|
||||
<Tooltip className="max-w-md" content={tooltip}>
|
||||
<FontAwesomeIcon icon={faQuestionCircle} size="sm" className="ml-1" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</p>
|
||||
</Switch>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -86,7 +84,7 @@ export const GitLabSyncFields = () => {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="h-[calc(100vh-20rem)] overflow-auto">
|
||||
<div className="h-[calc(100vh-28rem)] overflow-auto">
|
||||
<SecretSyncConnectionField
|
||||
onChange={() => {
|
||||
setValue("destinationConfig.projectId", "");
|
||||
@@ -175,7 +173,7 @@ export const GitLabSyncFields = () => {
|
||||
helperText={
|
||||
<Tooltip
|
||||
className="max-w-md"
|
||||
content="Ensure the project exists in the connection's GitLab instance URL."
|
||||
content="Ensure the project exists in the connection's GitLab instance URL and the connection has access to it."
|
||||
>
|
||||
<div>
|
||||
<span>Don't see the project you're looking for?</span>{" "}
|
||||
@@ -229,7 +227,7 @@ export const GitLabSyncFields = () => {
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<SecretProtectionOption
|
||||
id="should-protect-secrets"
|
||||
title="Mark Infisical secrets in GitLab as 'Protected' secrets"
|
||||
title="Mark secrets as Protected"
|
||||
isEnabled={value || false}
|
||||
onChange={onChange}
|
||||
/>
|
||||
@@ -242,7 +240,7 @@ export const GitLabSyncFields = () => {
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<SecretProtectionOption
|
||||
id="should-mask-secrets"
|
||||
title="Mark Infisical secrets in GitLab as 'Masked' secrets"
|
||||
title="Mark secrets as Masked"
|
||||
tooltip="GitLab has limitations for masked variables: secrets must be at least 8 characters long and not match existing CI/CD variable names. Secrets not meeting these criteria won't be masked."
|
||||
isEnabled={value || false}
|
||||
onChange={(checked) => {
|
||||
@@ -262,7 +260,7 @@ export const GitLabSyncFields = () => {
|
||||
<div className="max-h-32 opacity-100 transition-all duration-300">
|
||||
<SecretProtectionOption
|
||||
id="should-hide-secrets"
|
||||
title="Mark Infisical secrets in GitLab as 'Hidden' secrets"
|
||||
title="Mark secrets as Hidden"
|
||||
tooltip="Secrets can only be marked as hidden if they are also masked."
|
||||
isEnabled={value || false}
|
||||
onChange={onChange}
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||
|
||||
export const GitLabSyncReviewFields = () => {
|
||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.GitLab }>();
|
||||
const projectId = watch("destinationConfig.projectId");
|
||||
const projectName = watch("destinationConfig.projectName");
|
||||
const targetEnvironment = watch("destinationConfig.targetEnvironment");
|
||||
const groupId = watch("destinationConfig.groupId");
|
||||
const scope = watch("destinationConfig.scope");
|
||||
@@ -17,7 +17,7 @@ export const GitLabSyncReviewFields = () => {
|
||||
return (
|
||||
<>
|
||||
<GenericFieldLabel label="Scope">{scope}</GenericFieldLabel>
|
||||
<GenericFieldLabel label="Project ID">{projectId}</GenericFieldLabel>
|
||||
<GenericFieldLabel label="Project Name">{projectName}</GenericFieldLabel>
|
||||
{groupId && <GenericFieldLabel label="Group ID">{groupId}</GenericFieldLabel>}
|
||||
{targetEnvironment && (
|
||||
<GenericFieldLabel label="Environment">{targetEnvironment}</GenericFieldLabel>
|
||||
|
||||
@@ -75,7 +75,7 @@ export const SECRET_SYNC_MAP: Record<SecretSync, { name: string; image: string }
|
||||
image: "Flyio.svg"
|
||||
},
|
||||
[SecretSync.GitLab]: {
|
||||
name: "Gitlab",
|
||||
name: "GitLab",
|
||||
image: "GitLab.png"
|
||||
}
|
||||
};
|
||||
|
||||
@@ -7,3 +7,8 @@ export type TGitLabGroup = {
|
||||
id: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
export enum GitLabAccessTokenType {
|
||||
Personal = "personal",
|
||||
Project = "project"
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
|
||||
|
||||
import { GitLabAccessTokenType } from "../gitlab";
|
||||
|
||||
export enum GitlabConnectionMethod {
|
||||
AccessToken = "access-token",
|
||||
OAuth = "oauth"
|
||||
@@ -12,6 +14,7 @@ export type TGitlabConnection = TRootAppConnection & { app: AppConnection.Gitlab
|
||||
credentials: {
|
||||
instanceUrl?: string;
|
||||
accessToken: string;
|
||||
accessTokenType: GitLabAccessTokenType;
|
||||
};
|
||||
}
|
||||
| {
|
||||
|
||||
+62
-24
@@ -20,6 +20,7 @@ import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/
|
||||
import { isInfisicalCloud } from "@app/helpers/platform";
|
||||
import { useGetAppConnectionOption } from "@app/hooks/api/appConnections";
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
import { GitLabAccessTokenType } from "@app/hooks/api/appConnections/gitlab";
|
||||
import {
|
||||
GitlabConnectionMethod,
|
||||
TGitlabConnection
|
||||
@@ -41,6 +42,7 @@ const formSchema = z.discriminatedUnion("method", [
|
||||
method: z.literal(GitlabConnectionMethod.AccessToken),
|
||||
credentials: z.object({
|
||||
accessToken: z.string().min(1, "Access token is required"),
|
||||
accessTokenType: z.nativeEnum(GitLabAccessTokenType),
|
||||
instanceUrl: z
|
||||
.string()
|
||||
.trim()
|
||||
@@ -90,6 +92,7 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
method: GitlabConnectionMethod.AccessToken,
|
||||
credentials: {
|
||||
accessToken: "",
|
||||
accessTokenType: GitLabAccessTokenType.Personal,
|
||||
instanceUrl: ""
|
||||
}
|
||||
} as FormData))
|
||||
@@ -151,7 +154,7 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Unhandled Gitlab Connection method");
|
||||
throw new Error("Unhandled GitLab Connection method");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error handling form submission:", error);
|
||||
@@ -169,7 +172,7 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
isMissingConfig = false;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unhandled Gitlab Connection method: ${selectedMethod}`);
|
||||
throw new Error(`Unhandled GitLab Connection method: ${selectedMethod}`);
|
||||
}
|
||||
|
||||
const methodDetails = getAppConnectionMethodDetails(selectedMethod);
|
||||
@@ -211,7 +214,7 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
? `Environment variables have not been configured. ${
|
||||
isInfisicalCloud()
|
||||
? "Please contact Infisical."
|
||||
: `See Docs to configure Gitlab ${methodDetails.name} Connections.`
|
||||
: `See Docs to configure GitLab ${methodDetails.name} Connections.`
|
||||
}`
|
||||
: error?.message
|
||||
}
|
||||
@@ -245,24 +248,59 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
/>
|
||||
|
||||
{selectedMethod === GitlabConnectionMethod.AccessToken && (
|
||||
<Controller
|
||||
name="credentials.accessToken"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Access Token"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
tooltipText="Your Gitlab Access Token"
|
||||
>
|
||||
<SecretInput
|
||||
containerClassName="text-gray-400 group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<>
|
||||
<Controller
|
||||
name="credentials.accessTokenType"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Access Token Type"
|
||||
>
|
||||
<Select
|
||||
isDisabled={isUpdate}
|
||||
value={value}
|
||||
onValueChange={(val) => {
|
||||
onChange(val);
|
||||
if (val === GitlabConnectionMethod.OAuth) {
|
||||
setValue("credentials.code", "custom");
|
||||
}
|
||||
}}
|
||||
className="w-full border border-mineshaft-500"
|
||||
position="popper"
|
||||
dropdownContainerClassName="max-w-none"
|
||||
>
|
||||
{Object.values(GitLabAccessTokenType).map((method) => {
|
||||
return (
|
||||
<SelectItem value={method} key={method}>
|
||||
{method.charAt(0).toUpperCase() + method.slice(1)} Access Token
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="credentials.accessToken"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
label="Access Token"
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
tooltipText="Your GitLab Access Token"
|
||||
>
|
||||
<SecretInput
|
||||
containerClassName="text-gray-400 group-focus-within:!border-primary-400/50 border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
|
||||
value={value}
|
||||
onChange={(e) => onChange(e.target.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
||||
<div className="mt-8 flex items-center">
|
||||
@@ -280,10 +318,10 @@ export const GitLabConnectionForm = ({ appConnection, onSubmit: formSubmit }: Pr
|
||||
}
|
||||
>
|
||||
{isRedirecting && selectedMethod === GitlabConnectionMethod.OAuth
|
||||
? "Redirecting to Gitlab..."
|
||||
? "Redirecting to GitLab..."
|
||||
: isUpdate
|
||||
? "Reconnect to Gitlab"
|
||||
: "Connect to Gitlab"}
|
||||
? "Reconnect to GitLab"
|
||||
: "Connect to GitLab"}
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
|
||||
Reference in New Issue
Block a user