mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
Merge branch 'main' into feature/mongodb-secret-rotation
This commit is contained in:
@@ -20,9 +20,14 @@ export default function TeamInviteStep(): JSX.Element {
|
||||
const { mutateAsync } = useAddUsersToOrg();
|
||||
const { handlePopUpToggle, popUp, handlePopUpOpen } = usePopUp(["setUpEmail"] as const);
|
||||
|
||||
const orgId = String(localStorage.getItem("orgData.id"));
|
||||
|
||||
// Redirect user to the getting started page
|
||||
const redirectToHome = async () => {
|
||||
navigate({ to: "/organization/projects" as const });
|
||||
navigate({
|
||||
to: orgId ? ("/organizations/$orgId/projects" as const) : "/",
|
||||
params: { orgId }
|
||||
});
|
||||
};
|
||||
|
||||
const inviteUsers = async ({ emails: inviteEmails }: { emails: string }) => {
|
||||
@@ -32,7 +37,7 @@ export default function TeamInviteStep(): JSX.Element {
|
||||
.map(async (email) => {
|
||||
mutateAsync({
|
||||
inviteeEmails: [email],
|
||||
organizationId: String(localStorage.getItem("orgData.id")),
|
||||
organizationId: orgId,
|
||||
organizationRoleSlug: "member"
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,7 +70,8 @@ export default function NavHeader({
|
||||
{currentOrg?.name?.charAt(0)}
|
||||
</div>
|
||||
<Link
|
||||
to="/organization/projects"
|
||||
to="/organizations/$orgId/projects"
|
||||
params={{ orgId: currentOrg.id }}
|
||||
className="truncate pl-0.5 text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{currentOrg?.name}
|
||||
@@ -90,8 +91,8 @@ export default function NavHeader({
|
||||
<FontAwesomeIcon icon={faAngleRight} className="mr-3 ml-3 text-sm text-gray-400" />
|
||||
{pageName === "Secrets" ? (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/overview"
|
||||
params={{ projectId: currentProject.id }}
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/overview"
|
||||
params={{ orgId: currentOrg?.id || "", projectId: currentProject.id }}
|
||||
className="text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{pageName}
|
||||
@@ -126,8 +127,8 @@ export default function NavHeader({
|
||||
<div className="flex items-center space-x-3">
|
||||
<FontAwesomeIcon icon={faAngleRight} className="mr-1.5 ml-3 text-xs text-gray-400" />
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{ projectId: currentProject.id, envSlug: routerEnvSlug }}
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{ orgId: currentOrg.id, projectId: currentProject.id, envSlug: routerEnvSlug }}
|
||||
className="text-sm font-medium text-primary/80 hover:text-primary"
|
||||
>
|
||||
{userAvailableEnvs?.find(({ slug }) => slug === currentEnv)?.name}
|
||||
@@ -188,8 +189,9 @@ export default function NavHeader({
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{
|
||||
orgId: currentOrg?.id || "",
|
||||
projectId: currentProject.id,
|
||||
envSlug: routerEnvSlug || ""
|
||||
}}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { useOrganization } from "@app/context";
|
||||
import { useTimedReset } from "@app/hooks";
|
||||
|
||||
import { createNotification } from "../notifications";
|
||||
@@ -23,6 +24,7 @@ export const SecretDashboardPathBreadcrumb = ({
|
||||
projectId,
|
||||
disableCopy
|
||||
}: Props) => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const [, isCopying, setIsCopying] = useTimedReset({
|
||||
initialState: false
|
||||
});
|
||||
@@ -69,8 +71,9 @@ export const SecretDashboardPathBreadcrumb = ({
|
||||
</div>
|
||||
) : (
|
||||
<Link
|
||||
to="/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
to="/organizations/$orgId/projects/secret-management/$projectId/secrets/$envSlug"
|
||||
params={{
|
||||
orgId: currentOrg.id,
|
||||
projectId,
|
||||
envSlug: environmentSlug
|
||||
}}
|
||||
|
||||
@@ -57,7 +57,8 @@ export const CreateOrgModal: FC<CreateOrgModalProps> = ({ isOpen, onClose }) =>
|
||||
});
|
||||
|
||||
navigate({
|
||||
to: "/organization/projects"
|
||||
to: "/organizations/$orgId/projects",
|
||||
params: { orgId: organization.id }
|
||||
});
|
||||
|
||||
localStorage.setItem("orgData.id", organization.id);
|
||||
|
||||
@@ -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 = (
|
||||
|
||||
@@ -157,7 +157,7 @@ const NewProjectForm = ({ onOpenChange }: NewProjectFormProps) => {
|
||||
onOpenChange(false);
|
||||
navigate({
|
||||
to: getProjectHomePage(project.type, project.environments),
|
||||
params: { projectId: project.id }
|
||||
params: { projectId: project.id, orgId: currentOrg.id }
|
||||
});
|
||||
};
|
||||
const onSubmit = handleSubmit((data) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BookOpenIcon } from "lucide-react";
|
||||
import { ExternalLinkIcon } from "lucide-react";
|
||||
|
||||
import { Badge } from "@app/components/v3";
|
||||
|
||||
@@ -8,10 +8,10 @@ type TDocumentationLinkBadgeProps = {
|
||||
|
||||
export function DocumentationLinkBadge({ href }: TDocumentationLinkBadgeProps) {
|
||||
return (
|
||||
<Badge variant="neutral" asChild>
|
||||
<Badge variant="info" asChild>
|
||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
||||
<BookOpenIcon />
|
||||
Documentation
|
||||
<ExternalLinkIcon />
|
||||
</a>
|
||||
</Badge>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user