Merge branch 'main' into ENG-3674

This commit is contained in:
x032205
2025-09-10 17:32:30 -04:00
128 changed files with 5774 additions and 563 deletions
@@ -1,6 +1,7 @@
import { FunctionComponent, ReactNode } from "react";
import { BoundCanProps, Can } from "@casl/react";
import { TooltipProps } from "@app/components/v2/Tooltip/Tooltip";
import { TOrgPermission, useOrgPermission } from "@app/context/OrgPermissionContext";
import { AccessRestrictedBanner, Tooltip } from "../v2";
@@ -20,6 +21,7 @@ type Props = {
renderTooltip?: boolean;
allowedLabel?: string;
renderGuardBanner?: boolean;
tooltipProps?: Omit<TooltipProps, "children">;
} & BoundCanProps<TOrgPermission>;
export const OrgPermissionCan: FunctionComponent<Props> = ({
@@ -29,6 +31,7 @@ export const OrgPermissionCan: FunctionComponent<Props> = ({
renderTooltip,
allowedLabel,
renderGuardBanner,
tooltipProps,
...props
}) => {
const { permission } = useOrgPermission();
@@ -43,11 +46,19 @@ export const OrgPermissionCan: FunctionComponent<Props> = ({
: children;
if (!isAllowed && passThrough) {
return <Tooltip content={label}>{finalChild}</Tooltip>;
return (
<Tooltip content={label} {...tooltipProps}>
{finalChild}
</Tooltip>
);
}
if (isAllowed && renderTooltip && allowedLabel) {
return <Tooltip content={allowedLabel}>{finalChild}</Tooltip>;
return (
<Tooltip content={allowedLabel} {...tooltipProps}>
{finalChild}
</Tooltip>
);
}
if (!isAllowed && renderGuardBanner) {
@@ -34,7 +34,9 @@ const syntaxHighlight = (content?: string | null, isVisible?: boolean, isImport?
// akhilmhdh: Dont remove this br. I am still clueless how this works but weirdly enough
// when break is added a line break works properly
return formattedContent.concat(<br key={`secret-value-${formattedContent.length + 1}`} />);
return formattedContent.concat(
<br key={`secret-value-linebreak-${formattedContent.length + 1}`} />
);
};
type Props = TextareaHTMLAttributes<HTMLTextAreaElement> & {
@@ -3,7 +3,7 @@ import { useRouteContext } from "@tanstack/react-router";
import { fetchOrgSubscription, subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
export const useSubscription = () => {
export const useSubscription = (refreshCache?: boolean) => {
const organizationId = useRouteContext({
from: "/_authenticate/_inject-org-details",
select: (el) => el.organizationId
@@ -11,7 +11,7 @@ export const useSubscription = () => {
const { data: subscription } = useSuspenseQuery({
queryKey: subscriptionQueryKeys.getOrgSubsription(organizationId),
queryFn: () => fetchOrgSubscription(organizationId),
queryFn: () => fetchOrgSubscription(organizationId, refreshCache),
staleTime: Infinity
});
@@ -0,0 +1 @@
export * from "./mutations";
@@ -0,0 +1,17 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { gatewaysQueryKeys } from "../gateways/queries";
export const useDeleteGatewayV2ById = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id: string) => {
return apiRequest.delete(`/api/v2/gateways/${id}`);
},
onSuccess: () => {
queryClient.invalidateQueries(gatewaysQueryKeys.list());
}
});
};
@@ -0,0 +1,12 @@
export type TGatewayV2 = {
id: string;
identityId: string;
name: string;
createdAt: string;
updatedAt: string;
heartbeat: string;
identity: {
name: string;
id: string;
};
};
+16 -2
View File
@@ -2,6 +2,7 @@ import { queryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { TGatewayV2 } from "../gateways-v2/types";
import { TGateway } from "./types";
export const gatewaysQueryKeys = {
@@ -11,8 +12,21 @@ export const gatewaysQueryKeys = {
queryOptions({
queryKey: gatewaysQueryKeys.listKey(),
queryFn: async () => {
const { data } = await apiRequest.get<{ gateways: TGateway[] }>("/api/v1/gateways");
return data.gateways;
const [{ data }, { data: dataV2 }] = await Promise.all([
apiRequest.get<{ gateways: TGateway[] }>("/api/v1/gateways"),
apiRequest.get<TGatewayV2[]>("/api/v2/gateways")
]);
return [
...data.gateways.map((g) => ({
...g,
isV1: true
})),
...dataV2.map((g) => ({
...g,
isV1: false
}))
];
}
})
};
@@ -10,9 +10,9 @@ export const subscriptionQueryKeys = {
getOrgSubsription: (orgID: string) => ["plan", { orgID }] as const
};
export const fetchOrgSubscription = async (orgID: string) => {
export const fetchOrgSubscription = async (orgID: string, refreshCache: boolean = false) => {
const { data } = await apiRequest.get<{ plan: SubscriptionPlan }>(
`/api/v1/organizations/${orgID}/plan`
`/api/v1/organizations/${orgID}/plan${refreshCache ? "?refreshCache=true" : ""}`
);
return data.plan;
@@ -54,5 +54,7 @@ export type SubscriptionPlan = {
secretScanning: boolean;
enterpriseSecretSyncs: boolean;
enterpriseAppConnections: boolean;
cardDeclined?: boolean;
cardDeclinedReason?: string;
machineIdentityAuthTemplates: boolean;
};
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons";
import { faCircleQuestion, faUserCircle } from "@fortawesome/free-regular-svg-icons";
import {
@@ -8,6 +8,7 @@ import {
faCaretDown,
faCheck,
faEnvelope,
faExclamationTriangle,
faInfo,
faInfoCircle,
faServer,
@@ -111,6 +112,14 @@ export const Navbar = () => {
const { subscription } = useSubscription();
const { currentOrg } = useOrganization();
const [showAdminsModal, setShowAdminsModal] = useState(false);
const [showCardDeclinedModal, setShowCardDeclinedModal] = useState(false);
useEffect(() => {
if (subscription?.cardDeclined && !sessionStorage.getItem("paymentFailed")) {
sessionStorage.setItem("paymentFailed", "true");
setShowCardDeclinedModal(true);
}
}, [subscription]);
const { data: orgs } = useGetOrganizations();
const navigate = useNavigate();
@@ -222,6 +231,19 @@ export const Navbar = () => {
<div className="mr-1 rounded border border-mineshaft-500 px-1 text-xs text-bunker-300 !no-underline">
{getPlan(subscription)}
</div>
{subscription.cardDeclined && (
<Tooltip
content={`Your payment could not be processed${subscription.cardDeclinedReason ? `: ${subscription.cardDeclinedReason}` : ""}. Please update your payment method to continue enjoying premium features.`}
className="max-w-xs"
>
<div className="flex items-center">
<FontAwesomeIcon
icon={faExclamationTriangle}
className="animate-pulse cursor-help text-xs text-primary-400"
/>
</div>
</Tooltip>
)}
</div>
</Link>
<DropdownMenuTrigger asChild>
@@ -428,6 +450,49 @@ export const Navbar = () => {
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<Modal isOpen={showCardDeclinedModal} onOpenChange={setShowCardDeclinedModal}>
<ModalContent
title={
<div className="flex items-center gap-2">
<FontAwesomeIcon icon={faExclamationTriangle} className="text-lg text-primary-400" />
Your payment could not be processed.
</div>
}
>
<div>
<div>
<div className="mb-1">
<p>
We were unable to process your last payment
{subscription.cardDeclinedReason ? `: ${subscription.cardDeclinedReason}` : ""}.
Please update your payment information to continue using premium features.
</p>
</div>
<div className="mt-4">
<div className="flex space-x-3">
<Link to="/organization/billing" className="inline-flex">
<Button
colorSchema="primary"
variant="solid"
onClick={() => setShowCardDeclinedModal(false)}
>
Update Payment Method
</Button>
<Button
colorSchema="secondary"
variant="outline"
className="ml-2"
onClick={() => setShowCardDeclinedModal(false)}
>
Dismiss
</Button>
</Link>
</div>
</div>
</div>
</div>
</ModalContent>
</Modal>
<Modal isOpen={showAdminsModal} onOpenChange={setShowAdminsModal}>
<ModalContent title="Server Administrators" subTitle="View all server administrators">
<div className="mb-2">
@@ -1,5 +1,7 @@
import { useEffect } from "react";
import { faArrowUpRightFromSquare } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useQueryClient } from "@tanstack/react-query";
import { OrgPermissionCan } from "@app/components/permissions";
import { Button } from "@app/components/v2";
@@ -15,13 +17,15 @@ import {
useGetOrgPlanBillingInfo,
useGetOrgTrialUrl
} from "@app/hooks/api";
import { subscriptionQueryKeys } from "@app/hooks/api/subscriptions/queries";
import { usePopUp } from "@app/hooks/usePopUp";
import { ManagePlansModal } from "./ManagePlansModal";
export const PreviewSection = () => {
const { currentOrg } = useOrganization();
const { subscription } = useSubscription();
const { subscription } = useSubscription(true);
const queryClient = useQueryClient();
const { data, isPending } = useGetOrgPlanBillingInfo(currentOrg?.id ?? "");
const getOrgTrialUrl = useGetOrgTrialUrl();
const createCustomerPortalSession = useCreateCustomerPortalSession();
@@ -37,6 +41,12 @@ export const PreviewSection = () => {
return formattedTotal;
};
useEffect(() => {
queryClient.invalidateQueries({
queryKey: subscriptionQueryKeys.getOrgSubsription(currentOrg?.id ?? "")
});
}, []);
const formatDate = (date: number) => {
const createdDate = new Date(date * 1000);
const day: number = createdDate.getDate();
@@ -14,7 +14,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useQuery } from "@tanstack/react-query";
import { format, formatRelative } from "date-fns";
import { formatRelative } from "date-fns";
import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
@@ -48,13 +48,14 @@ import {
import { withPermission } from "@app/hoc";
import { usePopUp } from "@app/hooks";
import { gatewaysQueryKeys, useDeleteGatewayById } from "@app/hooks/api/gateways";
import { useDeleteGatewayV2ById } from "@app/hooks/api/gateways-v2";
import { EditGatewayDetailsModal } from "./components/EditGatewayDetailsModal";
export const GatewayListPage = withPermission(
() => {
const [search, setSearch] = useState("");
const { data: gateways, isPending: isGatewayLoading } = useQuery(gatewaysQueryKeys.list());
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
const { popUp, handlePopUpOpen, handlePopUpToggle } = usePopUp([
"deleteGateway",
@@ -62,16 +63,20 @@ export const GatewayListPage = withPermission(
] as const);
const deleteGatewayById = useDeleteGatewayById();
const deleteGatewayV2ById = useDeleteGatewayV2ById();
const handleDeleteGateway = async () => {
await deleteGatewayById.mutateAsync((popUp.deleteGateway.data as { id: string }).id, {
onSuccess: () => {
handlePopUpToggle("deleteGateway");
createNotification({
type: "success",
text: "Successfully delete gateway"
});
}
const data = popUp.deleteGateway.data as { id: string; isV1: boolean };
if (data.isV1) {
await deleteGatewayById.mutateAsync(data.id);
} else {
await deleteGatewayV2ById.mutateAsync(data.id);
}
handlePopUpToggle("deleteGateway");
createNotification({
type: "success",
text: "Successfully deleted gateway"
});
};
@@ -127,7 +132,6 @@ export const GatewayListPage = withPermission(
<THead>
<Tr>
<Th className="w-1/3">Name</Th>
<Th>Cert Issued At</Th>
<Th>Identity</Th>
<Th>
Health Check
@@ -143,13 +147,19 @@ export const GatewayListPage = withPermission(
</Tr>
</THead>
<TBody>
{isGatewayLoading && (
{isGatewaysLoading && (
<TableSkeleton innerKey="gateway-table" columns={4} key="gateway-table" />
)}
{filteredGateway?.map((el) => (
<Tr key={el.id}>
<Td>{el.name}</Td>
<Td>{format(new Date(el.issuedAt), "yyyy-MM-dd hh:mm:ss aaa")}</Td>
<Td>
<div className="flex items-center gap-2">
<span>{el.name}</span>
<span className="rounded bg-mineshaft-700 px-1.5 py-0.5 text-xs text-mineshaft-400">
Gateway v{el.isV1 ? "1" : "2"}
</span>
</div>
</Td>
<Td>{el.identity.name}</Td>
<Td>
{el.heartbeat
@@ -176,20 +186,22 @@ export const GatewayListPage = withPermission(
>
Copy ID
</DropdownMenuItem>
<OrgPermissionCan
I={OrgGatewayPermissionActions.EditGateways}
a={OrgPermissionSubjects.Gateway}
>
{(isAllowed: boolean) => (
<DropdownMenuItem
isDisabled={!isAllowed}
icon={<FontAwesomeIcon icon={faEdit} />}
onClick={() => handlePopUpOpen("editDetails", el)}
>
Edit Details
</DropdownMenuItem>
)}
</OrgPermissionCan>
{el.isV1 && (
<OrgPermissionCan
I={OrgGatewayPermissionActions.EditGateways}
a={OrgPermissionSubjects.Gateway}
>
{(isAllowed: boolean) => (
<DropdownMenuItem
isDisabled={!isAllowed}
icon={<FontAwesomeIcon icon={faEdit} />}
onClick={() => handlePopUpOpen("editDetails", el)}
>
Edit Details
</DropdownMenuItem>
)}
</OrgPermissionCan>
)}
<OrgPermissionCan
I={OrgPermissionAppConnectionActions.Delete}
a={OrgPermissionSubjects.AppConnections}
@@ -224,7 +236,7 @@ export const GatewayListPage = withPermission(
/>
</ModalContent>
</Modal>
{!isGatewayLoading && !filteredGateway?.length && (
{!isGatewaysLoading && !filteredGateway?.length && (
<EmptyState
title={
gateways?.length
@@ -251,8 +263,5 @@ export const GatewayListPage = withPermission(
</div>
);
},
{
action: OrgPermissionAppConnectionActions.Read,
subject: OrgPermissionSubjects.AppConnections
}
{ action: OrgGatewayPermissionActions.ListGateways, subject: OrgPermissionSubjects.Gateway }
);
@@ -24,11 +24,17 @@ enum EnforceAuthType {
export const OrgGeneralAuthSection = ({
isSamlConfigured,
isOidcConfigured,
isGoogleConfigured
isGoogleConfigured,
isSamlActive,
isOidcActive,
isLdapActive
}: {
isSamlConfigured: boolean;
isOidcConfigured: boolean;
isGoogleConfigured: boolean;
isSamlActive: boolean;
isOidcActive: boolean;
isLdapActive: boolean;
}) => {
const { currentOrg } = useOrganization();
const { subscription } = useSubscription();
@@ -126,6 +132,15 @@ export const OrgGeneralAuthSection = ({
}
};
const isGoogleOAuthEnforced = currentOrg.googleSsoAuthEnforced;
const getActiveSsoLabel = () => {
if (isSamlActive) return "SAML";
if (isOidcActive) return "OIDC";
if (isLdapActive) return "LDAP";
return "";
};
return (
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
<div>
@@ -135,7 +150,7 @@ export const OrgGeneralAuthSection = ({
</p>
</div>
<div className="flex flex-col gap-2 py-4">
<div className={twMerge("mt-4", !isSamlConfigured && "hidden")}>
<div className={twMerge("mt-4", (!isSamlConfigured || isGoogleOAuthEnforced) && "hidden")}>
<div className="mb-2 flex justify-between">
<div className="flex items-center gap-1">
<span className="text-md text-mineshaft-100">Enforce SAML SSO</span>
@@ -160,7 +175,7 @@ export const OrgGeneralAuthSection = ({
</p>
</div>
<div className={twMerge("mt-4", !isOidcConfigured && "hidden")}>
<div className={twMerge("mt-4", (!isOidcConfigured || isGoogleOAuthEnforced) && "hidden")}>
<div className="mb-2 flex justify-between">
<div className="flex items-center gap-1">
<span className="text-md text-mineshaft-100">Enforce OIDC SSO</span>
@@ -188,26 +203,47 @@ export const OrgGeneralAuthSection = ({
<div className={twMerge("mt-2", !isGoogleConfigured && "hidden")}>
<div className="mb-2 flex justify-between">
<div className="flex items-center gap-1">
<span className="text-md text-mineshaft-100">Enforce Google SSO</span>
<span className="text-md text-mineshaft-100">Enforce Google OAuth</span>
</div>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Sso}>
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.Sso}
tooltipProps={{
className: "max-w-sm",
side: "left"
}}
allowedLabel={
isOidcActive || isSamlActive || isLdapActive
? `You cannot enforce Google OAuth while ${getActiveSsoLabel()} SSO is enabled. Disable ${getActiveSsoLabel()} SSO to enforce Google OAuth.`
: undefined
}
renderTooltip={isOidcActive || isSamlActive || isLdapActive}
>
{(isAllowed) => (
<Switch
id="enforce-google-sso"
onCheckedChange={(value) =>
handleEnforceOrgAuthToggle(value, EnforceAuthType.GOOGLE)
}
isChecked={currentOrg?.googleSsoAuthEnforced ?? false}
isDisabled={!isAllowed || currentOrg?.authEnforced}
/>
<div>
<Switch
id="enforce-google-sso"
onCheckedChange={(value) =>
handleEnforceOrgAuthToggle(value, EnforceAuthType.GOOGLE)
}
isChecked={currentOrg?.googleSsoAuthEnforced ?? false}
isDisabled={
!isAllowed ||
currentOrg?.authEnforced ||
isOidcActive ||
isSamlActive ||
isLdapActive
}
/>
</div>
)}
</OrgPermissionCan>
</div>
<p className="text-sm text-mineshaft-300">
Enforce users to authenticate via Google OAuth SSO to access this organization.
Enforce users to authenticate via Google OAuth to access this organization.
<br />
When this is enabled your organization members will only be able to login with Google
SSO (not Google SAML).
OAuth (not Google SAML).
</p>
</div>
</div>
@@ -267,8 +303,8 @@ export const OrgGeneralAuthSection = ({
</div>
<p className="text-sm text-mineshaft-300">
<span>
Allow organization admins to bypass SAML enforcement when SSO is unavailable,
misconfigured, or inaccessible.
Allow organization admins to bypass SSO login enforcement when your SSO provider is
unavailable, misconfigured, or inaccessible.
</span>
</p>
</div>
@@ -94,6 +94,8 @@ export const OrgLDAPSection = (): JSX.Element => {
handlePopUpOpen("ldapGroupMap");
};
const isGoogleOAuthEnabled = currentOrg.googleSsoAuthEnforced;
return (
<div className="mb-4">
<div className="py-4">
@@ -116,16 +118,31 @@ export const OrgLDAPSection = (): JSX.Element => {
<div className="pt-4">
<div className="mb-2 flex items-center justify-between">
<h2 className="text-md text-mineshaft-100">Enable LDAP</h2>
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Ldap}>
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.Ldap}
tooltipProps={{
className: "max-w-sm",
side: "left"
}}
allowedLabel={
isGoogleOAuthEnabled
? "You cannot enable LDAP SSO while Google OAuth is enforced. Disable Google OAuth enforcement to enable LDAP SSO."
: undefined
}
renderTooltip={isGoogleOAuthEnabled}
>
{(isAllowed) => (
<Switch
id="enable-saml-sso"
onCheckedChange={(value) => handleLDAPToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed}
>
Enable
</Switch>
<div>
<Switch
id="enable-ldap-sso"
onCheckedChange={(value) => handleLDAPToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed || isGoogleOAuthEnabled}
>
Enable
</Switch>
</div>
)}
</OrgPermissionCan>
</div>
@@ -83,6 +83,8 @@ export const OrgOIDCSection = (): JSX.Element => {
}
};
const isGoogleOAuthEnabled = currentOrg.googleSsoAuthEnforced;
return (
<div className="mb-4 rounded-lg border-mineshaft-600 bg-mineshaft-900">
<div className="mb-4 flex items-center justify-between">
@@ -106,14 +108,29 @@ export const OrgOIDCSection = (): JSX.Element => {
<div className="mb-2 flex items-center justify-between">
<h2 className="text-md text-mineshaft-100">Enable OIDC</h2>
{!isPending && (
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Sso}>
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.Sso}
tooltipProps={{
className: "max-w-sm",
side: "left"
}}
allowedLabel={
isGoogleOAuthEnabled
? "You cannot enable OIDC SSO while Google OAuth is enforced. Disable Google OAuth enforcement to enable OIDC SSO."
: undefined
}
renderTooltip={isGoogleOAuthEnabled}
>
{(isAllowed) => (
<Switch
id="enable-oidc-sso"
onCheckedChange={(value) => handleOIDCToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed}
/>
<div>
<Switch
id="enable-oidc-sso"
onCheckedChange={(value) => handleOIDCToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed || isGoogleOAuthEnabled}
/>
</div>
)}
</OrgPermissionCan>
)}
@@ -78,6 +78,8 @@ export const OrgSSOSection = (): JSX.Element => {
}
};
const isGoogleOAuthEnabled = currentOrg.googleSsoAuthEnforced;
return (
<div className="space-y-4">
<div className="mb-4 flex items-center justify-between">
@@ -99,14 +101,29 @@ export const OrgSSOSection = (): JSX.Element => {
<div className="mb-2 flex items-center justify-between pt-4">
<h2 className="text-md text-mineshaft-100">Enable SAML</h2>
{!isPending && (
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Sso}>
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.Sso}
tooltipProps={{
className: "max-w-sm",
side: "left"
}}
allowedLabel={
isGoogleOAuthEnabled
? "You cannot enable SAML SSO while Google OAuth is enforced. Disable Google OAuth enforcement to enable SAML SSO."
: undefined
}
renderTooltip={isGoogleOAuthEnabled}
>
{(isAllowed) => (
<Switch
id="enable-saml-sso"
onCheckedChange={(value) => handleSamlSSOToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed}
/>
<div>
<Switch
id="enable-saml-sso"
onCheckedChange={(value) => handleSamlSSOToggle(value)}
isChecked={data ? data.isActive : false}
isDisabled={!isAllowed || isGoogleOAuthEnabled}
/>
</div>
)}
</OrgPermissionCan>
)}
@@ -184,6 +184,9 @@ export const OrgSsoTab = withPermission(
isSamlConfigured={isSamlConfigured}
isOidcConfigured={isOidcConfigured}
isGoogleConfigured={isGoogleConfigured}
isSamlActive={Boolean(samlConfig?.isActive)}
isOidcActive={Boolean(oidcConfig?.isActive)}
isLdapActive={Boolean(ldapConfig?.isActive)}
/>
)}
@@ -19,6 +19,7 @@ import {
SecretInput,
Select,
SelectItem,
Switch,
TextArea,
Tooltip
} from "@app/components/v2";
@@ -66,6 +67,7 @@ const formSchema = z.object({
creationStatement: z.string().min(1),
revocationStatement: z.string().min(1),
renewStatement: z.string().optional(),
sslEnabled: z.boolean().optional(),
ca: z.string().optional(),
gatewayId: z.string().optional()
}),
@@ -200,6 +202,7 @@ export const SqlDatabaseInputForm = ({
const createDynamicSecret = useCreateDynamicSecret();
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
const selectedClient = watch("provider.client");
const handleCreateDynamicSecret = async ({
name,
@@ -458,13 +461,34 @@ export const SqlDatabaseInputForm = ({
/>
</div>
<div>
{selectedClient === SqlProviders.MsSQL && (
<div className="mb-2 mt-2">
<Controller
control={control}
name="provider.sslEnabled"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
<Switch
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
id="sql-ds-ssl-enabled"
thumbClassName="bg-mineshaft-800"
isChecked={value}
onCheckedChange={onChange}
>
Encrypt Connection (SSL)
</Switch>
</FormControl>
)}
/>
</div>
)}
<Controller
control={control}
name="provider.ca"
render={({ field, fieldState: { error } }) => (
<FormControl
isOptional
label="CA(SSL)"
label="CA (SSL)"
isError={Boolean(error?.message)}
errorText={error?.message}
>
@@ -18,6 +18,7 @@ import {
SecretInput,
Select,
SelectItem,
Switch,
TextArea,
Tooltip
} from "@app/components/v2";
@@ -63,6 +64,7 @@ const formSchema = z.object({
creationStatement: z.string().min(1),
revocationStatement: z.string().min(1),
renewStatement: z.string().optional(),
sslEnabled: z.boolean().optional(),
ca: z.string().optional(),
gatewayId: z.string().optional().nullable()
})
@@ -151,6 +153,7 @@ export const EditDynamicSecretSqlProviderForm = ({
});
const { data: gateways, isPending: isGatewaysLoading } = useQuery(gatewaysQueryKeys.list());
const selectedClient = watch("inputs.client");
const updateDynamicSecret = useUpdateDynamicSecret();
const selectedGatewayId = watch("inputs.gatewayId");
@@ -407,13 +410,34 @@ export const EditDynamicSecretSqlProviderForm = ({
/>
</div>
<div>
{selectedClient === SqlProviders.MsSQL && (
<div className="mb-2 mt-2">
<Controller
control={control}
name="inputs.sslEnabled"
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl isError={Boolean(error?.message)} errorText={error?.message}>
<Switch
className="bg-mineshaft-400/50 shadow-inner data-[state=checked]:bg-green/80"
id="sql-ds-ssl-enabled"
thumbClassName="bg-mineshaft-800"
isChecked={Boolean(value)}
onCheckedChange={onChange}
>
Encrypt Connection (SSL)
</Switch>
</FormControl>
)}
/>
</div>
)}
<Controller
control={control}
name="inputs.ca"
render={({ field, fieldState: { error } }) => (
<FormControl
isOptional
label="CA(SSL)"
label="CA (SSL)"
isError={Boolean(error?.message)}
errorText={error?.message}
>