Merge pull request #4964 from Infisical/ENG-4217

improvement(frontend): update project identity creation flow
This commit is contained in:
Scott Wilson
2025-11-28 11:57:10 -08:00
committed by GitHub
3 changed files with 91 additions and 96 deletions

View File

@@ -203,7 +203,11 @@ export const IdentitySection = withPermission(
>
<ModalContent
bodyClassName="overflow-visible"
title="Add Machine Identity"
title={
isSubOrganization
? "Add Machine Identity to Sub-Organization"
: "Create Organization Machine Identity"
}
subTitle={
isSubOrganization
? "Create a new machine identity or assign an existing one"

View File

@@ -12,8 +12,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNavigate } from "@tanstack/react-router";
import { AnimatePresence, motion } from "framer-motion";
import { LinkIcon, PlusIcon } from "lucide-react";
import { InfoIcon } from "lucide-react";
import { twMerge } from "tailwind-merge";
import { createNotification } from "@app/components/notifications";
@@ -83,10 +82,9 @@ import { ProjectLinkIdentityModal } from "./components/ProjectLinkIdentityModal"
const MAX_ROLES_TO_BE_SHOWN_IN_TABLE = 2;
enum WizardSteps {
SelectAction = "select-action",
LinkIdentity = "link-identity",
ProjectIdentity = "project-identity"
enum AddIdentityType {
CreateNew,
AssignExisting
}
export const IdentityTab = withProjectPermission(
@@ -95,7 +93,9 @@ export const IdentityTab = withProjectPermission(
const navigate = useNavigate();
const { isSubOrganization, currentOrg } = useOrganization();
const [wizardStep, setWizardStep] = useState(WizardSteps.SelectAction);
const [addMachineIdentityType, setAddMachineIdentityType] = useState<AddIdentityType>(
AddIdentityType.CreateNew
);
const {
offset,
@@ -510,93 +510,89 @@ export const IdentityTab = withProjectPermission(
isOpen={popUp.createIdentity.isOpen}
onOpenChange={(open) => {
handlePopUpToggle("createIdentity", open);
if (!open) setWizardStep(WizardSteps.SelectAction);
}}
>
<ModalContent
bodyClassName="overflow-visible"
title="Add Project Machine Identity"
title="Add Machine Identity to Project"
subTitle="Create a new machine identity or assign an existing one"
>
<AnimatePresence mode="wait">
{wizardStep === WizardSteps.SelectAction && (
<motion.div
key="select-type-step"
transition={{ duration: 0.1 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: -30 }}
<div className="mb-4 flex items-center justify-center gap-x-2">
<div className="flex w-3/4 gap-x-0.5 rounded-md border border-mineshaft-600 bg-mineshaft-800 p-1">
<Button
variant="outline_bg"
onClick={() => {
setAddMachineIdentityType(AddIdentityType.CreateNew);
}}
size="xs"
className={twMerge(
"min-w-[2.4rem] flex-1 rounded border-none hover:bg-mineshaft-600",
addMachineIdentityType === AddIdentityType.CreateNew
? "bg-mineshaft-500"
: "bg-transparent"
)}
>
<div
className="cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
role="button"
tabIndex={0}
onClick={() => setWizardStep(WizardSteps.ProjectIdentity)}
onKeyDown={(e) => {
if (e.key === "Enter") {
setWizardStep(WizardSteps.ProjectIdentity);
}
}}
>
<div className="flex items-center gap-2">
<PlusIcon size="1rem" />
<div>Create Machine Identity</div>
</div>
<div className="mt-2 text-xs text-mineshaft-300">
Create a new machine identity specifically for this project. This machine
identity will be managed at the project-level.
</div>
</div>
<div
className="mt-4 cursor-pointer rounded-md border border-mineshaft-600 p-4 transition-all hover:bg-mineshaft-700"
role="button"
tabIndex={0}
onClick={() => setWizardStep(WizardSteps.LinkIdentity)}
onKeyDown={(e) => {
if (e.key === "Enter") {
setWizardStep(WizardSteps.LinkIdentity);
}
}}
>
<div className="flex items-center gap-2">
<LinkIcon size="1rem" />
<div>Assign Existing Machine Identity</div>
</div>
<div className="mt-2 text-xs text-mineshaft-300">
Assign an existing machine identity from your organization. The machine
identity will continue to be managed at its original scope.
</div>
</div>
</motion.div>
)}
{wizardStep === WizardSteps.ProjectIdentity && (
<motion.div
key="identity-step"
transition={{ duration: 0.1 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: -30 }}
Create New
</Button>
<Button
variant="outline_bg"
onClick={() => {
setAddMachineIdentityType(AddIdentityType.AssignExisting);
}}
size="xs"
className={twMerge(
"min-w-[2.4rem] flex-1 rounded border-none hover:bg-mineshaft-600",
addMachineIdentityType === AddIdentityType.AssignExisting
? "bg-mineshaft-500"
: "bg-transparent"
)}
>
<ProjectIdentityModal
onClose={() => {
handlePopUpClose("createIdentity");
setWizardStep(WizardSteps.SelectAction);
}}
/>
</motion.div>
)}
{wizardStep === WizardSteps.LinkIdentity && (
<motion.div
key="link-step"
transition={{ duration: 0.1 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: -30 }}
>
<ProjectLinkIdentityModal handlePopUpToggle={handlePopUpToggle} />
</motion.div>
)}
</AnimatePresence>
Assign Existing
</Button>
</div>
<Tooltip
className="max-w-sm"
position="right"
align="start"
content={
<>
<p className="mb-2 text-mineshaft-300">
You can add machine identities to your project in one of two ways:
</p>
<ul className="ml-3.5 flex list-disc flex-col gap-y-4">
<li className="text-mineshaft-200">
<strong className="font-medium text-mineshaft-100">Create New</strong> -
Create a dedicated machine identity managed at the project-level.
<p className="mt-2">
This method is recommended for autonomous teams that need to manage
machine identity authentication.
</p>
</li>
<li>
<strong className="font-medium text-mineshaft-100">Assign Existing</strong>{" "}
- Assign an existing machine identity from your organization.
<p className="mt-2">
This method is recommended for organizations that need to maintain
centralized control.
</p>
</li>
</ul>
</>
}
>
<InfoIcon size={16} className="text-mineshaft-400" />
</Tooltip>
</div>
{addMachineIdentityType === AddIdentityType.CreateNew && (
<ProjectIdentityModal
onClose={() => {
handlePopUpClose("createIdentity");
}}
/>
)}
{addMachineIdentityType === AddIdentityType.AssignExisting && (
<ProjectLinkIdentityModal handlePopUpToggle={handlePopUpToggle} />
)}
</ModalContent>
</Modal>
<DeleteActionModal

View File

@@ -5,7 +5,7 @@ import { useQuery } from "@tanstack/react-query";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FilterableSelect, FormControl, ModalClose, Spinner } from "@app/components/v2";
import { Button, FilterableSelect, FormControl, ModalClose } from "@app/components/v2";
import { useProject } from "@app/context";
import {
projectIdentityMembershipQuery,
@@ -101,13 +101,6 @@ export const ProjectLinkIdentityModal = ({ handlePopUpToggle }: Props) => {
handlePopUpToggle("createIdentity", false);
};
if (isMembershipsLoading || isRolesLoading)
return (
<div className="flex w-full items-center justify-center py-10">
<Spinner className="text-mineshaft-400" />
</div>
);
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<Controller
@@ -118,6 +111,7 @@ export const ProjectLinkIdentityModal = ({ handlePopUpToggle }: Props) => {
<FilterableSelect
value={value}
onChange={onChange}
isLoading={isMembershipsLoading}
placeholder="Select machine identity..."
// onInputChange={setSearchValue}
options={filteredIdentityMembershipOrgs.map((membership) => ({
@@ -142,6 +136,7 @@ export const ProjectLinkIdentityModal = ({ handlePopUpToggle }: Props) => {
>
<FilterableSelect
value={value}
isLoading={isRolesLoading}
onChange={onChange}
options={roles}
placeholder="Select role..."
@@ -159,7 +154,7 @@ export const ProjectLinkIdentityModal = ({ handlePopUpToggle }: Props) => {
isLoading={isSubmitting}
isDisabled={isSubmitting}
>
Link
Assign to Project
</Button>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">