mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 09:30:09 +00:00
Merge branch 'main' into ENG-3506
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faArrowUpRightFromSquare, faQuestionCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { FormLabel, Tooltip } from "../v2";
|
||||
@@ -10,15 +10,18 @@ export const TtlFormLabel = ({ label }: { label: string }) => (
|
||||
label={label}
|
||||
icon={
|
||||
<Tooltip
|
||||
className="max-w-lg"
|
||||
content={
|
||||
<span>
|
||||
Examples: 30m, 1h, 3d, etc.{" "}
|
||||
<a
|
||||
href="https://github.com/vercel/ms?tab=readme-ov-file#examples"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary-700"
|
||||
className="text-primary-500 hover:text-mineshaft-100"
|
||||
>
|
||||
More
|
||||
See More Examples{" "}
|
||||
<FontAwesomeIcon size="xs" className="mt-0.5" icon={faArrowUpRightFromSquare} />
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
@@ -26,7 +29,7 @@ export const TtlFormLabel = ({ label }: { label: string }) => (
|
||||
<FontAwesomeIcon
|
||||
icon={faQuestionCircle}
|
||||
size="sm"
|
||||
className="relative bottom-px right-1"
|
||||
className="relative right-1 mt-0.5 text-mineshaft-300"
|
||||
/>
|
||||
</Tooltip>
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { components, OptionProps } from "react-select";
|
||||
import { faCheckCircle } from "@fortawesome/free-regular-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
export const RoleOption = ({
|
||||
isSelected,
|
||||
children,
|
||||
...props
|
||||
}: OptionProps<{ name: string; slug: string; description?: string | undefined }>) => {
|
||||
return (
|
||||
<components.Option isSelected={isSelected} {...props}>
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
<div>
|
||||
<p className="truncate">{children}</p>
|
||||
{props.data.description ? (
|
||||
<p className="truncate text-xs leading-4 text-mineshaft-400">
|
||||
{props.data.description}
|
||||
</p>
|
||||
) : (
|
||||
<p className="text-xs leading-4 text-mineshaft-400/50">No Description</p>
|
||||
)}
|
||||
</div>
|
||||
{isSelected && (
|
||||
<FontAwesomeIcon className="ml-2 text-primary" icon={faCheckCircle} size="sm" />
|
||||
)}
|
||||
</div>
|
||||
</components.Option>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./RoleOption";
|
||||
+70
-24
@@ -5,7 +5,9 @@ import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/Se
|
||||
import { FilterableSelect, FormControl, Select, SelectItem } from "@app/components/v2";
|
||||
import { RENDER_SYNC_SCOPES } from "@app/helpers/secretSyncs";
|
||||
import {
|
||||
TRenderEnvironmentGroup,
|
||||
TRenderService,
|
||||
useRenderConnectionListEnvironmentGroups,
|
||||
useRenderConnectionListServices
|
||||
} from "@app/hooks/api/appConnections/render";
|
||||
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||
@@ -19,6 +21,7 @@ export const RenderSyncFields = () => {
|
||||
>();
|
||||
|
||||
const connectionId = useWatch({ name: "connection.id", control });
|
||||
const selectedScope = useWatch({ name: "destinationConfig.scope", control });
|
||||
|
||||
const { data: services = [], isPending: isServicesPending } = useRenderConnectionListServices(
|
||||
connectionId,
|
||||
@@ -27,11 +30,17 @@ export const RenderSyncFields = () => {
|
||||
}
|
||||
);
|
||||
|
||||
const { data: groups = [], isPending: isGroupsPending } =
|
||||
useRenderConnectionListEnvironmentGroups(connectionId, {
|
||||
enabled: Boolean(connectionId) && selectedScope === RenderSyncScope.EnvironmentGroup
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<SecretSyncConnectionField
|
||||
onChange={() => {
|
||||
setValue("destinationConfig.serviceId", "");
|
||||
setValue("destinationConfig.environmentGroupId", "");
|
||||
setValue("destinationConfig.type", RenderSyncType.Env);
|
||||
setValue("destinationConfig.scope", RenderSyncScope.Service);
|
||||
}}
|
||||
@@ -83,30 +92,67 @@ export const RenderSyncFields = () => {
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<Controller
|
||||
name="destinationConfig.serviceId"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl errorText={error?.message} isError={Boolean(error?.message)} label="Service">
|
||||
<FilterableSelect
|
||||
isLoading={isServicesPending && Boolean(connectionId)}
|
||||
isDisabled={!connectionId}
|
||||
value={services ? (services.find((service) => service.id === value) ?? []) : []}
|
||||
onChange={(option) => {
|
||||
onChange((option as SingleValue<TRenderService>)?.id ?? null);
|
||||
setValue(
|
||||
"destinationConfig.serviceName",
|
||||
(option as SingleValue<TRenderService>)?.name ?? ""
|
||||
);
|
||||
}}
|
||||
options={services}
|
||||
placeholder="Select a service..."
|
||||
getOptionLabel={(option) => option.name}
|
||||
getOptionValue={(option) => option.id.toString()}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
{selectedScope === RenderSyncScope.Service && (
|
||||
<Controller
|
||||
name="destinationConfig.serviceId"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Service"
|
||||
>
|
||||
<FilterableSelect
|
||||
isLoading={isServicesPending && Boolean(connectionId)}
|
||||
isDisabled={!connectionId}
|
||||
value={services ? (services.find((service) => service.id === value) ?? []) : []}
|
||||
onChange={(option) => {
|
||||
onChange((option as SingleValue<TRenderService>)?.id ?? null);
|
||||
setValue(
|
||||
"destinationConfig.serviceName",
|
||||
(option as SingleValue<TRenderService>)?.name ?? ""
|
||||
);
|
||||
}}
|
||||
options={services}
|
||||
placeholder="Select a service..."
|
||||
getOptionLabel={(option) => option.name}
|
||||
getOptionValue={(option) => option.id.toString()}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
|
||||
{selectedScope === RenderSyncScope.EnvironmentGroup && (
|
||||
<Controller
|
||||
name="destinationConfig.environmentGroupId"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
errorText={error?.message}
|
||||
isError={Boolean(error?.message)}
|
||||
label="Environment Group"
|
||||
>
|
||||
<FilterableSelect
|
||||
isLoading={isGroupsPending && Boolean(connectionId)}
|
||||
isDisabled={!connectionId}
|
||||
value={groups ? (groups.find((g) => g.id === value) ?? []) : []}
|
||||
onChange={(option) => {
|
||||
onChange((option as SingleValue<TRenderEnvironmentGroup>)?.id ?? null);
|
||||
setValue(
|
||||
"destinationConfig.environmentGroupName",
|
||||
(option as SingleValue<TRenderEnvironmentGroup>)?.name ?? ""
|
||||
);
|
||||
}}
|
||||
options={groups}
|
||||
placeholder="Select an environment group..."
|
||||
getOptionLabel={(option) => option.name}
|
||||
getOptionValue={(option) => option.id.toString()}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+12
-4
@@ -4,6 +4,7 @@ import { GenericFieldLabel } from "@app/components/secret-syncs";
|
||||
import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas";
|
||||
import { Badge } from "@app/components/v2";
|
||||
import { SecretSync } from "@app/hooks/api/secretSyncs";
|
||||
import { RenderSyncScope } from "@app/hooks/api/secretSyncs/types/render-sync";
|
||||
|
||||
export const RenderSyncOptionsReviewFields = () => {
|
||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Render }>();
|
||||
@@ -27,13 +28,20 @@ export const RenderSyncOptionsReviewFields = () => {
|
||||
|
||||
export const RenderSyncReviewFields = () => {
|
||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.Render }>();
|
||||
const serviceName = watch("destinationConfig.serviceName");
|
||||
const scope = watch("destinationConfig.scope");
|
||||
const config = watch("destinationConfig");
|
||||
|
||||
return (
|
||||
<>
|
||||
<GenericFieldLabel label="Scope">{scope}</GenericFieldLabel>
|
||||
<GenericFieldLabel label="Service">{serviceName}</GenericFieldLabel>
|
||||
<GenericFieldLabel label="Scope">{config.scope}</GenericFieldLabel>
|
||||
{config.scope === RenderSyncScope.Service ? (
|
||||
<GenericFieldLabel label="Service">
|
||||
{config.serviceName ?? config.serviceId}
|
||||
</GenericFieldLabel>
|
||||
) : (
|
||||
<GenericFieldLabel label="Service">
|
||||
{config.environmentGroupName ?? config.environmentGroupId}
|
||||
</GenericFieldLabel>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,6 +17,12 @@ export const RenderSyncDestinationSchema = BaseSecretSyncSchema(
|
||||
serviceId: z.string().trim().min(1, "Service is required"),
|
||||
serviceName: z.string().trim().optional(),
|
||||
type: z.nativeEnum(RenderSyncType)
|
||||
}),
|
||||
z.object({
|
||||
scope: z.literal(RenderSyncScope.EnvironmentGroup),
|
||||
environmentGroupId: z.string().trim().min(1, "Environment Group ID is required"),
|
||||
environmentGroupName: z.string().trim().optional(),
|
||||
type: z.nativeEnum(RenderSyncType)
|
||||
})
|
||||
])
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user