chore: issue sidebar and peek overview improvement (#3488)

* chore: issue peek overview and sidebar properties focused state improvement

* fix: added name of the issue in issue relation

* chore: issue sidebar and peek overview properties improvement

* chore: issue assignee improvement for sidebar and peek overview

---------

Co-authored-by: NarayanBavisetti <narayan3119@gmail.com>
This commit is contained in:
Anmol Singh Bhatia 2024-01-29 20:36:14 +05:30 committed by GitHub
parent 09a1a55da8
commit 483fc57601
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 203 additions and 76 deletions

View File

@ -304,6 +304,7 @@ class IssueRelationSerializer(BaseSerializer):
sequence_id = serializers.IntegerField( sequence_id = serializers.IntegerField(
source="related_issue.sequence_id", read_only=True source="related_issue.sequence_id", read_only=True
) )
name = serializers.CharField(source="related_issue.name", read_only=True)
relation_type = serializers.CharField(read_only=True) relation_type = serializers.CharField(read_only=True)
class Meta: class Meta:
@ -313,6 +314,7 @@ class IssueRelationSerializer(BaseSerializer):
"project_id", "project_id",
"sequence_id", "sequence_id",
"relation_type", "relation_type",
"name",
] ]
read_only_fields = [ read_only_fields = [
"workspace", "workspace",
@ -328,6 +330,7 @@ class RelatedIssueSerializer(BaseSerializer):
sequence_id = serializers.IntegerField( sequence_id = serializers.IntegerField(
source="issue.sequence_id", read_only=True source="issue.sequence_id", read_only=True
) )
name = serializers.CharField(source="issue.name", read_only=True)
relation_type = serializers.CharField(read_only=True) relation_type = serializers.CharField(read_only=True)
class Meta: class Meta:
@ -337,6 +340,7 @@ class RelatedIssueSerializer(BaseSerializer):
"project_id", "project_id",
"sequence_id", "sequence_id",
"relation_type", "relation_type",
"name",
] ]
read_only_fields = [ read_only_fields = [
"workspace", "workspace",

View File

@ -30,6 +30,7 @@ type ButtonProps = {
hideIcon: boolean; hideIcon: boolean;
hideText?: boolean; hideText?: boolean;
dropdownArrow: boolean; dropdownArrow: boolean;
isActive?: boolean;
dropdownArrowClassName: string; dropdownArrowClassName: string;
placeholder: string; placeholder: string;
tooltip: boolean; tooltip: boolean;
@ -51,6 +52,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
tooltip, tooltip,
} = props; } = props;
@ -60,6 +62,7 @@ const BorderButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -111,6 +114,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
tooltip, tooltip,
} = props; } = props;
@ -120,6 +124,7 @@ const TransparentButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -268,6 +273,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -279,6 +285,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "background-with-text" ? ( ) : buttonVariant === "background-with-text" ? (
@ -310,6 +317,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -321,6 +329,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : null} ) : null}

View File

