mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-10 19:28:51 +00:00
Merge pull request #3697 from Infisical/approvals-redesign
revamp UI for access requests
This commit is contained in:
+282
-206
@@ -1,11 +1,15 @@
|
|||||||
|
/* eslint-disable jsx-a11y/label-has-associated-control */
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
|
import { faEye, faTrashCan } from "@fortawesome/free-regular-svg-icons";
|
||||||
import {
|
import {
|
||||||
faArrowRotateLeft,
|
faArrowRotateLeft,
|
||||||
faCaretDown,
|
faCaretDown,
|
||||||
faCheck,
|
faCheck,
|
||||||
faClock,
|
faClock,
|
||||||
faLockOpen,
|
faLockOpen,
|
||||||
|
faPencil,
|
||||||
|
faPlus,
|
||||||
faTrash
|
faTrash
|
||||||
} from "@fortawesome/free-solid-svg-icons";
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
@@ -205,7 +209,7 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
if (!data.secretPath) {
|
if (!data.secretPath) {
|
||||||
createNotification({
|
createNotification({
|
||||||
type: "error",
|
type: "error",
|
||||||
text: "Please select a secret path",
|
text: "Please select a secret path...",
|
||||||
title: "Error"
|
title: "Error"
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -264,18 +268,18 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-4 w-full">
|
<div className="w-full">
|
||||||
<form onSubmit={privilegeForm.handleSubmit(handleSubmit)}>
|
<form onSubmit={privilegeForm.handleSubmit(handleSubmit)}>
|
||||||
<div className={twMerge("flex items-start gap-4", !privilege && "flex-wrap")}>
|
<div className={twMerge("flex items-start", !privilege && "flex-col")}>
|
||||||
<Controller
|
<Controller
|
||||||
control={privilegeForm.control}
|
control={privilegeForm.control}
|
||||||
name="environmentSlug"
|
name="environmentSlug"
|
||||||
render={({ field: { onChange, ...field } }) => (
|
render={({ field: { onChange, ...field } }) => (
|
||||||
<FormControl label="Environment">
|
<FormControl label="Environment" className="w-full">
|
||||||
<Select
|
<Select
|
||||||
{...field}
|
{...field}
|
||||||
isDisabled={isMemberEditDisabled}
|
isDisabled={isMemberEditDisabled}
|
||||||
className="bg-mineshaft-600 hover:bg-mineshaft-500"
|
className="w-full bg-mineshaft-900 hover:bg-mineshaft-800"
|
||||||
onValueChange={(e) => onChange(e)}
|
onValueChange={(e) => onChange(e)}
|
||||||
>
|
>
|
||||||
{currentWorkspace?.environments?.map(({ slug, id, name }) => (
|
{currentWorkspace?.environments?.map(({ slug, id, name }) => (
|
||||||
@@ -297,12 +301,13 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
isDisabled={!!selectablePaths.length}
|
isDisabled={!!selectablePaths.length}
|
||||||
content="The selected environment doesn't have any policies."
|
content="The selected environment doesn't have any policies."
|
||||||
>
|
>
|
||||||
<div>
|
<div className="w-full">
|
||||||
<FormControl label="Secret Path">
|
<FormControl label="Secret Path">
|
||||||
<Select
|
<Select
|
||||||
{...field}
|
{...field}
|
||||||
isDisabled={isMemberEditDisabled || !selectablePaths.length}
|
isDisabled={isMemberEditDisabled || !selectablePaths.length}
|
||||||
className="w-48"
|
className="w-full hover:bg-mineshaft-800"
|
||||||
|
placeholder="Select a secret path"
|
||||||
onValueChange={(e) => field.onChange(e)}
|
onValueChange={(e) => field.onChange(e)}
|
||||||
>
|
>
|
||||||
{selectablePaths.map((path) => (
|
{selectablePaths.map((path) => (
|
||||||
@@ -328,222 +333,287 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-grow justify-between">
|
<FormControl label="Permissions" className="w-full">
|
||||||
<Controller
|
<div className="flex w-full flex-col justify-between">
|
||||||
control={privilegeForm.control}
|
<div className="flex w-full flex-row gap-2">
|
||||||
name="read"
|
<Controller
|
||||||
render={({ field }) => (
|
control={privilegeForm.control}
|
||||||
<div className="flex flex-col items-center">
|
name="read"
|
||||||
<FormLabel label="View" className="mb-4" />
|
render={({ field }) => (
|
||||||
<Checkbox
|
<label
|
||||||
isDisabled={isMemberEditDisabled}
|
className={`group my-1 flex w-full cursor-pointer flex-row items-center justify-start gap-2 rounded-md border border-mineshaft-600 bg-mineshaft-900 p-3 duration-100 hover:border-primary/30 hover:bg-primary/10 ${field.value ? "border-primary/50 bg-primary/10 hover:border-primary/50" : ""}`}
|
||||||
id="secret-read"
|
htmlFor="secret-read"
|
||||||
className="h-5 w-5"
|
|
||||||
isChecked={field.value}
|
|
||||||
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={privilegeForm.control}
|
|
||||||
name="create"
|
|
||||||
render={({ field }) => (
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<FormLabel label="Create" className="mb-4" />
|
|
||||||
<Checkbox
|
|
||||||
isDisabled={isMemberEditDisabled}
|
|
||||||
id="secret-create"
|
|
||||||
className="h-5 w-5"
|
|
||||||
isChecked={field.value}
|
|
||||||
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={privilegeForm.control}
|
|
||||||
name="edit"
|
|
||||||
render={({ field }) => (
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<FormLabel label="Modify" className="mb-4" />
|
|
||||||
<Checkbox
|
|
||||||
isDisabled={isMemberEditDisabled}
|
|
||||||
id="secret-modify"
|
|
||||||
className="h-5 w-5"
|
|
||||||
isChecked={field.value}
|
|
||||||
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
<Controller
|
|
||||||
control={privilegeForm.control}
|
|
||||||
name="delete"
|
|
||||||
render={({ field }) => (
|
|
||||||
<div className="flex flex-col items-center">
|
|
||||||
<FormLabel label="Delete" className="mb-4" />
|
|
||||||
<Checkbox
|
|
||||||
isDisabled={isMemberEditDisabled}
|
|
||||||
id="secret-delete"
|
|
||||||
className="h-5 w-5"
|
|
||||||
isChecked={field.value}
|
|
||||||
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mt-6 flex items-center space-x-2">
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger disabled={isMemberEditDisabled}>
|
|
||||||
<div>
|
|
||||||
<Tooltip content={getAccessLabel(true)}>
|
|
||||||
<Button
|
|
||||||
variant="outline_bg"
|
|
||||||
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
|
|
||||||
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-2" />}
|
|
||||||
isDisabled={isMemberEditDisabled}
|
|
||||||
className={twMerge(
|
|
||||||
"border-none bg-mineshaft-600 py-2.5 text-xs capitalize hover:bg-mineshaft-500",
|
|
||||||
isTemporary && "text-primary",
|
|
||||||
isExpired && "text-red-600"
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{getAccessLabel(false)}
|
<Checkbox
|
||||||
</Button>
|
isDisabled={isMemberEditDisabled}
|
||||||
</Tooltip>
|
id="secret-read"
|
||||||
</div>
|
className={`mx-2 h-5 w-5 ${field.value ? "bg-primary hover:bg-primary/80" : ""}`}
|
||||||
</PopoverTrigger>
|
isChecked={field.value}
|
||||||
<PopoverContent
|
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
||||||
arrowClassName="fill-gray-600"
|
/>
|
||||||
side="right"
|
<div className="ml-1 flex flex-col text-mineshaft-300">
|
||||||
sideOffset={12}
|
<div className="flex flex-row items-center gap-1">
|
||||||
hideCloseBtn
|
<FontAwesomeIcon
|
||||||
className="border border-gray-600 pt-4"
|
icon={faEye}
|
||||||
>
|
className={`text-sm ${field.value ? "text-primary-200" : ""}`}
|
||||||
<div className="flex flex-col space-y-4">
|
/>
|
||||||
<div className="border-b border-b-gray-700 pb-2 text-sm text-mineshaft-300">
|
<FormLabel
|
||||||
Configure timed access
|
label="View"
|
||||||
</div>
|
className={`ml-0.5 mt-0 text-mineshaft-300 ${field.value ? "text-primary-200" : ""}`}
|
||||||
{isExpired && <Tag colorSchema="red">Expired</Tag>}
|
/>
|
||||||
<Controller
|
</div>
|
||||||
control={privilegeForm.control}
|
<p className="text-xs text-mineshaft-400">Read secret values</p>
|
||||||
defaultValue="1h"
|
</div>
|
||||||
name="temporaryAccess.temporaryRange"
|
</label>
|
||||||
render={({ field, fieldState: { error } }) => (
|
)}
|
||||||
<FormControl
|
/>
|
||||||
label={<TtlFormLabel label="Validity" />}
|
<Controller
|
||||||
isError={Boolean(error?.message)}
|
control={privilegeForm.control}
|
||||||
errorText={error?.message}
|
name="create"
|
||||||
|
render={({ field }) => (
|
||||||
|
<label
|
||||||
|
className={`group my-1 flex w-full cursor-pointer flex-row items-center justify-start gap-2 rounded-md border border-mineshaft-600 bg-mineshaft-900 p-3 duration-100 hover:border-primary/30 hover:bg-primary/10 ${field.value ? "border-primary/50 bg-primary/10 hover:border-primary/50" : ""}`}
|
||||||
|
htmlFor="secret-change"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
isDisabled={isMemberEditDisabled}
|
||||||
|
id="secret-change"
|
||||||
|
className={`mx-2 h-5 w-5 ${field.value ? "bg-primary hover:bg-primary/80" : ""}`}
|
||||||
|
isChecked={field.value}
|
||||||
|
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
||||||
|
/>
|
||||||
|
<div className="ml-1 flex flex-col text-mineshaft-300">
|
||||||
|
<div className="flex flex-row items-center gap-1">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faPlus}
|
||||||
|
className={`text-sm ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
<FormLabel
|
||||||
|
label="Create"
|
||||||
|
className={`ml-0.5 mt-0 text-mineshaft-300 ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-mineshaft-400">Create new secrets</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full flex-row gap-2">
|
||||||
|
<Controller
|
||||||
|
control={privilegeForm.control}
|
||||||
|
name="edit"
|
||||||
|
render={({ field }) => (
|
||||||
|
<label
|
||||||
|
className={`group my-1 flex w-full cursor-pointer flex-row items-center justify-start gap-2 rounded-md border border-mineshaft-600 bg-mineshaft-900 p-3 duration-100 hover:border-primary/30 hover:bg-primary/10 ${field.value ? "border-primary/50 bg-primary/10 hover:border-primary/50" : ""}`}
|
||||||
|
htmlFor="secret-modify"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
isDisabled={isMemberEditDisabled}
|
||||||
|
id="secret-modify"
|
||||||
|
className={`mx-2 h-5 w-5 ${field.value ? "bg-primary hover:bg-primary/80" : ""}`}
|
||||||
|
isChecked={field.value}
|
||||||
|
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
||||||
|
/>
|
||||||
|
<div className="ml-1 flex flex-col text-mineshaft-300">
|
||||||
|
<div className="flex flex-row items-center gap-1">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faPencil}
|
||||||
|
className={`text-sm ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
<FormLabel
|
||||||
|
label="Modify"
|
||||||
|
className={`ml-0.5 mt-0 text-mineshaft-300 ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-mineshaft-400">Update existing secrets</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Controller
|
||||||
|
control={privilegeForm.control}
|
||||||
|
name="delete"
|
||||||
|
render={({ field }) => (
|
||||||
|
<label
|
||||||
|
className={`group my-1 flex w-full cursor-pointer flex-row items-center justify-start gap-2 rounded-md border border-mineshaft-600 bg-mineshaft-900 p-3 duration-100 hover:border-primary/30 hover:bg-primary/10 ${field.value ? "border-primary/50 bg-primary/10 hover:border-primary/50" : ""}`}
|
||||||
|
htmlFor="secret-delete"
|
||||||
|
>
|
||||||
|
<Checkbox
|
||||||
|
isDisabled={isMemberEditDisabled}
|
||||||
|
id="secret-delete"
|
||||||
|
className={`mx-2 h-5 w-5 ${field.value ? "bg-primary hover:bg-primary/80" : ""}`}
|
||||||
|
isChecked={field.value}
|
||||||
|
onCheckedChange={(isChecked) => field.onChange(isChecked)}
|
||||||
|
/>
|
||||||
|
<div className="ml-1 flex flex-col text-mineshaft-300">
|
||||||
|
<div className="flex flex-row items-center gap-1">
|
||||||
|
<FontAwesomeIcon
|
||||||
|
icon={faTrashCan}
|
||||||
|
className={`text-sm ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
<FormLabel
|
||||||
|
label="Delete"
|
||||||
|
className={`ml-0.5 mt-0 text-mineshaft-300 ${field.value ? "text-primary-200" : ""}`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<p className="text-xs text-mineshaft-400">Delete existing secrets</p>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</FormControl>
|
||||||
|
<FormControl label="Time Period" className="w-full">
|
||||||
|
<div className="mt-1 flex w-full items-center space-x-2">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger disabled={isMemberEditDisabled}>
|
||||||
|
<div className="w-full">
|
||||||
|
<Tooltip content={getAccessLabel(true)}>
|
||||||
|
<Button
|
||||||
|
variant="outline_bg"
|
||||||
|
leftIcon={isTemporary ? <FontAwesomeIcon icon={faClock} /> : undefined}
|
||||||
|
rightIcon={<FontAwesomeIcon icon={faCaretDown} className="ml-4" />}
|
||||||
|
isDisabled={isMemberEditDisabled}
|
||||||
|
className={twMerge(
|
||||||
|
"w-full border-mineshaft-600 bg-mineshaft-900 py-2.5 text-sm capitalize text-mineshaft-300 hover:border-mineshaft-600 hover:bg-mineshaft-800",
|
||||||
|
isExpired && "text-red-600"
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<Input {...field} />
|
{getAccessLabel(false)}
|
||||||
</FormControl>
|
</Button>
|
||||||
)}
|
</Tooltip>
|
||||||
/>
|
</div>
|
||||||
<div className="flex items-center space-x-2">
|
</PopoverTrigger>
|
||||||
<Button
|
<PopoverContent
|
||||||
size="xs"
|
arrowClassName="fill-mineshaft-600"
|
||||||
onClick={() => {
|
side="right"
|
||||||
const temporaryRange = privilegeForm.getValues(
|
sideOffset={12}
|
||||||
"temporaryAccess.temporaryRange"
|
hideCloseBtn
|
||||||
);
|
className="border border-mineshaft-600 bg-mineshaft-800 pt-4"
|
||||||
if (!temporaryRange) {
|
>
|
||||||
privilegeForm.setError(
|
<div className="flex flex-col space-y-4">
|
||||||
"temporaryAccess.temporaryRange",
|
<div className="text-sm text-mineshaft-300">Configure timed access</div>
|
||||||
{ type: "required", message: "Required" },
|
{isExpired && <Tag colorSchema="red">Expired</Tag>}
|
||||||
{ shouldFocus: true }
|
<Controller
|
||||||
);
|
control={privilegeForm.control}
|
||||||
return;
|
defaultValue="1h"
|
||||||
}
|
name="temporaryAccess.temporaryRange"
|
||||||
privilegeForm.clearErrors("temporaryAccess.temporaryRange");
|
render={({ field, fieldState: { error } }) => (
|
||||||
privilegeForm.setValue(
|
<FormControl
|
||||||
"temporaryAccess",
|
label={<TtlFormLabel label="Validity" />}
|
||||||
{
|
isError={Boolean(error?.message)}
|
||||||
isTemporary: true,
|
errorText={error?.message}
|
||||||
temporaryAccessStartTime: new Date().toISOString(),
|
>
|
||||||
temporaryRange,
|
<Input {...field} />
|
||||||
temporaryAccessEndTime: new Date(
|
</FormControl>
|
||||||
new Date().getTime() + ms(temporaryRange)
|
)}
|
||||||
).toISOString()
|
/>
|
||||||
},
|
<div className="flex items-center space-x-2">
|
||||||
{ shouldDirty: true }
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{temporaryAccessField.isTemporary && !policies ? "Restart" : "Grant"}
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
{temporaryAccessField.isTemporary && (
|
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
variant="outline_bg"
|
|
||||||
colorSchema="danger"
|
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
privilegeForm.setValue("temporaryAccess", {
|
const temporaryRange = privilegeForm.getValues(
|
||||||
isTemporary: false
|
"temporaryAccess.temporaryRange"
|
||||||
});
|
);
|
||||||
|
if (!temporaryRange) {
|
||||||
|
privilegeForm.setError(
|
||||||
|
"temporaryAccess.temporaryRange",
|
||||||
|
{ type: "required", message: "Required" },
|
||||||
|
{ shouldFocus: true }
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
privilegeForm.clearErrors("temporaryAccess.temporaryRange");
|
||||||
|
privilegeForm.setValue(
|
||||||
|
"temporaryAccess",
|
||||||
|
{
|
||||||
|
isTemporary: true,
|
||||||
|
temporaryAccessStartTime: new Date().toISOString(),
|
||||||
|
temporaryRange,
|
||||||
|
temporaryAccessEndTime: new Date(
|
||||||
|
new Date().getTime() + ms(temporaryRange)
|
||||||
|
).toISOString()
|
||||||
|
},
|
||||||
|
{ shouldDirty: true }
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Cancel
|
{temporaryAccessField.isTemporary && !policies ? "Restart" : "Grant"}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
|
||||||
|
{temporaryAccessField.isTemporary && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant="outline_bg"
|
||||||
|
colorSchema="danger"
|
||||||
|
onClick={() => {
|
||||||
|
privilegeForm.setValue("temporaryAccess", {
|
||||||
|
isTemporary: false
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</PopoverContent>
|
||||||
</PopoverContent>
|
</Popover>
|
||||||
</Popover>
|
{/* eslint-disable-next-line no-nested-ternary */}
|
||||||
{/* eslint-disable-next-line no-nested-ternary */}
|
{privilegeForm.formState.isDirty && privilege ? (
|
||||||
{privilegeForm.formState.isDirty && privilege ? (
|
<>
|
||||||
<>
|
<Tooltip content="Cancel" className="mr-4">
|
||||||
<Tooltip content="Cancel" className="mr-4">
|
<IconButton
|
||||||
<IconButton
|
variant="outline_bg"
|
||||||
variant="outline_bg"
|
className="border border-mineshaft-500 bg-mineshaft-600 py-2.5 hover:border-red/70 hover:bg-red/20"
|
||||||
className="border border-mineshaft-500 bg-mineshaft-600 py-2.5 hover:border-red/70 hover:bg-red/20"
|
ariaLabel="delete-privilege"
|
||||||
ariaLabel="delete-privilege"
|
isDisabled={privilegeForm.formState.isSubmitting}
|
||||||
isDisabled={privilegeForm.formState.isSubmitting}
|
onClick={() => privilegeForm.reset()}
|
||||||
onClick={() => privilegeForm.reset()}
|
>
|
||||||
|
<FontAwesomeIcon icon={faArrowRotateLeft} className="py-0.5" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip
|
||||||
|
content={isMemberEditDisabled ? "Access restricted" : "Save"}
|
||||||
|
className="mr-4"
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faArrowRotateLeft} className="py-0.5" />
|
<IconButton
|
||||||
</IconButton>
|
isDisabled={isMemberEditDisabled}
|
||||||
</Tooltip>
|
className="border-none py-3"
|
||||||
|
ariaLabel="save-privilege"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
{privilegeForm.formState.isSubmitting ? (
|
||||||
|
<Spinner size="xs" className="m-0 h-3 w-3 text-slate-500" />
|
||||||
|
) : (
|
||||||
|
<FontAwesomeIcon icon={faCheck} className="px-0.5" />
|
||||||
|
)}
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
) : // eslint-disable-next-line no-nested-ternary
|
||||||
|
privilege ? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
content={isMemberEditDisabled ? "Access restricted" : "Save"}
|
content={isMemberEditDisabled ? "Access restricted" : "Delete"}
|
||||||
className="mr-4"
|
className="mr-4"
|
||||||
>
|
>
|
||||||
<IconButton
|
<IconButton
|
||||||
isDisabled={isMemberEditDisabled}
|
isDisabled={isMemberEditDisabled}
|
||||||
className="border-none py-3"
|
variant="outline_bg"
|
||||||
ariaLabel="save-privilege"
|
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
|
||||||
type="submit"
|
ariaLabel="delete-privilege"
|
||||||
|
onClick={() => handlePopUpOpen("deletePrivilege")}
|
||||||
>
|
>
|
||||||
{privilegeForm.formState.isSubmitting ? (
|
<FontAwesomeIcon icon={faTrash} />
|
||||||
<Spinner size="xs" className="m-0 h-3 w-3 text-slate-500" />
|
|
||||||
) : (
|
|
||||||
<FontAwesomeIcon icon={faCheck} className="px-0.5" />
|
|
||||||
)}
|
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
) : (
|
||||||
) : // eslint-disable-next-line no-nested-ternary
|
<div />
|
||||||
privilege ? (
|
)}
|
||||||
<Tooltip
|
</div>
|
||||||
content={isMemberEditDisabled ? "Access restricted" : "Delete"}
|
</FormControl>
|
||||||
className="mr-4"
|
|
||||||
>
|
|
||||||
<IconButton
|
|
||||||
isDisabled={isMemberEditDisabled}
|
|
||||||
variant="outline_bg"
|
|
||||||
className="border border-mineshaft-500 bg-mineshaft-600 py-3 hover:border-red/70 hover:bg-red/20"
|
|
||||||
ariaLabel="delete-privilege"
|
|
||||||
onClick={() => handlePopUpOpen("deletePrivilege")}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faTrash} />
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
) : (
|
|
||||||
<div />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-4 flex w-full">
|
<div className="mb-4 flex w-full">
|
||||||
<Controller
|
<Controller
|
||||||
@@ -552,7 +622,13 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<FormLabel label="Note" className="mb-2" />
|
<FormLabel label="Note" className="mb-2" />
|
||||||
<Input {...field} isDisabled={isMemberEditDisabled} maxLength={255} />
|
<Input
|
||||||
|
{...field}
|
||||||
|
isDisabled={isMemberEditDisabled}
|
||||||
|
maxLength={255}
|
||||||
|
placeholder="Add the reason for this access request..."
|
||||||
|
className="text-mineshaft-300"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+2
-2
@@ -158,8 +158,8 @@ export const RolePermissionsSection = ({ roleSlug, isDisabled }: Props) => {
|
|||||||
variant="outline_bg"
|
variant="outline_bg"
|
||||||
type="submit"
|
type="submit"
|
||||||
className={twMerge(
|
className={twMerge(
|
||||||
"mr-4 h-10 border border-primary",
|
"mr-4 h-10 border",
|
||||||
isDirty && "bg-primary text-black"
|
isDirty && "bg-primary text-black hover:bg-primary hover:opacity-80"
|
||||||
)}
|
)}
|
||||||
isDisabled={isSubmitting || !isDirty}
|
isDisabled={isSubmitting || !isDirty}
|
||||||
isLoading={isSubmitting}
|
isLoading={isSubmitting}
|
||||||
|
|||||||
+2
-2
@@ -14,9 +14,9 @@ export const RequestAccessModal = ({
|
|||||||
return (
|
return (
|
||||||
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
<Modal isOpen={isOpen} onOpenChange={onOpenChange}>
|
||||||
<ModalContent
|
<ModalContent
|
||||||
className="max-w-4xl"
|
className="max-w-xl"
|
||||||
title="Request Access"
|
title="Request Access"
|
||||||
subTitle="Your role has limited permissions, please contact your administrator to gain access"
|
subTitle="Request access to any secrets and resources based on the predefined policies."
|
||||||
>
|
>
|
||||||
<SpecificPrivilegeSecretForm onClose={() => onOpenChange(false)} policies={policies} />
|
<SpecificPrivilegeSecretForm onClose={() => onOpenChange(false)} policies={policies} />
|
||||||
</ModalContent>
|
</ModalContent>
|
||||||
|
|||||||
Reference in New Issue
Block a user