Merge remote-tracking branch 'origin/main' into feat/PKI-55

This commit is contained in:
Carlos Monastyrski
2025-11-30 22:30:38 -03:00
435 changed files with 8438 additions and 5076 deletions
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.0.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 120 60" width="120" height="60" style="enable-background:new 0 0 120 60;" xml:space="preserve">
<style type="text/css">
.st0{fill:#808285;}
.st1{fill:url(#SVGID_1_);}
.st2{fill:#005B99;}
.st3{enable-background:new ;}
.st4{fill:#77787B;}
</style>
<g>
<path class="st0" d="M34.1,42.6h9.4v-3.2C41.5,41.2,38.2,42.3,34.1,42.6L34.1,42.6z"/>
<path class="st0" d="M17.3,40.1v2.5h11.9c-2.4-0.2-5-0.6-7.6-1.2C20.1,41,18.7,40.6,17.3,40.1L17.3,40.1z"/>
<radialGradient id="SVGID_1_" cx="-183.5882" cy="811.1324" r="47.498" gradientTransform="matrix(1 0 0 1 241.0864 -776.3726)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#0095DA"/>
<stop offset="0.21" style="stop-color:#0095DA"/>
<stop offset="0.33" style="stop-color:#00ACE4"/>
<stop offset="0.9045" style="stop-color:#005093"/>
<stop offset="0.9335" style="stop-color:#005396"/>
<stop offset="0.954" style="stop-color:#005C9F"/>
<stop offset="0.9718" style="stop-color:#006BAE"/>
<stop offset="0.988" style="stop-color:#0080C4"/>
<stop offset="1" style="stop-color:#0095DA"/>
</radialGradient>
<path class="st1" d="M43.5,18.5H29.2C23,17.1,15.4,17.1,10,18.2c2.4-0.3,5.1-0.3,7.8,0.1c0.7,0.1,1.3,0.2,2,0.3l0,0
c2.9,0.5,5.7,1.2,8.1,2.2l0,0c0.3,0.1,0.5,0.2,0.8,0.3h0c0.1,0,0.2,0.1,0.3,0.1h0c0.1,0,0.2,0.1,0.3,0.1h0c0.1,0,0.2,0.1,0.2,0.1
l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.2,0.1,0.2,0.1l0,0l0,0h0c0.1,0,0.1,0.1,0.2,0.1l0,0
c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1l0,0c0.1,0,0.1,0.1,0.2,0.1
l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.2,0.1l0.1,0c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1
c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1c0.1,0,0.1,0.1,0.1,0.1l0.1,0.1c0,0,0.1,0.1,0.1,0.1c3.2,2.2,5.1,4.9,5.1,7.6c0,3.1-2.6,5.7-6.8,7.2
c2.9-1.5,4.6-3.6,4.6-6.1c0-3.1-2.7-6.3-7-8.7c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1
c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1l-0.2-0.1c-0.1,0-0.2-0.1-0.2-0.1
l-0.1-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1c-0.1,0-0.1-0.1-0.2-0.1
L26,22c-0.1,0-0.2-0.1-0.3-0.1h0l-0.2-0.1l0,0c-0.1,0-0.2-0.1-0.3-0.1l-0.1,0c-0.1-0.1-0.2-0.1-0.4-0.1h0c-0.1,0-0.2-0.1-0.3-0.1h0
c-0.1-0.1-0.3-0.1-0.5-0.2l-0.1,0c-0.1-0.1-0.3-0.1-0.5-0.1h0c-0.3-0.1-0.5-0.2-0.8-0.3l0,0c-0.3-0.1-0.6-0.2-0.8-0.3l0,0
c-0.2-0.1-0.3-0.1-0.5-0.1l0,0c-0.7-0.2-1.5-0.4-2.3-0.5l0,0c-0.6-0.1-1.2-0.2-1.8-0.3v19.2c0.2,0.1,0.4,0.1,0.6,0.1
C30.3,42,41,39.4,41.8,33.2c0.4-3.3-2-6.9-6.1-10c3.3,1.9,6,4.1,7.8,6.4c1,1.4,1.7,2.7,2,4.1c-0.1-1.9-0.9-4.8-2-6.9L43.5,18.5
L43.5,18.5z"/>
<g>
<path class="st2" d="M67.5,26.9c0,1-0.2,2-0.7,2.9c-0.4,0.9-1,1.7-1.8,2.3c-0.8,0.7-1.7,1.2-2.8,1.6c-1.1,0.4-2.2,0.6-3.5,0.6H49
v-9h4.5v5.3h5.2c0.6,0,1.2-0.1,1.7-0.3c0.5-0.2,1-0.4,1.4-0.7c0.4-0.3,0.7-0.7,0.9-1.1c0.2-0.4,0.3-0.9,0.3-1.4
c0-0.5-0.1-1-0.3-1.4c-0.2-0.4-0.5-0.8-0.9-1.1c-0.4-0.3-0.8-0.6-1.4-0.7c-0.5-0.2-1.1-0.3-1.7-0.3H49l2.9-3.8h6.8
c1.3,0,2.4,0.2,3.5,0.5c1.1,0.3,2,0.8,2.8,1.5s1.4,1.4,1.8,2.3C67.2,24.9,67.5,25.8,67.5,26.9z"/>
<g>
<path class="st2" d="M82.8,21.4v6.8l-8.9-8c-0.4-0.3-0.7-0.5-1-0.6c-0.3-0.1-0.6-0.1-0.8-0.1c-0.3,0-0.6,0.1-0.9,0.1
c-0.3,0.1-0.6,0.3-0.8,0.5c-0.2,0.2-0.4,0.5-0.5,0.8c-0.1,0.3-0.2,0.8-0.2,1.2v12h4.1v-8.5l8.9,8c0.3,0.3,0.7,0.5,0.9,0.6
c0.3,0.1,0.6,0.1,0.8,0.1c0.3,0,0.6-0.1,0.9-0.1c0.3-0.1,0.6-0.3,0.8-0.5c0.2-0.2,0.4-0.5,0.5-0.8c0.1-0.3,0.2-0.8,0.2-1.2V19.9
L82.8,21.4z"/>
</g>
<path class="st2" d="M103,25.5c1.8,0,3.1,0.3,4,1c0.9,0.7,1.4,1.6,1.4,3c0,0.7-0.1,1.4-0.3,2c-0.2,0.6-0.6,1.1-1.1,1.5
c-0.5,0.4-1.2,0.7-1.9,0.9c-0.8,0.2-1.7,0.3-2.8,0.3H88.7l2.9-3.7h11c0.5,0,0.9-0.1,1.2-0.3c0.3-0.2,0.4-0.4,0.4-0.8
s-0.1-0.7-0.4-0.8c-0.3-0.2-0.6-0.2-1.2-0.2h-7.9c-0.9,0-1.8-0.1-2.4-0.3c-0.7-0.2-1.2-0.5-1.7-0.8c-0.5-0.4-0.8-0.8-1-1.3
c-0.2-0.5-0.3-1.1-0.3-1.7c0-0.7,0.1-1.3,0.4-1.9c0.2-0.6,0.6-1,1.1-1.4c0.5-0.4,1.1-0.7,1.9-0.9c0.8-0.2,1.7-0.3,2.8-0.3h12.6
l-2.9,3.8H95.1c-0.5,0-0.9,0.1-1.2,0.2c-0.3,0.1-0.4,0.4-0.4,0.8c0,0.4,0.1,0.6,0.4,0.8c0.3,0.1,0.6,0.2,1.2,0.2L103,25.5
L103,25.5z"/>
</g>
<g class="st3">
<path class="st4" d="M57.5,36.6v5h-1.4v-2.7v-0.7l0.1-0.4v-0.4h-0.1l-0.2,0.3l-0.2,0.3l-0.4,0.7l-1.7,2.8h-1.3l-1.7-2.8l-0.4-0.7
l-0.2-0.3l-0.2-0.3h-0.1l0,0.4v0.4l0.1,0.7v2.7h-1.5v-5h2.4l1.4,2.3l0.4,0.7l0.2,0.3l0.2,0.3H53l0.2-0.3l0.2-0.3l0.4-0.7l1.4-2.3
L57.5,36.6L57.5,36.6z"/>
<path class="st4" d="M63.6,40.6h-3.3l-0.5,0.9h-1.6l2.6-5H63l2.6,5H64L63.6,40.6z M63.2,39.9l-1.3-2.6l-1.3,2.6H63.2z"/>
<path class="st4" d="M66.2,41.6v-5H70c1,0,1.8,0.2,2.2,0.5s0.7,0.8,0.7,1.6c0,0.7,0,1.2-0.1,1.5c0,0.3-0.2,0.6-0.5,0.9
c-0.3,0.3-1,0.5-2.3,0.5H66.2L66.2,41.6z M67.7,40.7h2.1c0.7,0,1.2-0.1,1.4-0.3s0.3-0.7,0.3-1.4c0-0.7-0.1-1.2-0.3-1.4
s-0.6-0.3-1.3-0.3h-2.2L67.7,40.7L67.7,40.7z"/>
<path class="st4" d="M75.3,37.4v1.3h3.6v0.7h-3.6v1.4h3.8v0.8h-5.3v-5h5.3v0.8L75.3,37.4L75.3,37.4z"/>
<path class="st4" d="M84.4,37.4v1.3H88v0.7h-3.6v1.4h3.8v0.8H83v-5h5.3v0.8L84.4,37.4L84.4,37.4z"/>
<path class="st4" d="M94,40.6h-3.3l-0.5,0.9h-1.6l2.6-5h2.2l2.6,5h-1.5L94,40.6z M93.7,39.9l-1.3-2.6L91,39.9H93.7z"/>
<path class="st4" d="M102.4,38.1H101v-0.1c0-0.3-0.1-0.4-0.3-0.5c-0.2-0.1-0.6-0.1-1.2-0.1c-0.7,0-1.2,0-1.4,0.1
c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.3,0.1,0.5,0.3,0.6s0.8,0.1,1.7,0.1c1.1,0,1.9,0.1,2.2,0.3c0.3,0.2,0.5,0.5,0.5,1.1
c0,0.7-0.2,1.1-0.6,1.3s-1.2,0.3-2.5,0.3c-1.3,0-2.2-0.1-2.5-0.3c-0.4-0.2-0.6-0.6-0.6-1.2V40h1.4v0.1c0,0.3,0.1,0.5,0.3,0.6
c0.2,0.1,0.7,0.1,1.5,0.1c0.7,0,1.1,0,1.2-0.1s0.3-0.3,0.3-0.6c0-0.3-0.1-0.4-0.2-0.5c-0.1-0.1-0.4-0.1-0.9-0.1l-0.8,0
c-1.2,0-2-0.1-2.3-0.3c-0.4-0.2-0.5-0.6-0.5-1.1c0-0.6,0.2-1,0.6-1.2c0.4-0.2,1.2-0.3,2.5-0.3c1.1,0,1.9,0.1,2.3,0.3
c0.4,0.2,0.6,0.5,0.6,1L102.4,38.1L102.4,38.1z"/>
<path class="st4" d="M110,36.6l-2.9,3.1v1.9h-1.5v-1.9l-2.8-3.1h1.7l1.2,1.3l0.3,0.4l0.2,0.2l0.2,0.2l0.2-0.2l0.2-0.2l0.3-0.4
l1.2-1.3H110z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

+1 -1
View File
@@ -289,7 +289,7 @@
}
},
"project": {
"title": "Settings",
"title": "Project Settings",
"description": "These settings only apply to the currently selected Project.",
"danger-zone": "Danger Zone",
"delete-project": "Delete Project",
@@ -87,17 +87,24 @@ const shouldShowConditionalAccess = (
folderPath: string,
conditionalFields: string[]
): boolean => {
return actionRuleMap.some((rule) => {
// Find all rules that apply to this environment/path
const applicableRules = actionRuleMap.filter((rule) => {
const ruleConditions = rule[action]?.conditions;
if (!ruleConditions) return false;
// Check if any of the conditional fields are present
const hasConditionalField = conditionalFields.some((field) => ruleConditions[field]);
if (!hasConditionalField) return false;
// Check if base conditions (environment and secretPath) apply
return doBaseConditionsApply(ruleConditions, environment, folderPath);
});
// If no rules apply, don't show conditional
if (applicableRules.length === 0) return false;
// Check if ALL applicable rules have conditional fields and if at least one rule applies without conditional fields, show full access
const allRulesHaveConditionalFields = applicableRules.every((rule) => {
const ruleConditions = rule[action]?.conditions;
if (!ruleConditions) return false;
return conditionalFields.some((field) => ruleConditions[field]);
});
return allRulesHaveConditionalFields;
};
const determineAccessLevel = (
@@ -3,14 +3,7 @@ import { ReactNode } from "@tanstack/react-router";
import { LucideIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import {
Badge,
InstanceIcon,
OrgIcon,
ProjectIcon,
SubOrgIcon,
TBadgeProps
} from "@app/components/v3";
import { InstanceIcon, OrgIcon, ProjectIcon, SubOrgIcon } from "@app/components/v3";
import { ProjectType } from "@app/hooks/api/projects/types";
type Props = {
@@ -21,41 +14,40 @@ type Props = {
scope: "org" | "namespace" | "instance" | ProjectType | null;
};
const SCOPE_NAME: Record<NonNullable<Props["scope"]>, { label: string; icon: LucideIcon }> = {
org: { label: "Organization", icon: OrgIcon },
[ProjectType.SecretManager]: { label: "Project", icon: ProjectIcon },
[ProjectType.CertificateManager]: { label: "Project", icon: ProjectIcon },
[ProjectType.SSH]: { label: "Project", icon: ProjectIcon },
[ProjectType.KMS]: { label: "Project", icon: ProjectIcon },
[ProjectType.PAM]: { label: "Project", icon: ProjectIcon },
[ProjectType.SecretScanning]: { label: "Project", icon: ProjectIcon },
namespace: { label: "Sub-Organization", icon: SubOrgIcon },
instance: { label: "Server", icon: InstanceIcon }
};
const SCOPE_VARIANT: Record<NonNullable<Props["scope"]>, TBadgeProps["variant"]> = {
org: "org",
[ProjectType.SecretManager]: "project",
[ProjectType.CertificateManager]: "project",
[ProjectType.SSH]: "project",
[ProjectType.KMS]: "project",
[ProjectType.PAM]: "project",
[ProjectType.SecretScanning]: "project",
namespace: "sub-org",
instance: "neutral"
const SCOPE_BADGE: Record<NonNullable<Props["scope"]>, { icon: LucideIcon; className: string }> = {
org: { className: "text-org", icon: OrgIcon },
[ProjectType.SecretManager]: { className: "text-project", icon: ProjectIcon },
[ProjectType.CertificateManager]: { className: "text-project", icon: ProjectIcon },
[ProjectType.SSH]: { className: "text-project", icon: ProjectIcon },
[ProjectType.KMS]: { className: "text-project", icon: ProjectIcon },
[ProjectType.PAM]: { className: "text-project", icon: ProjectIcon },
[ProjectType.SecretScanning]: { className: "text-project", icon: ProjectIcon },
namespace: { className: "text-sub-org", icon: SubOrgIcon },
instance: { className: "text-neutral", icon: InstanceIcon }
};
export const PageHeader = ({ title, description, children, className, scope }: Props) => (
<div className={twMerge("mb-10 w-full", className)}>
<div className="flex w-full justify-between">
<div className="mr-4 flex w-full items-center">
<h1 className="text-3xl font-medium text-white capitalize">{title}</h1>
{scope && (
<Badge variant={SCOPE_VARIANT[scope]} className="mt-1 ml-2.5">
{createElement(SCOPE_NAME[scope].icon)}
{SCOPE_NAME[scope].label}
</Badge>
)}
<h1
className={twMerge(
"text-3xl font-medium text-white capitalize underline decoration-2 underline-offset-4",
scope === "org" && "decoration-org/90",
scope === "instance" && "decoration-neutral/90",
scope === "namespace" && "decoration-sub-org/90",
Object.values(ProjectType).includes((scope as ProjectType) ?? "") &&
"decoration-project/90",
!scope && "no-underline"
)}
>
{scope &&
createElement(SCOPE_BADGE[scope].icon, {
size: 26,
className: twMerge(SCOPE_BADGE[scope].className, "mr-3 mb-1 inline-block")
})}
{title}
</h1>
</div>
<div className="flex items-center gap-2">{children}</div>
</div>
+2 -2
View File
@@ -47,8 +47,8 @@ export const Tab = ({
}) => (
<TabsPrimitive.Trigger
className={twMerge(
"flex h-10 cursor-pointer items-center justify-center border-transparent",
"px-3 text-sm font-medium whitespace-nowrap text-mineshaft-400 transition-all select-none",
"flex h-11 cursor-pointer items-center justify-center border-transparent",
"px-3 text-sm font-medium whitespace-nowrap text-mineshaft-300/75 transition-all select-none",
"data-[orientation=vertical]:xl:h-5 data-[orientation=vertical]:xl:border-b-0 data-[orientation=vertical]:xl:border-l",
"border-b hover:text-mineshaft-200",
"data-[state=active]:border-mineshaft-400 data-[state=active]:text-white",
+2 -2
View File
@@ -294,8 +294,8 @@ export const ROUTE_PATHS = Object.freeze({
},
CertManager: {
CertAuthDetailsByIDPage: setRoute(
"/organizations/$orgId/projects/cert-management/$projectId/ca/$caName",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caName"
"/organizations/$orgId/projects/cert-management/$projectId/ca/$caId",
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caId"
),
SubscribersPage: setRoute(
"/organizations/$orgId/projects/cert-management/$projectId/subscribers",
+4
View File
@@ -49,6 +49,7 @@ import { BitbucketConnectionMethod } from "@app/hooks/api/appConnections/types/b
import { ChecklyConnectionMethod } from "@app/hooks/api/appConnections/types/checkly-connection";
import { ChefConnectionMethod } from "@app/hooks/api/appConnections/types/chef-connection";
import { DigitalOceanConnectionMethod } from "@app/hooks/api/appConnections/types/digital-ocean";
import { DNSMadeEasyConnectionMethod } from "@app/hooks/api/appConnections/types/dns-made-easy-connection";
import { HerokuConnectionMethod } from "@app/hooks/api/appConnections/types/heroku-connection";
import { LaravelForgeConnectionMethod } from "@app/hooks/api/appConnections/types/laravel-forge-connection";
import { NetlifyConnectionMethod } from "@app/hooks/api/appConnections/types/netlify-connection";
@@ -111,6 +112,7 @@ export const APP_CONNECTION_MAP: Record<
[AppConnection.Flyio]: { name: "Fly.io", image: "Flyio.svg" },
[AppConnection.GitLab]: { name: "GitLab", image: "GitLab.png" },
[AppConnection.Cloudflare]: { name: "Cloudflare", image: "Cloudflare.png" },
[AppConnection.DNSMadeEasy]: { name: "DNS Made Easy", image: "DNSMadeEasy.svg", size: 120 },
[AppConnection.Zabbix]: { name: "Zabbix", image: "Zabbix.png" },
[AppConnection.Railway]: { name: "Railway", image: "Railway.png" },
[AppConnection.Bitbucket]: { name: "Bitbucket", image: "Bitbucket.png" },
@@ -214,6 +216,8 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
return { name: "Client Secret", icon: faKey };
case AzureClientSecretsConnectionMethod.Certificate:
return { name: "Certificate", icon: faCertificate };
case DNSMadeEasyConnectionMethod.APIKeySecret:
return { name: "API Key & Secret", icon: faKey };
default:
throw new Error(`Unhandled App Connection Method: ${method}`);
}
-5
View File
@@ -14,11 +14,6 @@ const secretsToBeAdded = [
secretValue: "OVERRIDE_THIS",
secretComment: "Override secrets with personal value"
},
{
secretKey: "DB_PASSWORD",
secretValue: "OVERRIDE_THIS",
secretComment: "Another secret override"
},
{
secretKey: "DB_PASSWORD",
secretValue: "example_password"
@@ -0,0 +1,2 @@
export * from "./queries";
export * from "./types";
@@ -0,0 +1,37 @@
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { appConnectionKeys } from "../queries";
import { TDNSMadeEasyZone } from "./types";
const dnsMadeEasyConnectionKeys = {
all: [...appConnectionKeys.all, "dns-made-easy"] as const,
listZones: (connectionId: string) =>
[...dnsMadeEasyConnectionKeys.all, "zones", connectionId] as const
};
export const useDNSMadeEasyConnectionListZones = (
connectionId: string,
options?: Omit<
UseQueryOptions<
TDNSMadeEasyZone[],
unknown,
TDNSMadeEasyZone[],
ReturnType<typeof dnsMadeEasyConnectionKeys.listZones>
>,
"queryKey" | "queryFn"
>
) => {
return useQuery({
queryKey: dnsMadeEasyConnectionKeys.listZones(connectionId),
queryFn: async () => {
const { data } = await apiRequest.get<TDNSMadeEasyZone[]>(
`/api/v1/app-connections/dns-made-easy/${connectionId}/dns-made-easy-zones`
);
return data;
},
...options
});
};
@@ -0,0 +1,4 @@
export type TDNSMadeEasyZone = {
id: string;
name: string;
};
@@ -29,6 +29,7 @@ export enum AppConnection {
Flyio = "flyio",
GitLab = "gitlab",
Cloudflare = "cloudflare",
DNSMadeEasy = "dns-made-easy",
Bitbucket = "bitbucket",
Zabbix = "zabbix",
Railway = "railway",
@@ -184,6 +184,10 @@ export type TRedisConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Redis;
};
export type TDNSMadeEasyConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.DNSMadeEasy;
};
export type TAppConnectionOption =
| TAwsConnectionOption
| TGitHubConnectionOption
@@ -225,7 +229,8 @@ export type TAppConnectionOption =
| TOktaConnectionOption
| TAzureAdCsConnectionOption
| TLaravelForgeConnectionOption
| TChefConnectionOption;
| TChefConnectionOption
| TDNSMadeEasyConnectionOption;
export type TAppConnectionOptionMap = {
[AppConnection.AWS]: TAwsConnectionOption;
@@ -257,6 +262,7 @@ export type TAppConnectionOptionMap = {
[AppConnection.Flyio]: TFlyioConnectionOption;
[AppConnection.GitLab]: TGitlabConnectionOption;
[AppConnection.Cloudflare]: TCloudflareConnectionOption;
[AppConnection.DNSMadeEasy]: TDNSMadeEasyConnectionOption;
[AppConnection.Bitbucket]: TBitbucketConnectionOption;
[AppConnection.Zabbix]: TZabbixConnectionOption;
[AppConnection.Railway]: TRailwayConnectionOption;
@@ -0,0 +1,14 @@
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
export enum DNSMadeEasyConnectionMethod {
APIKeySecret = "api-key-secret"
}
export type TDNSMadeEasyConnection = TRootAppConnection & { app: AppConnection.DNSMadeEasy } & {
method: DNSMadeEasyConnectionMethod.APIKeySecret;
credentials: {
apiKey: string;
secretKey: string;
};
};
@@ -15,6 +15,7 @@ import { TChefConnection } from "./chef-connection";
import { TCloudflareConnection } from "./cloudflare-connection";
import { TDatabricksConnection } from "./databricks-connection";
import { TDigitalOceanConnection } from "./digital-ocean";
import { TDNSMadeEasyConnection } from "./dns-made-easy-connection";
import { TFlyioConnection } from "./flyio-connection";
import { TGcpConnection } from "./gcp-connection";
import { TGitHubConnection } from "./github-connection";
@@ -57,6 +58,7 @@ export * from "./checkly-connection";
export * from "./chef-connection";
export * from "./cloudflare-connection";
export * from "./databricks-connection";
export * from "./dns-made-easy-connection";
export * from "./flyio-connection";
export * from "./gcp-connection";
export * from "./github-connection";
@@ -127,7 +129,8 @@ export type TAppConnection =
| TNorthflankConnection
| TOktaConnection
| TRedisConnection
| TChefConnection;
| TChefConnection
| TDNSMadeEasyConnection;
export type TAvailableAppConnection = Pick<TAppConnection, "name" | "id" | "projectId">;
+4 -2
View File
@@ -16,12 +16,14 @@ export const caStatusToNameMap: { [K in CaStatus]: string } = {
export const ACME_DNS_PROVIDER_NAME_MAP: Record<AcmeDnsProvider, string> = {
[AcmeDnsProvider.ROUTE53]: "Route53",
[AcmeDnsProvider.Cloudflare]: "Cloudflare"
[AcmeDnsProvider.Cloudflare]: "Cloudflare",
[AcmeDnsProvider.DNSMadeEasy]: "DNS Made Easy"
};
export const ACME_DNS_PROVIDER_APP_CONNECTION_MAP: Record<AcmeDnsProvider, AppConnection> = {
[AcmeDnsProvider.ROUTE53]: AppConnection.AWS,
[AcmeDnsProvider.Cloudflare]: AppConnection.Cloudflare
[AcmeDnsProvider.Cloudflare]: AppConnection.Cloudflare,
[AcmeDnsProvider.DNSMadeEasy]: AppConnection.DNSMadeEasy
};
export const CA_TYPE_CAPABILITIES_MAP: Record<CaType, CaCapability[]> = {
+2 -1
View File
@@ -21,7 +21,8 @@ export enum CaRenewalType {
export enum AcmeDnsProvider {
ROUTE53 = "route53",
Cloudflare = "cloudflare"
Cloudflare = "cloudflare",
DNSMadeEasy = "dns-made-easy"
}
export enum CaCapability {
+1 -1
View File
@@ -13,12 +13,12 @@ export {
export {
useGetAzureAdcsTemplates,
useGetCa,
useGetCaById,
useGetCaCert,
useGetCaCerts,
useGetCaCertTemplates,
useGetCaCrls,
useGetCaCsr,
useGetInternalCaById,
useListCasByProjectId,
useListCasByTypeAndProjectId,
useListExternalCasByProjectId
+14 -19
View File
@@ -27,21 +27,20 @@ import {
export const useUpdateCa = () => {
const queryClient = useQueryClient();
return useMutation<TUnifiedCertificateAuthority, object, TUpdateCertificateAuthorityDTO>({
mutationFn: async ({ caName, ...body }) => {
mutationFn: async ({ id, ...body }) => {
const { data } = await apiRequest.patch<TUnifiedCertificateAuthority>(
`/api/v1/pki/ca/${body.type}/${caName}`,
`/api/v1/cert-manager/ca/${body.type}/${id}`,
body
);
return data;
},
onSuccess: ({ projectId, type }, { caName }) => {
caKeys.getCaByNameAndProjectId(caName, projectId);
onSuccess: ({ projectId, type }, { id }) => {
queryClient.invalidateQueries({
queryKey: caKeys.listCasByTypeAndProjectId(type, projectId)
});
queryClient.invalidateQueries({
queryKey: caKeys.getCaByNameAndProjectId(caName, projectId)
queryKey: caKeys.getCaById(id)
});
// Invalidate external CAs list
queryClient.invalidateQueries({
@@ -56,7 +55,7 @@ export const useCreateCa = () => {
return useMutation<TUnifiedCertificateAuthority, object, TCreateCertificateAuthorityDTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TUnifiedCertificateAuthority>(
`/api/v1/pki/ca/${body.type}`,
`/api/v1/cert-manager/ca/${body.type}`,
body
);
return data;
@@ -76,14 +75,9 @@ export const useCreateCa = () => {
export const useDeleteCa = () => {
const queryClient = useQueryClient();
return useMutation<TUnifiedCertificateAuthority, object, TDeleteCertificateAuthorityDTO>({
mutationFn: async ({ caName, type, projectId }) => {
mutationFn: async ({ id, type }) => {
const { data } = await apiRequest.delete<TUnifiedCertificateAuthority>(
`/api/v1/pki/ca/${type}/${caName}`,
{
data: {
projectId
}
}
`/api/v1/cert-manager/ca/${type}/${id}`
);
return data;
},
@@ -104,7 +98,7 @@ export const useSignIntermediate = () => {
return useMutation<TSignIntermediateResponse, object, TSignIntermediateDTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TSignIntermediateResponse>(
`/api/v1/pki/ca/${body.caId}/sign-intermediate`,
`/api/v1/cert-manager/ca/internal/${body.caId}/sign-intermediate`,
body
);
return data;
@@ -117,13 +111,14 @@ export const useImportCaCertificate = (projectId: string) => {
return useMutation<TImportCaCertificateResponse, object, TImportCaCertificateDTO>({
mutationFn: async ({ caId, ...body }) => {
const { data } = await apiRequest.post<TImportCaCertificateResponse>(
`/api/v1/pki/ca/${caId}/import-certificate`,
`/api/v1/cert-manager/ca/internal/${caId}/import-certificate`,
body
);
return data;
},
onSuccess: (_, { caId }) => {
queryClient.invalidateQueries({ queryKey: projectKeys.getProjectCas({ projectId }) });
queryClient.invalidateQueries({ queryKey: caKeys.getCaById(caId) });
queryClient.invalidateQueries({ queryKey: caKeys.getCaCerts(caId) });
queryClient.invalidateQueries({ queryKey: caKeys.getCaCert(caId) });
queryClient.invalidateQueries({
@@ -133,7 +128,7 @@ export const useImportCaCertificate = (projectId: string) => {
});
};
// consider rename to issue certificate
// TODO: DEPRECATE
export const useCreateCertificate = () => {
const queryClient = useQueryClient();
return useMutation<TCreateCertificateResponse, object, TCreateCertificateDTO>({
@@ -157,7 +152,7 @@ export const useCreateCertificateV3 = (options?: { projectId?: string }) => {
return useMutation<TCreateCertificateV3Response, object, TCreateCertificateV3DTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TCreateCertificateV3Response>(
"/api/v3/pki/certificates/issue-certificate",
"/api/v1/cert-manager/certificates/issue-certificate",
body
);
return data;
@@ -185,7 +180,7 @@ export const useOrderCertificateWithProfile = () => {
return useMutation<TOrderCertificateResponse, object, TOrderCertificateDTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TOrderCertificateResponse>(
"/api/v3/pki/certificates/order-certificate",
"/api/v1/cert-manager/certificates/order-certificate",
body
);
return data;
@@ -203,7 +198,7 @@ export const useRenewCa = () => {
return useMutation<TRenewCaResponse, object, TRenewCaDTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TRenewCaResponse>(
`/api/v1/pki/ca/${body.caId}/renew`,
`/api/v1/cert-manager/ca/internal/${body.caId}/renew`,
body
);
return data;
+24 -27
View File
@@ -4,7 +4,11 @@ import { apiRequest } from "@app/config/request";
import { TCertificateTemplate } from "../certificateTemplates/types";
import { CaType } from "./enums";
import { TAzureAdCsTemplate, TCertificateAuthority, TUnifiedCertificateAuthority } from "./types";
import {
TAzureAdCsTemplate,
TInternalCertificateAuthority,
TUnifiedCertificateAuthority
} from "./types";
export const caKeys = {
getCaById: (caId: string) => [{ caId }, "ca"],
@@ -25,24 +29,16 @@ export const caKeys = {
]
};
export const useGetCa = ({
caName,
projectId,
type
}: {
caName: string;
projectId: string;
type: CaType;
}) => {
export const useGetCa = ({ caId, type }: { caId: string; type: CaType }) => {
return useQuery({
queryKey: caKeys.getCaByNameAndProjectId(caName, projectId),
queryKey: caKeys.getCaById(caId),
queryFn: async () => {
const { data } = await apiRequest.get<TUnifiedCertificateAuthority>(
`/api/v1/pki/ca/${type}/${caName}?projectId=${projectId}`
`/api/v1/cert-manager/ca/${type}/${caId}`
);
return data;
},
enabled: Boolean(caName && projectId && type)
enabled: Boolean(caId && type)
});
};
@@ -51,7 +47,7 @@ export const useListCasByTypeAndProjectId = (type: CaType, projectId: string) =>
queryKey: caKeys.listCasByTypeAndProjectId(type, projectId),
queryFn: async () => {
const { data } = await apiRequest.get<TUnifiedCertificateAuthority[]>(
`/api/v1/pki/ca/${type}?projectId=${projectId}`
`/api/v1/cert-manager/ca/${type}?projectId=${projectId}`
);
return data;
@@ -65,7 +61,7 @@ export const useListCasByProjectId = (projectId: string) => {
queryFn: async () => {
const { data } = await apiRequest.get<{
certificateAuthorities: TUnifiedCertificateAuthority[];
}>(`/api/v2/pki/ca?projectId=${projectId}`);
}>(`/api/v1/cert-manager/ca?projectId=${projectId}`);
return data.certificateAuthorities;
}
@@ -78,10 +74,10 @@ export const useListExternalCasByProjectId = (projectId: string) => {
queryFn: async () => {
const [acmeResponse, azureAdCsResponse] = await Promise.allSettled([
apiRequest.get<TUnifiedCertificateAuthority[]>(
`/api/v1/pki/ca/${CaType.ACME}?projectId=${projectId}`
`/api/v1/cert-manager/ca/${CaType.ACME}?projectId=${projectId}`
),
apiRequest.get<TUnifiedCertificateAuthority[]>(
`/api/v1/pki/ca/${CaType.AZURE_AD_CS}?projectId=${projectId}`
`/api/v1/cert-manager/ca/${CaType.AZURE_AD_CS}?projectId=${projectId}`
)
]);
@@ -100,14 +96,14 @@ export const useListExternalCasByProjectId = (projectId: string) => {
});
};
export const useGetCaById = (caId: string) => {
export const useGetInternalCaById = (caId: string) => {
return useQuery({
queryKey: caKeys.getCaById(caId),
queryFn: async () => {
const {
data: { ca }
} = await apiRequest.get<{ ca: TCertificateAuthority }>(`/api/v1/pki/ca/${caId}`);
return ca;
const { data } = await apiRequest.get<TInternalCertificateAuthority>(
`/api/v1/cert-manager/ca/internal/${caId}`
);
return data;
},
enabled: Boolean(caId)
});
@@ -124,7 +120,7 @@ export const useGetCaCerts = (caId: string) => {
serialNumber: string;
version: number;
}[]
>(`/api/v1/pki/ca/${caId}/ca-certificates`); // TODO: consider updating endpoint structure
>(`/api/v1/cert-manager/ca/internal/${caId}/ca-certificates`);
return data;
},
enabled: Boolean(caId)
@@ -139,7 +135,7 @@ export const useGetCaCert = (caId: string) => {
certificate: string;
certificateChain: string;
serialNumber: string;
}>(`/api/v1/pki/ca/${caId}/certificate`); // TODO: consider updating endpoint structure
}>(`/api/v1/cert-manager/ca/internal/${caId}/certificate`);
return data;
},
enabled: Boolean(caId)
@@ -154,7 +150,7 @@ export const useGetCaCsr = (caId: string) => {
data: { csr }
} = await apiRequest.get<{
csr: string;
}>(`/api/v1/pki/ca/${caId}/csr`);
}>(`/api/v1/cert-manager/ca/internal/${caId}/csr`);
return csr;
},
enabled: Boolean(caId)
@@ -170,13 +166,14 @@ export const useGetCaCrls = (caId: string) => {
id: string;
crl: string;
}[]
>(`/api/v1/pki/ca/${caId}/crls`);
>(`/api/v1/cert-manager/ca/internal/${caId}/crls`);
return data;
},
enabled: Boolean(caId)
});
};
// TODO: DEPRECATE
export const useGetCaCertTemplates = (caId: string) => {
return useQuery({
queryKey: caKeys.getCaCertTemplates(caId),
@@ -202,7 +199,7 @@ export const useGetAzureAdcsTemplates = ({
queryFn: async () => {
const { data } = await apiRequest.get<{
templates: TAzureAdCsTemplate[];
}>(`/api/v1/pki/ca/azure-ad-cs/${caId}/templates?projectId=${projectId}`);
}>(`/api/v1/cert-manager/ca/azure-ad-cs/${caId}/templates?projectId=${projectId}`);
return data;
},
enabled: Boolean(caId && projectId)
+7 -5
View File
@@ -66,17 +66,19 @@ export type TUnifiedCertificateAuthority =
| TAzureAdCsCertificateAuthority
| TInternalCertificateAuthority;
export type TCreateCertificateAuthorityDTO = Omit<TUnifiedCertificateAuthority, "id">;
export type TCreateCertificateAuthorityDTO = Omit<
TUnifiedCertificateAuthority,
"id" | "enableDirectIssuance"
>;
export type TUpdateCertificateAuthorityDTO = Partial<TUnifiedCertificateAuthority> & {
caName: string;
projectId: string;
id: string;
type: CaType;
};
export type TDeleteCertificateAuthorityDTO = {
caName: string;
type: CaType;
id: string;
projectId: string;
type: CaType;
};
export type TCertificateAuthority = {
@@ -17,7 +17,7 @@ export const useCreateCertificateProfile = () => {
mutationFn: async (data) => {
const { data: response } = await apiRequest.post<{
certificateProfile: TCertificateProfile;
}>("/api/v1/pki/certificate-profiles", data);
}>("/api/v1/cert-manager/certificate-profiles", data);
return response.certificateProfile;
},
onSuccess: (_, { projectId }) => {
@@ -35,7 +35,7 @@ export const useUpdateCertificateProfile = () => {
mutationFn: async ({ profileId, ...data }) => {
const { data: response } = await apiRequest.patch<{
certificateProfile: TCertificateProfile;
}>(`/api/v1/pki/certificate-profiles/${profileId}`, data);
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`, data);
return response.certificateProfile;
},
onSuccess: (profile, { profileId }) => {
@@ -56,7 +56,7 @@ export const useDeleteCertificateProfile = () => {
mutationFn: async ({ profileId }) => {
const { data: response } = await apiRequest.delete<{
certificateProfile: TCertificateProfile;
}>(`/api/v1/pki/certificate-profiles/${profileId}`);
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`);
return response.certificateProfile;
},
onSuccess: (profile, { profileId }) => {
@@ -71,7 +71,7 @@ export const useListCertificateProfiles = ({
const { data } = await apiRequest.get<{
certificateProfiles: TCertificateProfile[];
totalCount: number;
}>("/api/v1/pki/certificate-profiles", {
}>("/api/v1/cert-manager/certificate-profiles", {
params: {
projectId,
limit,
@@ -93,7 +93,7 @@ export const useGetCertificateProfileById = ({ profileId }: TGetCertificateProfi
queryFn: async () => {
const { data } = await apiRequest.get<{
certificateProfile: TCertificateProfileWithDetails;
}>(`/api/v1/pki/certificate-profiles/${profileId}`);
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}`);
return data.certificateProfile;
},
enabled: Boolean(profileId)
@@ -109,7 +109,7 @@ export const useGetCertificateProfileBySlug = ({
queryFn: async () => {
const { data } = await apiRequest.get<{
certificateProfile: TCertificateProfile;
}>(`/api/v1/pki/certificate-profiles/slug/${slug}`, {
}>(`/api/v1/cert-manager/certificate-profiles/slug/${slug}`, {
params: { projectId }
});
return data.certificateProfile;
@@ -125,7 +125,7 @@ export const useRevealAcmeEabSecret = ({ profileId }: TRevealAcmeEabSecretDTO) =
const { data } = await apiRequest.get<{
eabKid: string;
eabSecret: string;
}>(`/api/v1/pki/certificate-profiles/${profileId}/acme/eab-secret/reveal`);
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}/acme/eab-secret/reveal`);
return data;
},
enabled: Boolean(profileId)
@@ -144,7 +144,7 @@ export const useGetProfileCertificates = ({
queryFn: async () => {
const { data } = await apiRequest.get<{
certificates: TProfileCertificate[];
}>(`/api/v1/pki/certificate-profiles/${profileId}/certificates`, {
}>(`/api/v1/cert-manager/certificate-profiles/${profileId}/certificates`, {
params: {
offset,
limit,
@@ -21,6 +21,7 @@ import {
TUpdateEstConfigDTO
} from "./types";
// TODO: DEPRECATE
export const useCreateCertTemplate = () => {
const queryClient = useQueryClient();
return useMutation<TCertificateTemplate, object, TCreateCertificateTemplateDTO>({
@@ -40,6 +41,7 @@ export const useCreateCertTemplate = () => {
});
};
// TODO: DEPRECATE
export const useUpdateCertTemplate = () => {
const queryClient = useQueryClient();
return useMutation<TCertificateTemplate, object, TUpdateCertificateTemplateDTO>({
@@ -61,6 +63,7 @@ export const useUpdateCertTemplate = () => {
});
};
// TODO: DEPRECATE
export const useDeleteCertTemplate = () => {
const queryClient = useQueryClient();
return useMutation<TCertificateTemplate, object, TDeleteCertificateTemplateDTO>({
@@ -147,6 +150,7 @@ export const useDeleteCertTemplateV2 = () => {
});
};
// TODO: DEPRECATE
export const useCreateEstConfig = () => {
const queryClient = useQueryClient();
return useMutation<object, object, TCreateEstConfigDTO>({
@@ -165,6 +169,7 @@ export const useCreateEstConfig = () => {
});
};
// TODO: DEPRECATE
export const useUpdateEstConfig = () => {
const queryClient = useQueryClient();
return useMutation<object, object, TUpdateEstConfigDTO>({
@@ -193,7 +198,7 @@ export const useCreateCertificateTemplateV2WithPolicies = () => {
mutationFn: async (data) => {
const { data: response } = await apiRequest.post<{
certificateTemplate: TCertificateTemplateV2WithPolicies;
}>("/api/v2/certificate-templates", data);
}>("/api/v1/cert-manager/certificate-templates", data);
return response.certificateTemplate;
},
onSuccess: (_, { projectId }) => {
@@ -214,7 +219,7 @@ export const useUpdateCertificateTemplateV2WithPolicies = () => {
mutationFn: async ({ templateId, ...data }) => {
const { data: response } = await apiRequest.patch<{
certificateTemplate: TCertificateTemplateV2WithPolicies;
}>(`/api/v2/certificate-templates/${templateId}`, data);
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`, data);
return response.certificateTemplate;
},
onSuccess: (template, { templateId }) => {
@@ -238,7 +243,7 @@ export const useDeleteCertificateTemplateV2WithPolicies = () => {
mutationFn: async ({ templateId }) => {
const { data: response } = await apiRequest.delete<{
certificateTemplate: TCertificateTemplateV2WithPolicies;
}>(`/api/v2/certificate-templates/${templateId}`);
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`);
return response.certificateTemplate;
},
onSuccess: (template, { templateId }) => {
@@ -31,6 +31,7 @@ export const certTemplateKeys = {
getTemplateV2ById: (id: string) => ["cert-template-v2", id]
};
// TODO: DEPRECATE
export const useGetCertTemplate = (id: string) => {
return useQuery({
queryKey: certTemplateKeys.getCertTemplateById(id),
@@ -44,6 +45,7 @@ export const useGetCertTemplate = (id: string) => {
});
};
// TODO: DEPRECATE
export const useListCertificateTemplates = ({
limit = 100,
offset = 0,
@@ -67,6 +69,7 @@ export const useListCertificateTemplates = ({
});
};
// TODO: DEPRECATE
export const useGetEstConfig = (certificateTemplateId: string) => {
return useQuery({
queryKey: certTemplateKeys.getEstConfig(certificateTemplateId),
@@ -92,7 +95,7 @@ export const useListCertificateTemplatesV2 = ({
const { data } = await apiRequest.get<{
certificateTemplates: TCertificateTemplateV2WithPolicies[];
totalCount: number;
}>("/api/v2/certificate-templates", {
}>("/api/v1/cert-manager/certificate-templates", {
params: {
projectId,
limit,
@@ -113,7 +116,7 @@ export const useGetCertificateTemplateV2ById = ({
queryFn: async () => {
const { data } = await apiRequest.get<{
certificateTemplate: TCertificateTemplateV2WithPolicies;
}>(`/api/v2/certificate-templates/${templateId}`);
}>(`/api/v1/cert-manager/certificate-templates/${templateId}`);
return data.certificateTemplate;
},
enabled: Boolean(templateId)
@@ -21,11 +21,11 @@ import {
export const useDeleteCert = () => {
const queryClient = useQueryClient();
return useMutation<TCertificate, object, TDeleteCertDTO>({
mutationFn: async ({ serialNumber }) => {
mutationFn: async ({ id }) => {
const {
data: { certificate }
} = await apiRequest.delete<{ certificate: TCertificate }>(
`/api/v1/pki/certificates/${serialNumber}`
`/api/v1/cert-manager/certificates/${id}`
);
return certificate;
},
@@ -49,11 +49,11 @@ export const useDeleteCert = () => {
export const useRevokeCert = () => {
const queryClient = useQueryClient();
return useMutation<TCertificate, object, TRevokeCertDTO>({
mutationFn: async ({ serialNumber, revocationReason }) => {
mutationFn: async ({ id, revocationReason }) => {
const {
data: { certificate }
} = await apiRequest.post<{ certificate: TCertificate }>(
`/api/v1/pki/certificates/${serialNumber}/revoke`,
`/api/v1/cert-manager/certificates/${id}/revoke`,
{
revocationReason
}
@@ -82,7 +82,7 @@ export const useImportCertificate = () => {
return useMutation<TImportCertificateResponse, object, TImportCertificateDTO>({
mutationFn: async (body) => {
const { data } = await apiRequest.post<TImportCertificateResponse>(
"/api/v1/pki/certificates/import-certificate",
"/api/v1/cert-manager/certificates/import-certificate",
body
);
return data;
@@ -100,7 +100,7 @@ export const useRenewCertificate = () => {
return useMutation<TRenewCertificateResponse, object, TRenewCertificateDTO>({
mutationFn: async ({ certificateId }) => {
const { data } = await apiRequest.post<TRenewCertificateResponse>(
`/api/v3/pki/certificates/${certificateId}/renew`,
`/api/v1/cert-manager/certificates/${certificateId}/renew`,
{}
);
return data;
@@ -133,7 +133,7 @@ export const useUpdateRenewalConfig = () => {
>({
mutationFn: async ({ certificateId, renewBeforeDays, enableAutoRenewal }) => {
const { data } = await apiRequest.patch<{ message: string; renewBeforeDays?: number }>(
`/api/v3/pki/certificates/${certificateId}/config`,
`/api/v1/cert-manager/certificates/${certificateId}/config`,
{ renewBeforeDays, enableAutoRenewal }
);
return data;
@@ -151,10 +151,10 @@ export const useUpdateRenewalConfig = () => {
export const useDownloadCertPkcs12 = () => {
return useMutation<void, object, TDownloadPkcs12DTO>({
mutationFn: async ({ serialNumber, projectSlug, password, alias }) => {
mutationFn: async ({ certificateId, projectSlug, password, alias }) => {
try {
const response = await apiRequest.post(
`/api/v1/pki/certificates/${serialNumber}/pkcs12`,
`/api/v1/cert-manager/certificates/${certificateId}/pkcs12`,
{
password,
alias
@@ -170,7 +170,7 @@ export const useDownloadCertPkcs12 = () => {
const url = window.URL.createObjectURL(blob);
const link = document.createElement("a");
link.href = url;
link.download = `certificate-${serialNumber}.p12`;
link.download = `certificate-${certificateId}.p12`;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
+3 -3
View File
@@ -24,13 +24,13 @@ export type TCertificate = {
};
export type TDeleteCertDTO = {
id: string;
projectId: string;
serialNumber: string;
};
export type TRevokeCertDTO = {
projectId: string;
serialNumber: string;
id: string;
revocationReason: string;
};
@@ -75,7 +75,7 @@ export type TUpdateRenewalConfigDTO = {
};
export type TDownloadPkcs12DTO = {
serialNumber: string;
certificateId: string;
projectSlug: string;
password: string;
alias: string;
@@ -6,6 +6,7 @@ import { projectKeys } from "../projects";
import { pkiAlertKeys } from "./queries";
import { TCreatePkiAlertDTO, TDeletePkiAlertDTO, TPkiAlert, TUpdatePkiAlertDTO } from "./types";
// TODO: DEPRECATE
export const useCreatePkiAlert = () => {
const queryClient = useQueryClient();
return useMutation<TPkiAlert, object, TCreatePkiAlertDTO>({
@@ -19,6 +20,7 @@ export const useCreatePkiAlert = () => {
});
};
// TODO: DEPRECATE
export const useUpdatePkiAlert = () => {
const queryClient = useQueryClient();
return useMutation<TPkiAlert, object, TUpdatePkiAlertDTO>({
@@ -36,6 +38,7 @@ export const useUpdatePkiAlert = () => {
});
};
// TODO: DEPRECATE
export const useDeletePkiAlert = () => {
const queryClient = useQueryClient();
return useMutation<TPkiAlert, object, TDeletePkiAlertDTO>({
@@ -8,6 +8,7 @@ export const pkiAlertKeys = {
getPkiAlertById: (alertId: string) => [{ alertId }, "alert"]
};
// TODO: DEPRECATE
export const useGetPkiAlertById = (alertId: string) => {
return useQuery({
queryKey: pkiAlertKeys.getPkiAlertById(alertId),
@@ -11,7 +11,7 @@ export const useCreatePkiAlertV2 = () => {
return useMutation<TPkiAlertV2, unknown, TCreatePkiAlertV2>({
mutationFn: async (data) => {
const { data: response } = await apiRequest.post<{ alert: TPkiAlertV2 }>(
"/api/v2/pki/alerts",
"/api/v1/cert-manager/alerts",
data
);
return response.alert;
@@ -30,7 +30,7 @@ export const useUpdatePkiAlertV2 = () => {
return useMutation<TPkiAlertV2, unknown, TUpdatePkiAlertV2>({
mutationFn: async ({ alertId, ...data }) => {
const { data: response } = await apiRequest.patch<{ alert: TPkiAlertV2 }>(
`/api/v2/pki/alerts/${alertId}`,
`/api/v1/cert-manager/alerts/${alertId}`,
data
);
return response.alert;
@@ -52,7 +52,7 @@ export const useDeletePkiAlertV2 = () => {
return useMutation<TPkiAlertV2, unknown, TDeletePkiAlertV2>({
mutationFn: async ({ alertId }) => {
const { data } = await apiRequest.delete<{ alert: TPkiAlertV2 }>(
`/api/v2/pki/alerts/${alertId}`
`/api/v1/cert-manager/alerts/${alertId}`
);
return data.alert;
},
@@ -24,14 +24,16 @@ export const pkiAlertsV2Keys = {
};
const fetchPkiAlertsV2 = async (params: TGetPkiAlertsV2): Promise<TGetPkiAlertsV2Response> => {
const { data } = await apiRequest.get<TGetPkiAlertsV2Response>("/api/v2/pki/alerts", {
const { data } = await apiRequest.get<TGetPkiAlertsV2Response>("/api/v1/cert-manager/alerts", {
params
});
return data;
};
const fetchPkiAlertV2ById = async ({ alertId }: TGetPkiAlertV2ById): Promise<TPkiAlertV2> => {
const { data } = await apiRequest.get<{ alert: TPkiAlertV2 }>(`/api/v2/pki/alerts/${alertId}`);
const { data } = await apiRequest.get<{ alert: TPkiAlertV2 }>(
`/api/v1/cert-manager/alerts/${alertId}`
);
return data.alert;
};
@@ -40,7 +42,7 @@ const fetchPkiAlertV2MatchingCertificates = async (
): Promise<TGetPkiAlertV2MatchingCertificatesResponse> => {
const { alertId, ...queryParams } = params;
const { data } = await apiRequest.get<TGetPkiAlertV2MatchingCertificatesResponse>(
`/api/v2/pki/alerts/${alertId}/certificates`,
`/api/v1/cert-manager/alerts/${alertId}/certificates`,
{ params: queryParams }
);
return data;
@@ -50,7 +52,7 @@ const fetchPkiAlertV2CurrentMatchingCertificates = async (
params: TGetPkiAlertV2CurrentMatchingCertificates
): Promise<TGetPkiAlertV2CurrentMatchingCertificatesResponse> => {
const { data } = await apiRequest.post<TGetPkiAlertV2CurrentMatchingCertificatesResponse>(
"/api/v2/pki/alerts/preview/certificates",
"/api/v1/cert-manager/alerts/preview/certificates",
params
);
return data;
+30 -14
View File
@@ -17,7 +17,10 @@ export const useCreatePkiSync = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ destination, ...params }: TCreatePkiSyncDTO) => {
const { data } = await apiRequest.post<TPkiSync>(`/api/v1/pki/syncs/${destination}`, params);
const { data } = await apiRequest.post<TPkiSync>(
`/api/v1/cert-manager/syncs/${destination}`,
params
);
return data;
},
@@ -31,7 +34,7 @@ export const useUpdatePkiSync = () => {
return useMutation({
mutationFn: async ({ syncId, projectId, destination, ...params }: TUpdatePkiSyncDTO) => {
const { data } = await apiRequest.patch<TPkiSync>(
`/api/v1/pki/syncs/${destination}/${syncId}`,
`/api/v1/cert-manager/syncs/${destination}/${syncId}`,
params,
{ params: { projectId } }
);
@@ -49,9 +52,12 @@ export const useDeletePkiSync = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ syncId, projectId, destination }: TDeletePkiSyncDTO) => {
const { data } = await apiRequest.delete(`/api/v1/pki/syncs/${destination}/${syncId}`, {
params: { projectId }
});
const { data } = await apiRequest.delete(
`/api/v1/cert-manager/syncs/${destination}/${syncId}`,
{
params: { projectId }
}
);
return data;
},
@@ -66,7 +72,9 @@ export const useTriggerPkiSyncSyncCertificates = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncSyncCertificatesDTO) => {
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${destination}/${syncId}/sync`);
const { data } = await apiRequest.post(
`/api/v1/cert-manager/syncs/${destination}/${syncId}/sync`
);
return data;
},
@@ -111,7 +119,9 @@ export const useTriggerPkiSyncImportCertificates = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncImportCertificatesDTO) => {
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${destination}/${syncId}/import`);
const { data } = await apiRequest.post(
`/api/v1/cert-manager/syncs/${destination}/${syncId}/import`
);
return data;
},
@@ -157,7 +167,7 @@ export const useTriggerPkiSyncRemoveCertificates = () => {
return useMutation({
mutationFn: async ({ syncId, destination }: TTriggerPkiSyncRemoveCertificatesDTO) => {
const { data } = await apiRequest.post(
`/api/v1/pki/syncs/${destination}/${syncId}/remove-certificates`
`/api/v1/cert-manager/syncs/${destination}/${syncId}/remove-certificates`
);
return data;
@@ -209,9 +219,12 @@ export const useAddCertificatesToPkiSync = () => {
pkiSyncId: string;
certificateIds: string[];
}) => {
const { data } = await apiRequest.post(`/api/v1/pki/syncs/${pkiSyncId}/certificates`, {
certificateIds
});
const { data } = await apiRequest.post(
`/api/v1/cert-manager/syncs/${pkiSyncId}/certificates`,
{
certificateIds
}
);
return data;
},
@@ -231,9 +244,12 @@ export const useRemoveCertificatesFromPkiSync = () => {
pkiSyncId: string;
certificateIds: string[];
}) => {
const { data } = await apiRequest.delete(`/api/v1/pki/syncs/${pkiSyncId}/certificates`, {
data: { certificateIds }
});
const { data } = await apiRequest.delete(
`/api/v1/cert-manager/syncs/${pkiSyncId}/certificates`,
{
data: { certificateIds }
}
);
return data;
},
+6 -4
View File
@@ -37,7 +37,9 @@ export const usePkiSyncOptions = (
return useQuery({
queryKey: pkiSyncKeys.options(),
queryFn: async () => {
const { data } = await apiRequest.get<TListPkiSyncOptions>("/api/v1/pki/syncs/options");
const { data } = await apiRequest.get<TListPkiSyncOptions>(
"/api/v1/cert-manager/syncs/options"
);
return data.pkiSyncOptions;
},
@@ -58,7 +60,7 @@ export const fetchPkiSyncsByProjectId = async (projectId: string, certificateId?
params.certificateId = certificateId;
}
const { data } = await apiRequest.get<TListPkiSyncs>("/api/v1/pki/syncs", {
const { data } = await apiRequest.get<TListPkiSyncs>("/api/v1/cert-manager/syncs", {
params
});
@@ -110,7 +112,7 @@ export const useGetPkiSync = (
return useQuery({
queryKey: pkiSyncKeys.byId(syncId, projectId),
queryFn: async () => {
const { data } = await apiRequest.get<TPkiSync>(`/api/v1/pki/syncs/${syncId}`, {
const { data } = await apiRequest.get<TPkiSync>(`/api/v1/cert-manager/syncs/${syncId}`, {
params: { projectId }
});
@@ -138,7 +140,7 @@ export const useListPkiSyncCertificates = (
return useQuery({
queryKey: pkiSyncKeys.certificates(syncId, { offset, limit }),
queryFn: async () => {
const { data } = await apiRequest.get(`/api/v1/pki/syncs/${syncId}/certificates`, {
const { data } = await apiRequest.get(`/api/v1/cert-manager/syncs/${syncId}/certificates`, {
params: { offset, limit }
});
return {
-4
View File
@@ -1,9 +1,5 @@
@import "tailwindcss";
@import "@fontsource/inter/400.css" layer(base);
@import "@fontsource/inter/500.css" layer(base);
@import "@fontsource/inter/700.css" layer(base);
@source not "../public";
/*
+2 -2
View File
@@ -14,8 +14,8 @@ export const KmsLayout = () => {
const location = useLocation();
return (
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
@@ -22,8 +22,8 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { Link, useLocation, useNavigate, useRouter, useRouterState } from "@tanstack/react-router";
import { UserPlusIcon } from "lucide-react";
import { Link, useLocation, useNavigate, useRouter } from "@tanstack/react-router";
import { ChevronRight, UserPlusIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { Mfa } from "@app/components/auth/Mfa";
@@ -31,7 +31,6 @@ import { createNotification } from "@app/components/notifications";
import { OrgPermissionCan } from "@app/components/permissions";
import SecurityClient from "@app/components/utilities/SecurityClient";
import {
BreadcrumbContainer,
Button,
DropdownMenu,
DropdownMenuContent,
@@ -43,7 +42,6 @@ import {
IconButton,
Modal,
ModalContent,
TBreadcrumbFormat,
Tooltip
} from "@app/components/v2";
import { Badge, InstanceIcon, OrgIcon, SubOrgIcon } from "@app/components/v3";
@@ -69,6 +67,7 @@ import { MfaMethod } from "@app/hooks/api/auth/types";
import { getAuthToken } from "@app/hooks/api/reactQuery";
import { Organization, SubscriptionPlan } from "@app/hooks/api/types";
import { AuthMethod } from "@app/hooks/api/users/types";
import { ProjectSelect } from "@app/layouts/ProjectLayout/components/ProjectSelect";
import { navigateUserToOrg } from "@app/pages/auth/LoginPage/Login.utils";
import { ServerAdminsPanel } from "../ServerAdminsPanel/ServerAdminsPanel";
@@ -183,9 +182,6 @@ export const Navbar = () => {
}
}, [subscription, isBillingPage, isModalIntrusive]);
const matches = useRouterState({ select: (s) => s.matches.at(-1)?.context });
const breadcrumbs = matches && "breadcrumbs" in matches ? matches.breadcrumbs : undefined;
const handleOrgChange = async (orgId: string) => {
queryClient.removeQueries({ queryKey: authKeys.getAuthToken });
queryClient.removeQueries({ queryKey: projectKeys.getAllUserProjects() });
@@ -249,7 +245,9 @@ export const Navbar = () => {
const isServerAdminPanel = location.pathname.startsWith("/admin");
const isProjectScope = location.pathname.startsWith(`/organizations/${currentOrg.id}/projects`);
const isProjectScope =
location.pathname.startsWith(`/organizations/${currentOrg.id}/projects`) &&
location.pathname !== `/organizations/${currentOrg.id}/projects`;
const handleOrgNav = async (org: Organization) => {
if (currentOrg?.id === org.id) return;
@@ -279,64 +277,59 @@ export const Navbar = () => {
};
return (
<div className="z-10 flex min-h-12 items-center bg-mineshaft-900 px-4 pt-1">
<div className="mr-auto flex items-center overflow-hidden">
<div className="shrink-0">
<div className="z-10 flex min-h-12 items-center bg-mineshaft-900 px-4">
<div className="mr-auto flex h-full min-w-34 items-center">
<div className="mt-0.5 shrink-0">
<Link to="/organizations/$orgId/projects" params={{ orgId: currentOrg.id }}>
<img alt="infisical logo" src="/images/logotransparent.png" className="h-4" />
</Link>
</div>
<p className="pr-3 pl-1 text-lg text-mineshaft-400/70">/</p>
<ChevronRight size={18} className="mx-3 mt-[3px] text-mineshaft-400/70" />
{isServerAdminPanel ? (
<>
<Link
to="/admin"
className="group flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary"
>
<InstanceIcon className="size-3.5 text-xs text-bunker-300" />
<div className="whitespace-nowrap">Server Console</div>
</Link>
<p className="pr-3 pl-3 text-lg text-mineshaft-400/70">/</p>
{breadcrumbs ? (
// scott: remove /admin as we show server console above
<BreadcrumbContainer breadcrumbs={breadcrumbs.slice(1) as TBreadcrumbFormat[]} />
) : null}
</>
<Link
to="/admin"
className="group flex cursor-pointer items-center gap-2 text-sm text-white transition-all duration-100 hover:text-primary"
>
<InstanceIcon className="size-3.5 text-xs text-bunker-300" />
<div className="whitespace-nowrap">Server Console</div>
</Link>
) : (
<>
<div className="flex min-w-12 items-center overflow-hidden">
<div
className={twMerge(
"relative flex min-w-16 items-center self-end rounded-t-md border-x border-t pt-1.5 pr-2 pb-2.5 pl-3",
!isProjectScope && !isSubOrganization
? "border-org/15 bg-gradient-to-b from-org/10 to-org/[0.075]"
: "border-transparent"
)}
>
{/* scott: the below is used to hide the top border from the org nav bar */}
{!isProjectScope && !isSubOrganization && (
<div className="absolute -bottom-px left-0 h-px w-full bg-mineshaft-900">
<div className="h-full bg-org/[0.075]" />
</div>
)}
<DropdownMenu modal={false} open={isOrgSelectOpen} onOpenChange={setIsOrgSelectOpen}>
<div className="group flex cursor-pointer items-center gap-2 overflow-hidden text-sm text-white transition-all duration-100 hover:text-primary">
<Badge
asChild
variant="org"
isTruncatable
// TODO(scott): either add badge size/style variant or create designated component for namespace/org nav bar
className={twMerge(
"gap-x-1.5 text-sm",
(isProjectScope || isSubOrganization) &&
"bg-transparent text-mineshaft-200 hover:!bg-transparent hover:underline [&>svg]:!text-org"
)}
<div className="group mr-1 flex min-w-0 cursor-pointer items-center gap-2 overflow-hidden text-sm text-white transition-all duration-100">
<button
className="flex cursor-pointer items-center gap-x-2 truncate whitespace-nowrap"
type="button"
onClick={async () => {
navigate({
to: "/organizations/$orgId/projects",
params: { orgId: currentOrg.id }
});
if (isSubOrganization) {
await router.invalidate({ sync: true }).catch(() => null);
}
}}
>
<button
type="button"
onClick={async () => {
navigate({
to: "/organizations/$orgId/projects",
params: { orgId: currentOrg.id }
});
if (isSubOrganization) {
await router.invalidate({ sync: true }).catch(() => null);
}
}}
>
<OrgIcon className="size-[12px]" />
<span>{currentOrg?.name}</span>
</button>
</Badge>
<div className="mr-1 hidden rounded-sm border border-mineshaft-500 px-1 text-xs text-bunker-300 no-underline! md:inline-block">
{getPlan(subscription)}
</div>
<OrgIcon className={twMerge("size-[14px] shrink-0 text-org")} />
<span className="truncate">{currentOrg?.name}</span>
<Badge variant="org" className="hidden lg:inline-flex">
Organization
</Badge>
</button>
{subscription.cardDeclined && (
<Tooltip
content={`Your payment could not be processed${subscription.cardDeclinedReason ? `: ${subscription.cardDeclinedReason}` : ""}. Please update your payment method to continue enjoying premium features.`}
@@ -543,19 +536,15 @@ export const Navbar = () => {
)}
{isProjectScope && (
<>
<p className="pr-3 pl-1 text-lg text-mineshaft-400/70">/</p>
{breadcrumbs ? (
<BreadcrumbContainer
className="min-w-[15rem] flex-1"
breadcrumbs={[breadcrumbs[0]] as TBreadcrumbFormat[]}
/>
) : null}
<ChevronRight size={18} className="mx-3 mt-[3px] text-mineshaft-400/70" />
<ProjectSelect />
</>
)}
</>
)}
</div>
{subscription && subscription.slug === "starter" && !subscription.has_used_trial && (
{subscription && subscription.slug === "starter" && !subscription.has_used_trial ? (
<Tooltip content="Start Free Pro Trial">
<Button
variant="plain"
@@ -576,6 +565,10 @@ export const Navbar = () => {
Free Pro Trial
</Button>
</Tooltip>
) : (
<div className="mt-0.5 mr-3 hidden rounded-sm border border-mineshaft-400 px-1 text-xs text-mineshaft-100 no-underline! opacity-50 md:inline-block">
{getPlan(subscription)}
</div>
)}
{/* eslint-disable-next-line no-nested-ternary */}
{!location.pathname.startsWith("/admin") ? (
@@ -601,7 +594,7 @@ export const Navbar = () => {
}}
>
<UserPlusIcon className="inline-block size-3.5" />
<span className="ml-2 hidden md:inline-block">Invite Members</span>
<span className="ml-2 hidden md:inline-block">Invite Users</span>
</Link>
) : null
}
@@ -705,7 +698,7 @@ export const Navbar = () => {
}}
>
<DropdownMenuItem icon={<FontAwesomeIcon icon={faUserPlus} />}>
Invite Members
Invite Users
</DropdownMenuItem>
</Link>
) : null
@@ -19,9 +19,9 @@ export const OrgNavBar = ({ isHidden }: Props) => {
const variant = isRootOrganization ? "org" : "namespace";
return (
<>
<div className="bg-mineshaft-900">
{!isHidden && (
<div className="dark flex w-full flex-col overflow-x-hidden border-b border-mineshaft-600 bg-mineshaft-900 px-4">
<div className="dark flex w-full flex-col overflow-x-hidden border-y border-t-org/15 border-b-org/5 bg-gradient-to-b from-org/[0.075] to-org/[0.025] px-4 pt-0.5">
<motion.div
key="menu-org-items"
initial={{ x: -150 }}
@@ -114,6 +114,6 @@ export const OrgNavBar = ({ isHidden }: Props) => {
isOpen={popUp?.createOrg?.isOpen}
onClose={() => handlePopUpToggle("createOrg", false)}
/>
</>
</div>
);
};
+2 -2
View File
@@ -29,8 +29,8 @@ export const PamLayout = () => {
return (
<>
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
@@ -29,8 +29,8 @@ export const PkiManagerLayout = () => {
const location = useLocation();
return (
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
@@ -8,7 +8,7 @@ import {
faStar as faSolidStar
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Link, linkOptions } from "@tanstack/react-router";
import { Link, linkOptions, useParams } from "@tanstack/react-router";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { OrgPermissionCan } from "@app/components/permissions";
@@ -46,7 +46,7 @@ const PROJECT_TYPE_NAME: Record<ProjectType, string> = {
[ProjectType.SecretScanning]: "Secret Scanning"
};
export const ProjectSelect = () => {
const ProjectSelectInner = () => {
const [searchProject, setSearchProject] = useState("");
const { currentProject: currentWorkspace } = useProject();
const { currentOrg } = useOrganization();
@@ -92,7 +92,11 @@ export const ProjectSelect = () => {
}, [projects, projectFavorites, currentWorkspace]);
return (
<div className="mr-2 flex items-center gap-1 overflow-hidden">
<div className="relative mr-2 flex min-w-16 items-center gap-1 self-end rounded-t-md border-x border-t border-project/10 bg-gradient-to-b from-project/10 to-project/[0.075] pt-1.5 pr-1 pb-2.5 pl-3">
{/* scott: the below is used to hide the top border from the org nav bar */}
<div className="absolute -bottom-px left-0 h-px w-full bg-mineshaft-900">
<div className="h-full bg-project/[0.075]" />
</div>
<DropdownMenu modal={false}>
<Link
to={getProjectHomePage(currentWorkspace.type, currentWorkspace.environments)}
@@ -100,16 +104,12 @@ export const ProjectSelect = () => {
projectId: currentWorkspace.id,
orgId: currentWorkspace.orgId
}}
className="group flex cursor-pointer items-center gap-x-1.5 overflow-hidden hover:text-white"
className="group flex cursor-pointer items-center gap-x-2 overflow-hidden pt-0.5 text-sm text-white"
>
<p className="inline-block truncate text-mineshaft-200 group-hover:underline">
{currentWorkspace?.name}
</p>
<Badge variant="project">
<ProjectIcon />
<span className="hidden sm:inline-block">
{currentWorkspace.type ? PROJECT_TYPE_NAME[currentWorkspace.type] : "Project"}
</span>
<ProjectIcon className="size-[14px] shrink-0 text-project" />
<span className="truncate">{currentWorkspace?.name}</span>
<Badge variant="project" className="hidden lg:inline-flex">
{currentWorkspace.type ? PROJECT_TYPE_NAME[currentWorkspace.type] : "Project"}
</Badge>
</Link>
<DropdownMenuTrigger asChild>
@@ -118,7 +118,7 @@ export const ProjectSelect = () => {
variant="plain"
colorSchema="secondary"
ariaLabel="switch-project"
className="px-2 py-1"
className="top-px px-2 py-1"
>
<FontAwesomeIcon icon={faCaretDown} className="text-xs text-bunker-300" />
</IconButton>
@@ -238,3 +238,14 @@ export const ProjectSelect = () => {
</div>
);
};
export const ProjectSelect = () => {
const params = useParams({ strict: false });
// Return null during navigation when projectId is not available
if (!params.projectId) {
return null;
}
return <ProjectSelectInner />;
};
@@ -39,8 +39,8 @@ export const SecretManagerLayout = () => {
(secretApprovalReqCount?.open || 0) + (accessApprovalRequestCount?.pendingCount || 0);
return (
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
@@ -38,8 +38,8 @@ export const SecretScanningLayout = () => {
);
return (
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
+2 -2
View File
@@ -20,8 +20,8 @@ export const SshLayout = () => {
const location = useLocation();
return (
<div className="dark flex h-full w-full flex-col overflow-x-hidden">
<div className="border-b border-mineshaft-600 bg-mineshaft-900">
<div className="dark flex h-full w-full flex-col overflow-x-hidden bg-mineshaft-900">
<div className="border-y border-t-project/10 border-b-project/5 bg-gradient-to-b from-project/[0.075] to-project/[0.025] px-4 pt-0.5">
<motion.div
key="menu-project-items"
initial={{ x: -150 }}
+2
View File
@@ -12,6 +12,8 @@ import { NotFoundPage } from "./pages/public/NotFoundPage/NotFoundPage";
// Import the generated route tree
import { routeTree } from "./routeTree.gen";
import "@fontsource/inter/400.css";
import "@fontsource/inter/500.css";
import "@xyflow/react/dist/style.css";
import "nprogress/nprogress.css";
import "react-toastify/dist/ReactToastify.css";
@@ -17,7 +17,7 @@ export const AccessManagementPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope="instance"
title="Access Control"
title="Server Admin Access Control"
description="Manage server admins within your Infisical instance."
/>
<ServerAdminsTable />
@@ -29,7 +29,7 @@ export const ResourceOverviewPage = () => {
Users
</Tab>
<Tab variant="instance" value="tab-identities">
Identities
Machine Identities
</Tab>
</TabList>
<TabPanel value="tab-organizations">
@@ -90,7 +90,7 @@ const IdentityPanelTable = ({
value={searchIdentityFilter}
onChange={(e) => setSearchIdentityFilter(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search identities by name..."
placeholder="Search machine identities by name..."
className="flex-1"
/>
</div>
@@ -350,8 +350,8 @@ const ViewMembersModalContent = ({
className="my-auto bg-mineshaft-700"
title={
members.length
? "No organization members match search..."
: "No organization members found"
? "No organization users match search..."
: "No organization users found"
}
icon={faUsers}
/>
@@ -44,10 +44,9 @@ const Page = () => {
const params = useParams({
from: ROUTE_PATHS.CertManager.CertAuthDetailsByIDPage.id
});
const { caName } = params as { caName: string };
const { caId } = params as { caId: string };
const { data } = useGetCa({
caName,
projectId: currentProject?.id || "",
caId,
type: CaType.INTERNAL
}) as { data: TInternalCertificateAuthority };
@@ -66,7 +65,7 @@ const Page = () => {
if (!currentProject?.slug) return;
await deleteCa({
caName,
id: data.id,
projectId: currentProject.id,
type: CaType.INTERNAL
});
@@ -138,7 +137,7 @@ const Page = () => {
</PageHeader>
<div className="flex">
<div className="mr-4 w-96">
<CaDetailsSection caName={data.name} handlePopUpOpen={handlePopUpOpen} />
<CaDetailsSection caId={data.id} handlePopUpOpen={handlePopUpOpen} />
</div>
<div className="w-full">
<CaCertificatesSection caId={data.id} />
@@ -51,7 +51,7 @@ export const CaCrlsTable = ({ caId }: Props) => {
<Tr key={`ca-crl-${id}`}>
<Td>
<div className="flex items-center">
{`${window.origin}/api/v1/pki/crl/${id}`}
{`${window.origin}/api/v1/cert-manager/crl/${id}`}
</div>
</Td>
{/* <Td>{format(new Date(caCrlObj.thisUpdate), "yyyy-MM-dd")}</Td> */}
@@ -4,7 +4,7 @@ import { format } from "date-fns";
import { ProjectPermissionCan } from "@app/components/permissions";
import { Button, IconButton, Tooltip } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useProject } from "@app/context";
import { ProjectPermissionActions, ProjectPermissionSub } from "@app/context";
import { useTimedReset } from "@app/hooks";
import { CaStatus, CaType, InternalCaType, useGetCa } from "@app/hooks/api";
import { caStatusToNameMap, caTypeToNameMap } from "@app/hooks/api/ca/constants";
@@ -13,15 +13,14 @@ import { certKeyAlgorithmToNameMap } from "@app/hooks/api/certificates/constants
import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = {
caName: string;
caId: string;
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["ca", "renewCa", "installCaCert"]>,
data?: object
) => void;
};
export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => {
const { currentProject } = useProject();
export const CaDetailsSection = ({ caId, handlePopUpOpen }: Props) => {
const [copyTextId, isCopyingId, setCopyTextId] = useTimedReset<string>({
initialState: "Copy ID to clipboard"
});
@@ -30,8 +29,7 @@ export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => {
});
const { data } = useGetCa({
caName,
projectId: currentProject.id,
caId,
type: CaType.INTERNAL
});
@@ -53,7 +51,7 @@ export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("ca", {
name: ca.name
caId: ca.id
});
}}
>
@@ -154,10 +152,6 @@ export const CaDetailsSection = ({ caName, handlePopUpOpen }: Props) => {
: "-"}
</p>
</div>
<div className="mb-4">
<p className="text-sm font-medium text-mineshaft-300">Enable Direct Issuance</p>
<p className="text-sm text-mineshaft-300">{ca.enableDirectIssuance ? "True" : "False"}</p>
</div>
{ca.status === CaStatus.ACTIVE && (
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
@@ -3,7 +3,7 @@ import { createFileRoute, linkOptions } from "@tanstack/react-router";
import { CertAuthDetailsByIDPage } from "./CertAuthDetailsByIDPage";
export const Route = createFileRoute(
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caName"
"/_authenticate/_inject-org-details/_org-layout/organizations/$orgId/projects/cert-management/$projectId/_cert-manager-layout/ca/$caId"
)({
component: CertAuthDetailsByIDPage,
beforeLoad: ({ context, params }) => {
@@ -21,7 +21,7 @@ export const Route = createFileRoute(
})
},
{
label: params.caName
label: params.caId
}
]
};
@@ -9,8 +9,8 @@ import { Button, FormControl, Input, Select, SelectItem } from "@app/components/
import { useProject } from "@app/context";
import {
CaStatus,
useGetCaById,
useGetCaCsr,
useGetInternalCaById,
useImportCaCertificate,
useListWorkspaceCas,
useSignIntermediate
@@ -51,7 +51,7 @@ export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => {
projectId: currentProject.id,
status: CaStatus.ACTIVE
});
const { data: ca } = useGetCaById(caId);
const { data: ca } = useGetInternalCaById(caId);
const { data: csr } = useGetCaCsr(caId);
const { mutateAsync: signIntermediate } = useSignIntermediate();
@@ -83,18 +83,21 @@ export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => {
const parentCaId = watch("parentCaId");
const { data: parentCa } = useGetCaById(parentCaId);
const { data: parentCa } = useGetInternalCaById(parentCaId);
useEffect(() => {
if (parentCa?.maxPathLength) {
if (parentCa?.configuration.maxPathLength) {
setValue(
"maxPathLength",
(parentCa.maxPathLength === -1 ? 3 : parentCa.maxPathLength - 1).toString()
(parentCa.configuration.maxPathLength === -1
? 3
: parentCa.configuration.maxPathLength - 1
).toString()
);
}
if (parentCa?.notAfter) {
const parentCaNotAfter = new Date(parentCa.notAfter);
if (parentCa?.configuration.notAfter) {
const parentCaNotAfter = new Date(parentCa.configuration.notAfter);
const middleDate = getMiddleDate(new Date(), parentCaNotAfter);
setValue("notAfter", format(middleDate, "yyyy-MM-dd"));
}
@@ -197,7 +200,7 @@ export const InternalCaInstallForm = ({ caId, handlePopUpToggle }: Props) => {
onValueChange={onChange}
className="w-full"
>
{generatePathLengthOpts(parentCa?.maxPathLength || 0).map((value) => (
{generatePathLengthOpts(parentCa?.configuration.maxPathLength || 0).map((value) => (
<SelectItem value={String(value)} key={`ca-path-length-${value}`}>
{`${value}`}
</SelectItem>
@@ -46,7 +46,6 @@ const schema = z
name: slugSchema({
field: "Name"
}),
enableDirectIssuance: z.boolean(),
status: z.nativeEnum(CaStatus),
configuration: z
.object({
@@ -80,8 +79,7 @@ const caTypes = [
export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
const { currentProject } = useProject();
const { data: ca } = useGetCa({
caName: (popUp?.ca?.data as { name: string })?.name || "",
projectId: currentProject?.id || "",
caId: (popUp?.ca?.data as { caId: string })?.caId || "",
type: CaType.INTERNAL
});
@@ -100,7 +98,6 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: CaType.INTERNAL,
name: "",
status: CaStatus.ACTIVE,
enableDirectIssuance: true,
configuration: {
type: InternalCaType.ROOT,
organization: "",
@@ -124,7 +121,6 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: ca.type,
name: ca.name,
status: ca.status,
enableDirectIssuance: ca.enableDirectIssuance,
configuration: {
type: ca.configuration.type,
organization: ca.configuration.organization,
@@ -151,7 +147,6 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: CaType.INTERNAL,
name: "",
status: CaStatus.ACTIVE,
enableDirectIssuance: false,
configuration: {
type: InternalCaType.ROOT,
organization: "",
@@ -168,24 +163,16 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
}
}, [ca]);
const onFormSubmit = async ({
type,
name,
enableDirectIssuance,
status,
configuration
}: FormData) => {
const onFormSubmit = async ({ type, name, status, configuration }: FormData) => {
if (!currentProject?.slug) return;
if (ca) {
// update
await updateMutateAsync({
caName: ca.name,
projectId: currentProject.id,
id: ca.id,
name,
type: CaType.INTERNAL,
status,
enableDirectIssuance
status
});
} else {
// create
@@ -194,7 +181,6 @@ export const CaModal = ({ popUp, handlePopUpToggle }: Props) => {
name,
type,
status,
enableDirectIssuance,
configuration: {
...configuration,
maxPathLength: Number(configuration.maxPathLength)
@@ -26,10 +26,10 @@ export const CaSection = () => {
"caStatus" // enable / disable
] as const);
const onRemoveCaSubmit = async (caName: string) => {
const onRemoveCaSubmit = async (id: string) => {
if (!currentProject?.slug) return;
await deleteCa({ caName, projectId: currentProject.id, type: CaType.INTERNAL });
await deleteCa({ id, projectId: currentProject.id, type: CaType.INTERNAL });
createNotification({
text: "Successfully deleted CA",
@@ -39,10 +39,10 @@ export const CaSection = () => {
handlePopUpClose("deleteCa");
};
const onUpdateCaStatus = async ({ caName, status }: { caName: string; status: CaStatus }) => {
const onUpdateCaStatus = async ({ caId, status }: { caId: string; status: CaStatus }) => {
if (!currentProject?.slug) return;
await updateCa({ caName, projectId: currentProject.id, type: CaType.INTERNAL, status });
await updateCa({ id: caId, type: CaType.INTERNAL, status });
createNotification({
text: `Successfully ${status === CaStatus.ACTIVE ? "enabled" : "disabled"} CA`,
@@ -85,9 +85,7 @@ export const CaSection = () => {
subTitle="This action will delete other CAs and certificates below it in your CA hierarchy."
onChange={(isOpen) => handlePopUpToggle("deleteCa", isOpen)}
deleteKey="confirm"
onDeleteApproved={() =>
onRemoveCaSubmit((popUp?.deleteCa?.data as { caName: string })?.caName)
}
onDeleteApproved={() => onRemoveCaSubmit((popUp?.deleteCa?.data as { caId: string })?.caId)}
/>
<DeleteActionModal
isOpen={popUp.caStatus.isOpen}
@@ -104,7 +102,7 @@ export const CaSection = () => {
onChange={(isOpen) => handlePopUpToggle("caStatus", isOpen)}
deleteKey="confirm"
onDeleteApproved={() =>
onUpdateCaStatus(popUp?.caStatus?.data as { caName: string; status: CaStatus })
onUpdateCaStatus(popUp?.caStatus?.data as { caId: string; status: CaStatus })
}
/>
</div>
@@ -81,11 +81,11 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {
key={`ca-${ca.id}`}
onClick={() =>
navigate({
to: "/organizations/$orgId/projects/cert-management/$projectId/ca/$caName",
to: "/organizations/$orgId/projects/cert-management/$projectId/ca/$caId",
params: {
orgId: currentOrg.id,
projectId: currentProject.id,
caName: ca.name
caId: ca.id
}
})
}
@@ -180,7 +180,7 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("caStatus", {
caName: ca.name,
caId: ca.id,
status:
ca.status === CaStatus.ACTIVE
? CaStatus.DISABLED
@@ -207,7 +207,7 @@ export const CaTable = ({ handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("deleteCa", {
caName: ca.name
caId: ca.id
});
}}
disabled={!isAllowed}
@@ -14,8 +14,7 @@ import {
Modal,
ModalContent,
Select,
SelectItem,
Switch
SelectItem
} from "@app/components/v2";
import { useProject } from "@app/context";
import { APP_CONNECTION_MAP } from "@app/helpers/appConnections";
@@ -27,6 +26,10 @@ import {
TCloudflareZone,
useCloudflareConnectionListZones
} from "@app/hooks/api/appConnections/cloudflare";
import {
TDNSMadeEasyZone,
useDNSMadeEasyConnectionListZones
} from "@app/hooks/api/appConnections/dns-made-easy";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import {
AcmeDnsProvider,
@@ -59,7 +62,6 @@ const baseSchema = z.object({
name: slugSchema({
field: "Name"
}),
enableDirectIssuance: z.boolean(),
status: z.nativeEnum(CaStatus)
});
@@ -131,8 +133,7 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
const { currentProject } = useProject();
const { data: ca, isLoading: isCaLoading } = useGetCa({
caName: (popUp?.ca?.data as { name: string })?.name || "",
projectId: currentProject?.id || "",
caId: (popUp?.ca?.data as { caId: string })?.caId || "",
type: (popUp?.ca?.data as { type: CaType })?.type || ""
});
@@ -168,7 +169,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: CaType.AZURE_AD_CS,
name: "",
status: CaStatus.ACTIVE,
enableDirectIssuance: false,
configuration: {
azureAdcsConnection: {
id: "",
@@ -181,7 +181,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: CaType.ACME,
name: "",
status: CaStatus.ACTIVE,
enableDirectIssuance: true,
configuration: {
dnsAppConnection: {
id: "",
@@ -211,6 +210,11 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
enabled: caType === CaType.ACME
});
const { data: availableDNSMadeEasyConnections, isPending: isDNSMadeEasyPending } =
useListAvailableAppConnections(AppConnection.DNSMadeEasy, currentProject.id, {
enabled: caType === CaType.ACME
});
const { data: availableAzureConnections, isPending: isAzurePending } =
useListAvailableAppConnections(AppConnection.AzureADCS, currentProject.id, {
enabled: caType === CaType.AZURE_AD_CS
@@ -220,16 +224,24 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
if (caType === CaType.AZURE_AD_CS) {
return availableAzureConnections || [];
}
return [...(availableRoute53Connections || []), ...(availableCloudflareConnections || [])];
return [
...(availableRoute53Connections || []),
...(availableCloudflareConnections || []),
...(availableDNSMadeEasyConnections || [])
];
}, [
caType,
availableRoute53Connections,
availableCloudflareConnections,
availableDNSMadeEasyConnections,
availableAzureConnections
]);
const isPending =
isRoute53Pending || isCloudflarePending || (isAzurePending && caType === CaType.AZURE_AD_CS);
isRoute53Pending ||
isCloudflarePending ||
isDNSMadeEasyPending ||
(isAzurePending && caType === CaType.AZURE_AD_CS);
const dnsAppConnection =
caType === CaType.ACME && configuration && "dnsAppConnection" in configuration
@@ -241,6 +253,11 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
enabled: dnsProvider === AcmeDnsProvider.Cloudflare && !!dnsAppConnection.id
});
const { data: dnsMadeEasyZones = [], isPending: isDNSMadeEasyZonesPending } =
useDNSMadeEasyConnectionListZones(dnsAppConnection.id, {
enabled: dnsProvider === AcmeDnsProvider.DNSMadeEasy && !!dnsAppConnection.id
});
// Populate form with CA data when editing
useEffect(() => {
if (ca && !isCaLoading) {
@@ -253,7 +270,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: ca.type,
name: ca.name,
status: ca.status,
enableDirectIssuance: ca.enableDirectIssuance,
configuration: {
dnsAppConnection: {
id: ca.configuration.dnsAppConnectionId,
@@ -278,7 +294,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
type: ca.type,
name: ca.name,
status: ca.status,
enableDirectIssuance: false,
configuration: {
azureAdcsConnection: {
id: ca.configuration.azureAdcsConnectionId,
@@ -293,7 +308,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
const onFormSubmit = async ({
type,
name,
enableDirectIssuance,
status,
configuration: formConfiguration
}: FormData) => {
@@ -320,12 +334,11 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
if (ca) {
await updateMutateAsync({
caName: ca.name,
id: ca.id,
projectId: currentProject.id,
name,
type,
status,
enableDirectIssuance: type === CaType.AZURE_AD_CS ? false : enableDirectIssuance,
configuration: configPayload
});
} else {
@@ -334,7 +347,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
name,
type,
status,
enableDirectIssuance: type === CaType.AZURE_AD_CS ? false : enableDirectIssuance,
configuration: configPayload
});
}
@@ -500,6 +512,32 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
)}
/>
)}
{dnsProvider === AcmeDnsProvider.DNSMadeEasy && (
<Controller
name="configuration.dnsProviderConfig.hostedZoneId"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Zone"
>
<FilterableSelect
isLoading={isDNSMadeEasyZonesPending && !!dnsAppConnection.id}
isDisabled={!dnsAppConnection.id}
value={dnsMadeEasyZones.find((zone) => zone.id === value)}
onChange={(option) => {
onChange((option as SingleValue<TDNSMadeEasyZone>)?.id ?? null);
}}
options={dnsMadeEasyZones}
placeholder="Select a zone..."
getOptionLabel={(option) => option.name}
getOptionValue={(option) => option.id}
/>
</FormControl>
)}
/>
)}
<Controller
control={control}
defaultValue=""
@@ -601,25 +639,6 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
name="configuration.azureAdcsConnection"
/>
)}
{caType === CaType.ACME && (
<Controller
control={control}
name="enableDirectIssuance"
render={({ field, fieldState: { error } }) => {
return (
<FormControl isError={Boolean(error)} errorText={error?.message} className="my-8">
<Switch
id="is-active"
onCheckedChange={(value) => field.onChange(value)}
isChecked={field.value}
>
<p className="w-full">Enable Direct Issuance</p>
</Switch>
</FormControl>
);
}}
/>
)}
<div className="flex items-center">
<Button
className="mr-4"
@@ -22,10 +22,10 @@ export const ExternalCaSection = () => {
"caStatus" // enable / disable
] as const);
const onRemoveCaSubmit = async (caName: string, type: CaType) => {
const onRemoveCaSubmit = async (id: string, type: CaType) => {
if (!currentProject?.id) return;
await deleteCa({ caName, type, projectId: currentProject.id });
await deleteCa({ id, type, projectId: currentProject.id });
createNotification({
text: "Successfully deleted CA",
@@ -36,17 +36,17 @@ export const ExternalCaSection = () => {
};
const onUpdateCaStatus = async ({
name,
caId,
type,
status
}: {
name: string;
caId: string;
type: CaType;
status: CaStatus;
}) => {
if (!currentProject?.slug) return;
await updateCa({ caName: name, type, status, projectId: currentProject.id });
await updateCa({ id: caId, type, status });
createNotification({
text: `Successfully ${status === CaStatus.ACTIVE ? "enabled" : "disabled"} CA`,
@@ -88,7 +88,7 @@ export const ExternalCaSection = () => {
deleteKey="confirm"
onDeleteApproved={() =>
onRemoveCaSubmit(
(popUp?.deleteCa?.data as { name: string })?.name,
(popUp?.deleteCa?.data as { caId: string })?.caId,
(popUp?.deleteCa?.data as { type: CaType })?.type
)
}
@@ -110,7 +110,7 @@ export const ExternalCaSection = () => {
deleteKey="confirm"
onDeleteApproved={() =>
onUpdateCaStatus(
popUp?.caStatus?.data as { name: string; type: CaType; status: CaStatus }
popUp?.caStatus?.data as { caId: string; type: CaType; status: CaStatus }
)
}
/>
@@ -35,6 +35,7 @@ type Props = {
handlePopUpOpen: (
popUpName: keyof UsePopUpState<["ca", "deleteCa", "caStatus"]>,
data?: {
caId?: string;
name?: string;
type?: CaType;
status?: CaStatus;
@@ -70,6 +71,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => {
key={`ca-${ca.id}`}
onClick={() => {
handlePopUpOpen("ca", {
caId: ca.id,
name: ca.name,
type: ca.type
});
@@ -104,6 +106,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("ca", {
caId: ca.id,
name: ca.name,
type: ca.type
});
@@ -129,7 +132,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("caStatus", {
name: ca.name,
caId: ca.id,
type: ca.type,
status:
ca.status === CaStatus.ACTIVE
@@ -157,7 +160,7 @@ export const ExternalCaTable = ({ handlePopUpOpen }: Props) => {
onClick={(e) => {
e.stopPropagation();
handlePopUpOpen("deleteCa", {
name: ca.name,
caId: ca.id,
type: ca.type
});
}}
@@ -21,7 +21,13 @@ type Props = {
) => void;
onFormatSelected: (
format: "pem" | "pkcs12",
serialNumber: string,
{
certificateId,
serialNumber
}: {
certificateId: string;
serialNumber: string;
},
options?: ExportOptions
) => void;
};
@@ -42,8 +48,11 @@ export const CertificateExportModal = ({ popUp, handlePopUpToggle, onFormatSelec
alias: ""
});
const serialNumber =
(popUp?.certificateExport?.data as { serialNumber: string })?.serialNumber || "";
const { certificateId, serialNumber } =
(popUp?.certificateExport?.data as {
certificateId: string;
serialNumber: string;
}) || {};
// Reset form whenever the modal opens
useEffect(() => {
@@ -64,14 +73,21 @@ export const CertificateExportModal = ({ popUp, handlePopUpToggle, onFormatSelec
};
const handleExport = () => {
if (serialNumber && isFormValid()) {
if ((certificateId || serialNumber) && isFormValid()) {
const options: ExportOptions = {};
if (selectedFormat === "pkcs12") {
options.pkcs12 = pkcs12Options;
}
onFormatSelected(selectedFormat, serialNumber, options);
onFormatSelected(
selectedFormat,
{
certificateId,
serialNumber
},
options
);
handlePopUpToggle("certificateExport", false);
}
};
@@ -151,7 +167,7 @@ export const CertificateExportModal = ({ popUp, handlePopUpToggle, onFormatSelec
colorSchema="primary"
leftIcon={<FontAwesomeIcon icon={faDownload} />}
onClick={handleExport}
disabled={!serialNumber || !isFormValid()}
disabled={!(certificateId || serialNumber) || !isFormValid()}
>
Export {selectedFormat.toUpperCase()}
</Button>
@@ -50,11 +50,11 @@ export const CertificateRevocationModal = ({ popUp, handlePopUpToggle }: Props)
const onFormSubmit = async ({ revocationReason }: FormData) => {
if (!currentProject?.slug) return;
const { serialNumber } = popUp.revokeCertificate.data as { serialNumber: string };
const { certificateId } = popUp.revokeCertificate.data as { certificateId: string };
await revokeCertificate({
projectId: currentProject.id,
serialNumber,
id: certificateId,
revocationReason
});
@@ -26,8 +26,8 @@ import { useProject } from "@app/context";
import {
CaStatus,
useCreateCertTemplate,
useGetCaById,
useGetCertTemplate,
useGetInternalCaById,
useListWorkspaceCas,
useListWorkspacePkiCollections,
useUpdateCertTemplate
@@ -84,7 +84,7 @@ type Props = {
export const CertificateTemplateModal = ({ popUp, handlePopUpToggle, caId }: Props) => {
const { currentProject } = useProject();
const { data: ca } = useGetCaById(caId);
const { data: ca } = useGetInternalCaById(caId);
const { data: certTemplate } = useGetCertTemplate(
(popUp?.certificateTemplate?.data as { id: string })?.id || ""
@@ -39,11 +39,11 @@ export const CertificatesSection = () => {
"managePkiSyncs"
] as const);
const onRemoveCertificateSubmit = async (serialNumber: string) => {
const onRemoveCertificateSubmit = async (id: string) => {
if (!currentProject?.slug) return;
await deleteCert({
serialNumber,
id,
projectId: currentProject.id
});
@@ -57,7 +57,13 @@ export const CertificatesSection = () => {
const handleCertificateExport = async (
format: "pem" | "pkcs12",
serialNumber: string,
{
certificateId,
serialNumber
}: {
certificateId: string;
serialNumber: string;
},
options?: ExportOptions
) => {
if (format === "pem") {
@@ -75,7 +81,7 @@ export const CertificatesSection = () => {
try {
await downloadCertPkcs12({
serialNumber,
certificateId,
projectSlug: currentProject.slug,
password: options.pkcs12.password,
alias: options.pkcs12.alias
@@ -150,7 +156,7 @@ export const CertificatesSection = () => {
deleteKey="confirm"
onDeleteApproved={() =>
onRemoveCertificateSubmit(
(popUp?.deleteCertificate?.data as { serialNumber: string })?.serialNumber
(popUp?.deleteCertificate?.data as { certificateId: string })?.certificateId
)
}
/>
@@ -277,6 +277,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
)}
onClick={async () =>
handlePopUpOpen("certificateExport", {
certificateId: certificate.id,
serialNumber: certificate.serialNumber
})
}
@@ -501,7 +502,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
)}
onClick={async () =>
handlePopUpOpen("revokeCertificate", {
serialNumber: certificate.serialNumber
certificateId: certificate.id
})
}
disabled={!isAllowed}
@@ -524,7 +525,7 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
)}
onClick={async () =>
handlePopUpOpen("deleteCertificate", {
serialNumber: certificate.serialNumber,
certificateId: certificate.id,
commonName: certificate.commonName
})
}
@@ -49,7 +49,7 @@ export const IntegrationsListPage = () => {
<div className="mb-8">
<PageHeader
scope={ProjectType.CertificateManager}
title="Integrations"
title="Project Integrations"
description="Manage integrations with third-party certificate services."
/>
<Tabs orientation="vertical" value={currentTab} onValueChange={updateSelectedTab}>
@@ -171,7 +171,7 @@ export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen
onClick={() =>
handlePopUpOpen &&
handlePopUpOpen("revokeCertificate", {
serialNumber: certificate.serialNumber
certificateId: certificate.id
})
}
disabled={!isAllowed}
@@ -675,7 +675,7 @@ export const CreateProfileModal = ({
isDisabled={Boolean(isEdit)}
>
<SelectItem value="ca">Certificate Authority</SelectItem>
<SelectItem value="self-signed">Self-signed</SelectItem>
<SelectItem value="self-signed">Self-Signed</SelectItem>
</Select>
</FormControl>
)}
@@ -30,7 +30,7 @@ import {
ProjectPermissionSub
} from "@app/context/ProjectPermissionContext/types";
import { usePopUp, useToggle } from "@app/hooks";
import { useGetCaById } from "@app/hooks/api/ca/queries";
import { useGetInternalCaById } from "@app/hooks/api/ca/queries";
import { IssuerType, TCertificateProfile } from "@app/hooks/api/certificateProfiles";
import { useGetCertificateTemplateV2ById } from "@app/hooks/api/certificateTemplates/queries";
import { CertificateIssuanceModal } from "@app/pages/cert-manager/CertificatesPage/components/CertificateIssuanceModal";
@@ -50,9 +50,7 @@ export const ProfileRow = ({
}: Props) => {
const { permission } = useProjectPermission();
const { data: caData } = useGetCaById(
profile.certificateAuthority?.isExternal ? "" : (profile.caId ?? "")
);
const { data: caData } = useGetInternalCaById(profile.caId ?? "");
const { popUp, handlePopUpToggle } = usePopUp(["issueCertificate"] as const);
@@ -123,18 +121,15 @@ export const ProfileRow = ({
</Td>
<Td className="text-start">{getEnrollmentTypeBadge(profile.enrollmentType)}</Td>
<Td className="text-start">
<div className="flex items-center gap-2">
<span className="text-sm text-mineshaft-300">
{profile.issuerType === IssuerType.SELF_SIGNED
? "Self-signed"
: profile.certificateAuthority?.isExternal
? profile.certificateAuthority.name
: caData?.friendlyName ||
caData?.commonName ||
profile.certificateAuthority?.name ||
profile.caId}
</span>
</div>
<span className="text-sm text-mineshaft-300">
{profile.issuerType === IssuerType.SELF_SIGNED
? "Self-signed"
: profile.certificateAuthority?.isExternal
? profile.certificateAuthority.name
: caData?.configuration.friendlyName ||
caData?.configuration.commonName ||
profile.caId}
</span>
</Td>
<Td>
<span className="text-sm text-mineshaft-300">
@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -15,6 +18,7 @@ const tabs = [
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
@@ -22,7 +26,17 @@ export const SettingsPage = () => {
<title>{t("common.head-title", { title: t("settings.project.title") })}</title>
</Helmet>
<div className="w-full max-w-8xl">
<PageHeader scope={ProjectType.CertificateManager} title={t("settings.project.title")} />
<PageHeader scope={ProjectType.CertificateManager} title={t("settings.project.title")}>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList>
{tabs.map((tab) => (
@@ -20,7 +20,7 @@ export const OverviewPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope={ProjectType.KMS}
title="Overview"
title="Project Overview"
description="Manage keys and perform cryptographic operations."
/>
<ProjectPermissionCan
@@ -1,7 +1,10 @@
import { Helmet } from "react-helmet";
import { useTranslation } from "react-i18next";
import { Link } from "@tanstack/react-router";
import { InfoIcon } from "lucide-react";
import { PageHeader, Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { useOrganization } from "@app/context";
import { ProjectType } from "@app/hooks/api/projects/types";
import { ProjectGeneralTab } from "@app/pages/project/SettingsPage/components/ProjectGeneralTab";
@@ -16,6 +19,8 @@ const tabs = [
export const SettingsPage = () => {
const { t } = useTranslation();
const { currentOrg } = useOrganization();
return (
<div className="flex h-full w-full justify-center bg-bunker-800 text-white">
<Helmet>
@@ -24,9 +29,19 @@ export const SettingsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={ProjectType.KMS}
title="Settings"
title="Project Settings"
description="Configure general project settings"
/>
>
<Link
to="/organizations/$orgId/settings"
params={{
orgId: currentOrg.id
}}
className="flex items-center gap-x-1.5 text-xs whitespace-nowrap text-neutral hover:underline"
>
<InfoIcon size={12} /> Looking for organization settings?
</Link>
</PageHeader>
<Tabs orientation="vertical" defaultValue={tabs[0].key}>
<TabList>
{tabs.map((tab) => (
@@ -58,7 +58,7 @@ export const AccessManagementPage = () => {
},
{
key: OrgAccessControlTabSections.Identities,
label: "Identities",
label: "Machine Identities",
isHidden: permission.cannot(
OrgPermissionIdentityActions.Read,
OrgPermissionSubjects.Identity
@@ -83,8 +83,8 @@ export const AccessManagementPage = () => {
<div className="mx-auto mb-6 w-full max-w-8xl">
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Access Control"
description="Manage fine-grained access for users, groups, roles, and identities within your organization resources."
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Access Control`}
description="Manage fine-grained access for users, groups, roles, and machine identities within your organization resources."
/>
{!currentOrg.shouldUseNewPrivilegeSystem && (
<div className="mt-4 mb-4 flex flex-col rounded-r border-l-2 border-l-primary bg-mineshaft-300/5 px-4 py-2.5">
@@ -51,19 +51,19 @@ export const OrgGroupsSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Groups</p>
<p className="text-xl font-medium text-mineshaft-100">Organization Groups</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/groups" />
</div>
<OrgPermissionCan I={OrgPermissionGroupActions.Create} a={OrgPermissionSubjects.Groups}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => handleAddGroupModal()}
isDisabled={!isAllowed}
>
Create Group
Create Organization Group
</Button>
)}
</OrgPermissionCan>
@@ -159,7 +159,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search groups..."
placeholder="Search organization groups..."
/>
<TableContainer className="mt-4">
<Table>
@@ -205,7 +205,7 @@ export const OrgGroupsTable = ({ handlePopUpOpen }: Props) => {
</Th>
<Th>
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === GroupsOrderBy.Role ? "" : "opacity-30"}`}
@@ -154,7 +154,9 @@ export const IdentityAuthTemplateModal = ({ popUp, handlePopUpToggle }: Props) =
onOpenChange={handleClose}
>
<ModalContent
title={isEdit ? "Edit Identity Auth Template" : "Create Identity Auth Template"}
title={
isEdit ? "Edit Machine Identity Auth Template" : "Create Machine Identity Auth Template"
}
subTitle={
isEdit ? "Update the authentication template" : "Create a new authentication template"
}
@@ -73,7 +73,7 @@ export const IdentitySection = withPermission(
});
createNotification({
text: "Successfully deleted identity",
text: "Successfully deleted machine identity",
type: "success"
});
@@ -99,7 +99,9 @@ export const IdentitySection = withPermission(
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex flex-1 items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Identities</p>
<p className="text-xl font-medium text-mineshaft-100">
Organization Machine Identities
</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/machine-identities" />
</div>
<div className="flex items-center">
@@ -116,7 +118,7 @@ export const IdentitySection = withPermission(
if (!isMoreIdentitiesAllowed && !isEnterprise) {
handlePopUpOpen("upgradePlan", {
description:
"You can add more identities if you upgrade your Infisical Pro plan."
"You can add more machine identities if you upgrade your Infisical Pro plan."
});
return;
}
@@ -129,7 +131,9 @@ export const IdentitySection = withPermission(
}}
isDisabled={!isAllowed}
>
Create Identity
{isSubOrganization
? "Add Machine Identity to Sub-Organization"
: "Create Organization Machine Identity"}
</Button>
)}
</OrgPermissionCan>
@@ -141,7 +145,9 @@ export const IdentitySection = withPermission(
<div className="mt-4 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Identity Auth Templates</p>
<p className="text-xl font-medium text-mineshaft-100">
Machine Identity Auth Templates
</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/auth-templates" />
</div>
<OrgPermissionCan
@@ -150,14 +156,14 @@ export const IdentitySection = withPermission(
>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (subscription && !subscription.machineIdentityAuthTemplates) {
handlePopUpOpen("upgradePlan", {
isEnterpriseFeature: true,
text: "Your current plan does not include access to creating Identity Auth Templates. To unlock this feature, please upgrade to Infisical Enterprise plan."
text: "Your current plan does not include access to creating Machine Identity Auth Templates. To unlock this feature, please upgrade to Infisical Enterprise plan."
});
return;
}
@@ -197,9 +203,15 @@ export const IdentitySection = withPermission(
>
<ModalContent
bodyClassName="overflow-visible"
title="Add Identity"
title={
isSubOrganization
? "Add Machine Identity to Sub-Organization"
: "Create Organization Machine Identity"
}
subTitle={
isSubOrganization ? "Create a new identity or assign an existing identity" : undefined
isSubOrganization
? "Create a new machine identity or assign an existing one"
: undefined
}
>
<AnimatePresence mode="wait">
@@ -224,11 +236,11 @@ export const IdentitySection = withPermission(
>
<div className="flex items-center gap-2">
<PlusIcon size="1rem" />
<div>Create New Identity</div>
<div>Create Machine Identity</div>
</div>
<div className="mt-2 text-xs text-mineshaft-300">
Create a new machine identity specifically for this sub-organization. This
identity will be managed at the sub-organization level.
machine identity will be managed at the sub-organization level.
</div>
</div>
<div
@@ -244,11 +256,11 @@ export const IdentitySection = withPermission(
>
<div className="flex items-center gap-2">
<LinkIcon size="1rem" />
<div>Assign Existing Identity</div>
<div>Assign Existing Machine Identity</div>
</div>
<div className="mt-2 text-xs text-mineshaft-300">
Assign an existing identity from your parent organization. The identity will
continue to be managed at its original scope.
Assign an existing machine identity from your parent organization. The machine
identity will continue to be managed at its original scope.
</div>
</div>
</motion.div>
@@ -152,7 +152,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
});
createNotification({
text: "Successfully updated identity role",
text: "Successfully updated machine identity role",
type: "success"
});
};
@@ -178,7 +178,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
<DropdownMenu>
<DropdownMenuTrigger asChild>
<IconButton
ariaLabel="Filter Identities"
ariaLabel="Filter Machine Identities"
variant="plain"
size="sm"
className={twMerge(
@@ -200,7 +200,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Apply Roles to Filter Identities
Filter Organization Machine Identities by Role
</DropdownMenuLabel>
{roles?.map(({ id, slug, name }) => (
<DropdownMenuItem
@@ -229,7 +229,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search identities by name..."
placeholder="Search machine identities by name..."
/>
</div>
<TableContainer>
@@ -258,7 +258,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
</Th>
<Th>
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === OrgIdentityOrderBy.Role ? "" : "opacity-30"}`}
@@ -407,7 +407,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
}}
isDisabled={!isAllowed}
>
Edit Identity {isSubOrgIdentity ? "" : "Membership"}
Edit Machine Identity {isSubOrgIdentity ? "" : "Membership"}
</DropdownMenuItem>
)}
</OrgPermissionCan>
@@ -428,7 +428,7 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
icon={<FontAwesomeIcon icon={faTrash} />}
>
{isSubOrgIdentity
? "Delete Identity"
? "Delete Machine Identity"
: "Remove From Sub-Organization"}
</DropdownMenuItem>
)}
@@ -455,8 +455,8 @@ export const IdentityTable = ({ handlePopUpOpen }: Props) => {
<EmptyState
title={
debouncedSearch.trim().length > 0 || filter.roles?.length > 0
? "No identities match search filter"
: "No identities have been created in this organization"
? "No machine identities match search filter"
: "No machine identities have been created in this organization"
}
icon={faServer}
/>
@@ -78,11 +78,11 @@ export const OrgIdentityLinkForm = ({ onClose }: Props) => {
control={control}
name="identity"
render={({ field: { onChange, value }, fieldState: { error } }) => (
<FormControl label="Identity" errorText={error?.message} isError={Boolean(error)}>
<FormControl label="Machine Identity" errorText={error?.message} isError={Boolean(error)}>
<FilterableSelect
value={value}
onChange={onChange}
placeholder="Select identity..."
placeholder="Select machine identity..."
// onInputChange={setSearchValue}
options={rootOrgIdentities}
getOptionValue={(option) => option.id}
@@ -164,7 +164,7 @@ export const OrgIdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
}
createNotification({
text: `Successfully ${popUp?.identity?.data ? "updated" : "created"} identity`,
text: `Successfully ${popUp?.identity?.data ? "updated" : "created"} machine identity`,
type: "success"
});
@@ -255,9 +255,7 @@ export const OrgIdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
/>
</div>
<div className="grow">
{i === 0 && (
<FormLabel label="Value" className="text-xs text-mineshaft-400" isOptional />
)}
{i === 0 && <FormLabel label="Value" className="text-xs text-mineshaft-400" />}
<Controller
control={control}
name={`metadata.${i}.value`}
@@ -159,14 +159,16 @@ export const AddOrgMemberModal = ({
)
);
setCompleteInviteLinks(data?.completeInviteLinks ?? null);
if (data?.completeInviteLinks && data?.completeInviteLinks.length > 0) {
setCompleteInviteLinks(data.completeInviteLinks);
}
// only show this notification when email is configured.
// A [completeInviteLink] will not be sent if smtp is configured
if (!data.completeInviteLinks) {
if (!data.completeInviteLinks?.length) {
createNotification({
text: "Successfully invited user to the organization.",
text: `Successfully invited user${usernames.length > 1 ? "s" : ""} to the organization.`,
type: "success"
});
}
@@ -205,13 +205,13 @@ export const OrgMembersSection = () => {
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex flex-wrap items-center justify-between gap-2">
<div className="flex items-center gap-x-2">
<p className="text-xl font-medium text-mineshaft-100">Users</p>
<p className="text-xl font-medium text-mineshaft-100">Organization Users</p>
<DocumentationLinkBadge href="https://infisical.com/docs/documentation/platform/identities/user-identities" />
</div>
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Member}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<UserPlusIcon size={16} />}
onClick={() =>
@@ -219,7 +219,9 @@ export const OrgMembersSection = () => {
}
isDisabled={!isAllowed}
>
{isSubOrganization ? "Add Members" : "Invite Members"}
{isSubOrganization
? "Add Users to Sub-Organization"
: "Invite Users to Organization"}
</Button>
)}
</OrgPermissionCan>
@@ -336,7 +336,7 @@ export const OrgMembersTable = ({
</DropdownSubMenuTrigger>
<DropdownSubMenuContent className="max-h-80 thin-scrollbar overflow-y-auto rounded-l-none">
<DropdownMenuLabel className="sticky top-0 bg-mineshaft-900">
Apply Roles to Filter Users
Filter Organization Users by Role
</DropdownMenuLabel>
{roles?.map(({ id, slug, name }) => (
<DropdownMenuItem
@@ -365,7 +365,7 @@ export const OrgMembersTable = ({
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search members..."
placeholder="Search organization users..."
/>
</div>
<TableContainer className="mt-4">
@@ -434,7 +434,7 @@ export const OrgMembersTable = ({
</Th>
<Th className="w-1/3">
<div className="flex items-center">
Role
Organization Role
<IconButton
variant="plain"
className={`ml-2 ${orderBy === OrgMembersOrderBy.Role ? "" : "opacity-30"}`}
@@ -727,8 +727,8 @@ export const OrgMembersTable = ({
<EmptyState
title={
members.length
? "No organization members match search..."
: "No organization members found"
? "No organization users match search..."
: "No organization users found"
}
icon={members.length ? faSearch : faUsers}
/>
@@ -199,7 +199,7 @@ export const OrgRoleTable = () => {
<OrgPermissionCan I={OrgPermissionActions.Create} a={OrgPermissionSubjects.Role}>
{(isAllowed) => (
<Button
colorSchema="secondary"
variant="outline_bg"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
@@ -207,7 +207,7 @@ export const OrgRoleTable = () => {
}}
isDisabled={!isAllowed}
>
Add Role
Add Organization Role
</Button>
)}
</OrgPermissionCan>
@@ -216,7 +216,7 @@ export const OrgRoleTable = () => {
value={search}
onChange={(e) => setSearch(e.target.value)}
leftIcon={<FontAwesomeIcon icon={faMagnifyingGlass} />}
placeholder="Search roles..."
placeholder="Search organization roles..."
className="flex-1"
containerClassName="mb-4"
/>
@@ -441,7 +441,7 @@ export const OrgRoleTable = () => {
<EmptyState
title={
roles?.length
? "No roles match search..."
? "No organization roles match search..."
: "This organization does not have any roles"
}
icon={roles?.length ? faSearch : undefined}
@@ -27,7 +27,7 @@ export const AppConnectionsPage = withPermission(
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
className="w-full"
title="App Connections"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} App Connections`}
description="Manage organization App Connections"
/>
<div className="mb-4 flex w-full flex-col rounded-md border border-blue-500/50 bg-blue-500/30 px-4 py-2 text-sm text-blue-200">
@@ -24,6 +24,7 @@ import { ChefConnectionForm } from "./ChefConnectionForm";
import { CloudflareConnectionForm } from "./CloudflareConnectionForm";
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
import { DigitalOceanConnectionForm } from "./DigitalOceanConnectionForm";
import { DNSMadeEasyConnectionForm } from "./DNSMadeEasyConnectionForm";
import { FlyioConnectionForm } from "./FlyioConnectionForm";
import { GcpConnectionForm } from "./GcpConnectionForm";
import { GitHubConnectionForm } from "./GitHubConnectionForm";
@@ -148,6 +149,8 @@ const CreateForm = ({ app, onComplete, projectId }: CreateFormProps) => {
return <GitLabConnectionForm onSubmit={onSubmit} projectId={projectId} />;
case AppConnection.Cloudflare:
return <CloudflareConnectionForm onSubmit={onSubmit} />;
case AppConnection.DNSMadeEasy:
return <DNSMadeEasyConnectionForm onSubmit={onSubmit} />;
case AppConnection.Bitbucket:
return <BitbucketConnectionForm onSubmit={onSubmit} />;
case AppConnection.Zabbix:
@@ -306,6 +309,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
);
case AppConnection.Cloudflare:
return <CloudflareConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.DNSMadeEasy:
return <DNSMadeEasyConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Bitbucket:
return <BitbucketConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Zabbix:
@@ -0,0 +1,157 @@
import { Controller, FormProvider, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import {
Button,
FormControl,
Input,
ModalClose,
SecretInput,
Select,
SelectItem
} from "@app/components/v2";
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
import { TDNSMadeEasyConnection } from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { DNSMadeEasyConnectionMethod } from "@app/hooks/api/appConnections/types/dns-made-easy-connection";
import {
genericAppConnectionFieldsSchema,
GenericAppConnectionsFields
} from "./GenericAppConnectionFields";
type Props = {
appConnection?: TDNSMadeEasyConnection;
onSubmit: (formData: FormData) => Promise<void>;
};
const rootSchema = genericAppConnectionFieldsSchema.extend({
app: z.literal(AppConnection.DNSMadeEasy)
});
const formSchema = z.discriminatedUnion("method", [
rootSchema.extend({
method: z.literal(DNSMadeEasyConnectionMethod.APIKeySecret),
credentials: z.object({
apiKey: z.string().trim().min(1, "API Key required"),
secretKey: z.string().trim().min(1, "Secret Key required")
})
})
]);
type FormData = z.infer<typeof formSchema>;
export const DNSMadeEasyConnectionForm = ({ appConnection, onSubmit }: Props) => {
const isUpdate = Boolean(appConnection);
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: appConnection ?? {
app: AppConnection.DNSMadeEasy,
method: DNSMadeEasyConnectionMethod.APIKeySecret,
credentials: {
apiKey: "",
secretKey: ""
}
}
});
const {
handleSubmit,
control,
formState: { isSubmitting, isDirty }
} = form;
return (
<FormProvider {...form}>
<form onSubmit={handleSubmit(onSubmit)}>
{!isUpdate && <GenericAppConnectionsFields />}
<Controller
name="method"
control={control}
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipText={`The method you would like to use to connect with ${
APP_CONNECTION_MAP[AppConnection.DNSMadeEasy].name
}. This field cannot be changed after creation.`}
errorText={error?.message}
isError={Boolean(error?.message)}
label="Method"
>
<Select
isDisabled={isUpdate}
value={value}
onValueChange={(val) => onChange(val)}
className="w-full border border-mineshaft-500"
position="popper"
dropdownContainerClassName="max-w-none"
>
{Object.values(DNSMadeEasyConnectionMethod).map((method) => {
return (
<SelectItem value={method} key={method}>
{getAppConnectionMethodDetails(method).name}{" "}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
<Controller
name="credentials.apiKey"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="API Key"
>
<Input
value={value}
onChange={(e) => onChange(e.target.value)}
placeholder="af1b628f-3272-46aa-9cde-837d0c59155d"
/>
</FormControl>
)}
/>
<Controller
name="credentials.secretKey"
control={control}
shouldUnregister
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
errorText={error?.message}
isError={Boolean(error?.message)}
label="Secret Key"
>
<SecretInput
containerClassName="text-gray-400 group-focus-within:border-primary-400/50! border border-mineshaft-500 bg-mineshaft-900 px-2.5 py-1.5"
value={value}
onChange={(e) => onChange(e.target.value)}
/>
</FormControl>
)}
/>
<div className="mt-8 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
colorSchema="secondary"
isLoading={isSubmitting}
isDisabled={isSubmitting || !isDirty}
>
{isUpdate ? "Update Credentials" : "Connect to DNS Made Easy"}
</Button>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">
Cancel
</Button>
</ModalClose>
</div>
</form>
</FormProvider>
);
};
@@ -19,7 +19,7 @@ export const AuditLogsPage = () => {
<div className="w-full max-w-8xl">
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Audit Logs"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Audit Logs`}
description="Audit logs for security and compliance teams to monitor information access."
/>
<LogsSection pageView />
@@ -88,7 +88,7 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Groups
Organization Groups
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
@@ -55,7 +55,7 @@ const Page = () => {
});
createNotification({
text: "Successfully deleted identity",
text: "Successfully deleted machine identity",
type: "success"
});
@@ -82,11 +82,11 @@ const Page = () => {
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Identities
Organization Machine Identities
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
description={`${isSubOrganization ? "Sub-" : ""}Organization Identity`}
description={`${isSubOrganization ? "Sub-" : ""}Organization Machine Identity`}
title={data.identity.name}
>
<div className="flex items-center gap-2">
@@ -111,7 +111,7 @@ const Page = () => {
})
}
>
Unlink Identity
Unlink Machine Identity
</Button>
)}
</OrgPermissionCan>
@@ -142,7 +142,7 @@ const Page = () => {
>
<ModalContent
bodyClassName="overflow-visible"
title={`${popUp?.identity?.data ? "Update" : "Create"} Identity`}
title={`${popUp?.identity?.data ? "Update" : "Create"} Machine Identity`}
>
<OrgIdentityModal popUp={popUp} handlePopUpToggle={handlePopUpToggle} />
</ModalContent>
@@ -45,7 +45,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
return data ? (
<div className="rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
<h3 className="text-lg font-medium text-mineshaft-100">Identity Details</h3>
<h3 className="text-lg font-medium text-mineshaft-100">Details</h3>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
@@ -86,7 +86,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
}}
disabled={!isAllowed}
>
{isOrgIdentity ? "Edit Identity" : "Edit Identity Role"}
{isOrgIdentity ? "Edit Machine Identity" : "Edit Machine Identity Role"}
</DropdownMenuItem>
)}
</OrgPermissionCan>
@@ -110,7 +110,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
icon={<FontAwesomeIcon icon={faTrash} />}
disabled={!isAllowed}
>
{!isOrgIdentity ? "Remove From Sub-Organization" : "Delete Identity"}
{!isOrgIdentity ? "Remove From Sub-Organization" : "Delete Machine Identity"}
</DropdownMenuItem>
)}
</OrgPermissionCan>
@@ -119,7 +119,7 @@ export const IdentityDetailsSection = ({ identityId, handlePopUpOpen, isOrgIdent
</div>
<div className="pt-4">
<div className="mb-4">
<p className="text-sm font-medium text-mineshaft-300">Identity ID</p>
<p className="text-sm font-medium text-mineshaft-300">Machine Identity ID</p>
<div className="group flex align-top">
<p className="text-sm text-mineshaft-300">{data.identity.id}</p>
<div className="opacity-0 transition-opacity duration-300 group-hover:opacity-100">
@@ -167,7 +167,7 @@ export const IdentityAddToProjectModal = ({ identityId, popUp, handlePopUpToggle
handlePopUpToggle("addIdentityToProject", isOpen);
}}
>
<ModalContent bodyClassName="overflow-visible" title="Add Identity to Project">
<ModalContent bodyClassName="overflow-visible" title="Add Machine Identity to Project">
<Content identityId={identityId} handlePopUpToggle={handlePopUpToggle} />
</ModalContent>
</Modal>
@@ -151,7 +151,7 @@ export const IdentityProjectsTable = ({ identityId, handlePopUpOpen }: Props) =>
title={
projectMemberships.length
? "No projects match search..."
: "This identity has not been assigned to any projects"
: "This machine identity has not been assigned to any projects"
}
icon={projectMemberships.length ? faSearch : faFolder}
/>
@@ -55,10 +55,10 @@ const formSchemaWithIdentity = baseFormSchema.extend({
id: z.string(),
name: z.string()
},
{ required_error: "Identity is required" }
{ required_error: "Machine identity is required" }
)
.nullable()
.refine((val) => val !== null, { message: "Identity is required" })
.refine((val) => val !== null, { message: "Machine identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
@@ -275,8 +275,8 @@ export const GatewayCliDeploymentMethod = () => {
{canCreateToken && autogenerateToken ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your gateway will use for authentication."
label="Machine Identity"
tooltipText="The machine identity that your gateway will use for authentication."
className="mt-4"
/>
<FilterableSelect
@@ -290,7 +290,7 @@ export const GatewayCliDeploymentMethod = () => {
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
placeholder="Select machine identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
@@ -300,14 +300,14 @@ export const GatewayCliDeploymentMethod = () => {
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your gateway will use for authentication."
label="Machine Identity Token"
tooltipText="The machine identity token that your gateway will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
placeholder="Enter machine identity token..."
isError={Boolean(errors.identityToken)}
/>
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
@@ -325,15 +325,15 @@ export const GatewayCliDeploymentMethod = () => {
className="mr-2"
>
<div className="flex items-center">
<span>Automatically enable token auth and generate a token for identity</span>
<span>Automatically enable token auth and generate a token for machine identity</span>
<Tooltip
className="max-w-md"
content={
<>
Token authentication will be automatically enabled for the selected identity if
it isn&apos;t already configured. By default, it will be configured to allow all
IP addresses with a token TTL of 30 days. You can manage these settings in
Access Control.
Token authentication will be automatically enabled for the selected machine
identity if it isn&apos;t already configured. By default, it will be configured
to allow all IP addresses with a token TTL of 30 days. You can manage these
settings in Access Control.
<br />
<br />A token will automatically be generated to be used with the CLI command.
</>
@@ -55,10 +55,10 @@ const formSchemaWithIdentity = baseFormSchema.extend({
id: z.string(),
name: z.string()
},
{ required_error: "Identity is required" }
{ required_error: "Machine identity is required" }
)
.nullable()
.refine((val) => val !== null, { message: "Identity is required" })
.refine((val) => val !== null, { message: "Machine identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
@@ -297,8 +297,8 @@ export const GatewayCliSystemdDeploymentMethod = () => {
{canCreateToken && autogenerateToken ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your gateway will use for authentication."
label="Machine Identity"
tooltipText="The machine identity that your gateway will use for authentication."
className="mt-4"
/>
<FilterableSelect
@@ -312,7 +312,7 @@ export const GatewayCliSystemdDeploymentMethod = () => {
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
placeholder="Select machine identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
@@ -322,14 +322,14 @@ export const GatewayCliSystemdDeploymentMethod = () => {
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your gateway will use for authentication."
label="Machine Identity Token"
tooltipText="The machine identity token that your gateway will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
placeholder="Enter machine identity token..."
isError={Boolean(errors.identityToken)}
/>
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
@@ -347,15 +347,15 @@ export const GatewayCliSystemdDeploymentMethod = () => {
className="mr-2"
>
<div className="flex items-center">
<span>Automatically enable token auth and generate a token for identity</span>
<span>Automatically enable token auth and generate a token for machine identity</span>
<Tooltip
className="max-w-md"
content={
<>
Token authentication will be automatically enabled for the selected identity if
it isn&apos;t already configured. By default, it will be configured to allow all
IP addresses with a token TTL of 30 days. You can manage these settings in
Access Control.
Token authentication will be automatically enabled for the selected machine
identity if it isn&apos;t already configured. By default, it will be configured
to allow all IP addresses with a token TTL of 30 days. You can manage these
settings in Access Control.
<br />
<br />A token will automatically be generated to be used with the CLI command.
</>
@@ -41,10 +41,10 @@ const formSchemaWithIdentity = baseFormSchema.extend({
id: z.string(),
name: z.string()
},
{ required_error: "Identity is required" }
{ required_error: "Machine identity is required" }
)
.nullable()
.refine((val) => val !== null, { message: "Identity is required" })
.refine((val) => val !== null, { message: "Machine identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
@@ -229,8 +229,8 @@ export const RelayCliDeploymentMethod = () => {
{canCreateToken && autogenerateToken ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your relay will use for authentication."
label="Machine Identity"
tooltipText="The machine identity that your relay will use for authentication."
className="mt-4"
/>
<FilterableSelect
@@ -244,7 +244,7 @@ export const RelayCliDeploymentMethod = () => {
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
placeholder="Select machine identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
@@ -254,14 +254,14 @@ export const RelayCliDeploymentMethod = () => {
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your relay will use for authentication."
label="Machine Identity Token"
tooltipText="The machine identity token that your relay will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
placeholder="Enter machine identity token..."
isError={Boolean(errors.identityToken)}
/>
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
@@ -279,15 +279,15 @@ export const RelayCliDeploymentMethod = () => {
className="mr-2"
>
<div className="flex items-center">
<span>Automatically enable token auth and generate a token for identity</span>
<span>Automatically enable token auth and generate a token for machine identity</span>
<Tooltip
className="max-w-md"
content={
<>
Token authentication will be automatically enabled for the selected identity if
it isn&apos;t already configured. By default, it will be configured to allow all
IP addresses with a token TTL of 30 days. You can manage these settings in
Access Control.
Token authentication will be automatically enabled for the selected machine
identity if it isn&apos;t already configured. By default, it will be configured
to allow all IP addresses with a token TTL of 30 days. You can manage these
settings in Access Control.
<br />
<br />A token will automatically be generated to be used with the CLI command.
</>
@@ -41,10 +41,10 @@ const formSchemaWithIdentity = baseFormSchema.extend({
id: z.string(),
name: z.string()
},
{ required_error: "Identity is required" }
{ required_error: "Machine identity is required" }
)
.nullable()
.refine((val) => val !== null, { message: "Identity is required" })
.refine((val) => val !== null, { message: "Machine identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
@@ -270,8 +270,8 @@ export const RelayCliSystemdDeploymentMethod = () => {
{canCreateToken && autogenerateToken ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your relay will use for authentication."
label="Machine Identity"
tooltipText="The machine identity that your relay will use for authentication."
className="mt-4"
/>
<FilterableSelect
@@ -285,7 +285,7 @@ export const RelayCliSystemdDeploymentMethod = () => {
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
placeholder="Select machine identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
@@ -295,14 +295,14 @@ export const RelayCliSystemdDeploymentMethod = () => {
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your relay will use for authentication."
label="Machine Identity Token"
tooltipText="The machine identity token that your relay will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
placeholder="Enter machine identity token..."
isError={Boolean(errors.identityToken)}
/>
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
@@ -320,15 +320,15 @@ export const RelayCliSystemdDeploymentMethod = () => {
className="mr-2"
>
<div className="flex items-center">
<span>Automatically enable token auth and generate a token for identity</span>
<span>Automatically enable token auth and generate a token for machine identity</span>
<Tooltip
className="max-w-md"
content={
<>
Token authentication will be automatically enabled for the selected identity if
it isn&apos;t already configured. By default, it will be configured to allow all
IP addresses with a token TTL of 30 days. You can manage these settings in
Access Control.
Token authentication will be automatically enabled for the selected machine
identity if it isn&apos;t already configured. By default, it will be configured
to allow all IP addresses with a token TTL of 30 days. You can manage these
settings in Access Control.
<br />
<br />A token will automatically be generated to be used with the CLI command.
</>
@@ -42,10 +42,10 @@ const formSchemaWithIdentity = baseFormSchema.extend({
id: z.string(),
name: z.string()
},
{ required_error: "Identity is required" }
{ required_error: "Machine identity is required" }
)
.nullable()
.refine((val) => val !== null, { message: "Identity is required" })
.refine((val) => val !== null, { message: "Machine identity is required" })
});
const formSchemaWithToken = baseFormSchema.extend({
@@ -349,8 +349,8 @@ resource "aws_eip_association" "eip_assoc" {
{canCreateToken && autogenerateToken ? (
<>
<FormLabel
label="Identity"
tooltipText="The identity that your relay will use for authentication."
label="Machine Identity"
tooltipText="The machine identity that your relay will use for authentication."
className="mt-4"
/>
<FilterableSelect
@@ -364,7 +364,7 @@ resource "aws_eip_association" "eip_assoc" {
)
}
isLoading={isIdentitiesLoading}
placeholder="Select identity..."
placeholder="Select machine identity..."
options={identityMembershipOrgs.map((membership) => membership.identity)}
getOptionValue={(option) => option.id}
getOptionLabel={(option) => option.name}
@@ -374,14 +374,14 @@ resource "aws_eip_association" "eip_assoc" {
) : (
<>
<FormLabel
label="Identity Token"
tooltipText="The identity token that your relay will use for authentication."
label="Machine Identity Token"
tooltipText="The machine identity token that your relay will use for authentication."
className="mt-4"
/>
<Input
value={identityToken}
onChange={(e) => setIdentityToken(e.target.value)}
placeholder="Enter identity token..."
placeholder="Enter machine identity token..."
isError={Boolean(errors.identityToken)}
/>
{errors.identityToken && <p className="mt-1 text-sm text-red">{errors.identityToken}</p>}
@@ -399,15 +399,15 @@ resource "aws_eip_association" "eip_assoc" {
className="mr-2"
>
<div className="flex items-center">
<span>Automatically enable token auth and generate a token for identity</span>
<span>Automatically enable token auth and generate a token for machine identity</span>
<Tooltip
className="max-w-md"
content={
<>
Token authentication will be automatically enabled for the selected identity if
it isn&apos;t already configured. By default, it will be configured to allow all
IP addresses with a token TTL of 30 days. You can manage these settings in
Access Control.
Token authentication will be automatically enabled for the selected machine
identity if it isn&apos;t already configured. By default, it will be configured
to allow all IP addresses with a token TTL of 30 days. You can manage these
settings in Access Control.
<br />
<br />A token will automatically be generated to be used with the CLI command.
</>
@@ -81,7 +81,7 @@ export const ProjectsPage = () => {
</Helmet>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
title="Overview"
title={`${isSubOrganization ? "Sub-Organization" : "Organization"} Overview`}
description="Your team's complete security toolkit - organized and ready when you need them."
/>
{projectListView === ProjectListView.MyProjects ? (
@@ -20,7 +20,7 @@ export const SettingsPage = () => {
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}
description="Configure organization-wide settings"
title={t("settings.org.title")}
title={isSubOrganization ? "Sub-Organization Settings" : "Organization Settings"}
/>
<OrgTabGroup />
</div>
@@ -112,7 +112,7 @@ const Page = withPermission(
className="mb-4 flex items-center gap-x-2 text-sm text-mineshaft-400"
>
<FontAwesomeIcon icon={faChevronLeft} />
Users
Organization Users
</Link>
<PageHeader
scope={isSubOrganization ? "namespace" : "org"}

Some files were not shown because too many files have changed in this diff Show More