chore: fixed error with typings

This commit is contained in:
Ebezer Igbinoba
2023-08-23 16:36:48 +01:00
parent 9a1b453c86
commit ac66834daa
12 changed files with 297 additions and 437 deletions
@@ -0,0 +1,78 @@
import { faPlus } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Checkbox, PopoverContent } from "@app/components/v2";
import { WsTag } from "../../hooks/api/tags/types";
interface Props {
wsTags: WsTag[] | undefined;
secKey: string;
selectedTagIds: Record<string, boolean>;
handleSelectTag: (wsTag: WsTag) => void;
handleTagOnMouseEnter: (wsTag: WsTag) => void;
handleTagOnMouseLeave: () => void;
checkIfTagIsVisible: (wsTag: WsTag) => boolean;
handleOnCreateTagOpen: () => void
}
const AddTagPopoverContent = ({
wsTags,
secKey,
selectedTagIds,
handleSelectTag,
handleTagOnMouseEnter,
handleTagOnMouseLeave,
checkIfTagIsVisible,
handleOnCreateTagOpen
}: Props) => {
return (
<PopoverContent
side="left"
className="relative max-h-96 w-auto min-w-[200px] p-2 overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 text-bunker-200"
hideCloseBtn
>
<div className=" text-center text-sm font-medium text-bunker-200">
Add tags to {secKey || "this secret"}
</div>
<div className="absolute left-0 w-full border-mineshaft-600 border-t mt-2" />
<div className="flex flex-col space-y-1.5">
{wsTags?.map((wsTag: WsTag) => (
<div key={`tag-${wsTag._id}`} className="mt-4 h-[32px] relative flex items-center justify-start hover:border-mineshaft-600 hover:border hover:bg-mineshaft-700 p-2 rounded-md hover:text-bunker-200 bg-none"
onClick={() => handleSelectTag(wsTag)}
onMouseEnter={() => handleTagOnMouseEnter(wsTag)}
onMouseLeave={() => handleTagOnMouseLeave()}
tabIndex={0} role="button"
onKeyDown={() => { }}>
{
(checkIfTagIsVisible(wsTag) || selectedTagIds?.[wsTag.slug]) && <Checkbox
id="autoCapitalization"
isChecked={selectedTagIds?.[wsTag.slug]}
className="absolute top-[50%] translate-y-[-50%] left-[10px] "
checkIndicatorBg={`${!selectedTagIds?.[wsTag.slug] ? "text-transparent" : "text-mineshaft-800"}`}
/>
}
<div className="ml-7 flex items-center gap-3">
<div className="w-[10px] h-[10px] rounded-full" style={{ background: wsTag?.tagColor ? wsTag.tagColor : "#bec2c8" }}> </div>
<span >
{wsTag.slug}
</span>
</div>
</div>
))}
<div
className="h-[32px] relative flex items-center cursor-pointer justify-start border-mineshaft-600 border bg-mineshaft-700 p-2 rounded-md hover:text-bunker-200 bg-none"
onClick={() => handleOnCreateTagOpen()}
tabIndex={0} role="button"
onKeyDown={() => { }}>
<FontAwesomeIcon icon={faPlus} className="ml-1 mr-2" />
<span> Add new tag</span>
</div>
</div>
</PopoverContent>
)
}
export default AddTagPopoverContent
@@ -8,11 +8,12 @@ export type CheckboxProps = Omit<
CheckboxPrimitive.CheckboxProps, CheckboxPrimitive.CheckboxProps,
"checked" | "disabled" | "required" "checked" | "disabled" | "required"
> & { > & {
children: ReactNode; children?: ReactNode;
id: string; id: string;
isDisabled?: boolean; isDisabled?: boolean;
isChecked?: boolean; isChecked?: boolean;
isRequired?: boolean; isRequired?: boolean;
checkIndicatorBg?: string | undefined;
}; };
export const Checkbox = ({ export const Checkbox = ({
@@ -22,6 +23,7 @@ export const Checkbox = ({
isChecked, isChecked,
isDisabled, isDisabled,
isRequired, isRequired,
checkIndicatorBg,
...props ...props
}: CheckboxProps): JSX.Element => { }: CheckboxProps): JSX.Element => {
return ( return (
@@ -39,7 +41,7 @@ export const Checkbox = ({
{...props} {...props}
id={id} id={id}
> >
<CheckboxPrimitive.Indicator className="text-bunker-800"> <CheckboxPrimitive.Indicator className={`${checkIndicatorBg || "text-bunker-800"}`}>
<FontAwesomeIcon icon={faCheck} size="sm" /> <FontAwesomeIcon icon={faCheck} size="sm" />
</CheckboxPrimitive.Indicator> </CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root> </CheckboxPrimitive.Root>
+1 -13
View File
@@ -1,17 +1,10 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import { faClose } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { cva, VariantProps } from "cva"; import { cva, VariantProps } from "cva";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
type Props = { type Props = {
children: ReactNode; children: ReactNode;
className?: string; className?: string;
onClose?: () => void;
color?: string;
styles?: Record<string, string>
isDisabled?: boolean;
tagColor: string;
} & VariantProps<typeof tagVariants>; } & VariantProps<typeof tagVariants>;
const tagVariants = cva( const tagVariants = cva(
@@ -34,12 +27,7 @@ export const Tag = ({
children, children,
className, className,
colorSchema = "gray", colorSchema = "gray",
color, size = "sm" }: Props) => (
isDisabled,
size = "sm",
onClose,
styles = {}
}: Props) => (
<div <div
className={twMerge(tagVariants({ colorSchema, className, size }))} className={twMerge(tagVariants({ colorSchema, className, size }))}
> >
+18 -18
View File
@@ -55,65 +55,65 @@ export const leaveConfirmDefaultMessage = "Your changes will be lost if you leav
export const secretTagsColors = [ export const secretTagsColors = [
{ {
id: 1, id: 1,
hex: '#bec2c8', hex: "#bec2c8",
rgba: "rgb(128,128,128, 0.8)", rgba: "rgb(128,128,128, 0.8)",
name: 'Grey', name: "Grey",
selected: true selected: true
}, },
{ {
id: 2, id: 2,
hex: '#95a2b3', hex: "#95a2b3",
rgba: "rgb(0,0,255, 0.8)", rgba: "rgb(0,0,255, 0.8)",
name: 'blue', name: "blue",
selected: false selected: false
}, },
{ {
id: 3, id: 3,
hex: '#5e6ad2', hex: "#5e6ad2",
rgba: "rgb(128,0,128, 0.8)", rgba: "rgb(128,0,128, 0.8)",
name: 'Purple', name: "Purple",
selected: false selected: false
}, },
{ {
id: 4, id: 4,
hex: '#26b5ce', hex: "#26b5ce",
rgba: "rgb(0,128,128, 0.8)", rgba: "rgb(0,128,128, 0.8)",
name: 'Teal', name: "Teal",
selected: false selected: false
}, },
{ {
id: 5, id: 5,
hex: '#4cb782', hex: "#4cb782",
rgba: "rgb(0,128,0, 0.8)", rgba: "rgb(0,128,0, 0.8)",
name: 'Green', name: "Green",
selected: false selected: false
}, },
{ {
id: 6, id: 6,
hex: '#f2c94c', hex: "#f2c94c",
rgba: "rgb(255,255,0, 0.8)", rgba: "rgb(255,255,0, 0.8)",
name: 'Yellow', name: "Yellow",
selected: false selected: false
}, },
{ {
id: 7, id: 7,
hex: '#f2994a', hex: "#f2994a",
rgba: "rgb(128,128,0, 0.8)", rgba: "rgb(128,128,0, 0.8)",
name: 'Orange', name: "Orange",
selected: false selected: false
}, },
{ {
id: 8, id: 8,
hex: '#f7c8c1', hex: "#f7c8c1",
rgba: "rgb(128,0,0, 0.8)", rgba: "rgb(128,0,0, 0.8)",
name: 'Pink', name: "Pink",
selected: false selected: false
}, },
{ {
id: 9, id: 9,
hex: '#eb5757', hex: "#eb5757",
rgba: "rgb(255,0,0, 0.8)", rgba: "rgb(255,0,0, 0.8)",
name: 'Red', name: "Red",
selected: false selected: false
}, },
] ]
+7 -7
View File
@@ -7,9 +7,7 @@ import {
CreateTagRes, CreateTagRes,
DeleteTagDTO, DeleteTagDTO,
DeleteWsTagRes, DeleteWsTagRes,
QueryTag,
UserWsTags, UserWsTags,
WsTag
} from "./types"; } from "./types";
const workspaceTags = { const workspaceTags = {
@@ -32,33 +30,35 @@ export const useGetWsTags = (workspaceID: string) => {
}); });
} }
export const useCreateWsTag = () => { export const useCreateWsTag = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation<CreateTagRes, {}, CreateTagDTO>({ return useMutation<CreateTagRes, {}, CreateTagDTO>({
mutationFn: async ({ workspaceID, tagName, tagColor, tagSlug }: QueryTag) => { mutationFn: async ({ workspaceID, tagName, tagColor, tagSlug }) => {
const { data } = await apiRequest.post(`/api/v2/workspace/${workspaceID}/tags`, { const { data } = await apiRequest.post(`/api/v2/workspace/${workspaceID}/tags`, {
name: tagName, name: tagName,
tagColor: tagColor, tagColor,
slug: tagSlug slug: tagSlug
}) })
return data; return data;
}, },
onSuccess: (tagData: WsTag) => { onSuccess: (tagData) => {
queryClient.invalidateQueries(workspaceTags.getWsTags(tagData?.workspace)); queryClient.invalidateQueries(workspaceTags.getWsTags(tagData?.workspace));
} }
}); });
}; };
export const useDeleteWsTag = () => { export const useDeleteWsTag = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation<DeleteWsTagRes, {}, DeleteTagDTO>({ return useMutation<DeleteWsTagRes, {}, DeleteTagDTO>({
mutationFn: async ({ tagID }: {tagID: string}) => { mutationFn: async ({ tagID }) => {
const { data } = await apiRequest.delete(`/api/v2/workspace/tags/${tagID}`); const { data } = await apiRequest.delete(`/api/v2/workspace/tags/${tagID}`);
return data return data
}, },
onSuccess: (tagData: WsTag) => { onSuccess: (tagData) => {
queryClient.invalidateQueries(workspaceTags.getWsTags(tagData?.workspace)); queryClient.invalidateQueries(workspaceTags.getWsTags(tagData?.workspace));
} }
}); });
+3 -7
View File
@@ -4,6 +4,7 @@ export type WsTag = {
_id: string; _id: string;
name: string; name: string;
slug: string; slug: string;
tagColor?: string;
workspace: string; workspace: string;
createdAt: string; createdAt: string;
updatedAt: string; updatedAt: string;
@@ -16,6 +17,7 @@ export type CreateTagDTO = {
workspaceID: string; workspaceID: string;
tagSlug: string; tagSlug: string;
tagName: string; tagName: string;
tagColor: string;
}; };
export type CreateTagRes = { export type CreateTagRes = {
@@ -23,6 +25,7 @@ export type CreateTagRes = {
slug: string; slug: string;
workspace: string; workspace: string;
createdAt: string; createdAt: string;
tagColor?: string;
user: string; user: string;
_id: string; _id: string;
}; };
@@ -52,10 +55,3 @@ export type TagColor = {
name: string name: string
selected: boolean selected: boolean
} }
export type QueryTag = {
workspaceID: string;
tagName: string;
tagColor: string;
tagSlug: string
}
@@ -297,6 +297,8 @@ export const DashboardPage = () => {
resolver: yupResolver(schema) resolver: yupResolver(schema)
}); });
console.log("300 => secrets", secrets)
const { const {
register, register,
control, control,
@@ -58,7 +58,8 @@ const secretSchema = yup.object({
yup.object({ yup.object({
_id: yup.string().required(), _id: yup.string().required(),
name: yup.string().required(), name: yup.string().required(),
slug: yup.string().required() slug: yup.string().required(),
tagColor: yup.string().nullable(),
}) })
), ),
overrideAction: yup.string().notRequired().oneOf(Object.values(SecretActionType)), overrideAction: yup.string().notRequired().oneOf(Object.values(SecretActionType)),
@@ -1,17 +1,17 @@
import { useState, useEffect } from 'react'; import { useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form"; import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { secretTagsColors } from "~/const"
import { import {
faCheck faCheck
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { Button, FormControl, Input, ModalClose, Tooltip } from "@app/components/v2"; import { Button, FormControl, Input, ModalClose, Tooltip } from "@app/components/v2";
import { isValidHexColor } from "~/components/utilities/isValidHexColor";
import { TagColor } from '~/hooks/api/tags/types'; import { isValidHexColor } from "../../../../components/utilities/isValidHexColor";
import { secretTagsColors } from "../../../../const"
import { TagColor } from "../../../../hooks/api/tags/types";
type Props = { type Props = {
@@ -33,8 +33,8 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
resolver: yupResolver(createTagSchema) resolver: yupResolver(createTagSchema)
}); });
const [tagsColors, setTagsColors] = useState<TagColor>(secretTagsColors) const [tagsColors] = useState<TagColor[]>(secretTagsColors)
const [selectedTagColor, setSelectedTagColor] = useState<TagColor>({}) const [selectedTagColor, setSelectedTagColor] = useState<TagColor>(tagsColors[0])
const [showHexInput, setShowHexInput] = useState<boolean>(false) const [showHexInput, setShowHexInput] = useState<boolean>(false)
const [tagColor, setTagColor] = useState<string>("") const [tagColor, setTagColor] = useState<string>("")
@@ -46,12 +46,11 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
useEffect(() => { useEffect(() => {
const clonedTagColors = [...tagsColors] const clonedTagColors = [...tagsColors]
for (const tagColor of clonedTagColors) { const selectedTagBgColor = clonedTagColors.find($tagColor => $tagColor.selected);
if (tagColor.selected) {
setSelectedTagColor(tagColor) if (selectedTagBgColor) {
setTagColor(tagColor.hex) setSelectedTagColor(selectedTagBgColor);
break setTagColor(selectedTagBgColor.hex);
}
} }
}, []) }, [])
@@ -60,34 +59,37 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
const tagsHexWrapper = document.querySelector(".tags-hex-wrapper") const tagsHexWrapper = document.querySelector(".tags-hex-wrapper")
if (showHexInput) { if (showHexInput) {
tagsList?.classList.add('hide-tags') tagsList?.classList.add("hide-tags")
tagsList?.classList.remove('show-tags') tagsList?.classList.remove("show-tags")
tagsHexWrapper?.classList.add('show-hex-input') tagsHexWrapper?.classList.add("show-hex-input")
tagsHexWrapper?.classList.remove('hide-hex-input') tagsHexWrapper?.classList.remove("hide-hex-input")
} else { } else {
tagsList?.classList.remove('hide-tags') tagsList?.classList.remove("hide-tags")
tagsList?.classList.add('show-tags') tagsList?.classList.add("show-tags")
tagsHexWrapper?.classList.remove('show-hex-input') tagsHexWrapper?.classList.remove("show-hex-input")
tagsHexWrapper?.classList.add('hide-hex-input') tagsHexWrapper?.classList.add("hide-hex-input")
} }
}, [showHexInput]) }, [showHexInput])
const handleColorChange = (tagColor: TagColor) => {
const clonedTagColors = [...tagsColors] const handleColorChange = (clickedTagColor: TagColor) => {
const tagColorIndex = clonedTagColors.findIndex(_tagColor => _tagColor.id === tagColor.id) const updatedTagColors = [...tagsColors];
const _selectedTagColor = clonedTagColors[tagColorIndex] const clickedTagColorIndex = updatedTagColors.findIndex(($tagColor) => $tagColor.id === clickedTagColor.id);
clonedTagColors.forEach(tagColor => { const updatedClickedTagColor = updatedTagColors[clickedTagColorIndex];
tagColor.selected = false
}) updatedTagColors.forEach((tgColor) => {
if (selectedTagColor.id !== tagColor.id) { // eslint-disable-next-line no-param-reassign
_selectedTagColor.selected = !_selectedTagColor.selected tgColor.selected = false;
setSelectedTagColor(_selectedTagColor) });
setTagColor(_selectedTagColor.hex)
} if (selectedTagColor.id !== clickedTagColor.id) {
updatedClickedTagColor.selected = !updatedClickedTagColor.selected;
setSelectedTagColor(updatedClickedTagColor);
setTagColor(updatedClickedTagColor.hex);
} }
};
return ( return (
<>
<form onSubmit={handleSubmit(onFormSubmit)}> <form onSubmit={handleSubmit(onFormSubmit)}>
<Controller <Controller
control={control} control={control}
@@ -101,46 +103,51 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
/> />
<div className="mt-2"> <div className="mt-2">
<label className="text-mineshaft-400">Tag color</label> <h6 className="text-mineshaft-400">Tag color</h6>
<div className="flex gap-2 h-[50px]"> <div className="flex gap-2 h-[50px]">
<div className="w-[12%] h-[2.813rem] inline-flex font-inter items-center justify-center border relative rounded-md border-mineshaft-500 bg-mineshaft-900 hover:bg-mineshaft-800"> <div className="w-[12%] h-[2.813rem] inline-flex font-inter items-center justify-center border relative rounded-md border-mineshaft-500 bg-mineshaft-900 hover:bg-mineshaft-800">
<div className={`w-[26px] h-[26px] rounded-full`} style={{ background: `${tagColor}` }}></div> <div className="w-[26px] h-[26px] rounded-full" style={{ background: `${tagColor}` }} />
</div> </div>
<div className="w-[88%] h-[2.813rem] flex-wrap inline-flex gap-3 items-center border relative rounded-md border-mineshaft-500 bg-mineshaft-900 hover:bg-mineshaft-800 relative"> <div className="w-[88%] h-[2.813rem] flex-wrap inline-flex gap-3 items-center border rounded-md border-mineshaft-500 bg-mineshaft-900 hover:bg-mineshaft-800 relative">
{
(
<div className="flex-wrap inline-flex gap-3 items-center secret-tags-wrapper pl-3"> <div className="flex-wrap inline-flex gap-3 items-center secret-tags-wrapper pl-3">
{ {
tagsColors.map((tagColor: TagColor) => { tagsColors.map(($tagColor: TagColor) => {
return ( return (
<Tooltip content={`${tagColor.name}`}> <div key={`tag-color-${$tagColor.id}`}>
<div className={`flex items-center justify-center w-[26px] h-[26px] hover:ring-offset-2 hover:ring-2 bg-[#bec2c8] border-2 p-2 hover:shadow-lg border-transparent hover:border-black rounded-full`} key={`tag-${tagColor.id}`} style={{ backgroundColor: `${tagColor.hex}` }} onClick={() => handleColorChange(tagColor)}> <Tooltip content={`${$tagColor.name}`}>
<div className=" flex items-center justify-center w-[26px] h-[26px] hover:ring-offset-2 hover:ring-2 bg-[#bec2c8] border-2 p-2 hover:shadow-lg border-transparent hover:border-black rounded-full"
key={`tag-${$tagColor.id}`}
style={{ backgroundColor: `${$tagColor.hex}` }}
onClick={() => handleColorChange($tagColor)}
tabIndex={0} role="button"
onKeyDown={() => { }}
>
{ {
tagColor.selected && <FontAwesomeIcon icon={faCheck} style={{ color: `#00000070` }} /> $tagColor.selected && <FontAwesomeIcon icon={faCheck} style={{ color: "#00000070" }} />
} }
</div> </div>
</Tooltip> </Tooltip>
</div>
) )
}) })
} }
</div> </div>
)
}
<div className="flex items-center gap-2 px-2 tags-hex-wrapper" > <div className="flex items-center gap-2 px-2 tags-hex-wrapper" >
<div className="w-1/6 flex items-center relative rounded-md hover:bg-mineshaft-800"> <div className="w-1/6 flex items-center relative rounded-md hover:bg-mineshaft-800">
{ {
isValidHexColor(tagColor) && ( isValidHexColor(tagColor) && (
<div className={`w-[26px] h-[26px] rounded-full flex items-center justify-center`} style={{ background: `${tagColor}` }}> <div className="w-[26px] h-[26px] rounded-full flex items-center justify-center" style={{ background: `${tagColor}` }}>
<FontAwesomeIcon icon={faCheck} style={{ color: `#00000070` }} /> <FontAwesomeIcon icon={faCheck} style={{ color: "#00000070" }} />
</div> </div>
) )
} }
{ {
!isValidHexColor(tagColor) && ( !isValidHexColor(tagColor) && (
<div class="border-dashed border bg-blue rounded-full w-[26px] h-[26px] border-mineshaft-500"></div> <div className="border-dashed border bg-blue rounded-full w-[26px] h-[26px] border-mineshaft-500" />
) )
} }
</div> </div>
@@ -156,8 +163,10 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
</div> </div>
<div className="w-[26px] h-[26px] flex items-center justify-center absolute top-[10px] right-[-4px] translate-x-[-50%]"> <div className="w-[26px] h-[26px] flex items-center justify-center absolute top-[10px] right-[-4px] translate-x-[-50%]">
<div className="border-mineshaft-500 border h-[2.1rem] mr-4 absolute right-5"></div> <div className="border-mineshaft-500 border h-[2.1rem] mr-4 absolute right-5" />
<div className={`flex items-center justify-center w-[26px] h-[26px] bg-transparent cursor-pointer hover:ring-offset-1 hover:ring-2 border-mineshaft-500 border bg-mineshaft-900 rounded-[3px] p-2 ${showHexInput ? 'tags-conic-bg rounded-full' : ''}`} onClick={() => setShowHexInput((prev) => !prev)} style={{ border: '1px solid rgba(220, 216, 254, 0.376)' }}> <div className={`flex items-center justify-center w-[26px] h-[26px] bg-transparent cursor-pointer hover:ring-offset-1 hover:ring-2 border-mineshaft-500 border bg-mineshaft-900 rounded-[3px] p-2 ${showHexInput ? "tags-conic-bg rounded-full" : ""}`} onClick={() => setShowHexInput((prev) => !prev)} style={{ border: "1px solid rgba(220, 216, 254, 0.376)" }}
tabIndex={0} role="button"
onKeyDown={() => { }}>
{ {
!showHexInput && <span>#</span> !showHexInput && <span>#</span>
} }
@@ -178,6 +187,5 @@ export const CreateTagModal = ({ onCreateTag }: Props): JSX.Element => {
</ModalClose> </ModalClose>
</div> </div>
</form> </form>
</>
); );
}; };
@@ -1,138 +0,0 @@
import { Controller, useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as yup from "yup";
import { Button, FormControl, Input, ModalClose, Tooltip, IconButton, Tag } from "@app/components/v2";
import { useToggle } from "@app/hooks";
import { TagDesign } from "~/hooks/api/tags/types";
import {
faEye,
faEyeSlash
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useState } from 'react';
import { WsTag } from '../../../../hooks/api/tags/types';
type TagData = {
tagBackground: string;
tagLabel: string
}
type Props = {
onDesignTag: (tagData: TagData) => void;
selectedTag: WsTag
};
const designTagSchema = yup.object({
tagBackground: yup.string().required().trim().label("Tag Background"),
tagLabel: yup.string().required().trim().label("Tag Label"),
});
type FormData = yup.InferType<typeof designTagSchema>;
export const DesignTagModal = ({ onDesignTag, selectedTag }: Props): JSX.Element => {
const [tagDesignObj, setTagDesignObj] = useState({
tagColor: {
bg: "",
text: ""
}
})
const {
control,
reset,
formState,
handleSubmit,
setValue
} = useForm<FormData>({
resolver: yupResolver(designTagSchema)
});
const onFormSubmit = ({ tagBackground, tagLabel }: FormData) => {
onDesignTag({ tagBackground, tagLabel });
reset();
};
const [previewTag, setPreviewTag] = useToggle(false);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, type: string) => {
setTagDesignObj((prev: { tagColor: { bg: string, text: string }; }) => ({
tagColor: {
...prev.tagColor,
[type]: e.target.value
}
}))
if (type === 'bg') {
setValue('tagBackground', e.target.value)
} else {
setValue('tagLabel', e.target.value)
}
}
return (
<form onSubmit={handleSubmit(onFormSubmit)}>
<div className="relative">
<Controller
control={control}
name="tagBackground"
defaultValue=""
render={({ field, fieldState: { error } }) => {
return (
<>
<FormControl label="Tag Background" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} type="color" onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleInputChange(e, 'bg')} />
</FormControl>
</>
)
}}
/>
{/* <Tooltip content={previewTag ? "Hide Preview" : "Show Preview"}> */}
<div >
<FontAwesomeIcon icon={previewTag ? faEye : faEyeSlash} onClick={() => setPreviewTag.toggle()} className="absolute top-[2px] left-[127px] cursor-pointer" />
{previewTag && (
<Tag
styles={{
backgroundColor: tagDesignObj.tagColor.bg,
color: tagDesignObj.tagColor.text
}}
isDisabled={true}
onClose={() => void (0)}
key={selectedTag._id}
className="absolute top-[-5px] right-[-5px] cursor-pointer"
>
{selectedTag.slug}
</Tag>
)}
</div>
{/* </Tooltip> */}
</div>
<Controller
control={control}
name="tagLabel"
defaultValue="#000000"
render={({ field, fieldState: { error } }) => {
return (
<>
<FormControl label="Tag Label" isError={Boolean(error)} errorText={error?.message}>
<Input {...field} type="color" onChange={(e: React.ChangeEvent<HTMLInputElement>) => handleInputChange(e, 'text')} value={tagDesignObj.tagColor.text} />
</FormControl>
</>
)
}}
/>
<div className="mt-8 flex items-center">
<Button className="mr-4" type="submit" isDisabled={formState.isSubmitting} isLoading={formState.isSubmitting}>
Save
</Button>
<ModalClose asChild>
<Button variant="plain" colorSchema="secondary">
Cancel
</Button>
</ModalClose>
</div>
</form>
);
};
@@ -1 +0,0 @@
export {DesignTagModal} from "./DesignTagModal"
@@ -1,5 +1,5 @@
/* eslint-disable react/jsx-no-useless-fragment */ /* eslint-disable react/jsx-no-useless-fragment */
import { memo, useEffect, useRef, useState } from "react"; import { memo, useEffect,useRef, useState } from "react";
import { import {
Control, Control,
Controller, Controller,
@@ -15,7 +15,6 @@ import {
faCopy, faCopy,
faEllipsis, faEllipsis,
faInfoCircle, faInfoCircle,
faPlus,
faTags, faTags,
faXmark faXmark
} from "@fortawesome/free-solid-svg-icons"; } from "@fortawesome/free-solid-svg-icons";
@@ -24,41 +23,21 @@ import { cx } from "cva";
import { twMerge } from "tailwind-merge"; import { twMerge } from "tailwind-merge";
import { import {
Button,
Checkbox,
FormControl,
HoverCard, HoverCard,
HoverCardContent, HoverCardContent,
HoverCardTrigger, HoverCardTrigger,
IconButton, IconButton,
Input, Input,
Popover, Popover,
PopoverContent,
PopoverTrigger, PopoverTrigger,
SecretInput, SecretInput,
Tag, Tag,
TextArea, Tooltip} from "@app/components/v2";
Tooltip, import { useToggle } from "@app/hooks";
Modal,
ModalContent,
} from "@app/components/v2";
import { WsTag } from "@app/hooks/api/types"; import { WsTag } from "@app/hooks/api/types";
import AddTagPopoverContent from "../../../../components/AddTagPopoverContent/AddTagPopoverContent";
import { FormData, SecretActionType } from "../../DashboardPage.utils"; import { FormData, SecretActionType } from "../../DashboardPage.utils";
import { SecretTags } from "~/hooks/api/tags/types";
import { useToggle } from "@app/hooks";
const tagColors = [
{ bg: "bg-[#f1c40f]/40", text: "text-[#fcf0c3]/70" },
{ bg: "bg-[#cb1c8d]/40", text: "text-[#f2c6e3]/70" },
{ bg: "bg-[#badc58]/40", text: "text-[#eef6d5]/70" },
{ bg: "bg-[#ff5400]/40", text: "text-[#ffddcc]/70" },
{ bg: "bg-[#3AB0FF]/40", text: "text-[#f0fffd]/70" },
{ bg: "bg-[#6F1AB6]/40", text: "text-[#FFE5F1]/70" },
{ bg: "bg-[#C40B13]/40", text: "text-[#FFDEDE]/70" },
{ bg: "bg-[#332FD0]/40", text: "text-[#DFF6FF]/70" }
];
type Props = { type Props = {
index: number; index: number;
@@ -77,7 +56,6 @@ type Props = {
// tag props // tag props
wsTags?: WsTag[]; wsTags?: WsTag[];
onCreateTagOpen: () => void; onCreateTagOpen: () => void;
onDesignTagOpen: (selectedTag: WsTag, selectedFieldIndex: number) => void;
// rhf specific functions, dont put this using useFormContext. This is passed as props to avoid re-rendering // rhf specific functions, dont put this using useFormContext. This is passed as props to avoid re-rendering
control: Control<FormData>; control: Control<FormData>;
register: UseFormRegister<FormData>; register: UseFormRegister<FormData>;
@@ -97,11 +75,10 @@ export const SecretInputRow = memo(
isAddOnly, isAddOnly,
wsTags, wsTags,
onCreateTagOpen, onCreateTagOpen,
onDesignTagOpen,
onSecretDelete, onSecretDelete,
searchTerm, searchTerm,
control, control,
register, // register,
setValue, setValue,
isKeyError, isKeyError,
keyError, keyError,
@@ -116,8 +93,6 @@ export const SecretInputRow = memo(
append append
} = useFieldArray({ control, name: `secrets.${index}.tags` }); } = useFieldArray({ control, name: `secrets.${index}.tags` });
const tagColorByTagId = new Map((wsTags || []).map((wsTag, i) => [wsTag._id, tagColors[i % tagColors.length]]))
// display the tags in alphabetical order // display the tags in alphabetical order
secretTags.sort((a, b) => a?.name?.localeCompare(b?.name)) secretTags.sort((a, b) => a?.name?.localeCompare(b?.name))
@@ -152,7 +127,19 @@ export const SecretInputRow = memo(
const isOverridden = const isOverridden =
overrideAction === SecretActionType.Created || overrideAction === SecretActionType.Modified; overrideAction === SecretActionType.Created || overrideAction === SecretActionType.Modified;
const [editorRef, setEditorRef] = useState(isOverridden ? secValueOverride : secValue); const [editorRef, setEditorRef] = useState(isOverridden ? secValueOverride : secValue);
const [hoveredTag, setHoveredTag] = useState<WsTag | null>(null);
const handleTagOnMouseEnter = (wsTag: WsTag) => {
setHoveredTag(wsTag);
}
const handleTagOnMouseLeave = () => {
setHoveredTag(null);
}
const checkIfTagIsVisible = (wsTag: WsTag) => wsTag._id === hoveredTag?._id;
const secId = useWatch({ control, name: `secrets.${index}._id`, exact: true }); const secId = useWatch({ control, name: `secrets.${index}._id`, exact: true });
const tags = useWatch({ control, name: `secrets.${index}.tags`, exact: true, defaultValue: [] }) || []; const tags = useWatch({ control, name: `secrets.${index}.tags`, exact: true, defaultValue: [] }) || [];
@@ -164,6 +151,7 @@ export const SecretInputRow = memo(
const [isInviteLinkCopied, setInviteLinkCopied] = useToggle(false); const [isInviteLinkCopied, setInviteLinkCopied] = useToggle(false);
useEffect(() => { useEffect(() => {
let timer: NodeJS.Timeout; let timer: NodeJS.Timeout;
if (isInviteLinkCopied) { if (isInviteLinkCopied) {
@@ -172,6 +160,7 @@ export const SecretInputRow = memo(
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [isInviteLinkCopied]); }, [isInviteLinkCopied]);
useEffect(() => { useEffect(() => {
setEditorRef(isOverridden ? secValueOverride : secValue); setEditorRef(isOverridden ? secValueOverride : secValue);
}, [isOverridden]); }, [isOverridden]);
@@ -202,7 +191,8 @@ export const SecretInputRow = memo(
const onSelectTag = (selectedTag: WsTag) => { const onSelectTag = (selectedTag: WsTag) => {
const shouldAppend = !selectedTagIds[selectedTag.slug]; const shouldAppend = !selectedTagIds[selectedTag.slug];
if (shouldAppend) { if (shouldAppend) {
append(selectedTag); const {_id: id, name, slug, tagColor} = selectedTag
append({_id: id, name, slug, tagColor});
} else { } else {
const pos = tags.findIndex(({ slug }: { slug: string }) => selectedTag.slug === slug); const pos = tags.findIndex(({ slug }: { slug: string }) => selectedTag.slug === slug);
remove(pos); remove(pos);
@@ -229,8 +219,6 @@ export const SecretInputRow = memo(
return <></>; return <></>;
} }
return ( return (
<tr className="group flex flex-row hover:bg-mineshaft-700" key={index}> <tr className="group flex flex-row hover:bg-mineshaft-700" key={index}>
<td className="flex h-10 w-10 items-center justify-center border-none px-4"> <td className="flex h-10 w-10 items-center justify-center border-none px-4">
@@ -335,67 +323,37 @@ export const SecretInputRow = memo(
</td> </td>
<td className="min-w-sm flex"> <td className="min-w-sm flex">
<div className="flex h-8 items-center pl-2"> <div className="flex h-8 items-center pl-2">
{secretTags.map(({ id, _id, slug, tagColor }: SecretTags, i: number) => { {secretTags.map(({ id, slug, tagColor}) => {
return ( return (
<>
<Popover> <Popover>
<PopoverTrigger asChild> <PopoverTrigger asChild>
<div> <div>
<Tag <Tag
isDisabled={isReadOnly || isAddOnly || isRollbackMode} // isDisabled={isReadOnly || isAddOnly || isRollbackMode}
onClose={() => remove(i)} // onClose={() => remove(i)}
key={id} key={id}
className="cursor-pointer" className="cursor-pointer"
> >
<div className="rounded-md rounded-full border-mineshaft-500 bg-transparent flex items-center gap-1.5 justify-around"> <div className="rounded-full border-mineshaft-500 bg-transparent flex items-center gap-1.5 justify-around">
<div className="w-[10px] h-[10px] rounded-full" style={{ background: tagColor ? tagColor : "#bec2c8" }}></div> <div className="w-[10px] h-[10px] rounded-full" style={{ background: tagColor || "#bec2c8" }} />
{slug} {slug}
</div> </div>
</Tag> </Tag>
</div> </div>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <AddTagPopoverContent
side="left" wsTags={wsTags}
className="max-h-96 w-auto min-w-[200px] p-2 overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 text-bunker-200" secKey={secKey || "this secret"}
hideCloseBtn selectedTagIds={selectedTagIds}
> handleSelectTag={(wsTag: WsTag) => onSelectTag(wsTag)}
<div className=" text-center text-sm font-medium text-bunker-200"> handleTagOnMouseEnter={(wsTag: WsTag) => handleTagOnMouseEnter(wsTag)}
Add tags to {secKey || "this secret"} handleTagOnMouseLeave={() => handleTagOnMouseLeave()}
</div> checkIfTagIsVisible={(wsTag: WsTag) => checkIfTagIsVisible(wsTag)}
<div className="flex flex-col space-y-2.5"> handleOnCreateTagOpen={() => onCreateTagOpen()}
{wsTags?.map((wsTag) => ( />
<Button
variant="star"
size="md"
className={`mt-4 justify-start px-1 hover:bg-mineshaft-600 hover:border-mineshaft-500 hover:text-bunker-200 ${selectedTagIds?.[wsTag.slug] && "text-primary hover:text-primary"}`}
onClick={() => onSelectTag(wsTag)}
leftIcon={
<Checkbox
className="mr-0 data-[state=checked]:bg-primary border-mineshaft-500 border"
id="autoCapitalization"
isChecked={selectedTagIds?.[wsTag.slug]}
>
{ }
</Checkbox>
}
key={wsTag._id}
>
{wsTag.slug}
</Button>
))}
<Button
variant="star"
size="md"
className="mt-4 justify-start px-1 hover:bg-mineshaft-600 hover:border-mineshaft-500 hover:text-bunker-200"
onClick={onCreateTagOpen}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
>
Add new tag
</Button>
</div>
</PopoverContent>
</Popover> </Popover>
</>
) )
})} })}
<div className="w-0 overflow-hidden group-hover:w-6"> <div className="w-0 overflow-hidden group-hover:w-6">
@@ -428,46 +386,16 @@ export const SecretInputRow = memo(
</Tooltip> </Tooltip>
</div> </div>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <AddTagPopoverContent
side="left" wsTags={wsTags}
className="max-h-96 w-auto min-w-[200px] p-2 overflow-y-auto overflow-x-hidden border border-mineshaft-600 bg-mineshaft-800 text-bunker-200" secKey={secKey || "this secret"}
hideCloseBtn selectedTagIds={selectedTagIds}
> handleSelectTag={(wsTag: WsTag) => onSelectTag(wsTag)}
<div className=" text-center text-sm font-medium text-bunker-200"> handleTagOnMouseEnter={(wsTag: WsTag) => handleTagOnMouseEnter(wsTag)}
Add tags to {secKey || "this secret"} handleTagOnMouseLeave={() => handleTagOnMouseLeave()}
</div> checkIfTagIsVisible={(wsTag: WsTag) => checkIfTagIsVisible(wsTag)}
<div className="flex flex-col space-y-2.5"> handleOnCreateTagOpen={() => onCreateTagOpen()}
{wsTags?.map((wsTag) => ( />
<Button
variant="star"
size="md"
className={`mt-4 justify-start px-1 hover:bg-mineshaft-600 hover:border-mineshaft-500 hover:text-bunker-200 ${selectedTagIds?.[wsTag.slug] && "text-primary hover:text-primary"}`}
onClick={() => onSelectTag(wsTag)}
leftIcon={
<Checkbox
className="mr-0 data-[state=checked]:bg-primary border-mineshaft-500"
id="autoCapitalization"
isChecked={selectedTagIds?.[wsTag.slug]}
>
{ }
</Checkbox>
}
key={wsTag._id}
>
{wsTag.slug}
</Button>
))}
<Button
variant="star"
size="md"
className="mt-4 justify-start px-1 hover:bg-mineshaft-600 hover:border-mineshaft-500 hover:text-bunker-200"
onClick={onCreateTagOpen}
leftIcon={<FontAwesomeIcon icon={faPlus} />}
>
Add new tag
</Button>
</div>
</PopoverContent>
</Popover> </Popover>
</div> </div>
)} )}
@@ -511,20 +439,16 @@ export const SecretInputRow = memo(
<FontAwesomeIcon icon={faComment} /> <FontAwesomeIcon icon={faComment} />
</IconButton> </IconButton>
</PopoverTrigger> </PopoverTrigger>
<PopoverContent <AddTagPopoverContent
className="w-auto border border-mineshaft-600 bg-mineshaft-800 p-2 drop-shadow-2xl" wsTags={wsTags}
sticky="always" secKey={secKey || "this secret"}
> selectedTagIds={selectedTagIds}
<FormControl label="Comment" className="mb-0"> handleSelectTag={(wsTag: WsTag) => onSelectTag(wsTag)}
<TextArea handleTagOnMouseEnter={(wsTag: WsTag) => handleTagOnMouseEnter(wsTag)}
isDisabled={isReadOnly || isRollbackMode || shouldBeBlockedInAddOnly} handleTagOnMouseLeave={() => handleTagOnMouseLeave()}
className="border border-mineshaft-600 text-sm" checkIfTagIsVisible={(wsTag: WsTag) => checkIfTagIsVisible(wsTag)}
{...register(`secrets.${index}.comment`)} handleOnCreateTagOpen={() => onCreateTagOpen()}
rows={8}
cols={30}
/> />
</FormControl>
</PopoverContent>
</Popover> </Popover>
</div> </div>
</Tooltip> </Tooltip>