mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 23:28:31 +00:00
Make the model look simpler
This commit is contained in:
@@ -5,7 +5,7 @@ description: "Comprehensive guide to Infisical's organization-level permissions"
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Infisical's organization permissions system follows a role-based access control (RBAC) model built on a subject-action-object framework. At the organization level, these permissions determine what actions users can perform on various resources across the entire organization.
|
Infisical's organization permissions system follows a role-based access control (RBAC) model built on a subject-action-object framework. At the organization level, these permissions determine what actions users/machines can perform on various resources across the entire organization.
|
||||||
|
|
||||||
Each permission consists of:
|
Each permission consists of:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ description: "Comprehensive guide to Infisical's project-level permissions"
|
|||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
Infisical's project permissions system follows a role-based access control (RBAC) model built on a subject-action-object framework. At the project level, these permissions determine what actions users can perform on various resources within a specific project.
|
Infisical's project permissions system follows a role-based access control (RBAC) model built on a subject-action-object framework. At the project level, these permissions determine what actions users/machines can perform on various resources within a specific project.
|
||||||
|
|
||||||
Each permission consists of:
|
Each permission consists of:
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,7 @@ export const AccessManagementPage = () => {
|
|||||||
<p className="mb-2 mt-1 text-sm text-bunker-300">
|
<p className="mb-2 mt-1 text-sm text-bunker-300">
|
||||||
We've developed an improved privilege management system to better serve your
|
We've developed an improved privilege management system to better serve your
|
||||||
security needs. Upgrade to our new permission-based approach that allows you to
|
security needs. Upgrade to our new permission-based approach that allows you to
|
||||||
explicitly designate who can modify specific access levels, rather than relying on
|
explicitly designate who can modify specific access levels, rather than relying on hierarchy comparisons.
|
||||||
traditional hierarchy comparisons.
|
|
||||||
</p>
|
</p>
|
||||||
<Button
|
<Button
|
||||||
colorSchema="primary"
|
colorSchema="primary"
|
||||||
|
|||||||
+218
-212
@@ -1,8 +1,7 @@
|
|||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { faCheck, faCircleInfo, faWarning } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
import { createNotification } from "@app/components/notifications";
|
import { createNotification } from "@app/components/notifications";
|
||||||
import { Button, Checkbox, Modal, ModalContent } from "@app/components/v2";
|
import { Button, Checkbox, Modal, ModalContent } from "@app/components/v2";
|
||||||
@@ -23,6 +22,7 @@ type Props = {
|
|||||||
|
|
||||||
export const UpgradePrivilegeSystemModal = ({ isOpen, onOpenChange }: Props) => {
|
export const UpgradePrivilegeSystemModal = ({ isOpen, onOpenChange }: Props) => {
|
||||||
const { membership } = useOrgPermission();
|
const { membership } = useOrgPermission();
|
||||||
|
const [step, setStep] = useState<"info" | "upgrade">("info");
|
||||||
|
|
||||||
const {
|
const {
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -60,225 +60,231 @@ export const UpgradePrivilegeSystemModal = ({ isOpen, onOpenChange }: Props) =>
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
onOpenChange(false);
|
||||||
|
setStep("info");
|
||||||
|
};
|
||||||
|
|
||||||
const isAdmin = membership?.role === "admin";
|
const isAdmin = membership?.role === "admin";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
<Modal isOpen={isOpen} onOpenChange={handleClose}>
|
||||||
<ModalContent title="Privilege Management System Upgrade" className="max-w-2xl">
|
<ModalContent title="Privilege Management System Upgrade" className="max-w-2xl">
|
||||||
<div className="mb-4">
|
{step === "info" ? (
|
||||||
<h4 className="mb-2 text-lg font-semibold">
|
<>
|
||||||
Introducing Permission-Based Privilege Management
|
|
||||||
</h4>
|
|
||||||
<p className="mb-4 leading-7 text-mineshaft-100">
|
|
||||||
We've developed an improved privilege management system that enhances how access
|
|
||||||
controls work in your organization.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div className="mb-4 rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
|
||||||
<div className="mb-3">
|
|
||||||
<div className="mb-2 flex items-start gap-2">
|
|
||||||
<FontAwesomeIcon icon={faCircleInfo} className="mt-1 text-primary" />
|
|
||||||
<p className="font-medium">How it works:</p>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3 ml-7">
|
|
||||||
<p className="mb-3">
|
|
||||||
<strong>Legacy system:</strong> Users with higher privilege levels could modify
|
|
||||||
access for anyone below them. This rigid hierarchy makes it difficult to implement
|
|
||||||
precise access control policies, forcing you to either over-grant permissions or
|
|
||||||
create complex workarounds when specialized roles (like team leads) need to manage
|
|
||||||
their team's access without receiving broader administrative powers.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<strong>New system:</strong> Users need explicit permission to modify specific
|
|
||||||
access levels, providing targeted control. After upgrading, you'll need to
|
|
||||||
grant the new 'Manage Privileges' permission. At the organization level,
|
|
||||||
this is available for the{" "}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/internals/permissions/organization-permissions#subject%3A-groups"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
|
||||||
>
|
|
||||||
Groups
|
|
||||||
</a>{" "}
|
|
||||||
and{" "}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/internals/permissions/organization-permissions#subject%3A-identity"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
|
||||||
>
|
|
||||||
Identity
|
|
||||||
</a>{" "}
|
|
||||||
subjects while at the project level, this is available for the{" "}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-member"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
|
||||||
>
|
|
||||||
Member,
|
|
||||||
</a>{" "}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-groups"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
|
||||||
>
|
|
||||||
Groups,
|
|
||||||
</a>{" "}
|
|
||||||
and{" "}
|
|
||||||
<a
|
|
||||||
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-identity"
|
|
||||||
target="_blank"
|
|
||||||
rel="noreferrer"
|
|
||||||
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
|
||||||
>
|
|
||||||
Identity
|
|
||||||
</a>{" "}
|
|
||||||
subjects.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="mt-3">
|
|
||||||
<div className="mb-2 flex items-start gap-2">
|
|
||||||
<FontAwesomeIcon icon={faCheck} className="mt-1 text-primary" />
|
|
||||||
<p className="font-medium">Benefits:</p>
|
|
||||||
</div>
|
|
||||||
<div className="ml-7">
|
|
||||||
<ul className="list-disc pl-5">
|
|
||||||
<li>More granular control over who can modify access levels</li>
|
|
||||||
<li>Improved security through precise permission checks</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p className="mb-4 leading-7 text-mineshaft-100">
|
|
||||||
This upgrade affects operations like updating roles, managing group memberships, and
|
|
||||||
modifying privileges across your organization and projects.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="mt-6 flex max-w-2xl flex-col rounded-lg border border-primary/50 bg-primary/10 px-6 py-5">
|
|
||||||
<div className="mb-4 flex items-start gap-2">
|
|
||||||
<FontAwesomeIcon icon={faWarning} size="xl" className="mt-1 text-primary" />
|
|
||||||
<p className="text-xl font-semibold">Upgrade privilege system</p>
|
|
||||||
</div>
|
|
||||||
<p className="mx-1 mb-4 leading-7 text-mineshaft-100">
|
|
||||||
Your existing access control workflows will continue to function. However, actions that
|
|
||||||
involve changing privileges or permissions will now use the new permission-based system,
|
|
||||||
requiring users to have explicit permission to modify access levels.
|
|
||||||
</p>
|
|
||||||
<p className="mb-6 text-mineshaft-100">
|
|
||||||
Once upgraded, your organization <span className="font-bold">cannot</span> revert to the
|
|
||||||
legacy privilege system. Please ensure you've completed all preparations before
|
|
||||||
proceeding.
|
|
||||||
</p>
|
|
||||||
<form onSubmit={handleSubmit(handlePrivilegeSystemUpgrade)}>
|
|
||||||
<div className="mb-4">
|
<div className="mb-4">
|
||||||
<p className="mb-3 font-medium">Required preparation checklist:</p>
|
<p className="mb-4 text-sm text-mineshaft-300">
|
||||||
|
We've developed an improved privilege management system that enhances how access controls work in your organization.
|
||||||
|
</p>
|
||||||
|
|
||||||
<div className="flex flex-col space-y-4">
|
<div className="mb-4 rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||||
<Controller
|
<div className="mb-3">
|
||||||
control={control}
|
<div className="mb-3">
|
||||||
name="isProjectPrivilegesUpdated"
|
<p className="mb-3 text-sm text-mineshaft-300">
|
||||||
defaultValue={false}
|
<strong>Current system: </strong>
|
||||||
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
Users with higher privilege levels can modify access for anyone below them.
|
||||||
<Checkbox
|
This rigid hierarchy makes it difficult to implement precise access control policies,
|
||||||
containerClassName="items-start"
|
forcing you to either over-grant permissions or create complex workarounds when specialized roles (like team leads) need to manage their team's access without receiving broader administrative powers.
|
||||||
className="mt-0.5 items-start"
|
</p>
|
||||||
id="is-project-privileges-updated"
|
<p className="text-sm text-mineshaft-300">
|
||||||
indicatorClassName="flex h-full w-full items-center justify-center"
|
<strong>New system:</strong> Users need explicit permission to modify specific
|
||||||
allowMultilineLabel
|
access levels, providing targeted control. After upgrading, you'll need to
|
||||||
isChecked={value}
|
grant the new 'Manage Privileges' permission. At the organization level,
|
||||||
onCheckedChange={onChange}
|
this is available for the{" "}
|
||||||
onBlur={onBlur}
|
<a
|
||||||
isError={Boolean(error?.message)}
|
href="https://infisical.com/docs/internals/permissions/organization-permissions#subject%3A-groups"
|
||||||
>
|
target="_blank"
|
||||||
I have reviewed project-level privileges and updated them if necessary
|
rel="noreferrer"
|
||||||
</Checkbox>
|
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
||||||
)}
|
>
|
||||||
/>
|
Group
|
||||||
|
</a>{" "}
|
||||||
|
and{" "}
|
||||||
|
<a
|
||||||
|
href="https://infisical.com/docs/internals/permissions/organization-permissions#subject%3A-identity"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
||||||
|
>
|
||||||
|
Identity
|
||||||
|
</a>{" "}
|
||||||
|
subjects while at the project level, this is available for the{" "}
|
||||||
|
<a
|
||||||
|
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-member"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
||||||
|
>
|
||||||
|
Member,
|
||||||
|
</a>{" "}
|
||||||
|
<a
|
||||||
|
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-groups"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
||||||
|
>
|
||||||
|
Group,
|
||||||
|
</a>{" "}
|
||||||
|
and{" "}
|
||||||
|
<a
|
||||||
|
href="https://infisical.com/docs/internals/permissions/project-permissions#subject%3A-identity"
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="underline hover:text-bunker-200 hover:decoration-primary-700"
|
||||||
|
>
|
||||||
|
Identity
|
||||||
|
</a>{" "}
|
||||||
|
subjects.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Controller
|
<div className="mt-4 flex justify-end">
|
||||||
control={control}
|
<Button
|
||||||
name="isOrgPrivilegesUpdated"
|
onClick={() => setStep("upgrade")}
|
||||||
defaultValue={false}
|
variant="solid"
|
||||||
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
colorSchema="primary"
|
||||||
<Checkbox
|
size="md"
|
||||||
containerClassName="items-start"
|
className="w-[120px] bg-primary hover:bg-primary-600"
|
||||||
className="mt-0.5 items-start"
|
>
|
||||||
indicatorClassName="flex h-full w-full items-center justify-center"
|
Continue
|
||||||
allowMultilineLabel
|
</Button>
|
||||||
id="is-org-privileges-updated"
|
|
||||||
isChecked={value}
|
|
||||||
onCheckedChange={onChange}
|
|
||||||
onBlur={onBlur}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
>
|
|
||||||
I have reviewed organization-level privileges and updated them if necessary
|
|
||||||
</Checkbox>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="isInfrastructureUpdated"
|
|
||||||
defaultValue={false}
|
|
||||||
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
|
||||||
<Checkbox
|
|
||||||
containerClassName="items-start"
|
|
||||||
className="mt-0.5 items-start"
|
|
||||||
id="is-infrastructure-updated"
|
|
||||||
indicatorClassName="flex h-full w-full items-center justify-center"
|
|
||||||
allowMultilineLabel
|
|
||||||
isChecked={value}
|
|
||||||
onCheckedChange={onChange}
|
|
||||||
onBlur={onBlur}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
>
|
|
||||||
I have checked Terraform configurations and API integrations for compatibility
|
|
||||||
with the new system
|
|
||||||
</Checkbox>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Controller
|
|
||||||
control={control}
|
|
||||||
name="acknowledgesPermanentChange"
|
|
||||||
defaultValue={false}
|
|
||||||
rules={{ required: true }}
|
|
||||||
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
|
||||||
<Checkbox
|
|
||||||
containerClassName="items-start"
|
|
||||||
className="mt-0.5 items-start"
|
|
||||||
id="acknowledges-permanent-change"
|
|
||||||
indicatorClassName="flex h-full w-full items-center justify-center"
|
|
||||||
allowMultilineLabel
|
|
||||||
isChecked={value}
|
|
||||||
onCheckedChange={onChange}
|
|
||||||
onBlur={onBlur}
|
|
||||||
isError={Boolean(error?.message)}
|
|
||||||
>
|
|
||||||
<span className="font-bold">
|
|
||||||
I understand that this upgrade is permanent and cannot be reversed
|
|
||||||
</span>
|
|
||||||
</Checkbox>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
</>
|
||||||
type="submit"
|
) : (
|
||||||
isDisabled={!isAdmin || !isAllChecksCompleted}
|
<div className="mb-4">
|
||||||
isLoading={isSubmitting}
|
<p className="mb-4 text-sm text-mineshaft-300">
|
||||||
className="mt-5 w-full"
|
Your existing access control workflows will continue to function. However, actions that
|
||||||
>
|
involve modifying privileges or permissions will now use the new permission-based system,
|
||||||
{isAdmin ? "Upgrade Privilege System" : "Upgrade requires admin privilege"}
|
requiring users to have explicit permission to modify given resource.
|
||||||
</Button>
|
</p>
|
||||||
</form>
|
|
||||||
</div>
|
<p className="mb-4 text-sm text-mineshaft-300">
|
||||||
|
This upgrade affects operations like updating roles, managing group memberships, and
|
||||||
|
modifying privileges across your organization and projects.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mb-4 rounded-lg border border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||||
|
<p className="mb-4 text-sm text-mineshaft-300">
|
||||||
|
Once upgraded, your organization <span className="font-bold">cannot</span> revert to the
|
||||||
|
legacy privilege system. Please ensure you've completed all preparations before
|
||||||
|
proceeding.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div className="mb-4">
|
||||||
|
<p className="mb-3 text-sm font-medium">Required preparation checklist:</p>
|
||||||
|
|
||||||
|
<div className="flex flex-col space-y-4">
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="isProjectPrivilegesUpdated"
|
||||||
|
defaultValue={false}
|
||||||
|
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
||||||
|
<Checkbox
|
||||||
|
containerClassName="items-start"
|
||||||
|
className="mt-0.5 items-start"
|
||||||
|
id="is-project-privileges-updated"
|
||||||
|
indicatorClassName="flex h-full w-full items-center justify-center"
|
||||||
|
allowMultilineLabel
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
>
|
||||||
|
I have reviewed project-level privileges and updated them if necessary
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="isOrgPrivilegesUpdated"
|
||||||
|
defaultValue={false}
|
||||||
|
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
||||||
|
<Checkbox
|
||||||
|
containerClassName="items-start"
|
||||||
|
className="mt-0.5 items-start"
|
||||||
|
id="is-org-privileges-updated"
|
||||||
|
indicatorClassName="flex h-full w-full items-center justify-center"
|
||||||
|
allowMultilineLabel
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
>
|
||||||
|
I have reviewed organization-level privileges and updated them if necessary
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="isInfrastructureUpdated"
|
||||||
|
defaultValue={false}
|
||||||
|
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
||||||
|
<Checkbox
|
||||||
|
containerClassName="items-start"
|
||||||
|
className="mt-0.5 items-start"
|
||||||
|
id="is-infrastructure-updated"
|
||||||
|
indicatorClassName="flex h-full w-full items-center justify-center"
|
||||||
|
allowMultilineLabel
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
>
|
||||||
|
I have checked Terraform configurations and API integrations for compatibility
|
||||||
|
with the new system
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={control}
|
||||||
|
name="acknowledgesPermanentChange"
|
||||||
|
defaultValue={false}
|
||||||
|
render={({ field: { onBlur, value, onChange }, fieldState: { error } }) => (
|
||||||
|
<Checkbox
|
||||||
|
containerClassName="items-start"
|
||||||
|
className="mt-0.5 items-start"
|
||||||
|
id="acknowledges-permanent-change"
|
||||||
|
indicatorClassName="flex h-full w-full items-center justify-center"
|
||||||
|
allowMultilineLabel
|
||||||
|
isChecked={value}
|
||||||
|
onCheckedChange={onChange}
|
||||||
|
onBlur={onBlur}
|
||||||
|
isError={Boolean(error?.message)}
|
||||||
|
>
|
||||||
|
I understand that this upgrade is permanent and cannot be reversed
|
||||||
|
</Checkbox>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form onSubmit={handleSubmit(handlePrivilegeSystemUpgrade)}>
|
||||||
|
<div className="mt-6 flex items-center justify-end gap-4">
|
||||||
|
<button
|
||||||
|
onClick={() => setStep("info")}
|
||||||
|
className="w-[120px] text-sm text-mineshaft-300 hover:text-mineshaft-200"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
variant="solid"
|
||||||
|
colorSchema="primary"
|
||||||
|
size="md"
|
||||||
|
className="w-[120px] bg-primary hover:bg-primary-600"
|
||||||
|
isDisabled={!isAllChecksCompleted || !isAdmin}
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
>
|
||||||
|
Upgrade
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user