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

View File

@ -30,6 +30,7 @@ type ButtonProps = {
hideIcon: boolean;
hideText?: boolean;
dropdownArrow: boolean;
isActive?: boolean;
dropdownArrowClassName: string;
placeholder: string;
tooltip: boolean;
@ -51,6 +52,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
placeholder,
tooltip,
} = props;
@ -60,6 +62,7 @@ const BorderButton = (props: ButtonProps) => {
<div
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",
{ "bg-custom-background-80": isActive },
className
)}
>
@ -111,6 +114,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
placeholder,
tooltip,
} = props;
@ -120,6 +124,7 @@ const TransparentButton = (props: ButtonProps) => {
<div
className={cn(
"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
)}
>
@ -268,6 +273,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "border-without-text" ? (
@ -279,6 +285,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "background-with-text" ? (
@ -310,6 +317,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "transparent-without-text" ? (
@ -321,6 +329,7 @@ export const CycleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : null}

View File

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

View File

@ -31,6 +31,7 @@ type ButtonProps = {
dropdownArrowClassName: string;
hideIcon?: boolean;
hideText?: boolean;
isActive?: boolean;
placeholder: string;
tooltip: boolean;
};
@ -51,6 +52,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
placeholder,
tooltip,
} = props;
@ -64,6 +66,7 @@ const BorderButton = (props: ButtonProps) => {
<div
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",
{ "bg-custom-background-80": isActive },
className
)}
>
@ -123,6 +126,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
placeholder,
tooltip,
} = props;
@ -136,6 +140,7 @@ const TransparentButton = (props: ButtonProps) => {
<div
className={cn(
"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
)}
>
@ -276,6 +281,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "border-without-text" ? (
@ -287,6 +293,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "background-with-text" ? (
@ -318,6 +325,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "transparent-without-text" ? (
@ -329,6 +337,7 @@ export const EstimateDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : null}

View File

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

View File

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

View File

@ -38,6 +38,7 @@ type ButtonProps = {
dropdownArrowClassName: string;
hideIcon?: boolean;
hideText?: boolean;
isActive?: boolean;
module: IModule | null;
placeholder: string;
tooltip: boolean;
@ -50,6 +51,7 @@ const BorderButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
module,
placeholder,
tooltip,
@ -60,6 +62,7 @@ const BorderButton = (props: ButtonProps) => {
<div
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",
{ "bg-custom-background-80": isActive },
className
)}
>
@ -110,6 +113,7 @@ const TransparentButton = (props: ButtonProps) => {
dropdownArrowClassName,
hideIcon = false,
hideText = false,
isActive = false,
module,
placeholder,
tooltip,
@ -120,6 +124,7 @@ const TransparentButton = (props: ButtonProps) => {
<div
className={cn(
"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
)}
>
@ -267,6 +272,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "border-without-text" ? (
@ -278,6 +284,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "background-with-text" ? (
@ -309,6 +316,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
dropdownArrowClassName={dropdownArrowClassName}
hideIcon={hideIcon}
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : buttonVariant === "transparent-without-text" ? (
@ -320,6 +328,7 @@ export const ModuleDropdown: React.FC<Props> = observer((props) => {
hideIcon={hideIcon}
hideText
placeholder={placeholder}
isActive={isOpen}
tooltip={tooltip}
/>
) : null}

View File

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

View File

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

View File

@ -64,6 +64,7 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
{
"cursor-not-allowed": disabled,
"hover:bg-custom-background-80": !disabled,
"bg-custom-background-80": isParentIssueModalOpen,
},
className
)}
@ -72,15 +73,20 @@ export const IssueParentSelect: React.FC<TIssueParentSelect> = observer((props)
>
{issue.parent_id && parentIssue ? (
<div className="flex items-center gap-1 bg-green-500/20 text-green-700 rounded px-1.5 py-1">
<Link
href={`/${workspaceSlug}/projects/${projectId}/issues/${parentIssue?.id}`}
className="text-xs font-medium"
>
{parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id}
</Link>
<Tooltip tooltipHeading="Title" tooltipContent={parentIssue.name}>
<Link
href={`/${workspaceSlug}/projects/${projectId}/issues/${parentIssue?.id}`}
target="_blank"
rel="noopener noreferrer"
className="text-xs font-medium mt-0.5"
onClick={(e) => e.stopPropagation()}
>
{parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id}
</Link>
</Tooltip>
{!disabled && (
<Tooltip tooltipContent="Remove">
<Tooltip tooltipContent="Remove" position="bottom">
<span
onClick={(e) => {
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>
)}
{!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>
</>
);

View File

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

View File

@ -184,7 +184,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
projectId={projectId?.toString() ?? ""}
placeholder="Add assignees"
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"
buttonContainerClassName="w-full text-left"
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"}`}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/>
</div>
@ -257,6 +258,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/>
</div>
@ -332,8 +334,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/>
</div>
<div className="flex items-center 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-2 min-h-8">
<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" />
<span>Relates to</span>
</div>
@ -347,8 +349,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/>
</div>
<div className="flex items-center 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-2 min-h-8">
<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" />
<span>Blocking</span>
</div>
@ -362,8 +364,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/>
</div>
<div className="flex items-center 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-2 min-h-8">
<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" />
<span>Blocked by</span>
</div>
@ -377,8 +379,8 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
/>
</div>
<div className="flex items-center 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-2 min-h-8">
<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" />
<span>Duplicate of</span>
</div>

View File

@ -99,7 +99,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
projectId={projectId}
placeholder="Add assignees"
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"
buttonContainerClassName="w-full text-left"
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"}`}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/>
</div>
@ -173,6 +174,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline"
showPlaceholderIcon
/>
</div>
@ -251,8 +253,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div>
{/* relates to */}
<div className="flex items-center 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 gap-3 min-h-8">
<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" />
<span>Relates to</span>
</div>
@ -267,8 +269,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div>
{/* blocking */}
<div className="flex items-center 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 gap-3 min-h-8">
<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" />
<span>Blocking</span>
</div>
@ -283,8 +285,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div>
{/* blocked by */}
<div className="flex items-center 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 gap-3 min-h-8">
<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" />
<span>Blocked by</span>
</div>
@ -299,8 +301,8 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
</div>
{/* duplicate of */}
<div className="flex items-center 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 gap-3 min-h-8">
<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" />
<span>Duplicate of</span>
</div>