Merge remote-tracking branch 'origin' into groups-phase-2c

This commit is contained in:
Tuan Dang
2024-04-29 11:55:53 -07:00
43 changed files with 912 additions and 134 deletions
@@ -21,15 +21,17 @@ import { ProjectVersion } from "@app/hooks/api/workspace/types";
import { CloudIntegrationSection } from "./components/CloudIntegrationSection";
import { FrameworkIntegrationSection } from "./components/FrameworkIntegrationSection";
import { InfrastructureIntegrationSection } from "./components/InfrastructureIntegrationSection/InfrastructureIntegrationSection";
import { IntegrationsSection } from "./components/IntegrationsSection";
import { generateBotKey, redirectForProviderAuth } from "./IntegrationPage.utils";
type Props = {
frameworkIntegrations: Array<{ name: string; slug: string; image: string; docsLink: string }>;
infrastructureIntegrations: Array<{ name: string; slug: string; image: string; docsLink: string }>;
};
export const IntegrationsPage = withProjectPermission(
({ frameworkIntegrations }: Props) => {
({ frameworkIntegrations, infrastructureIntegrations }: Props) => {
const { t } = useTranslation();
@@ -228,6 +230,7 @@ export const IntegrationsPage = withProjectPermission(
</ModalContent>
</Modal>
<FrameworkIntegrationSection frameworks={frameworkIntegrations} />
<InfrastructureIntegrationSection integrations={infrastructureIntegrations} />
</div>
);
},
@@ -109,7 +109,7 @@ export const CloudIntegrationSection = ({
</div>
{cloudIntegration.isAvailable &&
Boolean(integrationAuths?.[cloudIntegration.slug]) && (
<div className="absolute top-0 right-0 z-40 h-full">
<div className="absolute top-0 right-0 z-30 h-full">
<div className="relative h-full">
<div className="absolute top-0 right-0 w-24 flex-row items-center overflow-hidden whitespace-nowrap rounded-tr-md rounded-bl-md bg-primary py-0.5 px-2 text-xs text-black opacity-80 transition-all duration-300 group-hover:w-0 group-hover:p-0">
<FontAwesomeIcon icon={faCheck} className="mr-2 text-xs" />
@@ -1,4 +1,7 @@
import { useTranslation } from "react-i18next";
import { faKeyboard } from "@fortawesome/free-regular-svg-icons";
import { faComputer } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
type Props = {
frameworks: Array<{
@@ -50,6 +53,36 @@ export const FrameworkIntegrationSection = ({ frameworks }: Props) => {
</div>
</a>
))}
<a
key="framework-integration-more"
href="https://infisical.com/docs/cli/commands/run"
rel="noopener noreferrer"
target="_blank"
className="relative flex h-32 cursor-pointer flex-row items-center justify-center rounded-md p-0.5 duration-200"
>
<div
className="flex h-full w-full cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-800 font-semibold text-gray-300 duration-200 hover:bg-mineshaft-700 group-hover:text-gray-200 px-1 text-xl w-full max-w-xs text-center"
>
<FontAwesomeIcon className="text-5xl mb-2 text-white/90" icon={faKeyboard} />
<div className="h-2" />
CLI
</div>
</a>
<a
key="framework-integration-more"
href="https://infisical.com/docs/sdks/overview"
rel="noopener noreferrer"
target="_blank"
className="relative flex h-32 cursor-pointer flex-row items-center justify-center rounded-md p-0.5 duration-200"
>
<div
className="flex h-full w-full cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-800 font-semibold text-gray-300 duration-200 hover:bg-mineshaft-700 group-hover:text-gray-200 px-1 text-xl w-full max-w-xs text-center"
>
<FontAwesomeIcon className="text-5xl mb-1 text-white/90" icon={faComputer} />
<div className="h-2" />
SDKs
</div>
</a>
</div>
</>
);
@@ -0,0 +1,50 @@
type Props = {
integrations: Array<{
name: string;
image: string;
slug: string;
docsLink: string;
}>;
};
export const InfrastructureIntegrationSection = ({ integrations }: Props) => {
const sortedIntegrations = integrations.sort((a, b) => a.name.localeCompare(b.name));
return (
<>
<div className="mx-4 mt-12 mb-4 flex flex-col items-start justify-between px-2 text-xl">
<h1 className="text-3xl font-semibold">Infrastructure Integrations</h1>
<p className="text-base text-gray-400">Click on of the integration to read the documentation.</p>
</div>
<div className="mx-6 grid grid-cols-2 gap-4 lg:grid-cols-3 2xl:grid-cols-4">
{sortedIntegrations.map((integration) => (
<a
key={`framework-integration-${integration.slug}`}
href={integration.docsLink}
rel="noopener noreferrer"
target="_blank"
className="relative w-full flex h-32 cursor-pointer flex-row items-center justify-center rounded-md p-0.5 duration-200"
>
<div
onKeyDown={() => null}
role="button"
tabIndex={0}
className="group relative w-full cursor-pointer duration-200 hover:bg-mineshaft-700 flex h-32 flex-row items-center rounded-md border border-mineshaft-600 bg-mineshaft-800 p-4"
key={integration?.name}
>
<img
src={`/images/integrations/${integration.image}.png`}
height={integration?.name ? 60 : 90}
width={integration?.name ? 60 : 90}
alt="integration logo"
/>
<div className="ml-4 max-w-xs text-xl font-semibold text-gray-300 duration-200 group-hover:text-gray-200">
{integration?.name && integration.name}
</div>
</div>
</a>
))}
</div>
</>
);
};
@@ -0,0 +1 @@
export { InfrastructureIntegrationSection } from "./InfrastructureIntegrationSection";
@@ -137,7 +137,7 @@ export const IntegrationsSection = ({
"App"
}
/>
<div className="min-w-[8rem] max-w-[12rem] overflow-clip text-ellipsis whitespace-nowrap rounded-md border border-mineshaft-700 bg-mineshaft-900 px-3 py-2 font-inter text-sm text-bunker-200">
<div className="min-w-[8rem] max-w-[12rem] overflow-scroll no-scrollbar no-scrollbar::-webkit-scrollbar whitespace-nowrap rounded-md border border-mineshaft-700 bg-mineshaft-900 px-3 py-2 font-inter text-sm text-bunker-200">
{(integration.integration === "hashicorp-vault" &&
`${integration.app} - path: ${integration.path}`) ||
(integration.scope === "github-org" && `${integration.owner}`) ||
@@ -217,11 +217,12 @@ export const IntegrationsSection = ({
isOpen={popUp.deleteConfirmation.isOpen}
title={`Are you sure want to remove ${
(popUp?.deleteConfirmation.data as TIntegration)?.integration || " "
} integration for ${(popUp?.deleteConfirmation.data as TIntegration)?.app || " "}?`}
} integration for ${(popUp?.deleteConfirmation.data as TIntegration)?.app || "this project"}?`}
onChange={(isOpen) => handlePopUpToggle("deleteConfirmation", isOpen)}
deleteKey={
(popUp?.deleteConfirmation?.data as TIntegration)?.app ||
(popUp?.deleteConfirmation?.data as TIntegration)?.owner ||
(popUp?.deleteConfirmation?.data as TIntegration)?.path ||
""
}
onDeleteApproved={async () =>
@@ -34,6 +34,7 @@ import {
Tag,
Tooltip
} from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import {
ProjectPermissionActions,
ProjectPermissionSub,
@@ -115,6 +116,7 @@ const SpecificPrivilegeSecretForm = ({
});
const temporaryAccessField = privilegeForm.watch("temporaryAccess");
const selectedEnvironmentSlug = privilegeForm.watch("environmentSlug");
const isTemporary = temporaryAccessField?.isTemporary;
const isExpired =
temporaryAccessField.isTemporary &&
@@ -220,7 +222,12 @@ const SpecificPrivilegeSecretForm = ({
name="secretPath"
render={({ field }) => (
<FormControl label="Secret Path">
<Input {...field} isDisabled={isMemberEditDisabled} className="w-48" />
<SecretPathInput
{...field}
isDisabled={isMemberEditDisabled}
environment={selectedEnvironmentSlug}
containerClassName="w-48"
/>
</FormControl>
)}
/>
@@ -34,6 +34,7 @@ import {
Tag,
Tooltip
} from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import {
ProjectPermissionActions,
ProjectPermissionSub,
@@ -107,6 +108,7 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
});
const temporaryAccessField = privilegeForm.watch("temporaryAccess");
const selectedEnvironmentSlug = privilegeForm.watch("environmentSlug");
const isTemporary = temporaryAccessField?.isTemporary;
const isExpired =
temporaryAccessField.isTemporary &&
@@ -208,7 +210,12 @@ const SpecificPrivilegeSecretForm = ({ privilege }: { privilege: TProjectUserPri
name="secretPath"
render={({ field }) => (
<FormControl label="Secret Path">
<Input {...field} isDisabled={isMemberEditDisabled} className="w-48" />
<SecretPathInput
{...field}
isDisabled={isMemberEditDisabled}
containerClassName="w-48"
environment={selectedEnvironmentSlug}
/>
</FormControl>
)}
/>
@@ -20,6 +20,7 @@ import {
Select,
SelectItem
} from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { useWorkspace } from "@app/context";
import { useCreateSecretApprovalPolicy, useUpdateSecretApprovalPolicy } from "@app/hooks/api";
import { TSecretApprovalPolicy } from "@app/hooks/api/types";
@@ -59,13 +60,14 @@ export const SecretPolicyForm = ({
control,
handleSubmit,
reset,
watch,
formState: { isSubmitting }
} = useForm<TFormSchema>({
resolver: zodResolver(formSchema),
values: editValues ? { ...editValues, environment: editValues.environment.slug } : undefined
});
const { currentWorkspace } = useWorkspace();
const selectedEnvironment = watch("environment");
const environments = currentWorkspace?.environments || [];
useEffect(() => {
@@ -174,7 +176,11 @@ export const SecretPolicyForm = ({
name="secretPath"
render={({ field, fieldState: { error } }) => (
<FormControl label="Secret Path" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} value={field.value || ""} />
<SecretPathInput
{...field}
value={field.value || ""}
environment={selectedEnvironment}
/>
</FormControl>
)}
/>
@@ -4,15 +4,8 @@ import { AxiosError } from "axios";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import {
Button,
FormControl,
Input,
Modal,
ModalContent,
Select,
SelectItem
} from "@app/components/v2";
import { Button, FormControl, Modal, ModalContent, Select, SelectItem } from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { useWorkspace } from "@app/context";
import { useCreateSecretImport } from "@app/hooks/api";
@@ -50,12 +43,12 @@ export const CreateSecretImportForm = ({
handleSubmit,
control,
reset,
watch,
formState: { isSubmitting }
} = useForm<TFormSchema>({ resolver: zodResolver(typeSchema) });
const { currentWorkspace } = useWorkspace();
const environments = currentWorkspace?.environments || [];
const selectedEnvironment = watch("environment");
const { mutateAsync: createSecretImport } = useCreateSecretImport();
@@ -130,7 +123,7 @@ export const CreateSecretImportForm = ({
defaultValue="/"
render={({ field, fieldState: { error } }) => (
<FormControl label="Secret Path" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} />
<SecretPathInput {...field} environment={selectedEnvironment} />
</FormControl>
)}
/>
@@ -28,6 +28,7 @@ import {
Skeleton,
Tooltip
} from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { useDebounce } from "@app/hooks";
import { useGetProjectSecrets } from "@app/hooks/api";
@@ -76,7 +77,6 @@ export const CopySecretsFromBoard = ({
handleSubmit,
control,
watch,
register,
reset,
setValue,
formState: { isDirty }
@@ -192,9 +192,19 @@ export const CopySecretsFromBoard = ({
</FormControl>
)}
/>
<FormControl label="Secret Path" className="flex-grow" isRequired>
<Input {...register("secretPath")} placeholder="Provide a path, default is /" />
</FormControl>
<Controller
control={control}
name="secretPath"
render={({ field }) => (
<FormControl label="Secret Path" className="flex-grow" isRequired>
<SecretPathInput
{...field}
placeholder="Provide a path, default is /"
environment={selectedEnvSlug}
/>
</FormControl>
)}
/>
</div>
<div className="border-t border-mineshaft-600 pt-4">
<div className="mb-4 flex items-center justify-between">
@@ -3,6 +3,7 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { Button, FormControl, Input, Select, SelectItem, Spinner } from "@app/components/v2";
import { SecretPathInput } from "@app/components/v2/SecretPathInput";
import { useWorkspace } from "@app/context";
import { useGetProjectSecrets, useGetUserWsKey } from "@app/hooks/api";
@@ -78,7 +79,7 @@ export const RotationOutputForm = ({ onSubmit, onCancel, outputSchema = {} }: Pr
defaultValue="/"
render={({ field }) => (
<FormControl className="capitalize" label="Secret path">
<Input {...field} />
<SecretPathInput {...field} environment={environment} />
</FormControl>
)}
/>