@ -2,7 +2,7 @@ import React, { useRef, useState } from "react";
import { Combobox } from "@headlessui/react"; import { Combobox } from "@headlessui/react";
import DatePicker from "react-datepicker"; import DatePicker from "react-datepicker";
import { usePopper } from "react-popper"; import { usePopper } from "react-popper";
import { CalendarDays, X } from "lucide-react"; import { Calendar, CalendarDays, X } from "lucide-react";
// hooks // hooks
import { useDropdownKeyDown } from "hooks/use-dropdown-key-down"; import { useDropdownKeyDown } from "hooks/use-dropdown-key-down";
import useOutsideClickDetector from "hooks/use-outside-click-detector"; import useOutsideClickDetector from "hooks/use-outside-click-detector";
@ -23,6 +23,7 @@ type Props = TDropdownProps & {
onChange: (val: Date | null) => void; onChange: (val: Date | null) => void;
value: Date | string | null; value: Date | string | null;
closeOnSelect?: boolean; closeOnSelect?: boolean;
showPlaceholderIcon?: boolean;
}; };
type ButtonProps = { type ButtonProps = {
@ -33,9 +34,11 @@ type ButtonProps = {
isClearable: boolean; isClearable: boolean;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
onClear: () => void; onClear: () => void;
placeholder: string; placeholder: string;
tooltip: boolean; tooltip: boolean;
showPlaceholderIcon?: boolean;
}; };
const BorderButton = (props: ButtonProps) => { const BorderButton = (props: ButtonProps) => {
@ -47,6 +50,7 @@ const BorderButton = (props: ButtonProps) => {
isClearable, isClearable,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
onClear, onClear,
placeholder, placeholder,
tooltip, tooltip,
@ -61,6 +65,7 @@ const BorderButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -131,9 +136,11 @@ const TransparentButton = (props: ButtonProps) => {
isClearable, isClearable,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
onClear, onClear,
placeholder, placeholder,
tooltip, tooltip,
showPlaceholderIcon = false,
} = props; } = props;
return ( return (
@ -145,11 +152,16 @@ const TransparentButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
{!hideIcon && icon} {!hideIcon && icon}
{!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>} {!hideText && <span className="flex-grow truncate">{date ? renderFormattedDate(date) : placeholder}</span>}
{showPlaceholderIcon && !date && (
<Calendar className="h-2.5 w-2.5 flex-shrink-0 hidden group-hover:inline text-custom-text-400" />
)}
{isClearable && ( {isClearable && (
<X <X
className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)} className={cn("h-2 w-2 flex-shrink-0", clearIconClassName)}
@ -183,6 +195,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
placement, placement,
tabIndex, tabIndex,
tooltip = false, tooltip = false,
showPlaceholderIcon = false,
value, value,
} = props; } = props;
const [isOpen, setIsOpen] = useState(false); const [isOpen, setIsOpen] = useState(false);
@ -246,6 +259,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
placeholder={placeholder} placeholder={placeholder}
isClearable={isClearable && isDateSelected} isClearable={isClearable && isDateSelected}
onClear={() => onChange(null)} onClear={() => onChange(null)}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -258,6 +272,7 @@ export const DateDropdown: React.FC<Props> = (props) => {
placeholder={placeholder} placeholder={placeholder}
isClearable={isClearable && isDateSelected} isClearable={isClearable && isDateSelected}
onClear={() => onChange(null)} onClear={() => onChange(null)}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />
@ -296,7 +311,9 @@ export const DateDropdown: React.FC<Props> = (props) => {
placeholder={placeholder} placeholder={placeholder}
isClearable={isClearable && isDateSelected} isClearable={isClearable && isDateSelected}
onClear={() => onChange(null)} onClear={() => onChange(null)}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
showPlaceholderIcon={showPlaceholderIcon}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
<TransparentButton <TransparentButton
@ -308,8 +325,10 @@ export const DateDropdown: React.FC<Props> = (props) => {
placeholder={placeholder} placeholder={placeholder}
isClearable={isClearable && isDateSelected} isClearable={isClearable && isDateSelected}
onClear={() => onChange(null)} onClear={() => onChange(null)}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
showPlaceholderIcon={showPlaceholderIcon}
/> />
) : null} ) : null}
</button> </button>

View File

@ -31,6 +31,7 @@ type ButtonProps = {
dropdownArrowClassName: string; dropdownArrowClassName: string;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
placeholder: string; placeholder: string;
tooltip: boolean; tooltip: boolean;
}; };
@ -51,6 +52,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
tooltip, tooltip,
} = props; } = props;
@ -64,6 +66,7 @@ const BorderButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -123,6 +126,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
tooltip, tooltip,
} = props; } = props;
@ -136,6 +140,7 @@ const TransparentButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -276,6 +281,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -287,6 +293,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "background-with-text" ? ( ) : buttonVariant === "background-with-text" ? (
@ -318,6 +325,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -329,6 +337,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : null} ) : null}

View File

