mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 13:27:46 +00:00
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:
@@ -284,7 +284,7 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateSubscriptionOrgMemberCount = async (orgId: string, tx?: Knex) => {
|
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` });
|
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
||||||
|
|
||||||
const rootOrgId = org.id;
|
const rootOrgId = org.id;
|
||||||
|
|||||||
@@ -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 {
|
try {
|
||||||
const org = await db
|
const org = await (tx ?? db.replicaNode())(TableName.Organization)
|
||||||
.replicaNode()(TableName.Organization)
|
|
||||||
.select(selectAllTableCols(TableName.Organization))
|
.select(selectAllTableCols(TableName.Organization))
|
||||||
.where(
|
.where(
|
||||||
"id",
|
"id",
|
||||||
|
|||||||
@@ -679,7 +679,7 @@ export const orgServiceFactory = ({
|
|||||||
|
|
||||||
const organization = await (trx ? createOrg(trx) : orgDAL.transaction(createOrg));
|
const organization = await (trx ? createOrg(trx) : orgDAL.transaction(createOrg));
|
||||||
|
|
||||||
await licenseService.updateSubscriptionOrgMemberCount(organization.id);
|
await licenseService.updateSubscriptionOrgMemberCount(organization.id, trx);
|
||||||
return organization;
|
return organization;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ export const OrgGeneralTab = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||||
{isSubOrganization ? <SubOrgNameChangeSection /> : <OrgNameChangeSection />}
|
{isSubOrganization ? <SubOrgNameChangeSection /> : <OrgNameChangeSection />}
|
||||||
<OrgIncidentContactsSection />
|
{!isSubOrganization && <OrgIncidentContactsSection />}
|
||||||
{hasOrgRole(OrgMembershipRole.Admin) && <OrgDeleteSection />}
|
{hasOrgRole(OrgMembershipRole.Admin) && <OrgDeleteSection />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
+118
-143
@@ -70,154 +70,129 @@ export const ProjectTemplateRolesSection = ({ projectTemplate, isInfisicalTempla
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<AnimatePresence>
|
{popUp?.editRole.isOpen ? (
|
||||||
{popUp?.editRole.isOpen ? (
|
<ProjectTemplateEditRoleForm
|
||||||
<motion.div
|
onGoBack={() => handlePopUpClose("editRole")}
|
||||||
key="edit-role"
|
projectTemplate={projectTemplate}
|
||||||
transition={{ duration: 0.3 }}
|
role={editRole}
|
||||||
initial={{ opacity: 0, translateX: 30 }}
|
isDisabled={
|
||||||
animate={{ opacity: 1, translateX: 0 }}
|
permission.cannot(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates) ||
|
||||||
exit={{ opacity: 0, translateX: 30 }}
|
(editRole && !isCustomProjectRole(editRole.slug))
|
||||||
className="absolute min-h-40 w-full"
|
}
|
||||||
>
|
/>
|
||||||
<ProjectTemplateEditRoleForm
|
) : (
|
||||||
onGoBack={() => handlePopUpClose("editRole")}
|
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
projectTemplate={projectTemplate}
|
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
||||||
role={editRole}
|
<div>
|
||||||
isDisabled={
|
<h2 className="text-lg font-medium">Project Roles</h2>
|
||||||
permission.cannot(
|
<p className="text-sm text-mineshaft-400">
|
||||||
OrgPermissionActions.Edit,
|
{isInfisicalTemplate
|
||||||
OrgPermissionSubjects.ProjectTemplates
|
? "Click a role to view the associated permissions"
|
||||||
) ||
|
: "Add, edit and remove roles for this project template"}
|
||||||
(editRole && !isCustomProjectRole(editRole.slug))
|
</p>
|
||||||
}
|
</div>
|
||||||
/>
|
{!isInfisicalTemplate && (
|
||||||
<div className="h-4 w-full" />
|
<OrgPermissionCan
|
||||||
</motion.div>
|
I={OrgPermissionActions.Edit}
|
||||||
) : (
|
a={OrgPermissionSubjects.ProjectTemplates}
|
||||||
<motion.div
|
>
|
||||||
key="role-list"
|
{(isAllowed) => (
|
||||||
transition={{ duration: 0.3 }}
|
<Button
|
||||||
initial={{ opacity: 0, translateX: 0 }}
|
onClick={() => {
|
||||||
animate={{ opacity: 1, translateX: 0 }}
|
handlePopUpOpen("editRole");
|
||||||
exit={{ opacity: 0, translateX: -30 }}
|
}}
|
||||||
className="absolute w-full"
|
colorSchema="primary"
|
||||||
>
|
className="ml-auto"
|
||||||
<div className="w-full rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
variant="outline_bg"
|
||||||
<div className="flex items-center justify-between border-b border-mineshaft-400 pb-4">
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
<div>
|
isDisabled={!isAllowed}
|
||||||
<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) => (
|
Add Role
|
||||||
<Button
|
</Button>
|
||||||
onClick={() => {
|
|
||||||
handlePopUpOpen("editRole");
|
|
||||||
}}
|
|
||||||
colorSchema="primary"
|
|
||||||
className="ml-auto"
|
|
||||||
variant="outline_bg"
|
|
||||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
|
||||||
isDisabled={!isAllowed}
|
|
||||||
>
|
|
||||||
Add Role
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</OrgPermissionCan>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</OrgPermissionCan>
|
||||||
<div className="py-4">
|
)}
|
||||||
<TableContainer>
|
</div>
|
||||||
<Table>
|
<div className="py-4">
|
||||||
<THead>
|
<TableContainer>
|
||||||
<Tr>
|
<Table>
|
||||||
<Th>Name</Th>
|
<THead>
|
||||||
<Th>Slug</Th>
|
<Tr>
|
||||||
<Th className="w-5" />
|
<Th>Name</Th>
|
||||||
</Tr>
|
<Th>Slug</Th>
|
||||||
</THead>
|
<Th className="w-5" />
|
||||||
<TBody>
|
</Tr>
|
||||||
{roles.length ? (
|
</THead>
|
||||||
roles.map((role) => {
|
<TBody>
|
||||||
return (
|
{roles.length ? (
|
||||||
<Tr
|
roles.map((role) => {
|
||||||
key={role.slug}
|
return (
|
||||||
className="group w-full cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
<Tr
|
||||||
role="button"
|
key={role.slug}
|
||||||
tabIndex={0}
|
className="group w-full cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700"
|
||||||
onKeyDown={(evt) => {
|
role="button"
|
||||||
if (evt.key === "Enter") {
|
tabIndex={0}
|
||||||
handlePopUpOpen("editRole", role);
|
onKeyDown={(evt) => {
|
||||||
}
|
if (evt.key === "Enter") {
|
||||||
}}
|
handlePopUpOpen("editRole", role);
|
||||||
onClick={() => handlePopUpOpen("editRole", role)}
|
}
|
||||||
>
|
}}
|
||||||
<Td>{role.name}</Td>
|
onClick={() => handlePopUpOpen("editRole", role)}
|
||||||
<Td>{role.slug}</Td>
|
>
|
||||||
<Td>
|
<Td>{role.name}</Td>
|
||||||
{isCustomProjectRole(role.slug) && (
|
<Td>{role.slug}</Td>
|
||||||
<div className="flex space-x-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
<Td>
|
||||||
<OrgPermissionCan
|
{isCustomProjectRole(role.slug) && (
|
||||||
I={OrgPermissionActions.Edit}
|
<div className="flex space-x-2 opacity-0 transition-opacity duration-300 group-hover:opacity-100">
|
||||||
a={OrgPermissionSubjects.ProjectTemplates}
|
<OrgPermissionCan
|
||||||
renderTooltip
|
I={OrgPermissionActions.Edit}
|
||||||
allowedLabel="Remove Role"
|
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) => (
|
<FontAwesomeIcon icon={faTrash} />
|
||||||
<IconButton
|
</IconButton>
|
||||||
colorSchema="danger"
|
)}
|
||||||
ariaLabel="delete-icon"
|
</OrgPermissionCan>
|
||||||
variant="plain"
|
</div>
|
||||||
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} />
|
|
||||||
</Td>
|
</Td>
|
||||||
</Tr>
|
</Tr>
|
||||||
)}
|
);
|
||||||
</TBody>
|
})
|
||||||
</Table>
|
) : (
|
||||||
</TableContainer>
|
<Tr>
|
||||||
</div>
|
<Td colSpan={2}>
|
||||||
<DeleteActionModal
|
<EmptyState title="No roles assigned to template" icon={faUnlock} />
|
||||||
isOpen={popUp.removeRole.isOpen}
|
</Td>
|
||||||
deleteKey="remove"
|
</Tr>
|
||||||
title={`Are you sure you want to remove the role ${roleToDelete?.slug}?`}
|
)}
|
||||||
onChange={(isOpen) => handlePopUpToggle("removeRole", isOpen)}
|
</TBody>
|
||||||
onDeleteApproved={() => handleRemoveRole(roleToDelete?.slug)}
|
</Table>
|
||||||
/>
|
</TableContainer>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-4 w-full" />
|
<DeleteActionModal
|
||||||
</motion.div>
|
isOpen={popUp.removeRole.isOpen}
|
||||||
)}
|
deleteKey="remove"
|
||||||
</AnimatePresence>
|
title={`Are you sure you want to remove the role ${roleToDelete?.slug}?`}
|
||||||
|
onChange={(isOpen) => handlePopUpToggle("removeRole", isOpen)}
|
||||||
|
onDeleteApproved={() => handleRemoveRole(roleToDelete?.slug)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
+62
-86
@@ -1,7 +1,6 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
|
import { faArrowUpRightFromSquare, faBookOpen, faPlus } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { AnimatePresence, motion } from "framer-motion";
|
|
||||||
|
|
||||||
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
import { UpgradePlanModal } from "@app/components/license/UpgradePlanModal";
|
||||||
import { OrgPermissionCan } from "@app/components/permissions";
|
import { OrgPermissionCan } from "@app/components/permissions";
|
||||||
@@ -25,93 +24,70 @@ export const ProjectTemplatesSection = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<AnimatePresence>
|
{editTemplate ? (
|
||||||
{editTemplate ? (
|
<EditProjectTemplateSection template={editTemplate} onBack={() => setEditTemplate(null)} />
|
||||||
<motion.div
|
) : (
|
||||||
key="edit-project-template"
|
<div>
|
||||||
transition={{ duration: 0.3 }}
|
<p className="mb-6 font-inter text-bunker-300">
|
||||||
initial={{ opacity: 0, translateX: 30 }}
|
Create and configure templates with predefined roles and environments to streamline
|
||||||
animate={{ opacity: 1, translateX: 0 }}
|
project setup
|
||||||
exit={{ opacity: 0, translateX: 30 }}
|
</p>
|
||||||
className="absolute min-h-40 w-full"
|
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-4">
|
||||||
>
|
<div className="mb-4 flex items-start">
|
||||||
<EditProjectTemplateSection
|
<p className="text-xl font-medium text-mineshaft-100">Project Templates</p>
|
||||||
template={editTemplate}
|
<a
|
||||||
onBack={() => setEditTemplate(null)}
|
target="_blank"
|
||||||
/>
|
rel="noopener noreferrer"
|
||||||
</motion.div>
|
href="https://infisical.com/docs/documentation/platform/project-templates"
|
||||||
) : (
|
>
|
||||||
<motion.div
|
<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">
|
||||||
key="project-templates-list"
|
<FontAwesomeIcon icon={faBookOpen} className="mr-1.5" />
|
||||||
transition={{ duration: 0.3 }}
|
<span>Docs</span>
|
||||||
initial={{ opacity: 0, translateX: 30 }}
|
<FontAwesomeIcon
|
||||||
animate={{ opacity: 1, translateX: 0 }}
|
icon={faArrowUpRightFromSquare}
|
||||||
exit={{ opacity: 0, translateX: 30 }}
|
className="mb-[0.07rem] ml-1.5 text-[10px]"
|
||||||
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>
|
|
||||||
</div>
|
</div>
|
||||||
<ProjectTemplatesTable onEdit={setEditTemplate} />
|
</a>
|
||||||
<ProjectTemplateDetailsModal
|
<OrgPermissionCan
|
||||||
onComplete={(template) => setEditTemplate(template)}
|
I={OrgPermissionActions.Create}
|
||||||
isOpen={popUp.addTemplate.isOpen}
|
a={OrgPermissionSubjects.ProjectTemplates}
|
||||||
onOpenChange={(isOpen) => handlePopUpToggle("addTemplate", isOpen)}
|
>
|
||||||
/>
|
{(isAllowed) => (
|
||||||
<UpgradePlanModal
|
<Button
|
||||||
isOpen={popUp.upgradePlan.isOpen}
|
colorSchema="secondary"
|
||||||
onOpenChange={(isOpen) => handlePopUpToggle("upgradePlan", isOpen)}
|
type="submit"
|
||||||
text="You can create project templates if you switch to Infisical's Enterprise plan."
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
/>
|
onClick={() => {
|
||||||
</div>
|
if (!subscription?.projectTemplates) {
|
||||||
|
handlePopUpOpen("upgradePlan");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
handlePopUpOpen("addTemplate");
|
||||||
|
}}
|
||||||
|
isDisabled={!isAllowed}
|
||||||
|
className="ml-auto"
|
||||||
|
>
|
||||||
|
Add Template
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</OrgPermissionCan>
|
||||||
</div>
|
</div>
|
||||||
</motion.div>
|
<ProjectTemplatesTable onEdit={setEditTemplate} />
|
||||||
)}
|
<ProjectTemplateDetailsModal
|
||||||
</AnimatePresence>
|
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>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user