fix: update create org to properly handle tx (super admin), remove sub org incidents, remove clipping animation container for project templates ui

This commit is contained in:
Scott Wilson
2025-10-20 16:36:46 -07:00
parent 339e00dedf
commit 0b5c823390
6 changed files with 185 additions and 235 deletions

View File

@@ -284,7 +284,7 @@ export const licenseServiceFactory = ({
};
const updateSubscriptionOrgMemberCount = async (orgId: string, tx?: Knex) => {
const org = await orgDAL.findRootOrgDetails(orgId);
const org = await orgDAL.findRootOrgDetails(orgId, tx);
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
const rootOrgId = org.id;

View File

@@ -705,10 +705,9 @@ export const orgDALFactory = (db: TDbClient) => {
}
};
const findRootOrgDetails = async (orgId: string): Promise<TOrganizations | undefined> => {
const findRootOrgDetails = async (orgId: string, tx?: Knex): Promise<TOrganizations | undefined> => {
try {
const org = await db
.replicaNode()(TableName.Organization)
const org = await (tx ?? db.replicaNode())(TableName.Organization)
.select(selectAllTableCols(TableName.Organization))
.where(
"id",

View File

@@ -679,7 +679,7 @@ export const orgServiceFactory = ({
const organization = await (trx ? createOrg(trx) : orgDAL.transaction(createOrg));
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
await licenseService.updateSubscriptionOrgMemberCount(organization.id, trx);
return organization;
};

View File

@@ -11,7 +11,7 @@ export const OrgGeneralTab = () => {
return (
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
{isSubOrganization ? <SubOrgNameChangeSection /> : <OrgNameChangeSection />}
<OrgIncidentContactsSection />
{!isSubOrganization && <OrgIncidentContactsSection />}
{hasOrgRole(OrgMembershipRole.Admin) && <OrgDeleteSection />}
</div>
);

View File

@@ -70,154 +70,129 @@ export const ProjectTemplateRolesSection = ({ projectTemplate, isInfisicalTempla
return (
<div className="relative">
<AnimatePresence>
{popUp?.editRole.isOpen ? (
<motion.div
key="edit-role"
transition={{ duration: 0.3 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
className="absolute min-h-40 w-full"
>
<ProjectTemplateEditRoleForm
onGoBack={() => handlePopUpClose("editRole")}
projectTemplate={projectTemplate}
role={editRole}
isDisabled={
permission.cannot(
OrgPermissionActions.Edit,
OrgPermissionSubjects.ProjectTemplates
) ||
(editRole && !isCustomProjectRole(editRole.slug))
}
/>
<div className="h-4 w-full" />
</motion.div>
) : (
<motion.div
key="role-list"
transition={{ duration: 0.3 }}
initial={{ opacity: 0, translateX: 0 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: -30 }}
className="absolute w-full"
>
<div className="w-full 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">
<div>
<h2 className="text-lg font-medium">Project Roles</h2>
<p className="text-sm text-mineshaft-400">
{isInfisicalTemplate
? "Click a role to view the associated permissions"
: "Add, edit and remove roles for this project template"}
</p>
</div>
{!isInfisicalTemplate && (
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.ProjectTemplates}
{popUp?.editRole.isOpen ? (
<ProjectTemplateEditRoleForm
onGoBack={() => handlePopUpClose("editRole")}
projectTemplate={projectTemplate}
role={editRole}
isDisabled={
permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates) ||
(editRole && !isCustomProjectRole(editRole.slug))
}
/>
) : (
<div className="w-full 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">
<div>
<h2 className="text-lg font-medium">Project Roles</h2>
<p className="text-sm text-mineshaft-400">
{isInfisicalTemplate
? "Click a role to view the associated permissions"
: "Add, edit and remove roles for this project template"}
</p>
</div>
{!isInfisicalTemplate && (
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.ProjectTemplates}
>
{(isAllowed) => (
<Button
onClick={() => {
handlePopUpOpen("editRole");
}}
colorSchema="primary"
className="ml-auto"
variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
isDisabled={!isAllowed}
>
{(isAllowed) => (
<Button
onClick={() => {
handlePopUpOpen("editRole");
}}
colorSchema="primary"
className="ml-auto"
variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
isDisabled={!isAllowed}
>
Add Role
</Button>
)}
</OrgPermissionCan>
Add Role
</Button>
)}
</div>
<div className="py-4">
<TableContainer>
<Table>
<THead>
<Tr>
<Th>Name</Th>
<Th>Slug</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{roles.length ? (
roles.map((role) => {
return (
<Tr
key={role.slug}
className="group w-full cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
role="button"
tabIndex={0}
onKeyDown={(evt) => {
if (evt.key === "Enter") {
handlePopUpOpen("editRole", role);
}
}}
onClick={() => handlePopUpOpen("editRole", role)}
>
<Td>{role.name}</Td>
<Td>{role.slug}</Td>
<Td>
{isCustomProjectRole(role.slug) && (
<div className="flex space-x-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100">
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.ProjectTemplates}
renderTooltip
allowedLabel="Remove Role"
</OrgPermissionCan>
)}
</div>
<div className="py-4">
<TableContainer>
<Table>
<THead>
<Tr>
<Th>Name</Th>
<Th>Slug</Th>
<Th className="w-5" />
</Tr>
</THead>
<TBody>
{roles.length ? (
roles.map((role) => {
return (
<Tr
key={role.slug}
className="group w-full cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
role="button"
tabIndex={0}
onKeyDown={(evt) => {
if (evt.key === "Enter") {
handlePopUpOpen("editRole", role);
}
}}
onClick={() => handlePopUpOpen("editRole", role)}
>
<Td>{role.name}</Td>
<Td>{role.slug}</Td>
<Td>
{isCustomProjectRole(role.slug) && (
<div className="flex space-x-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100">
<OrgPermissionCan
I={OrgPermissionActions.Edit}
a={OrgPermissionSubjects.ProjectTemplates}
renderTooltip
allowedLabel="Remove Role"
>
{(isAllowed) => (
<IconButton
colorSchema="danger"
ariaLabel="delete-icon"
variant="plain"
className="group relative"
isDisabled={!isAllowed}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
handlePopUpOpen("removeRole", role);
}}
>
{(isAllowed) => (
<IconButton
colorSchema="danger"
ariaLabel="delete-icon"
variant="plain"
className="group relative"
isDisabled={!isAllowed}
onClick={(e) => {
e.stopPropagation();
e.preventDefault();
handlePopUpOpen("removeRole", role);
}}
>
<FontAwesomeIcon icon={faTrash} />
</IconButton>
)}
</OrgPermissionCan>
</div>
)}
</Td>
</Tr>
);
})
) : (
<Tr>
<Td colSpan={2}>
<EmptyState title="No roles assigned to template" icon={faUnlock} />
<FontAwesomeIcon icon={faTrash} />
</IconButton>
)}
</OrgPermissionCan>
</div>
)}
</Td>
</Tr>
)}
</TBody>
</Table>
</TableContainer>
</div>
<DeleteActionModal
isOpen={popUp.removeRole.isOpen}
deleteKey="remove"
title={`Are you sure you want to remove the role ${roleToDelete?.slug}?`}
onChange={(isOpen) => handlePopUpToggle("removeRole", isOpen)}
onDeleteApproved={() => handleRemoveRole(roleToDelete?.slug)}
/>
</div>
<div className="h-4 w-full" />
</motion.div>
)}
</AnimatePresence>
);
})
) : (
<Tr>
<Td colSpan={2}>
<EmptyState title="No roles assigned to template" icon={faUnlock} />
</Td>
</Tr>
)}
</TBody>
</Table>
</TableContainer>
</div>
<DeleteActionModal
isOpen={popUp.removeRole.isOpen}
deleteKey="remove"
title={`Are you sure you want to remove the role ${roleToDelete?.slug}?`}
onChange={(isOpen) => handlePopUpToggle("removeRole", isOpen)}
onDeleteApproved={() => handleRemoveRole(roleToDelete?.slug)}
/>
</div>
)}
</div>
);
};

View File

@@ -1,7 +1,6 @@
import { useState } from "react";
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { AnimatePresence, motion } from "framer-motion";
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
import { OrgPermissionCan } from "@app/components/permissions";
@@ -25,93 +24,70 @@ export const ProjectTemplatesSection = () => {
return (
<div className="relative">
<AnimatePresence>
{editTemplate ? (
<motion.div
key="edit-project-template"
transition={{ duration: 0.3 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
className="absolute min-h-40 w-full"
>
<EditProjectTemplateSection
template={editTemplate}
onBack={() => setEditTemplate(null)}
/>
</motion.div>
) : (
<motion.div
key="project-templates-list"
transition={{ duration: 0.3 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}
exit={{ opacity: 0, translateX: 30 }}
className="absolute min-h-40 w-full"
>
<div>
<p className="mb-6 font-inter text-bunker-300">
Create and configure templates with predefined roles and environments to streamline
project setup
</p>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-start">
<p className="text-xl font-medium text-mineshaft-100">Project Templates</p>
<a
target="_blank"
rel="noopener noreferrer"
href="https://infisical.com/docs/documentation/platform/project-templates"
>
<div className="mt-[0.32rem] ml-2 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
</a>
<OrgPermissionCan
I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.ProjectTemplates}
>
{(isAllowed) => (
<Button
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (!subscription?.projectTemplates) {
handlePopUpOpen("upgradePlan");
return;
}
handlePopUpOpen("addTemplate");
}}
isDisabled={!isAllowed}
className="ml-auto"
>
Add Template
</Button>
)}
</OrgPermissionCan>
{editTemplate ? (
<EditProjectTemplateSection template={editTemplate} onBack={() => setEditTemplate(null)} />
) : (
<div>
<p className="mb-6 font-inter text-bunker-300">
Create and configure templates with predefined roles and environments to streamline
project setup
</p>
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
<div className="mb-4 flex items-start">
<p className="text-xl font-medium text-mineshaft-100">Project Templates</p>
<a
target="_blank"
rel="noopener noreferrer"
href="https://infisical.com/docs/documentation/platform/project-templates"
>
<div className="mt-[0.32rem] ml-2 inline-block rounded-md bg-yellow/20 px-1.5 text-sm text-yellow opacity-80 hover:opacity-100">
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
<span>Docs</span>
<FontAwesomeIcon
icon={faArrowUpRightFromSquare}
className="mb-[0.07rem] ml-1.5 text-[10px]"
/>
</div>
<ProjectTemplatesTable onEdit={setEditTemplate} />
<ProjectTemplateDetailsModal
onComplete={(template) => setEditTemplate(template)}
isOpen={popUp.addTemplate.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("addTemplate", isOpen)}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can create project templates if you switch to Infisical's Enterprise plan."
/>
</div>
</a>
<OrgPermissionCan
I={OrgPermissionActions.Create}
a={OrgPermissionSubjects.ProjectTemplates}
>
{(isAllowed) => (
<Button
colorSchema="secondary"
type="submit"
leftIcon={<FontAwesomeIcon icon={faPlus} />}
onClick={() => {
if (!subscription?.projectTemplates) {
handlePopUpOpen("upgradePlan");
return;
}
handlePopUpOpen("addTemplate");
}}
isDisabled={!isAllowed}
className="ml-auto"
>
Add Template
</Button>
)}
</OrgPermissionCan>
</div>
</motion.div>
)}
</AnimatePresence>
<ProjectTemplatesTable onEdit={setEditTemplate} />
<ProjectTemplateDetailsModal
onComplete={(template) => setEditTemplate(template)}
isOpen={popUp.addTemplate.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("addTemplate", isOpen)}
/>
<UpgradePlanModal
isOpen={popUp.upgradePlan.isOpen}
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
text="You can create project templates if you switch to Infisical's Enterprise plan."
/>
</div>
</div>
)}
</div>
);
};