Merge branch 'main' into ENG-3506

This commit is contained in:
x032205
2025-08-27 04:10:12 -04:00
181 changed files with 7268 additions and 1288 deletions
@@ -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>
);
};
+1
View File
@@ -0,0 +1 @@
export * from "./RoleOption";
@@ -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>
)}
/>
)}
</>
);
};
@@ -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)
})
])
})