mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Fix adding res and add missing forms
This commit is contained in:
@@ -67,10 +67,11 @@ export const executeWithGateway = async <T>(
|
|||||||
async (proxyPort) => {
|
async (proxyPort) => {
|
||||||
const protocol = url.protocol === "https:" ? "https" : "http";
|
const protocol = url.protocol === "https:" ? "https" : "http";
|
||||||
const baseUrl = `${protocol}://localhost:${proxyPort}`;
|
const baseUrl = `${protocol}://localhost:${proxyPort}`;
|
||||||
|
// const baseUrl = `http://localhost:${proxyPort}`;
|
||||||
return operation(baseUrl, httpsAgent);
|
return operation(baseUrl, httpsAgent);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
protocol: GatewayProxyProtocol.Http,
|
protocol: GatewayProxyProtocol.Tcp,
|
||||||
relayHost: platformConnectionDetails.relayHost,
|
relayHost: platformConnectionDetails.relayHost,
|
||||||
gateway: platformConnectionDetails.gateway,
|
gateway: platformConnectionDetails.gateway,
|
||||||
relay: platformConnectionDetails.relay,
|
relay: platformConnectionDetails.relay,
|
||||||
@@ -92,9 +93,6 @@ export const kubernetesResourceFactory: TPamResourceFactory<
|
|||||||
// Validate connection by checking API server version
|
// Validate connection by checking API server version
|
||||||
try {
|
try {
|
||||||
await axios.get(`${baseUrl}/version`, {
|
await axios.get(`${baseUrl}/version`, {
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json"
|
|
||||||
},
|
|
||||||
...(httpsAgent ? { httpsAgent } : {}),
|
...(httpsAgent ? { httpsAgent } : {}),
|
||||||
signal: AbortSignal.timeout(EXTERNAL_REQUEST_TIMEOUT),
|
signal: AbortSignal.timeout(EXTERNAL_REQUEST_TIMEOUT),
|
||||||
timeout: EXTERNAL_REQUEST_TIMEOUT
|
timeout: EXTERNAL_REQUEST_TIMEOUT
|
||||||
|
|||||||
@@ -6,17 +6,19 @@ import {
|
|||||||
PamResourceType,
|
PamResourceType,
|
||||||
PamSessionStatus
|
PamSessionStatus
|
||||||
} from "../enums";
|
} from "../enums";
|
||||||
|
import { TKubernetesAccount, TKubernetesResource } from "./kubernetes-resource";
|
||||||
import { TMySQLAccount, TMySQLResource } from "./mysql-resource";
|
import { TMySQLAccount, TMySQLResource } from "./mysql-resource";
|
||||||
import { TPostgresAccount, TPostgresResource } from "./postgres-resource";
|
import { TPostgresAccount, TPostgresResource } from "./postgres-resource";
|
||||||
import { TSSHAccount, TSSHResource } from "./ssh-resource";
|
import { TSSHAccount, TSSHResource } from "./ssh-resource";
|
||||||
|
|
||||||
|
export * from "./kubernetes-resource";
|
||||||
export * from "./mysql-resource";
|
export * from "./mysql-resource";
|
||||||
export * from "./postgres-resource";
|
export * from "./postgres-resource";
|
||||||
export * from "./ssh-resource";
|
export * from "./ssh-resource";
|
||||||
|
|
||||||
export type TPamResource = TPostgresResource | TMySQLResource | TSSHResource;
|
export type TPamResource = TPostgresResource | TMySQLResource | TSSHResource | TKubernetesResource;
|
||||||
|
|
||||||
export type TPamAccount = TPostgresAccount | TMySQLAccount | TSSHAccount;
|
export type TPamAccount = TPostgresAccount | TMySQLAccount | TSSHAccount | TKubernetesAccount;
|
||||||
|
|
||||||
export type TPamFolder = {
|
export type TPamFolder = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|||||||
35
frontend/src/hooks/api/pam/types/kubernetes-resource.ts
Normal file
35
frontend/src/hooks/api/pam/types/kubernetes-resource.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { PamResourceType } from "../enums";
|
||||||
|
import { TBasePamAccount } from "./base-account";
|
||||||
|
import { TBasePamResource } from "./base-resource";
|
||||||
|
|
||||||
|
export enum KubernetesAuthMethod {
|
||||||
|
ServiceAccountToken = "service-account-token"
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TKubernetesConnectionDetails = {
|
||||||
|
url: string;
|
||||||
|
namespace: string;
|
||||||
|
skipTLSVerify: boolean;
|
||||||
|
caCertificate?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TKubernetesServiceAccountTokenCredentials = {
|
||||||
|
authMethod: KubernetesAuthMethod.ServiceAccountToken;
|
||||||
|
serviceAccountName: string;
|
||||||
|
serviceAccountToken: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TKubernetesCredentials = TKubernetesServiceAccountTokenCredentials;
|
||||||
|
|
||||||
|
// Resources
|
||||||
|
export type TKubernetesResource = TBasePamResource & {
|
||||||
|
resourceType: PamResourceType.Kubernetes;
|
||||||
|
} & {
|
||||||
|
connectionDetails: TKubernetesConnectionDetails;
|
||||||
|
rotationAccountCredentials?: TKubernetesCredentials | null;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Accounts
|
||||||
|
export type TKubernetesAccount = TBasePamAccount & {
|
||||||
|
credentials: TKubernetesCredentials;
|
||||||
|
};
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { Button, ModalClose } from "@app/components/v2";
|
||||||
|
import { KubernetesAuthMethod, PamResourceType, TKubernetesResource } from "@app/hooks/api/pam";
|
||||||
|
import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants";
|
||||||
|
|
||||||
|
import { KubernetesResourceFields } from "./shared/KubernetesResourceFields";
|
||||||
|
import { KubernetesRotateAccountFields } from "./shared/KubernetesRotateAccountFields";
|
||||||
|
import { GenericResourceFields, genericResourceFieldsSchema } from "./GenericResourceFields";
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
resource?: TKubernetesResource;
|
||||||
|
onSubmit: (formData: FormData) => Promise<void>;
|
||||||
|
};
|
||||||
|
|
||||||
|
const KubernetesConnectionDetailsSchema = z.object({
|
||||||
|
url: z.string().url().trim().max(500),
|
||||||
|
namespace: z.string().trim().max(255),
|
||||||
|
skipTLSVerify: z.boolean(),
|
||||||
|
caCertificate: z.string().trim().max(10000).optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
const KubernetesServiceAccountTokenCredentialsSchema = z.object({
|
||||||
|
authMethod: z.literal(KubernetesAuthMethod.ServiceAccountToken),
|
||||||
|
serviceAccountName: z.string().trim().max(255),
|
||||||
|
serviceAccountToken: z.string().trim().max(10000)
|
||||||
|
});
|
||||||
|
|
||||||
|
const formSchema = genericResourceFieldsSchema.extend({
|
||||||
|
resourceType: z.literal(PamResourceType.Kubernetes),
|
||||||
|
connectionDetails: KubernetesConnectionDetailsSchema,
|
||||||
|
rotationAccountCredentials: KubernetesServiceAccountTokenCredentialsSchema.nullable().optional()
|
||||||
|
});
|
||||||
|
|
||||||
|
type FormData = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
|
export const KubernetesResourceForm = ({ resource, onSubmit }: Props) => {
|
||||||
|
const isUpdate = Boolean(resource);
|
||||||
|
|
||||||
|
const form = useForm<FormData>({
|
||||||
|
resolver: zodResolver(formSchema),
|
||||||
|
defaultValues: resource
|
||||||
|
? {
|
||||||
|
...resource,
|
||||||
|
rotationAccountCredentials: resource.rotationAccountCredentials
|
||||||
|
? {
|
||||||
|
...resource.rotationAccountCredentials,
|
||||||
|
serviceAccountToken: UNCHANGED_PASSWORD_SENTINEL
|
||||||
|
}
|
||||||
|
: resource.rotationAccountCredentials
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
resourceType: PamResourceType.Kubernetes,
|
||||||
|
connectionDetails: {
|
||||||
|
url: "",
|
||||||
|
namespace: "default",
|
||||||
|
skipTLSVerify: false,
|
||||||
|
caCertificate: undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
handleSubmit,
|
||||||
|
formState: { isSubmitting, isDirty }
|
||||||
|
} = form;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormProvider {...form}>
|
||||||
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
<GenericResourceFields />
|
||||||
|
<KubernetesResourceFields />
|
||||||
|
<KubernetesRotateAccountFields isUpdate={isUpdate} />
|
||||||
|
<div className="mt-6 flex items-center">
|
||||||
|
<Button
|
||||||
|
className="mr-4"
|
||||||
|
size="sm"
|
||||||
|
type="submit"
|
||||||
|
colorSchema="secondary"
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
isDisabled={isSubmitting || !isDirty}
|
||||||
|
>
|
||||||
|
{isUpdate ? "Update Details" : "Create Resource"}
|
||||||
|
</Button>
|
||||||
|
<ModalClose asChild>
|
||||||
|
<Button colorSchema="secondary" variant="plain">
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
</ModalClose>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</FormProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import { DiscriminativePick } from "@app/types";
|
import { DiscriminativePick } from "@app/types";
|
||||||
|
|
||||||
import { PamResourceHeader } from "../PamResourceHeader";
|
import { PamResourceHeader } from "../PamResourceHeader";
|
||||||
|
import { KubernetesResourceForm } from "./KubernetesResourceForm";
|
||||||
import { MySQLResourceForm } from "./MySQLResourceForm";
|
import { MySQLResourceForm } from "./MySQLResourceForm";
|
||||||
import { PostgresResourceForm } from "./PostgresResourceForm";
|
import { PostgresResourceForm } from "./PostgresResourceForm";
|
||||||
import { SSHResourceForm } from "./SSHResourceForm";
|
import { SSHResourceForm } from "./SSHResourceForm";
|
||||||
@@ -54,6 +55,8 @@ const CreateForm = ({ resourceType, onComplete, projectId }: CreateFormProps) =>
|
|||||||
return <MySQLResourceForm onSubmit={onSubmit} />;
|
return <MySQLResourceForm onSubmit={onSubmit} />;
|
||||||
case PamResourceType.SSH:
|
case PamResourceType.SSH:
|
||||||
return <SSHResourceForm onSubmit={onSubmit} />;
|
return <SSHResourceForm onSubmit={onSubmit} />;
|
||||||
|
case PamResourceType.Kubernetes:
|
||||||
|
return <KubernetesResourceForm onSubmit={onSubmit} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled resource: ${resourceType}`);
|
throw new Error(`Unhandled resource: ${resourceType}`);
|
||||||
}
|
}
|
||||||
@@ -84,6 +87,8 @@ const UpdateForm = ({ resource, onComplete }: UpdateFormProps) => {
|
|||||||
return <MySQLResourceForm resource={resource} onSubmit={onSubmit} />;
|
return <MySQLResourceForm resource={resource} onSubmit={onSubmit} />;
|
||||||
case PamResourceType.SSH:
|
case PamResourceType.SSH:
|
||||||
return <SSHResourceForm resource={resource} onSubmit={onSubmit} />;
|
return <SSHResourceForm resource={resource} onSubmit={onSubmit} />;
|
||||||
|
case PamResourceType.Kubernetes:
|
||||||
|
return <KubernetesResourceForm resource={resource} onSubmit={onSubmit} />;
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unhandled resource: ${(resource as any).resourceType}`);
|
throw new Error(`Unhandled resource: ${(resource as any).resourceType}`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import { Controller, useFormContext } from "react-hook-form";
|
||||||
|
|
||||||
|
import { FormControl, Input, Switch, TextArea } from "@app/components/v2";
|
||||||
|
|
||||||
|
export const KubernetesResourceFields = () => {
|
||||||
|
const { control, watch } = useFormContext();
|
||||||
|
|
||||||
|
const skipTLSVerify = watch("connectionDetails.skipTLSVerify");
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-4 rounded-sm border border-mineshaft-600 bg-mineshaft-700/70 p-3">
|
||||||
|
<div className="mt-[0.675rem] flex flex-col gap-4">
|
||||||
|
<Controller
|
||||||
|
name="connectionDetails.url"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Kubernetes API URL"
|
||||||
|
>
|
||||||
|
<Input placeholder="https://kubernetes.example.com:6443" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="connectionDetails.namespace"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Namespace"
|
||||||
|
>
|
||||||
|
<Input placeholder="default" {...field} />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="connectionDetails.skipTLSVerify"
|
||||||
|
control={control}
|
||||||
|
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="skip-tls-verify"
|
||||||
|
thumbClassName="bg-mineshaft-800"
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
>
|
||||||
|
Skip TLS Verification
|
||||||
|
</Switch>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="connectionDetails.caCertificate"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
className={skipTLSVerify ? "opacity-50" : ""}
|
||||||
|
label="CA Certificate"
|
||||||
|
isOptional
|
||||||
|
>
|
||||||
|
<TextArea
|
||||||
|
className="h-14 resize-none!"
|
||||||
|
{...field}
|
||||||
|
isDisabled={skipTLSVerify}
|
||||||
|
placeholder="-----BEGIN CERTIFICATE-----..."
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import { Controller, useFormContext, useWatch } from "react-hook-form";
|
||||||
|
|
||||||
|
import { FormControl, Input, Switch } from "@app/components/v2";
|
||||||
|
import { KubernetesAuthMethod } from "@app/hooks/api/pam";
|
||||||
|
import { UNCHANGED_PASSWORD_SENTINEL } from "@app/hooks/api/pam/constants";
|
||||||
|
|
||||||
|
export const KubernetesRotateAccountFields = ({ isUpdate }: { isUpdate: boolean }) => {
|
||||||
|
const { control, setValue, getValues } = useFormContext();
|
||||||
|
const [showToken, setShowToken] = useState(false);
|
||||||
|
|
||||||
|
const rotationServiceAccountName = useWatch({
|
||||||
|
control,
|
||||||
|
name: "rotationAccountCredentials.serviceAccountName"
|
||||||
|
});
|
||||||
|
const rotationServiceAccountToken = useWatch({
|
||||||
|
control,
|
||||||
|
name: "rotationAccountCredentials.serviceAccountToken"
|
||||||
|
});
|
||||||
|
|
||||||
|
const [enabled, setEnabled] = useState(false);
|
||||||
|
const [wasRotationTokenSentinelInitially, setWasRotationTokenSentinelInitially] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const initialRotationToken = getValues("rotationAccountCredentials.serviceAccountToken");
|
||||||
|
if (initialRotationToken === UNCHANGED_PASSWORD_SENTINEL) {
|
||||||
|
setWasRotationTokenSentinelInitially(true);
|
||||||
|
}
|
||||||
|
}, [getValues]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (rotationServiceAccountToken === UNCHANGED_PASSWORD_SENTINEL) {
|
||||||
|
setShowToken(false);
|
||||||
|
}
|
||||||
|
}, [rotationServiceAccountToken]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const isServiceAccountNamePopulated =
|
||||||
|
rotationServiceAccountName && rotationServiceAccountName !== "";
|
||||||
|
const isTokenPopulated =
|
||||||
|
rotationServiceAccountToken &&
|
||||||
|
rotationServiceAccountToken !== "" &&
|
||||||
|
rotationServiceAccountToken !== UNCHANGED_PASSWORD_SENTINEL;
|
||||||
|
|
||||||
|
if (isServiceAccountNamePopulated || isTokenPopulated) {
|
||||||
|
setEnabled(true);
|
||||||
|
}
|
||||||
|
}, [rotationServiceAccountName, rotationServiceAccountToken]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col gap-2">
|
||||||
|
<Switch
|
||||||
|
id="account-rotation"
|
||||||
|
onCheckedChange={(value) => {
|
||||||
|
setEnabled(value);
|
||||||
|
if (value) {
|
||||||
|
setValue(
|
||||||
|
"rotationAccountCredentials.authMethod",
|
||||||
|
KubernetesAuthMethod.ServiceAccountToken,
|
||||||
|
{
|
||||||
|
shouldDirty: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
setValue("rotationAccountCredentials.serviceAccountName", "", {
|
||||||
|
shouldDirty: true
|
||||||
|
});
|
||||||
|
setValue("rotationAccountCredentials.serviceAccountToken", "", {
|
||||||
|
shouldDirty: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setValue("rotationAccountCredentials", null, {
|
||||||
|
shouldDirty: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
isChecked={enabled}
|
||||||
|
containerClassName="flex-row-reverse w-fit"
|
||||||
|
className="ml-0"
|
||||||
|
>
|
||||||
|
<p className="ml-2">Credential Rotation</p>
|
||||||
|
</Switch>
|
||||||
|
|
||||||
|
{enabled && (
|
||||||
|
<>
|
||||||
|
<div className="flex gap-2">
|
||||||
|
<Controller
|
||||||
|
name="rotationAccountCredentials.serviceAccountName"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className="mb-0 flex-1"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Service Account Name"
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
|
<Input {...field} autoComplete="off" />
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
name="rotationAccountCredentials.serviceAccountToken"
|
||||||
|
control={control}
|
||||||
|
render={({ field, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
className="mb-0 flex-1"
|
||||||
|
errorText={error?.message}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
label="Service Account Token"
|
||||||
|
>
|
||||||
|
<div className="relative">
|
||||||
|
<Input
|
||||||
|
{...field}
|
||||||
|
type={showToken ? "text" : "password"}
|
||||||
|
autoComplete="new-password"
|
||||||
|
onFocus={() => {
|
||||||
|
if (isUpdate && field.value === UNCHANGED_PASSWORD_SENTINEL) {
|
||||||
|
field.onChange("");
|
||||||
|
}
|
||||||
|
setShowToken(true);
|
||||||
|
}}
|
||||||
|
onBlur={() => {
|
||||||
|
if (isUpdate && field.value === "" && wasRotationTokenSentinelInitially) {
|
||||||
|
field.onChange(UNCHANGED_PASSWORD_SENTINEL);
|
||||||
|
}
|
||||||
|
setShowToken(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="mb-2 text-xs text-mineshaft-400">
|
||||||
|
Credentials of the privileged service account which will be used for rotating other
|
||||||
|
accounts under this resource
|
||||||
|
</p>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -38,7 +38,6 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
|||||||
{ name: "Redis", resource: PamResourceType.Redis },
|
{ name: "Redis", resource: PamResourceType.Redis },
|
||||||
{ name: "RDP", resource: PamResourceType.RDP },
|
{ name: "RDP", resource: PamResourceType.RDP },
|
||||||
{ name: "SSH", resource: PamResourceType.SSH },
|
{ name: "SSH", resource: PamResourceType.SSH },
|
||||||
{ name: "Kubernetes", resource: PamResourceType.Kubernetes },
|
|
||||||
{ name: "MCP", resource: PamResourceType.MCP },
|
{ name: "MCP", resource: PamResourceType.MCP },
|
||||||
{ name: "Web Application", resource: PamResourceType.WebApp }
|
{ name: "Web Application", resource: PamResourceType.WebApp }
|
||||||
];
|
];
|
||||||
@@ -78,7 +77,6 @@ export const ResourceTypeSelect = ({ onSelect }: Props) => {
|
|||||||
// We temporarily show a special license modal for these because we will have to write some code to complete the integration
|
// We temporarily show a special license modal for these because we will have to write some code to complete the integration
|
||||||
if (
|
if (
|
||||||
resource === PamResourceType.RDP ||
|
resource === PamResourceType.RDP ||
|
||||||
resource === PamResourceType.Kubernetes ||
|
|
||||||
resource === PamResourceType.MCP ||
|
resource === PamResourceType.MCP ||
|
||||||
resource === PamResourceType.Redis ||
|
resource === PamResourceType.Redis ||
|
||||||
resource === PamResourceType.MongoDB ||
|
resource === PamResourceType.MongoDB ||
|
||||||
|
|||||||
Reference in New Issue
Block a user