This commit is contained in:
Daniel Hougaard
2023-11-28 00:54:55 +04:00
parent d92b1d3cd8
commit 3c2a66f722
@@ -52,7 +52,6 @@ import { WsTag } from "@app/hooks/api/types";
import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils"; import { formSchema, SecretActionType, TFormSchema } from "./SecretListView.utils";
import { CreateReminderForm } from "./CreateReminderForm"; import { CreateReminderForm } from "./CreateReminderForm";
type Props = { type Props = {
secret: DecryptedSecret; secret: DecryptedSecret;
onSaveSecret: ( onSaveSecret: (
@@ -71,8 +70,6 @@ type Props = {
secretPath: string; secretPath: string;
}; };
export const SecretItem = memo( export const SecretItem = memo(
({ ({
secret, secret,
@@ -189,346 +186,344 @@ export const SecretItem = memo(
return ( return (
<> <>
<CreateReminderForm
isOpen={createReminderFormOpen}
onClose={(data) => {
if (data) {
setValue("reminderCron", data.cron, { shouldDirty: true });
setValue("reminderNote", data.note, { shouldDirty: true });
}
setCreateReminderFormOpen.off();
}}
/>
<CreateReminderForm <form onSubmit={handleSubmit(handleFormSubmit)}>
isOpen={createReminderFormOpen} <div
onClose={data => { className={twMerge(
if(data) { "border-b border-mineshaft-600 bg-mineshaft-800 shadow-none hover:bg-mineshaft-700",
setValue("reminderCron", data.cron, {shouldDirty: true}); isDirty && "border-primary-400/50"
setValue("reminderNote", data.note, {shouldDirty: true}); )}
} >
setCreateReminderFormOpen.off(); <div className="group flex">
}} <div
/> className={twMerge(
"flex h-11 w-11 items-center justify-center px-4 py-3",
<form onSubmit={handleSubmit(handleFormSubmit)}> isDirty && "text-primary"
<div )}
className={twMerge( >
"border-b border-mineshaft-600 bg-mineshaft-800 shadow-none hover:bg-mineshaft-700", <Checkbox
isDirty && "border-primary-400/50" id={`checkbox-${secret._id}`}
)} isChecked={isSelected}
> onCheckedChange={() => onToggleSecretSelect(secret._id)}
<div className="group flex"> className={twMerge("ml-3 hidden group-hover:flex", isSelected && "flex")}
<div />
className={twMerge( <FontAwesomeIcon
"flex h-11 w-11 items-center justify-center px-4 py-3", icon={faKey}
isDirty && "text-primary" className={twMerge("ml-3 block group-hover:hidden", isSelected && "hidden")}
)} />
> </div>
<Checkbox <div className="flex h-11 w-80 flex-shrink-0 items-center px-4 py-2">
id={`checkbox-${secret._id}`} <Controller
isChecked={isSelected} name="key"
onCheckedChange={() => onToggleSecretSelect(secret._id)} control={control}
className={twMerge("ml-3 hidden group-hover:flex", isSelected && "flex")} render={({ field }) => (
/> <Input
<FontAwesomeIcon autoComplete="off"
icon={faKey} isReadOnly={isReadOnly}
className={twMerge("ml-3 block group-hover:hidden", isSelected && "hidden")} autoCapitalization={currentWorkspace?.autoCapitalization}
/> variant="plain"
</div> isDisabled={isOverriden}
<div className="flex h-11 w-80 flex-shrink-0 items-center px-4 py-2"> {...field}
<Controller className="w-full px-0 focus:text-bunker-100 focus:ring-transparent"
name="key" />
control={control} )}
render={({ field }) => ( />
<Input </div>
autoComplete="off" <div
isReadOnly={isReadOnly} className="flex flex-grow items-center border-x border-mineshaft-600 py-1 pl-4 pr-2"
autoCapitalization={currentWorkspace?.autoCapitalization} tabIndex={0}
variant="plain" role="button"
isDisabled={isOverriden} >
{...field} {isOverriden ? (
className="w-full px-0 focus:text-bunker-100 focus:ring-transparent" <Controller
name="valueOverride"
key="value-overriden"
control={control}
render={({ field }) => (
<SecretInput
key="value-overriden"
isVisible={isVisible}
isReadOnly={isReadOnly}
{...field}
containerClassName="py-1.5 rounded-md transition-all group-hover:mr-2"
/>
)}
/>
) : (
<Controller
name="value"
key="secret-value"
control={control}
render={({ field }) => (
<SecretInput
isReadOnly={isReadOnly}
key="secret-value"
isVisible={isVisible}
{...field}
containerClassName="py-1.5 rounded-md transition-all group-hover:mr-2"
/>
)}
/> />
)} )}
/> <div key="actions" className="flex h-8 flex-shrink-0 self-start transition-all">
</div> <Tooltip content="Copy secret">
<div
className="flex flex-grow items-center border-x border-mineshaft-600 py-1 pl-4 pr-2"
tabIndex={0}
role="button"
>
{isOverriden ? (
<Controller
name="valueOverride"
key="value-overriden"
control={control}
render={({ field }) => (
<SecretInput
key="value-overriden"
isVisible={isVisible}
isReadOnly={isReadOnly}
{...field}
containerClassName="py-1.5 rounded-md transition-all group-hover:mr-2"
/>
)}
/>
) : (
<Controller
name="value"
key="secret-value"
control={control}
render={({ field }) => (
<SecretInput
isReadOnly={isReadOnly}
key="secret-value"
isVisible={isVisible}
{...field}
containerClassName="py-1.5 rounded-md transition-all group-hover:mr-2"
/>
)}
/>
)}
<div key="actions" className="flex h-8 flex-shrink-0 self-start transition-all">
<Tooltip content="Copy secret">
<IconButton
ariaLabel="copy-value"
variant="plain"
size="sm"
className="w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5"
onClick={copyTokenToClipboard}
>
<FontAwesomeIcon icon={isSecValueCopied ? faCheck : faCopy} />
</IconButton>
</Tooltip>
<DropdownMenu>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
>
{(isAllowed) => (
<DropdownMenuTrigger asChild disabled={!isAllowed}>
<IconButton
ariaLabel="tags"
variant="plain"
size="sm"
className={twMerge(
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-5",
hasTagsApplied && "w-5 text-primary"
)}
isDisabled={!isAllowed}
>
<Tooltip content="Tags">
<FontAwesomeIcon icon={faTags} />
</Tooltip>
</IconButton>
</DropdownMenuTrigger>
)}
</ProjectPermissionCan>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Apply tags to this secrets</DropdownMenuLabel>
{tags.map((tag) => {
const { _id: tagId, name, tagColor } = tag;
const isTagSelected = selectedTagsGroupById?.[tagId];
return (
<DropdownMenuItem
onClick={() => handleTagSelect(tag)}
key={tagId}
icon={isTagSelected && <FontAwesomeIcon icon={faCheckCircle} />}
iconPos="right"
>
<div className="flex items-center">
<div
className="mr-2 h-2 w-2 rounded-full"
style={{ background: tagColor || "#bec2c8" }}
/>
{name}
</div>
</DropdownMenuItem>
);
})}
<DropdownMenuItem className="px-1.5">
<Button
size="xs"
className="w-full"
colorSchema="primary"
variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faTag} />}
onClick={onCreateTag}
>
Create a tag
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
renderTooltip
allowedLabel="Override"
>
{(isAllowed) => (
<IconButton <IconButton
ariaLabel="override-value" ariaLabel="copy-value"
isDisabled={!isAllowed}
variant="plain" variant="plain"
size="sm" size="sm"
onClick={handleOverrideClick} className="w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5"
className={twMerge( onClick={copyTokenToClipboard}
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5",
isOverriden && "w-5 text-primary"
)}
> >
<FontAwesomeIcon icon={faCodeBranch} /> <FontAwesomeIcon icon={isSecValueCopied ? faCheck : faCopy} />
</IconButton> </IconButton>
)} </Tooltip>
</ProjectPermissionCan> <DropdownMenu>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
>
{(isAllowed) => (
<DropdownMenuTrigger asChild disabled={!isAllowed}>
<IconButton
ariaLabel="tags"
variant="plain"
size="sm"
className={twMerge(
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-5",
hasTagsApplied && "w-5 text-primary"
)}
isDisabled={!isAllowed}
>
<Tooltip content="Tags">
<FontAwesomeIcon icon={faTags} />
</Tooltip>
</IconButton>
</DropdownMenuTrigger>
)}
</ProjectPermissionCan>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Apply tags to this secrets</DropdownMenuLabel>
{tags.map((tag) => {
const { _id: tagId, name, tagColor } = tag;
const isTagSelected = selectedTagsGroupById?.[tagId];
<IconButton return (
className={twMerge( <DropdownMenuItem
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-6", onClick={() => handleTagSelect(tag)}
hasReminder && "w-5 text-primary" key={tagId}
)} icon={isTagSelected && <FontAwesomeIcon icon={faCheckCircle} />}
variant="plain" iconPos="right"
size="md" >
ariaLabel="add-reminder" <div className="flex items-center">
> <div
<Tooltip content="Reminder"> className="mr-2 h-2 w-2 rounded-full"
<FontAwesomeIcon style={{ background: tagColor || "#bec2c8" }}
onClick={() => { />
if(!hasReminder) { {name}
setCreateReminderFormOpen.on(); </div>
} </DropdownMenuItem>
else { );
setValue("reminderCron", null, {shouldDirty: true}); })}
setValue("reminderNote", null, {shouldDirty: true}); <DropdownMenuItem className="px-1.5">
} <Button
}} size="xs"
icon={faClock} /> className="w-full"
</Tooltip> colorSchema="primary"
</IconButton> variant="outline_bg"
leftIcon={<FontAwesomeIcon icon={faTag} />}
<Popover> onClick={onCreateTag}
>
Create a tag
</Button>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<ProjectPermissionCan <ProjectPermissionCan
I={ProjectPermissionActions.Edit} I={ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })} a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
>
{(isAllowed) => (
<PopoverTrigger asChild disabled={!isAllowed}>
<IconButton
className={twMerge(
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-6",
hasComment && "w-5 text-primary"
)}
variant="plain"
size="md"
ariaLabel="add-comment"
isDisabled={!isAllowed}
>
<Tooltip content="Comment">
<FontAwesomeIcon icon={faComment} />
</Tooltip>
</IconButton>
</PopoverTrigger>
)}
</ProjectPermissionCan>
<PopoverContent
className="w-auto border border-mineshaft-600 bg-mineshaft-800 p-2 drop-shadow-2xl"
sticky="always"
>
<FormControl label="Comment" className="mb-0">
<TextArea
className="border border-mineshaft-600 text-sm"
rows={8}
cols={30}
{...register("comment")}
/>
</FormControl>
</PopoverContent>
</Popover>
</div>
</div>
<AnimatePresence exitBeforeEnter>
{!isDirty ? (
<motion.div
key="options"
className="flex h-10 flex-shrink-0 items-center space-x-4 px-3"
initial={{ x: 0, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: 10, opacity: 0 }}
>
<Tooltip content="More">
<IconButton
ariaLabel="more"
variant="plain"
size="md"
className="p-0 opacity-0 group-hover:opacity-100"
onClick={() => onDetailViewSecret(secret)}
>
<FontAwesomeIcon icon={faEllipsis} size="lg" />
</IconButton>
</Tooltip>
<ProjectPermissionCan
I={ProjectPermissionActions.Delete}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
renderTooltip renderTooltip
allowedLabel="Delete" allowedLabel="Override"
> >
{(isAllowed) => ( {(isAllowed) => (
<IconButton <IconButton
ariaLabel="delete-value" ariaLabel="override-value"
variant="plain"
colorSchema="danger"
size="md"
className="p-0 opacity-0 group-hover:opacity-100"
onClick={() => onDeleteSecret(secret)}
isDisabled={!isAllowed} isDisabled={!isAllowed}
variant="plain"
size="sm"
onClick={handleOverrideClick}
className={twMerge(
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5",
isOverriden && "w-5 text-primary"
)}
> >
<FontAwesomeIcon icon={faClose} size="lg" /> <FontAwesomeIcon icon={faCodeBranch} />
</IconButton> </IconButton>
)} )}
</ProjectPermissionCan> </ProjectPermissionCan>
</motion.div>
) : ( <IconButton
<motion.div className={twMerge(
key="options-save" "w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-6",
className="flex h-10 flex-shrink-0 items-center space-x-4 px-3" hasReminder && "w-5 text-primary"
initial={{ x: -10, opacity: 0 }} )}
animate={{ x: 0, opacity: 1 }} variant="plain"
exit={{ x: -10, opacity: 0 }} size="md"
> ariaLabel="add-reminder"
<Tooltip content="Save"> >
<IconButton <Tooltip content="Reminder">
ariaLabel="more" <FontAwesomeIcon
variant="plain" onClick={() => {
type="submit" if (!hasReminder) {
size="md" setCreateReminderFormOpen.on();
className={twMerge( } else {
"p-0 text-primary opacity-0 group-hover:opacity-100", setValue("reminderCron", null, { shouldDirty: true });
isDirty && "opacity-100" setValue("reminderNote", null, { shouldDirty: true });
)} }
isDisabled={isSubmitting} }}
icon={faClock}
/>
</Tooltip>
</IconButton>
<Popover>
<ProjectPermissionCan
I={ProjectPermissionActions.Edit}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
> >
{isSubmitting ? ( {(isAllowed) => (
<Spinner className="m-0 h-4 w-4 p-0" /> <PopoverTrigger asChild disabled={!isAllowed}>
) : ( <IconButton
<FontAwesomeIcon icon={faCheck} size="lg" className="text-primary" /> className={twMerge(
"w-0 overflow-hidden p-0 group-hover:mr-2 group-hover:w-5 data-[state=open]:w-6",
hasComment && "w-5 text-primary"
)}
variant="plain"
size="md"
ariaLabel="add-comment"
isDisabled={!isAllowed}
>
<Tooltip content="Comment">
<FontAwesomeIcon icon={faComment} />
</Tooltip>
</IconButton>
</PopoverTrigger>
)} )}
</IconButton> </ProjectPermissionCan>
</Tooltip> <PopoverContent
<Tooltip content="Cancel"> className="w-auto border border-mineshaft-600 bg-mineshaft-800 p-2 drop-shadow-2xl"
<IconButton sticky="always"
ariaLabel="more"
variant="plain"
size="md"
className={twMerge(
"p-0 opacity-0 group-hover:opacity-100",
isDirty && "opacity-100"
)}
onClick={() => reset()}
isDisabled={isSubmitting}
> >
<FontAwesomeIcon icon={faClose} size="lg" /> <FormControl label="Comment" className="mb-0">
</IconButton> <TextArea
</Tooltip> className="border border-mineshaft-600 text-sm"
</motion.div> rows={8}
)} cols={30}
</AnimatePresence> {...register("comment")}
/>
</FormControl>
</PopoverContent>
</Popover>
</div>
</div>
<AnimatePresence exitBeforeEnter>
{!isDirty ? (
<motion.div
key="options"
className="flex h-10 flex-shrink-0 items-center space-x-4 px-3"
initial={{ x: 0, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: 10, opacity: 0 }}
>
<Tooltip content="More">
<IconButton
ariaLabel="more"
variant="plain"
size="md"
className="p-0 opacity-0 group-hover:opacity-100"
onClick={() => onDetailViewSecret(secret)}
>
<FontAwesomeIcon icon={faEllipsis} size="lg" />
</IconButton>
</Tooltip>
<ProjectPermissionCan
I={ProjectPermissionActions.Delete}
a={subject(ProjectPermissionSub.Secrets, { environment, secretPath })}
renderTooltip
allowedLabel="Delete"
>
{(isAllowed) => (
<IconButton
ariaLabel="delete-value"
variant="plain"
colorSchema="danger"
size="md"
className="p-0 opacity-0 group-hover:opacity-100"
onClick={() => onDeleteSecret(secret)}
isDisabled={!isAllowed}
>
<FontAwesomeIcon icon={faClose} size="lg" />
</IconButton>
)}
</ProjectPermissionCan>
</motion.div>
) : (
<motion.div
key="options-save"
className="flex h-10 flex-shrink-0 items-center space-x-4 px-3"
initial={{ x: -10, opacity: 0 }}
animate={{ x: 0, opacity: 1 }}
exit={{ x: -10, opacity: 0 }}
>
<Tooltip content="Save">
<IconButton
ariaLabel="more"
variant="plain"
type="submit"
size="md"
className={twMerge(
"p-0 text-primary opacity-0 group-hover:opacity-100",
isDirty && "opacity-100"
)}
isDisabled={isSubmitting}
>
{isSubmitting ? (
<Spinner className="m-0 h-4 w-4 p-0" />
) : (
<FontAwesomeIcon icon={faCheck} size="lg" className="text-primary" />
)}
</IconButton>
</Tooltip>
<Tooltip content="Cancel">
<IconButton
ariaLabel="more"
variant="plain"
size="md"
className={twMerge(
"p-0 opacity-0 group-hover:opacity-100",
isDirty && "opacity-100"
)}
onClick={() => reset()}
isDisabled={isSubmitting}
>
<FontAwesomeIcon icon={faClose} size="lg" />
</IconButton>
</Tooltip>
</motion.div>
)}
</AnimatePresence>
</div>
</div> </div>
</div> </form>
</form>
</> </>
); );
} }