diff --git a/apiserver/plane/app/serializers/issue.py b/apiserver/plane/app/serializers/issue.py index 7bea75fa0e..4cdcc7b768 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/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx index 418dc26da9..d15317719b 100644 --- a/web/components/cycles/active-cycle-details.tsx +++ b/web/components/cycles/active-cycle-details.tsx @@ -2,6 +2,7 @@ import { MouseEvent } from "react"; import Link from "next/link"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; +import { useTheme } from "next-themes"; // hooks import { useCycle, useIssues, useProject, useUser } from "hooks/store"; import useToast from "hooks/use-toast"; @@ -43,6 +44,7 @@ interface IActiveCycleDetails { export const ActiveCycleDetails: React.FC = observer((props) => { // props const { workspaceSlug, projectId } = props; + const { resolvedTheme } = useTheme(); // store hooks const { currentUser } = useUser(); const { @@ -76,7 +78,9 @@ export const ActiveCycleDetails: React.FC = observer((props ); const emptyStateDetail = CYCLE_EMPTY_STATE_DETAILS["active"]; - const emptyStateImage = getEmptyStateImagePath("cycle", "active", currentUser?.theme.theme === "light"); + + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("cycle", "active", isLightMode); if (!activeCycle && isLoading) return ( diff --git a/web/components/cycles/cycles-board.tsx b/web/components/cycles/cycles-board.tsx index 1365e4aa48..19e7f22252 100644 --- a/web/components/cycles/cycles-board.tsx +++ b/web/components/cycles/cycles-board.tsx @@ -1,5 +1,6 @@ import { FC } from "react"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useUser } from "hooks/store"; // components @@ -18,11 +19,15 @@ export interface ICyclesBoard { export const CyclesBoard: FC = observer((props) => { const { cycleIds, filter, workspaceSlug, projectId, peekCycle } = props; + // theme + const { resolvedTheme } = useTheme(); // store hooks const { currentUser } = useUser(); const emptyStateDetail = CYCLE_EMPTY_STATE_DETAILS[filter as keyof typeof CYCLE_EMPTY_STATE_DETAILS]; - const emptyStateImage = getEmptyStateImagePath("cycle", filter, currentUser?.theme.theme === "light"); + + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("cycle", filter, isLightMode); return ( <> diff --git a/web/components/cycles/cycles-list.tsx b/web/components/cycles/cycles-list.tsx index 3dfa2130b2..90fcdd8f9f 100644 --- a/web/components/cycles/cycles-list.tsx +++ b/web/components/cycles/cycles-list.tsx @@ -1,5 +1,6 @@ import { FC } from "react"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useUser } from "hooks/store"; // components @@ -19,11 +20,15 @@ export interface ICyclesList { export const CyclesList: FC = observer((props) => { const { cycleIds, filter, workspaceSlug, projectId } = props; + // theme + const { resolvedTheme } = useTheme(); // store hooks const { currentUser } = useUser(); const emptyStateDetail = CYCLE_EMPTY_STATE_DETAILS[filter as keyof typeof CYCLE_EMPTY_STATE_DETAILS]; - const emptyStateImage = getEmptyStateImagePath("cycle", filter, currentUser?.theme.theme === "light"); + + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("cycle", filter, isLightMode); return ( <> diff --git a/web/components/dashboard/home-dashboard-widgets.tsx b/web/components/dashboard/home-dashboard-widgets.tsx index fb6055a678..2e2f9ef88b 100644 --- a/web/components/dashboard/home-dashboard-widgets.tsx +++ b/web/components/dashboard/home-dashboard-widgets.tsx @@ -50,11 +50,11 @@ export const DashboardWidgets = observer(() => { // if the widget is full width, return it in a 2 column grid if (widget.fullWidth) return ( -
+
); - else return ; + else return ; })}
); diff --git a/web/components/dashboard/widgets/created-issues.tsx b/web/components/dashboard/widgets/created-issues.tsx index 6f2913197c..f5727f277d 100644 --- a/web/components/dashboard/widgets/created-issues.tsx +++ b/web/components/dashboard/widgets/created-issues.tsx @@ -99,7 +99,7 @@ export const CreatedIssuesWidget: React.FC = observer((props) => { {ISSUES_TABS_LIST.map((tab) => ( - + = observer((props) => {
{projectDetails.members?.map((member) => ( - + ))}
diff --git a/web/components/dropdowns/cycle.tsx b/web/components/dropdowns/cycle.tsx index 51c84098a3..39b72fe08d 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 3cbf3449ad..5dac4ee494 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 18144540da..31b2a840d3 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 c1ec93c535..e1664cdb4a 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 7cd8788412..cc16505272 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 e415558025..4fc5e0e220 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 dff1f5aaa4..7f96a3bd1e 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 fb8446d234..9ad41622b0 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 34923318a1..7ad8c836fb 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 405dee3d7d..1fdd353a63 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 f811078f87..0a38c30175 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/issue-layouts/empty-states/archived-issues.tsx b/web/components/issues/issue-layouts/empty-states/archived-issues.tsx index 33f46ba24e..f04144d049 100644 --- a/web/components/issues/issue-layouts/empty-states/archived-issues.tsx +++ b/web/components/issues/issue-layouts/empty-states/archived-issues.tsx @@ -1,6 +1,7 @@ import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; import size from "lodash/size"; +import { useTheme } from "next-themes"; // hooks import { useIssues, useUser } from "hooks/store"; // components @@ -26,6 +27,9 @@ export const ProjectArchivedEmptyState: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; + // theme + const { resolvedTheme } = useTheme(); + // store hooks const { membership: { currentProjectRole }, currentUser, @@ -35,12 +39,9 @@ export const ProjectArchivedEmptyState: React.FC = observer(() => { const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - const currentLayoutEmptyStateImagePath = getEmptyStateImagePath( - "empty-filters", - activeLayout ?? "list", - currentUser?.theme.theme === "light" - ); - const EmptyStateImagePath = getEmptyStateImagePath("archived", "empty-issues", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const currentLayoutEmptyStateImagePath = getEmptyStateImagePath("empty-filters", activeLayout ?? "list", isLightMode); + const EmptyStateImagePath = getEmptyStateImagePath("archived", "empty-issues", isLightMode); const issueFilterCount = size( Object.fromEntries( diff --git a/web/components/issues/issue-layouts/empty-states/draft-issues.tsx b/web/components/issues/issue-layouts/empty-states/draft-issues.tsx index 258d0d5d37..ba6a9ed2a1 100644 --- a/web/components/issues/issue-layouts/empty-states/draft-issues.tsx +++ b/web/components/issues/issue-layouts/empty-states/draft-issues.tsx @@ -1,6 +1,7 @@ import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; import size from "lodash/size"; +import { useTheme } from "next-themes"; // hooks import { useIssues, useUser } from "hooks/store"; // components @@ -26,6 +27,9 @@ export const ProjectDraftEmptyState: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; + // theme + const { resolvedTheme } = useTheme(); + // store hooks const { membership: { currentProjectRole }, currentUser, @@ -35,12 +39,9 @@ export const ProjectDraftEmptyState: React.FC = observer(() => { const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - const currentLayoutEmptyStateImagePath = getEmptyStateImagePath( - "empty-filters", - activeLayout ?? "list", - currentUser?.theme.theme === "light" - ); - const EmptyStateImagePath = getEmptyStateImagePath("draft", "empty-issues", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const currentLayoutEmptyStateImagePath = getEmptyStateImagePath("empty-filters", activeLayout ?? "list", isLightMode); + const EmptyStateImagePath = getEmptyStateImagePath("draft", "empty-issues", isLightMode); const issueFilterCount = size( Object.fromEntries( diff --git a/web/components/issues/issue-layouts/empty-states/project-issues.tsx b/web/components/issues/issue-layouts/empty-states/project-issues.tsx index 49de72acae..ee6216634c 100644 --- a/web/components/issues/issue-layouts/empty-states/project-issues.tsx +++ b/web/components/issues/issue-layouts/empty-states/project-issues.tsx @@ -1,6 +1,7 @@ import { observer } from "mobx-react-lite"; import { useRouter } from "next/router"; import size from "lodash/size"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useIssues, useUser } from "hooks/store"; // components @@ -26,6 +27,8 @@ export const ProjectEmptyState: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId } = router.query; + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: commandPaletteStore, @@ -40,12 +43,9 @@ export const ProjectEmptyState: React.FC = observer(() => { const userFilters = issuesFilter?.issueFilters?.filters; const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout; - const currentLayoutEmptyStateImagePath = getEmptyStateImagePath( - "empty-filters", - activeLayout ?? "list", - currentUser?.theme.theme === "light" - ); - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "issues", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const currentLayoutEmptyStateImagePath = getEmptyStateImagePath("empty-filters", activeLayout ?? "list", isLightMode); + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "issues", isLightMode); const issueFilterCount = size( Object.fromEntries( diff --git a/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx b/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx index 4b3f3fe830..2e189c9f4f 100644 --- a/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx +++ b/web/components/issues/issue-layouts/kanban/roots/profile-issues-root.tsx @@ -28,7 +28,7 @@ export const ProfileIssuesKanBanLayout: React.FC = observer(() => { [EIssueActions.UPDATE]: async (issue: TIssue) => { if (!workspaceSlug || !userId) return; - await issues.updateIssue(workspaceSlug, userId, issue.id, issue); + await issues.updateIssue(workspaceSlug, issue.project_id, issue.id, issue, userId); }, [EIssueActions.DELETE]: async (issue: TIssue) => { if (!workspaceSlug || !userId) return; diff --git a/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx b/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx index 1e7e364d54..91e80382a6 100644 --- a/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx +++ b/web/components/issues/issue-layouts/list/roots/profile-issues-root.tsx @@ -29,7 +29,7 @@ export const ProfileIssuesListLayout: FC = observer(() => { [EIssueActions.UPDATE]: async (issue: TIssue) => { if (!workspaceSlug || !userId) return; - await issues.updateIssue(workspaceSlug, userId, issue.id, issue); + await issues.updateIssue(workspaceSlug, issue.project_id, issue.id, issue, userId); }, [EIssueActions.DELETE]: async (issue: TIssue) => { if (!workspaceSlug || !userId) return; diff --git a/web/components/issues/issue-layouts/properties/labels.tsx b/web/components/issues/issue-layouts/properties/labels.tsx index 0a33ed886f..0f121bed79 100644 --- a/web/components/issues/issue-layouts/properties/labels.tsx +++ b/web/components/issues/issue-layouts/properties/labels.tsx @@ -82,17 +82,17 @@ export const IssuePropertyLabels: React.FC = observer((pro if (storeLabels && storeLabels.length > 0) projectLabels = storeLabels; const options = projectLabels.map((label) => ({ - value: label.id, - query: label.name, + value: label?.id, + query: label?.name, content: (
-
{label.name}
+
{label?.name}
), })); @@ -106,11 +106,11 @@ export const IssuePropertyLabels: React.FC = observer((pro value.length <= maxRender ? ( <> {projectLabels - ?.filter((l) => value.includes(l.id)) + ?.filter((l) => value.includes(l?.id)) .map((label) => ( - +
= observer((pro backgroundColor: label?.color ?? "#000000", }} /> -
{label.name}
+
{label?.name}
@@ -138,8 +138,8 @@ export const IssuePropertyLabels: React.FC = observer((pro position="top" tooltipHeading="Labels" tooltipContent={projectLabels - ?.filter((l) => value.includes(l.id)) - .map((l) => l.name) + ?.filter((l) => value.includes(l?.id)) + .map((l) => l?.name) .join(", ")} >
diff --git a/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx index d808bded24..be853b64a5 100644 --- a/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx +++ b/web/components/issues/issue-layouts/roots/all-issue-layout-root.tsx @@ -3,6 +3,7 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import useSWR from "swr"; import isEmpty from "lodash/isEmpty"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useGlobalView, useIssues, useProject, useUser } from "hooks/store"; import { useWorkspaceIssueProperties } from "hooks/use-workspace-issue-properties"; @@ -25,6 +26,8 @@ export const AllIssueLayoutRoot: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, globalViewId } = router.query; + // theme + const { resolvedTheme } = useTheme(); //swr hook for fetching issue properties useWorkspaceIssueProperties(workspaceSlug); // store @@ -46,7 +49,8 @@ export const AllIssueLayoutRoot: React.FC = observer(() => { const currentView = isDefaultView ? groupedIssueIds.dataViewId : "custom-view"; const currentViewDetails = ALL_ISSUES_EMPTY_STATE_DETAILS[currentView as keyof typeof ALL_ISSUES_EMPTY_STATE_DETAILS]; - const emptyStateImage = getEmptyStateImagePath("all-issues", currentView, currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("all-issues", currentView, isLightMode); // filter init from the query params diff --git a/web/components/issues/peek-overview/properties.tsx b/web/components/issues/peek-overview/properties.tsx index 3b72a31fef..6aee23a23d 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
diff --git a/web/components/modules/modules-list-view.tsx b/web/components/modules/modules-list-view.tsx index 0708187c14..93b12d94c0 100644 --- a/web/components/modules/modules-list-view.tsx +++ b/web/components/modules/modules-list-view.tsx @@ -1,5 +1,6 @@ import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useModule, useUser } from "hooks/store"; import useLocalStorage from "hooks/use-local-storage"; @@ -15,6 +16,8 @@ export const ModulesListView: React.FC = observer(() => { // router const router = useRouter(); const { workspaceSlug, projectId, peekModule } = router.query; + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: commandPaletteStore } = useApplication(); const { @@ -25,7 +28,8 @@ export const ModulesListView: React.FC = observer(() => { const { storedValue: modulesView } = useLocalStorage("modules_view", "grid"); - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "modules", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "modules", isLightMode); const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; diff --git a/web/components/notifications/notification-header.tsx b/web/components/notifications/notification-header.tsx index dc92dc9d52..39bf0e8fb5 100644 --- a/web/components/notifications/notification-header.tsx +++ b/web/components/notifications/notification-header.tsx @@ -95,6 +95,7 @@ export const NotificationHeader: React.FC = (props) =>
} + closeOnSelect >
diff --git a/web/components/page-views/workspace-dashboard.tsx b/web/components/page-views/workspace-dashboard.tsx index fa5f7c2c12..3ae0b9e62a 100644 --- a/web/components/page-views/workspace-dashboard.tsx +++ b/web/components/page-views/workspace-dashboard.tsx @@ -1,4 +1,5 @@ import { useEffect } from "react"; +import { useTheme } from "next-themes"; import { observer } from "mobx-react-lite"; // hooks import { useApplication, useDashboard, useProject, useUser } from "hooks/store"; @@ -14,6 +15,8 @@ import { Spinner } from "@plane/ui"; import { EUserWorkspaceRoles } from "constants/workspace"; export const WorkspaceDashboardView = observer(() => { + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: { toggleCreateProjectModal }, @@ -28,7 +31,8 @@ export const WorkspaceDashboardView = observer(() => { const { homeDashboardId, fetchHomeDashboardWidgets } = useDashboard(); const { joinedProjectIds } = useProject(); - const emptyStateImage = getEmptyStateImagePath("onboarding", "dashboard", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("onboarding", "dashboard", isLightMode); const handleTourCompleted = () => { updateTourCompleted() diff --git a/web/components/pages/pages-list/list-view.tsx b/web/components/pages/pages-list/list-view.tsx index d1bde308d2..4b56347369 100644 --- a/web/components/pages/pages-list/list-view.tsx +++ b/web/components/pages/pages-list/list-view.tsx @@ -1,5 +1,6 @@ import { FC } from "react"; import { useRouter } from "next/router"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useUser } from "hooks/store"; import useLocalStorage from "hooks/use-local-storage"; @@ -18,7 +19,9 @@ type IPagesListView = { export const PagesListView: FC = (props) => { const { pageIds: projectPageIds } = props; - + // theme + const { resolvedTheme } = useTheme(); + // store hooks const { commandPalette: { toggleCreatePageModal }, } = useApplication(); @@ -36,11 +39,8 @@ export const PagesListView: FC = (props) => { ? PAGE_EMPTY_STATE_DETAILS[pageTab as keyof typeof PAGE_EMPTY_STATE_DETAILS] : PAGE_EMPTY_STATE_DETAILS["All"]; - const emptyStateImage = getEmptyStateImagePath( - "pages", - currentPageTabDetails.key, - currentUser?.theme.theme === "light" - ); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("pages", currentPageTabDetails.key, isLightMode); const isButtonVisible = currentPageTabDetails.key !== "archived" && currentPageTabDetails.key !== "favorites"; diff --git a/web/components/pages/pages-list/recent-pages-list.tsx b/web/components/pages/pages-list/recent-pages-list.tsx index 24916debc0..960d5253bd 100644 --- a/web/components/pages/pages-list/recent-pages-list.tsx +++ b/web/components/pages/pages-list/recent-pages-list.tsx @@ -1,5 +1,6 @@ import React, { FC } from "react"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useUser } from "hooks/store"; import { useProjectPages } from "hooks/store/use-project-specific-pages"; @@ -14,6 +15,8 @@ import { replaceUnderscoreIfSnakeCase } from "helpers/string.helper"; import { EUserProjectRoles } from "constants/project"; export const RecentPagesList: FC = observer(() => { + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: commandPaletteStore } = useApplication(); const { @@ -22,7 +25,8 @@ export const RecentPagesList: FC = observer(() => { } = useUser(); const { recentProjectPages } = useProjectPages(); - const EmptyStateImagePath = getEmptyStateImagePath("pages", "recent", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("pages", "recent", isLightMode); // FIXME: replace any with proper type const isEmpty = recentProjectPages && Object.values(recentProjectPages).every((value: any) => value.length === 0); diff --git a/web/components/profile/profile-issues.tsx b/web/components/profile/profile-issues.tsx index 4b37211034..81c9b141c9 100644 --- a/web/components/profile/profile-issues.tsx +++ b/web/components/profile/profile-issues.tsx @@ -2,6 +2,7 @@ import React from "react"; import { useRouter } from "next/router"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // components import { ProfileIssuesListLayout } from "components/issues/issue-layouts/list/roots/profile-issues-root"; import { ProfileIssuesKanBanLayout } from "components/issues/issue-layouts/kanban/roots/profile-issues-root"; @@ -27,6 +28,9 @@ export const ProfileIssuesPage = observer((props: IProfileIssuesPage) => { workspaceSlug: string; userId: string; }; + // theme + const { resolvedTheme } = useTheme(); + // store hooks const { membership: { currentWorkspaceRole }, currentUser, @@ -46,7 +50,8 @@ export const ProfileIssuesPage = observer((props: IProfileIssuesPage) => { } ); - const emptyStateImage = getEmptyStateImagePath("profile", type, currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("profile", type, isLightMode); const activeLayout = issueFilters?.displayFilters?.layout || undefined; diff --git a/web/components/project/card-list.tsx b/web/components/project/card-list.tsx index ebb166f494..76e67e1b70 100644 --- a/web/components/project/card-list.tsx +++ b/web/components/project/card-list.tsx @@ -1,16 +1,17 @@ import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useProject, useUser } from "hooks/store"; // components import { ProjectCard } from "components/project"; import { Loader } from "@plane/ui"; import { EmptyState, getEmptyStateImagePath } from "components/empty-state"; -// icons -import { Plus } from "lucide-react"; // constants import { EUserWorkspaceRoles } from "constants/workspace"; export const ProjectCardList = observer(() => { + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: commandPaletteStore, @@ -22,7 +23,8 @@ export const ProjectCardList = observer(() => { } = useUser(); const { workspaceProjectIds, searchedProjects, getProjectById } = useProject(); - const emptyStateImage = getEmptyStateImagePath("onboarding", "projects", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const emptyStateImage = getEmptyStateImagePath("onboarding", "projects", isLightMode); const isEditingAllowed = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER; diff --git a/web/components/project/sidebar-list.tsx b/web/components/project/sidebar-list.tsx index 24735e5060..5452c861df 100644 --- a/web/components/project/sidebar-list.tsx +++ b/web/components/project/sidebar-list.tsx @@ -206,7 +206,7 @@ export const ProjectSidebarList: FC = observer(() => { type="button" className="group flex w-full items-center gap-1 whitespace-nowrap rounded px-1.5 text-left text-sm font-semibold text-custom-sidebar-text-400 hover:bg-custom-sidebar-background-80" > - Projects + Your projects {open ? ( ) : ( diff --git a/web/components/views/views-list.tsx b/web/components/views/views-list.tsx index 6b3b3e45aa..13ad104419 100644 --- a/web/components/views/views-list.tsx +++ b/web/components/views/views-list.tsx @@ -1,6 +1,7 @@ import { useState } from "react"; import { observer } from "mobx-react-lite"; import { Search } from "lucide-react"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useProjectView, useUser } from "hooks/store"; // components @@ -14,6 +15,8 @@ import { EUserProjectRoles } from "constants/project"; export const ProjectViewsList = observer(() => { // states const [query, setQuery] = useState(""); + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: { toggleCreateViewModal }, @@ -43,7 +46,8 @@ export const ProjectViewsList = observer(() => { const viewsList = projectViewIds.map((viewId) => getViewById(viewId)); - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "views", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "views", isLightMode); const filteredViewsList = viewsList.filter((v) => v?.name.toLowerCase().includes(query.toLowerCase())); diff --git a/web/constants/issue.ts b/web/constants/issue.ts index f351b25f14..378123f3a0 100644 --- a/web/constants/issue.ts +++ b/web/constants/issue.ts @@ -304,7 +304,17 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: { }, my_issues: { spreadsheet: { - filters: ["priority", "state_group", "labels", "assignees", "created_by", "project", "start_date", "target_date"], + filters: [ + "priority", + "state_group", + "labels", + "assignees", + "created_by", + "subscriber", + "project", + "start_date", + "target_date", + ], display_properties: true, display_filters: { type: [null, "active", "backlog"], diff --git a/web/hooks/use-user-notifications.tsx b/web/hooks/use-user-notifications.tsx index e8a0c1d34c..17a2c63dcc 100644 --- a/web/hooks/use-user-notifications.tsx +++ b/web/hooks/use-user-notifications.tsx @@ -264,6 +264,13 @@ const useUserNotification = () => { await userNotificationServices .markAllNotificationsAsRead(workspaceSlug.toString(), markAsReadParams) + .then(() => { + setToastAlert({ + type: "success", + title: "Success!", + message: "All Notifications marked as read.", + }); + }) .catch(() => { setToastAlert({ type: "error", diff --git a/web/pages/[workspaceSlug]/analytics.tsx b/web/pages/[workspaceSlug]/analytics.tsx index fcaef9f70b..3d6d501f2e 100644 --- a/web/pages/[workspaceSlug]/analytics.tsx +++ b/web/pages/[workspaceSlug]/analytics.tsx @@ -1,6 +1,7 @@ import React, { Fragment, ReactElement } from "react"; import { observer } from "mobx-react-lite"; import { Tab } from "@headlessui/react"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useProject, useUser } from "hooks/store"; // layouts @@ -16,6 +17,8 @@ import { EUserWorkspaceRoles } from "constants/workspace"; import { NextPageWithLayout } from "lib/types"; const AnalyticsPage: NextPageWithLayout = observer(() => { + // theme + const { resolvedTheme } = useTheme(); // store hooks const { commandPalette: { toggleCreateProjectModal }, @@ -27,7 +30,8 @@ const AnalyticsPage: NextPageWithLayout = observer(() => { } = useUser(); const { workspaceProjectIds } = useProject(); - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "analytics", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "analytics", isLightMode); const isEditingAllowed = !!currentWorkspaceRole && currentWorkspaceRole >= EUserWorkspaceRoles.MEMBER; return ( diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index c007773192..d0dbb35147 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -2,6 +2,7 @@ import { Fragment, useCallback, useState, ReactElement } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; import { Tab } from "@headlessui/react"; +import { useTheme } from "next-themes"; // hooks import { useCycle, useUser } from "hooks/store"; import useLocalStorage from "hooks/use-local-storage"; @@ -22,6 +23,8 @@ import { EUserWorkspaceRoles } from "constants/workspace"; const ProjectCyclesPage: NextPageWithLayout = observer(() => { const [createModal, setCreateModal] = useState(false); + // theme + const { resolvedTheme } = useTheme(); // store hooks const { membership: { currentProjectRole }, @@ -49,7 +52,9 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { }, [handleCurrentLayout, setCycleTab] ); - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "cycles", currentUser?.theme.theme === "light"); + + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "cycles", isLightMode); const totalCycles = currentProjectCycleIds?.length ?? 0; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx index 32299747fc..10cda05e12 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/index.tsx @@ -4,6 +4,7 @@ import dynamic from "next/dynamic"; import { Tab } from "@headlessui/react"; import useSWR from "swr"; import { observer } from "mobx-react-lite"; +import { useTheme } from "next-themes"; // hooks import { useApplication, useUser } from "hooks/store"; import useLocalStorage from "hooks/use-local-storage"; @@ -48,7 +49,9 @@ const ProjectPagesPage: NextPageWithLayout = observer(() => { const { workspaceSlug, projectId } = router.query; // states const [createUpdatePageModal, setCreateUpdatePageModal] = useState(false); - // store + // theme + const { resolvedTheme } = useTheme(); + // store hooks const { currentUser, currentUserLoader, @@ -94,7 +97,8 @@ const ProjectPagesPage: NextPageWithLayout = observer(() => { } }; - const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "pages", currentUser?.theme.theme === "light"); + const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser?.theme.theme === "light"; + const EmptyStateImagePath = getEmptyStateImagePath("onboarding", "pages", isLightMode); const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserWorkspaceRoles.MEMBER; diff --git a/web/store/issue/helpers/issue-filter-helper.store.ts b/web/store/issue/helpers/issue-filter-helper.store.ts index f3a4456fb6..ac89c5018e 100644 --- a/web/store/issue/helpers/issue-filter-helper.store.ts +++ b/web/store/issue/helpers/issue-filter-helper.store.ts @@ -76,6 +76,8 @@ export class IssueFilterHelperStore implements IIssueFilterHelperStore { labels: filters?.labels || undefined, start_date: filters?.start_date || undefined, target_date: filters?.target_date || undefined, + project: filters.project || undefined, + subscriber: filters.subscriber || undefined, // display filters type: displayFilters?.type || undefined, sub_issue: displayFilters?.sub_issue ?? true,