@ -14,6 +14,7 @@ type ButtonProps = {
placeholder: string; placeholder: string;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
tooltip: boolean; tooltip: boolean;
userIds: string | string[] | null; userIds: string | string[] | null;
}; };
@ -50,6 +51,7 @@ export const BorderButton = observer((props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
userIds, userIds,
tooltip, tooltip,
@ -57,7 +59,7 @@ export const BorderButton = observer((props: ButtonProps) => {
// store hooks // store hooks
const { getUserDetails } = useMember(); const { getUserDetails } = useMember();
const isMultiple = Array.isArray(userIds); const isArray = Array.isArray(userIds);
return ( return (
<Tooltip <Tooltip
@ -68,13 +70,18 @@ export const BorderButton = observer((props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />} {!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
{!hideText && ( {!hideText && (
<span className="flex-grow truncate"> <span className="flex-grow truncate text-sm leading-5">
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} {isArray && userIds.length > 0
? userIds.length === 1
? getUserDetails(userIds[0])?.display_name
: ""
: placeholder}
</span> </span>
)} )}
{dropdownArrow && ( {dropdownArrow && (
@ -99,7 +106,7 @@ export const BackgroundButton = observer((props: ButtonProps) => {
// store hooks // store hooks
const { getUserDetails } = useMember(); const { getUserDetails } = useMember();
const isMultiple = Array.isArray(userIds); const isArray = Array.isArray(userIds);
return ( return (
<Tooltip <Tooltip
@ -115,8 +122,12 @@ export const BackgroundButton = observer((props: ButtonProps) => {
> >
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />} {!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
{!hideText && ( {!hideText && (
<span className="flex-grow truncate"> <span className="flex-grow truncate text-sm leading-5">
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} {isArray && userIds.length > 0
? userIds.length === 1
? getUserDetails(userIds[0])?.display_name
: ""
: placeholder}
</span> </span>
)} )}
{dropdownArrow && ( {dropdownArrow && (
@ -134,6 +145,7 @@ export const TransparentButton = observer((props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
placeholder, placeholder,
userIds, userIds,
tooltip, tooltip,
@ -141,7 +153,7 @@ export const TransparentButton = observer((props: ButtonProps) => {
// store hooks // store hooks
const { getUserDetails } = useMember(); const { getUserDetails } = useMember();
const isMultiple = Array.isArray(userIds); const isArray = Array.isArray(userIds);
return ( return (
<Tooltip <Tooltip
@ -152,13 +164,18 @@ export const TransparentButton = observer((props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
{!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />} {!hideIcon && <ButtonAvatars tooltip={tooltip} userIds={userIds} />}
{!hideText && ( {!hideText && (
<span className="flex-grow truncate"> <span className="flex-grow truncate text-sm leading-5">
{userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} {isArray && userIds.length > 0
? userIds.length === 1
? getUserDetails(userIds[0])?.display_name
: ""
: placeholder}
</span> </span>
)} )}
{dropdownArrow && ( {dropdownArrow && (

View File

@ -147,6 +147,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -157,6 +158,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />
@ -189,6 +191,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -199,6 +202,7 @@ export const ProjectMemberDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />

View File

@ -38,6 +38,7 @@ type ButtonProps = {
dropdownArrowClassName: string; dropdownArrowClassName: string;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
module: IModule | null; module: IModule | null;
placeholder: string; placeholder: string;
tooltip: boolean; tooltip: boolean;
@ -50,6 +51,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
module, module,
placeholder, placeholder,
tooltip, tooltip,
@ -60,6 +62,7 @@ const BorderButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -110,6 +113,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
module, module,
placeholder, placeholder,
tooltip, tooltip,
@ -120,6 +124,7 @@ const TransparentButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{ "bg-custom-background-80": isActive },
className className
)} )}
> >
@ -267,6 +272,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -278,6 +284,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "background-with-text" ? ( ) : buttonVariant === "background-with-text" ? (
@ -309,6 +316,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -320,6 +328,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon} hideIcon={hideIcon}
hideText hideText
placeholder={placeholder} placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : null} ) : null}

View File

@ -31,6 +31,7 @@ type ButtonProps = {
dropdownArrowClassName: string; dropdownArrowClassName: string;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
highlightUrgent: boolean; highlightUrgent: boolean;
priority: TIssuePriorities; priority: TIssuePriorities;
tooltip: boolean; tooltip: boolean;
@ -181,6 +182,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
highlightUrgent, highlightUrgent,
priority, priority,
tooltip, tooltip,
@ -207,6 +209,7 @@ const TransparentButton = (props: ButtonProps) => {
"px-0.5": hideText, "px-0.5": hideText,
// highlight the whole button if text is hidden and priority is urgent // highlight the whole button if text is hidden and priority is urgent
"bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent, "bg-red-500 border-red-500": priority === "urgent" && hideText && highlightUrgent,
"bg-custom-background-80": isActive,
}, },
className className
)} )}
@ -312,7 +315,13 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
as="div" as="div"
ref={dropdownRef} ref={dropdownRef}
tabIndex={tabIndex} tabIndex={tabIndex}
className={cn("h-full", className)} className={cn(
"h-full",
{
"bg-custom-background-80": isOpen,
},
className
)}
value={value} value={value}
onChange={onChange} onChange={onChange}
disabled={disabled} disabled={disabled}
@ -402,6 +411,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -414,6 +424,7 @@ export const PriorityDropdown: React.FC<Props> = (props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />

View File

@ -30,6 +30,7 @@ type ButtonProps = {
dropdownArrowClassName: string; dropdownArrowClassName: string;
hideIcon?: boolean; hideIcon?: boolean;
hideText?: boolean; hideText?: boolean;
isActive?: boolean;
state: IState | undefined; state: IState | undefined;
tooltip: boolean; tooltip: boolean;
}; };
@ -41,6 +42,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
state, state,
tooltip, tooltip,
} = props; } = props;
@ -50,6 +52,9 @@ const BorderButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5", "h-full flex items-center gap-1.5 border-[0.5px] border-custom-border-300 hover:bg-custom-background-80 rounded text-xs px-2 py-0.5",
{
"bg-custom-background-80": isActive,
},
className className
)} )}
> >
@ -111,6 +116,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName, dropdownArrowClassName,
hideIcon = false, hideIcon = false,
hideText = false, hideText = false,
isActive = false,
state, state,
tooltip, tooltip,
} = props; } = props;
@ -120,6 +126,9 @@ const TransparentButton = (props: ButtonProps) => {
<div <div
className={cn( className={cn(
"h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80", "h-full flex items-center gap-1.5 rounded text-xs px-2 py-0.5 hover:bg-custom-background-80",
{
"bg-custom-background-80": isActive,
},
className className
)} )}
> >
@ -251,6 +260,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "border-without-text" ? ( ) : buttonVariant === "border-without-text" ? (
@ -260,6 +270,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />
@ -289,6 +300,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
/> />
) : buttonVariant === "transparent-without-text" ? ( ) : buttonVariant === "transparent-without-text" ? (
@ -298,6 +310,7 @@ export const StateDropdown: React.FC<Props> = observer((props) => {
dropdownArrow={dropdownArrow && !disabled} dropdownArrow={dropdownArrow && !disabled}
dropdownArrowClassName={dropdownArrowClassName} dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon} hideIcon={hideIcon}
isActive={isOpen}
tooltip={tooltip} tooltip={tooltip}
hideText hideText
/> />

View File

@ -64,6 +64,7 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
{ {
"cursor-not-allowed": disabled, "cursor-not-allowed": disabled,
"hover:bg-custom-background-80": !disabled, "hover:bg-custom-background-80": !disabled,
"bg-custom-background-80": isParentIssueModalOpen,
}, },
className className
)} )}
@ -72,15 +73,20 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
> >
{issue.parent_id && parentIssue ? ( {issue.parent_id && parentIssue ? (
<div className="flex items-center gap-1 bg-green-500/20 text-green-700 rounded px-1.5 py-1"> <div className="flex items-center gap-1 bg-green-500/20 text-green-700 rounded px-1.5 py-1">
<Link <Tooltip tooltipHeading="Title" tooltipContent={parentIssue.name}>
href={`/${workspaceSlug}/projects/${projectId}/issues/${parentIssue?.id}`} <Link
className="text-xs font-medium" href={`/${workspaceSlug}/projects/${projectId}/issues/${parentIssue?.id}`}
> target="_blank"
{parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id} rel="noopener noreferrer"
</Link> className="text-xs font-medium mt-0.5"
onClick={(e) => e.stopPropagation()}
>
{parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id}
</Link>
</Tooltip>
{!disabled && ( {!disabled && (
<Tooltip tooltipContent="Remove"> <Tooltip tooltipContent="Remove" position="bottom">
<span <span
onClick={(e) => { onClick={(e) => {
e.preventDefault(); e.preventDefault();
@ -96,7 +102,15 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
) : ( ) : (
<span className="text-sm text-custom-text-400">Add parent issue</span> <span className="text-sm text-custom-text-400">Add parent issue</span>
)} )}
{!disabled && <Pencil className="h-4 w-4 flex-shrink-0 hidden group-hover:inline" />} {!disabled && (
<span
className={cn("p-1 flex-shrink-0 opacity-0 group-hover:opacity-100", {
"text-custom-text-400": !issue.parent_id && !parentIssue,
})}
>
<Pencil className="h-2.5 w-2.5 flex-shrink-0" />
</span>
)}
</button> </button>
</> </>
); );

View File

@ -1,4 +1,5 @@
import React from "react"; import React from "react";
import Link from "next/link";
import { observer } from "mobx-react-lite"; import { observer } from "mobx-react-lite";
import { CircleDot, CopyPlus, Pencil, X, XCircle } from "lucide-react"; import { CircleDot, CopyPlus, Pencil, X, XCircle } from "lucide-react";
// hooks // hooks
@ -101,59 +102,72 @@ export const IssueRelationSelect: React.FC<TIssueRelationSelect> = observer((pro
<button <button
type="button" type="button"
className={cn( className={cn(
"group flex items-center justify-between gap-2 px-2 py-0.5 rounded outline-none", "group flex items-center gap-2 px-2 py-0.5 rounded outline-none",
{ {
"cursor-not-allowed": disabled, "cursor-not-allowed": disabled,
"hover:bg-custom-background-80": !disabled, "hover:bg-custom-background-80": !disabled,
"bg-custom-background-80": isRelationModalOpen === relationKey,
}, },
className className
)} )}
onClick={() => toggleRelationModal(relationKey)} onClick={() => toggleRelationModal(relationKey)}
disabled={disabled} disabled={disabled}
> >
{relationIssueIds.length > 0 ? ( <div className="flex items-start justify-between w-full">
<div className="flex items-center gap-2 flex-wrap"> {relationIssueIds.length > 0 ? (
{relationIssueIds.map((relationIssueId) => { <div className="flex items-center gap-2 py-0.5 flex-wrap">
const currentIssue = issueMap[relationIssueId]; {relationIssueIds.map((relationIssueId) => {
if (!currentIssue) return; const currentIssue = issueMap[relationIssueId];
if (!currentIssue) return;
const projectDetails = getProjectById(currentIssue.project_id); const projectDetails = getProjectById(currentIssue.project_id);
return ( return (
<div <div
key={relationIssueId} key={relationIssueId}
className={`group flex items-center gap-1 rounded px-1.5 py-1 ${issueRelationObject[relationKey].className}`} className={`group flex items-center gap-1 rounded px-1.5 pt-1 pb-1 leading-3 hover:bg-custom-background-90 ${issueRelationObject[relationKey].className}`}
>
<a
href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues/${currentIssue.id}`}
target="_blank"
rel="noopener noreferrer"
className="text-xs font-medium"
onClick={(e) => e.stopPropagation()}
> >
{`${projectDetails?.identifier}-${currentIssue?.sequence_id}`} <Tooltip tooltipHeading="Title" tooltipContent={currentIssue.name}>
</a> <Link
{!disabled && ( href={`/${workspaceSlug}/projects/${projectDetails?.id}/issues/${currentIssue.id}`}
<Tooltip tooltipContent="Remove"> target="_blank"
<span rel="noopener noreferrer"
onClick={(e) => { className="text-xs font-medium mt-0.5"
e.preventDefault(); onClick={(e) => e.stopPropagation()}
e.stopPropagation();
removeRelation(workspaceSlug, projectId, issueId, relationKey, relationIssueId);
}}
> >
<X className="h-2.5 w-2.5 text-custom-text-300 hover:text-red-500" /> {`${projectDetails?.identifier}-${currentIssue?.sequence_id}`}
</span> </Link>
</Tooltip> </Tooltip>
)} {!disabled && (
</div> <Tooltip tooltipContent="Remove" position="bottom">
); <span
})} onClick={(e) => {
</div> e.preventDefault();
) : ( e.stopPropagation();
<span className="text-sm text-custom-text-400">{issueRelationObject[relationKey].placeholder}</span> removeRelation(workspaceSlug, projectId, issueId, relationKey, relationIssueId);
)} }}
{!disabled && <Pencil className="h-4 w-4 flex-shrink-0 hidden group-hover:inline" />} >
<X className="h-2.5 w-2.5 text-custom-text-300 hover:text-red-500" />
</span>
</Tooltip>
)}
</div>
);
})}
</div>
) : (
<span className="text-sm text-custom-text-400">{issueRelationObject[relationKey].placeholder}</span>
)}
{!disabled && (
<span
className={cn("p-1 flex-shrink-0 opacity-0 group-hover:opacity-100", {
"text-custom-text-400": relationIssueIds.length === 0,
})}
>
<Pencil className="h-2.5 w-2.5 flex-shrink-0" />
</span>
)}
</div>
</button> </button>
</> </>
); );

View File

@ -184,7 +184,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
projectId={projectId?.toString() ?? ""} projectId={projectId?.toString() ?? ""}
placeholder="Add assignees" placeholder="Add assignees"
multiple multiple
buttonVariant={issue?.assignee_ids?.length > 0 ? "transparent-without-text" : "transparent-with-text"} buttonVariant={issue?.assignee_ids?.length > 1 ? "transparent-without-text" : "transparent-with-text"}
className="w-3/5 flex-grow group" className="w-3/5 flex-grow group"
buttonContainerClassName="w-full text-left" buttonContainerClassName="w-full text-left"
buttonClassName={`text-sm justify-between ${ buttonClassName={`text-sm justify-between ${
@ -233,6 +233,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`} buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`}
hideIcon hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline" clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/> />
</div> </div>
@ -257,6 +258,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`} buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`}
hideIcon hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline" clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/> />
</div> </div>
@ -332,8 +334,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/> />
</div> </div>
<div className="flex items-center gap-2 min-h-8"> <div className="flex gap-2 min-h-8">
<div className="flex items-center gap-1 w-2/5 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex gap-1 pt-2 w-2/5 flex-shrink-0 text-sm text-custom-text-300">
<RelatedIcon className="h-4 w-4 flex-shrink-0" /> <RelatedIcon className="h-4 w-4 flex-shrink-0" />
<span>Relates to</span> <span>Relates to</span>
</div> </div>
@ -347,8 +349,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/> />
</div> </div>
<div className="flex items-center gap-2 min-h-8"> <div className="flex gap-2 min-h-8">
<div className="flex items-center gap-1 w-2/5 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex gap-1 pt-2 w-2/5 flex-shrink-0 text-sm text-custom-text-300">
<XCircle className="h-4 w-4 flex-shrink-0" /> <XCircle className="h-4 w-4 flex-shrink-0" />
<span>Blocking</span> <span>Blocking</span>
</div> </div>
@ -362,8 +364,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/> />
</div> </div>
<div className="flex items-center gap-2 min-h-8"> <div className="flex gap-2 min-h-8">
<div className="flex items-center gap-1 w-2/5 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex gap-1 pt-2 w-2/5 flex-shrink-0 text-sm text-custom-text-300">
<CircleDot className="h-4 w-4 flex-shrink-0" /> <CircleDot className="h-4 w-4 flex-shrink-0" />
<span>Blocked by</span> <span>Blocked by</span>
</div> </div>
@ -377,8 +379,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/> />
</div> </div>
<div className="flex items-center gap-2 min-h-8"> <div className="flex gap-2 min-h-8">
<div className="flex items-center gap-1 w-2/5 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex gap-1 pt-2 w-2/5 flex-shrink-0 text-sm text-custom-text-300">
<CopyPlus className="h-4 w-4 flex-shrink-0" /> <CopyPlus className="h-4 w-4 flex-shrink-0" />
<span>Duplicate of</span> <span>Duplicate of</span>
</div> </div>

View File

@ -99,7 +99,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
projectId={projectId} projectId={projectId}
placeholder="Add assignees" placeholder="Add assignees"
multiple multiple
buttonVariant={issue?.assignee_ids?.length > 0 ? "transparent-without-text" : "transparent-with-text"} buttonVariant={issue?.assignee_ids?.length > 1 ? "transparent-without-text" : "transparent-with-text"}
className="w-3/4 flex-grow group" className="w-3/4 flex-grow group"
buttonContainerClassName="w-full text-left" buttonContainerClassName="w-full text-left"
buttonClassName={`text-sm justify-between ${issue?.assignee_ids.length > 0 ? "" : "text-custom-text-400"}`} buttonClassName={`text-sm justify-between ${issue?.assignee_ids.length > 0 ? "" : "text-custom-text-400"}`}
@ -148,6 +148,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`} buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`}
hideIcon hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline" clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/> />
</div> </div>
@ -173,6 +174,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`} buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`}
hideIcon hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline" clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/> />
</div> </div>
@ -251,8 +253,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div> </div>
{/* relates to */} {/* relates to */}
<div className="flex items-center gap-3 min-h-8"> <div className="flex gap-3 min-h-8">
<div className="flex items-center gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex pt-2 gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300">
<RelatedIcon className="h-4 w-4 flex-shrink-0" /> <RelatedIcon className="h-4 w-4 flex-shrink-0" />
<span>Relates to</span> <span>Relates to</span>
</div> </div>
@ -267,8 +269,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div> </div>
{/* blocking */} {/* blocking */}
<div className="flex items-center gap-3 min-h-8"> <div className="flex gap-3 min-h-8">
<div className="flex items-center gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex pt-2 gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300">
<XCircle className="h-4 w-4 flex-shrink-0" /> <XCircle className="h-4 w-4 flex-shrink-0" />
<span>Blocking</span> <span>Blocking</span>
</div> </div>
@ -283,8 +285,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div> </div>
{/* blocked by */} {/* blocked by */}
<div className="flex items-center gap-3 min-h-8"> <div className="flex gap-3 min-h-8">
<div className="flex items-center gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex pt-2 gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300">
<CircleDot className="h-4 w-4 flex-shrink-0" /> <CircleDot className="h-4 w-4 flex-shrink-0" />
<span>Blocked by</span> <span>Blocked by</span>
</div> </div>
@ -299,8 +301,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div> </div>
{/* duplicate of */} {/* duplicate of */}
<div className="flex items-center gap-3 min-h-8"> <div className="flex gap-3 min-h-8">
<div className="flex items-center gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300"> <div className="flex pt-2 gap-1 w-1/4 flex-shrink-0 text-sm text-custom-text-300">
<CopyPlus className="h-4 w-4 flex-shrink-0" /> <CopyPlus className="h-4 w-4 flex-shrink-0" />
<span>Duplicate of</span> <span>Duplicate of</span>
</div> </div>