diff --git a/apiserver/plane/app/serializers/issue.py b/apiserver/plane/app/serializers/issue.py index 7bea75fa0..4cdcc7b76 100644 --- a/apiserver/plane/app/serializers/issue.py +++ b/apiserver/plane/app/serializers/issue.py @@ -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", diff --git a/web/components/dropdowns/cycle.tsx b/web/components/dropdowns/cycle.tsx index 51c84098a..39b72fe08 100644 --- a/web/components/dropdowns/cycle.tsx +++ b/web/components/dropdowns/cycle.tsx @@ -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) => {
@@ -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) => {
@@ -268,6 +273,7 @@ export const CycleDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : buttonVariant === "background-with-text" ? ( @@ -310,6 +317,7 @@ export const CycleDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : null} diff --git a/web/components/dropdowns/date.tsx b/web/components/dropdowns/date.tsx index 3cbf3449a..5dac4ee49 100644 --- a/web/components/dropdowns/date.tsx +++ b/web/components/dropdowns/date.tsx @@ -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) => {
@@ -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) => {
{!hideIcon && icon} {!hideText && {date ? renderFormattedDate(date) : placeholder}} + {showPlaceholderIcon && !date && ( + + )} + {isClearable && ( = (props) => { placement, tabIndex, tooltip = false, + showPlaceholderIcon = false, value, } = props; const [isOpen, setIsOpen] = useState(false); @@ -246,6 +259,7 @@ export const DateDropdown: React.FC = (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) => { placeholder={placeholder} isClearable={isClearable && isDateSelected} onClear={() => onChange(null)} + isActive={isOpen} tooltip={tooltip} hideText /> @@ -296,7 +311,9 @@ export const DateDropdown: React.FC = (props) => { placeholder={placeholder} isClearable={isClearable && isDateSelected} onClear={() => onChange(null)} + isActive={isOpen} tooltip={tooltip} + showPlaceholderIcon={showPlaceholderIcon} /> ) : buttonVariant === "transparent-without-text" ? ( = (props) => { placeholder={placeholder} isClearable={isClearable && isDateSelected} onClear={() => onChange(null)} + isActive={isOpen} tooltip={tooltip} hideText + showPlaceholderIcon={showPlaceholderIcon} /> ) : null} diff --git a/web/components/dropdowns/estimate.tsx b/web/components/dropdowns/estimate.tsx index 18144540d..31b2a840d 100644 --- a/web/components/dropdowns/estimate.tsx +++ b/web/components/dropdowns/estimate.tsx @@ -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) => {
@@ -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) => {
@@ -276,6 +281,7 @@ export const EstimateDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : buttonVariant === "background-with-text" ? ( @@ -318,6 +325,7 @@ export const EstimateDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : null} diff --git a/web/components/dropdowns/member/buttons.tsx b/web/components/dropdowns/member/buttons.tsx index c1ec93c53..e1664cdb4 100644 --- a/web/components/dropdowns/member/buttons.tsx +++ b/web/components/dropdowns/member/buttons.tsx @@ -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 ( {
{!hideIcon && } {!hideText && ( - - {userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} + + {isArray && userIds.length > 0 + ? userIds.length === 1 + ? getUserDetails(userIds[0])?.display_name + : "" + : placeholder} )} {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 ( { > {!hideIcon && } {!hideText && ( - - {userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} + + {isArray && userIds.length > 0 + ? userIds.length === 1 + ? getUserDetails(userIds[0])?.display_name + : "" + : placeholder} )} {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 ( {
{!hideIcon && } {!hideText && ( - - {userIds ? (isMultiple ? placeholder : getUserDetails(userIds)?.display_name) : placeholder} + + {isArray && userIds.length > 0 + ? userIds.length === 1 + ? getUserDetails(userIds[0])?.display_name + : "" + : placeholder} )} {dropdownArrow && ( diff --git a/web/components/dropdowns/member/project-member.tsx b/web/components/dropdowns/member/project-member.tsx index 7cd878841..cc1650527 100644 --- a/web/components/dropdowns/member/project-member.tsx +++ b/web/components/dropdowns/member/project-member.tsx @@ -147,6 +147,7 @@ export const ProjectMemberDropdown: React.FC = 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 = observer((props) => { dropdownArrowClassName={dropdownArrowClassName} hideIcon={hideIcon} placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} hideText /> @@ -189,6 +191,7 @@ export const ProjectMemberDropdown: React.FC = 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 = observer((props) => { dropdownArrowClassName={dropdownArrowClassName} hideIcon={hideIcon} placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} hideText /> diff --git a/web/components/dropdowns/module.tsx b/web/components/dropdowns/module.tsx index e41555802..4fc5e0e22 100644 --- a/web/components/dropdowns/module.tsx +++ b/web/components/dropdowns/module.tsx @@ -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) => {
@@ -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) => {
@@ -267,6 +272,7 @@ export const ModuleDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : buttonVariant === "background-with-text" ? ( @@ -309,6 +316,7 @@ export const ModuleDropdown: React.FC = 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 = observer((props) => { hideIcon={hideIcon} hideText placeholder={placeholder} + isActive={isOpen} tooltip={tooltip} /> ) : null} diff --git a/web/components/dropdowns/priority.tsx b/web/components/dropdowns/priority.tsx index dff1f5aaa..7f96a3bd1 100644 --- a/web/components/dropdowns/priority.tsx +++ b/web/components/dropdowns/priority.tsx @@ -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) => { 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) => { 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) => { dropdownArrow={dropdownArrow && !disabled} dropdownArrowClassName={dropdownArrowClassName} hideIcon={hideIcon} + isActive={isOpen} tooltip={tooltip} hideText /> diff --git a/web/components/dropdowns/state.tsx b/web/components/dropdowns/state.tsx index fb8446d23..9ad41622b 100644 --- a/web/components/dropdowns/state.tsx +++ b/web/components/dropdowns/state.tsx @@ -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) => {
@@ -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) => {
@@ -251,6 +260,7 @@ export const StateDropdown: React.FC = 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 = observer((props) => { dropdownArrow={dropdownArrow && !disabled} dropdownArrowClassName={dropdownArrowClassName} hideIcon={hideIcon} + isActive={isOpen} tooltip={tooltip} hideText /> @@ -289,6 +300,7 @@ export const StateDropdown: React.FC = 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 = observer((props) => { dropdownArrow={dropdownArrow && !disabled} dropdownArrowClassName={dropdownArrowClassName} hideIcon={hideIcon} + isActive={isOpen} tooltip={tooltip} hideText /> diff --git a/web/components/issues/issue-detail/parent-select.tsx b/web/components/issues/issue-detail/parent-select.tsx index 34923318a..7ad8c836f 100644 --- a/web/components/issues/issue-detail/parent-select.tsx +++ b/web/components/issues/issue-detail/parent-select.tsx @@ -64,6 +64,7 @@ export const IssueParentSelect: React.FC = 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 = observer((props) > {issue.parent_id && parentIssue ? (
- - {parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id} - + + e.stopPropagation()} + > + {parentIssueProjectDetails?.identifier}-{parentIssue.sequence_id} + + {!disabled && ( - + { e.preventDefault(); @@ -96,7 +102,15 @@ export const IssueParentSelect: React.FC = observer((props) ) : ( Add parent issue )} - {!disabled && } + {!disabled && ( + + + + )} ); diff --git a/web/components/issues/issue-detail/relation-select.tsx b/web/components/issues/issue-detail/relation-select.tsx index 405dee3d7..1fdd353a6 100644 --- a/web/components/issues/issue-detail/relation-select.tsx +++ b/web/components/issues/issue-detail/relation-select.tsx @@ -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 = observer((pro ); diff --git a/web/components/issues/issue-detail/sidebar.tsx b/web/components/issues/issue-detail/sidebar.tsx index f811078f8..0a38c3017 100644 --- a/web/components/issues/issue-detail/sidebar.tsx +++ b/web/components/issues/issue-detail/sidebar.tsx @@ -184,7 +184,7 @@ export const IssueDetailsSidebar: React.FC = 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 = observer((props) => { buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" + showPlaceholderIcon />
@@ -257,6 +258,7 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" + showPlaceholderIcon />
@@ -332,8 +334,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { />
-
-
+
+
Relates to
@@ -347,8 +349,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { />
-
-
+
+
Blocking
@@ -362,8 +364,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { />
-
-
+
+
Blocked by
@@ -377,8 +379,8 @@ export const IssueDetailsSidebar: React.FC = observer((props) => { />
-
-
+
+
Duplicate of
diff --git a/web/components/issues/peek-overview/properties.tsx b/web/components/issues/peek-overview/properties.tsx index 3b72a31fe..6aee23a23 100644 --- a/web/components/issues/peek-overview/properties.tsx +++ b/web/components/issues/peek-overview/properties.tsx @@ -99,7 +99,7 @@ export const PeekOverviewProperties: FC = 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 = observer((pro buttonClassName={`text-sm ${issue?.start_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" + showPlaceholderIcon />
@@ -173,6 +174,7 @@ export const PeekOverviewProperties: FC = observer((pro buttonClassName={`text-sm ${issue?.target_date ? "" : "text-custom-text-400"}`} hideIcon clearIconClassName="h-3 w-3 hidden group-hover:inline" + showPlaceholderIcon />
@@ -251,8 +253,8 @@ export const PeekOverviewProperties: FC = observer((pro
{/* relates to */} -
-
+
+
Relates to
@@ -267,8 +269,8 @@ export const PeekOverviewProperties: FC = observer((pro
{/* blocking */} -
-
+
+
Blocking
@@ -283,8 +285,8 @@ export const PeekOverviewProperties: FC = observer((pro
{/* blocked by */} -
-
+
+
Blocked by
@@ -299,8 +301,8 @@ export const PeekOverviewProperties: FC = observer((pro
{/* duplicate of */} -
-
+
+
Duplicate of