chore: added None filter option to the dashboard widgets (#3556)

* chore: added tab change animation

* chore: widgets filtering logic updated

* refactor: issues list widget

* fix: tab navigation transition

* fix: extra top spacing on opening the peek overview
This commit is contained in:
Aaryan Khandelwal 2024-02-05 19:12:33 +05:30 committed by GitHub
parent ee0e3e2e25
commit 0ee93dfd8c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 270 additions and 147 deletions

View File

@ -145,6 +145,23 @@ def dashboard_assigned_issues(self, request, slug):
)
).order_by("priority_order")
if issue_type == "pending":
pending_issues_count = assigned_issues.filter(
state__group__in=["backlog", "started", "unstarted"]
).count()
pending_issues = assigned_issues.filter(
state__group__in=["backlog", "started", "unstarted"]
)[:5]
return Response(
{
"issues": IssueSerializer(
pending_issues, many=True, expand=self.expand
).data,
"count": pending_issues_count,
},
status=status.HTTP_200_OK,
)
if issue_type == "completed":
completed_issues_count = assigned_issues.filter(
state__group__in=["completed"]
@ -257,6 +274,23 @@ def dashboard_created_issues(self, request, slug):
)
).order_by("priority_order")
if issue_type == "pending":
pending_issues_count = created_issues.filter(
state__group__in=["backlog", "started", "unstarted"]
).count()
pending_issues = created_issues.filter(
state__group__in=["backlog", "started", "unstarted"]
)[:5]
return Response(
{
"issues": IssueSerializer(
pending_issues, many=True, expand=self.expand
).data,
"count": pending_issues_count,
},
status=status.HTTP_200_OK,
)
if issue_type == "completed":
completed_issues_count = created_issues.filter(
state__group__in=["completed"]

View File

@ -13,9 +13,10 @@ export type TWidgetKeys =
| "recent_projects"
| "recent_collaborators";
export type TIssuesListTypes = "upcoming" | "overdue" | "completed";
export type TIssuesListTypes = "pending" | "upcoming" | "overdue" | "completed";
export type TDurationFilterOptions =
| "none"
| "today"
| "this_week"
| "this_month"

View File

@ -17,7 +17,7 @@ import { getCustomDates, getRedirectionFilters } from "helpers/dashboard.helper"
// types
import { TAssignedIssuesWidgetFilters, TAssignedIssuesWidgetResponse } from "@plane/types";
// constants
import { ISSUES_TABS_LIST } from "constants/dashboard";
import { FILTERED_ISSUES_TABS_LIST, UNFILTERED_ISSUES_TABS_LIST } from "constants/dashboard";
const WIDGET_KEY = "assigned_issues";
@ -30,6 +30,8 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
// derived values
const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY);
const widgetStats = getWidgetStats<TAssignedIssuesWidgetResponse>(workspaceSlug, dashboardId, WIDGET_KEY);
const selectedTab = widgetDetails?.widget_filters.tab ?? "pending";
const selectedDurationFilter = widgetDetails?.widget_filters.target_date ?? "none";
const handleUpdateFilters = async (filters: Partial<TAssignedIssuesWidgetFilters>) => {
if (!widgetDetails) return;
@ -41,68 +43,79 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
filters,
});
const filterDates = getCustomDates(filters.target_date ?? selectedDurationFilter);
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
issue_type: filters.tab ?? widgetDetails.widget_filters.tab ?? "upcoming",
target_date: getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "this_week"),
issue_type: filters.tab ?? selectedTab,
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
expand: "issue_relation",
}).finally(() => setFetching(false));
};
useEffect(() => {
const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week");
const filterDates = getCustomDates(selectedDurationFilter);
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
issue_type: widgetDetails?.widget_filters.tab ?? "upcoming",
target_date: filterDates,
issue_type: selectedTab,
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
expand: "issue_relation",
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
const filterParams = getRedirectionFilters(selectedTab);
const tabsList = selectedDurationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
<div className="flex items-start justify-between gap-2 p-6 pl-7">
<div>
<Link
href={`/${workspaceSlug}/workspace-views/assigned/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned to you
</Link>
<p className="mt-3 text-xs font-medium text-custom-text-300">
Filtered by{" "}
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
</p>
</div>
<div className="flex items-center justify-between gap-2 p-6 pl-7">
<Link
href={`/${workspaceSlug}/workspace-views/assigned/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned to you
</Link>
<DurationFilterDropdown
value={widgetDetails.widget_filters.target_date ?? "this_week"}
onChange={(val) =>
handleUpdateFilters({
target_date: val,
})
}
value={selectedDurationFilter}
onChange={(val) => {
if (val === selectedDurationFilter) return;
// switch to pending tab if target date is changed to none
if (val === "none" && selectedTab !== "completed") {
handleUpdateFilters({ target_date: val, tab: "pending" });
return;
}
// switch to upcoming tab if target date is changed to other than none
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") {
handleUpdateFilters({
target_date: val,
tab: "upcoming",
});
return;
}
handleUpdateFilters({ target_date: val });
}}
/>
</div>
<Tab.Group
as="div"
defaultIndex={ISSUES_TABS_LIST.findIndex((t) => t.key === widgetDetails.widget_filters.tab ?? "upcoming")}
selectedIndex={tabsList.findIndex((tab) => tab.key === selectedTab)}
onChange={(i) => {
const selectedTab = ISSUES_TABS_LIST[i];
handleUpdateFilters({ tab: selectedTab.key ?? "upcoming" });
const selectedTab = tabsList[i];
handleUpdateFilters({ tab: selectedTab?.key ?? "pending" });
}}
className="h-full flex flex-col"
>
<div className="px-6">
<TabsList />
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
</div>
<Tab.Panels as="div" className="h-full">
{ISSUES_TABS_LIST.map((tab) => (
{tabsList.map((tab) => (
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
<WidgetIssuesList
issues={widgetStats.issues}

View File

@ -17,7 +17,7 @@ import { getCustomDates, getRedirectionFilters } from "helpers/dashboard.helper"
// types
import { TCreatedIssuesWidgetFilters, TCreatedIssuesWidgetResponse } from "@plane/types";
// constants
import { ISSUES_TABS_LIST } from "constants/dashboard";
import { FILTERED_ISSUES_TABS_LIST, UNFILTERED_ISSUES_TABS_LIST } from "constants/dashboard";
const WIDGET_KEY = "created_issues";
@ -30,6 +30,8 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
// derived values
const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY);
const widgetStats = getWidgetStats<TCreatedIssuesWidgetResponse>(workspaceSlug, dashboardId, WIDGET_KEY);
const selectedTab = widgetDetails?.widget_filters.tab ?? "pending";
const selectedDurationFilter = widgetDetails?.widget_filters.target_date ?? "none";
const handleUpdateFilters = async (filters: Partial<TCreatedIssuesWidgetFilters>) => {
if (!widgetDetails) return;
@ -41,64 +43,76 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
filters,
});
const filterDates = getCustomDates(filters.target_date ?? selectedDurationFilter);
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
issue_type: filters.tab ?? widgetDetails.widget_filters.tab ?? "upcoming",
target_date: getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "this_week"),
issue_type: filters.tab ?? selectedTab,
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
}).finally(() => setFetching(false));
};
useEffect(() => {
const filterDates = getCustomDates(selectedDurationFilter);
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
issue_type: widgetDetails?.widget_filters.tab ?? "upcoming",
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
issue_type: selectedTab,
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const filterParams = getRedirectionFilters(widgetDetails?.widget_filters.tab ?? "upcoming");
const filterParams = getRedirectionFilters(selectedTab);
const tabsList = selectedDurationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full hover:shadow-custom-shadow-4xl duration-300 flex flex-col min-h-96">
<div className="flex items-start justify-between gap-2 p-6 pl-7">
<div>
<Link
href={`/${workspaceSlug}/workspace-views/created/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Created by you
</Link>
<p className="mt-3 text-xs font-medium text-custom-text-300">
Filtered by{" "}
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
</p>
</div>
<div className="flex items-center justify-between gap-2 p-6 pl-7">
<Link
href={`/${workspaceSlug}/workspace-views/created/${filterParams}`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Created by you
</Link>
<DurationFilterDropdown
value={widgetDetails.widget_filters.target_date ?? "this_week"}
onChange={(val) =>
handleUpdateFilters({
target_date: val,
})
}
value={selectedDurationFilter}
onChange={(val) => {
if (val === selectedDurationFilter) return;
// switch to pending tab if target date is changed to none
if (val === "none" && selectedTab !== "completed") {
handleUpdateFilters({ target_date: val, tab: "pending" });
return;
}
// switch to upcoming tab if target date is changed to other than none
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") {
handleUpdateFilters({
target_date: val,
tab: "upcoming",
});
return;
}
handleUpdateFilters({ target_date: val });
}}
/>
</div>
<Tab.Group
as="div"
defaultIndex={ISSUES_TABS_LIST.findIndex((t) => t.key === widgetDetails.widget_filters.tab ?? "upcoming")}
selectedIndex={tabsList.findIndex((tab) => tab.key === selectedTab)}
onChange={(i) => {
const selectedTab = ISSUES_TABS_LIST[i];
handleUpdateFilters({ tab: selectedTab.key ?? "upcoming" });
const selectedTab = tabsList[i];
handleUpdateFilters({ tab: selectedTab.key ?? "pending" });
}}
className="h-full flex flex-col"
>
<div className="px-6">
<TabsList />
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
</div>
<Tab.Panels as="div" className="h-full">
{ISSUES_TABS_LIST.map((tab) => (
{tabsList.map((tab) => (
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
<WidgetIssuesList
issues={widgetStats.issues}

View File

@ -14,7 +14,7 @@ import {
IssueListItemProps,
} from "components/dashboard/widgets";
// ui
import { Loader, getButtonStyling } from "@plane/ui";
import { getButtonStyling } from "@plane/ui";
// helpers
import { cn } from "helpers/common.helper";
import { getRedirectionFilters } from "helpers/dashboard.helper";
@ -41,16 +41,18 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
const filterParams = getRedirectionFilters(tab);
const ISSUE_LIST_ITEM: {
[key in string]: {
[key: string]: {
[key in TIssuesListTypes]: React.FC<IssueListItemProps>;
};
} = {
assigned: {
pending: AssignedUpcomingIssueListItem,
upcoming: AssignedUpcomingIssueListItem,
overdue: AssignedOverdueIssueListItem,
completed: AssignedCompletedIssueListItem,
},
created: {
pending: CreatedUpcomingIssueListItem,
upcoming: CreatedUpcomingIssueListItem,
overdue: CreatedOverdueIssueListItem,
completed: CreatedCompletedIssueListItem,
@ -61,12 +63,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
<>
<div className="h-full">
{isLoading ? (
<Loader className="mt-7 mx-6 space-y-4">
<Loader.Item height="25px" />
<Loader.Item height="25px" />
<Loader.Item height="25px" />
<Loader.Item height="25px" />
</Loader>
<></>
) : issues.length > 0 ? (
<>
<div className="mt-7 mx-6 border-b-[0.5px] border-custom-border-200 grid grid-cols-6 gap-1 text-xs text-custom-text-300 pb-1">
@ -81,7 +78,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
{totalIssues}
</span>
</h6>
{tab === "upcoming" && <h6 className="text-center">Due date</h6>}
{["upcoming", "pending"].includes(tab) && <h6 className="text-center">Due date</h6>}
{tab === "overdue" && <h6 className="text-center">Due by</h6>}
{type === "assigned" && tab !== "completed" && <h6 className="text-center">Blocked by</h6>}
{type === "created" && <h6 className="text-center">Assigned to</h6>}

View File

@ -1,26 +1,63 @@
import { observer } from "mobx-react";
import { Tab } from "@headlessui/react";
// helpers
import { cn } from "helpers/common.helper";
// types
import { TDurationFilterOptions, TIssuesListTypes } from "@plane/types";
// constants
import { ISSUES_TABS_LIST } from "constants/dashboard";
import { FILTERED_ISSUES_TABS_LIST, UNFILTERED_ISSUES_TABS_LIST } from "constants/dashboard";
export const TabsList = () => (
<Tab.List
as="div"
className="border-[0.5px] border-custom-border-200 rounded grid grid-cols-3 bg-custom-background-80"
>
{ISSUES_TABS_LIST.map((tab) => (
<Tab
key={tab.key}
className={({ selected }) =>
cn("font-semibold text-xs rounded py-1.5 focus:outline-none", {
"bg-custom-background-100 text-custom-text-300 shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selected,
"text-custom-text-400": !selected,
})
}
>
{tab.label}
</Tab>
))}
</Tab.List>
);
type Props = {
durationFilter: TDurationFilterOptions;
selectedTab: TIssuesListTypes;
};
export const TabsList: React.FC<Props> = observer((props) => {
const { durationFilter, selectedTab } = props;
const tabsList = durationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
const selectedTabIndex = tabsList.findIndex((tab) => tab.key === (selectedTab ?? "pending"));
return (
<Tab.List
as="div"
className="relative border-[0.5px] border-custom-border-200 rounded bg-custom-background-80 grid"
style={{
gridTemplateColumns: `repeat(${tabsList.length}, 1fr)`,
}}
>
<div
className={cn("absolute bg-custom-background-100 rounded transition-all duration-500 ease-in-out", {
// right shadow
"shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== tabsList.length - 1,
// left shadow
"shadow-[-2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== 0,
})}
style={{
height: "calc(100% - 1px)",
width: `${100 / tabsList.length}%`,
transform: `translateX(${selectedTabIndex * 100}%)`,
}}
/>
{tabsList.map((tab) => (
<Tab
key={tab.key}
className={cn(
"relative z-[1] font-semibold text-xs rounded py-1.5 text-custom-text-400 focus:outline-none",
"transition duration-500",
{
"text-custom-text-100 bg-custom-background-100": selectedTab === tab.key,
"hover:text-custom-text-300": selectedTab !== tab.key,
// // right shadow
// "shadow-[2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== tabsList.length - 1,
// // left shadow
// "shadow-[-2px_0_8px_rgba(167,169,174,0.15)]": selectedTabIndex !== 0,
}
)}
>
<span className="scale-110">{tab.label}</span>
</Tab>
))}
</Tab.List>
);
});

View File

@ -84,16 +84,18 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
filters,
});
const filterDates = getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "none");
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
target_date: getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "this_week"),
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
});
};
useEffect(() => {
const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "none");
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@ -129,21 +131,15 @@ export const IssuesByPriorityWidget: React.FC<WidgetProps> = observer((props) =>
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden min-h-96 flex flex-col">
<div className="flex items-start justify-between gap-2 pl-7 pr-6">
<div>
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned by priority
</Link>
<p className="mt-3 text-xs font-medium text-custom-text-300">
Filtered by{" "}
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
</p>
</div>
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned by priority
</Link>
<DurationFilterDropdown
value={widgetDetails.widget_filters.target_date ?? "this_week"}
value={widgetDetails.widget_filters.target_date ?? "none"}
onChange={(val) =>
handleUpdateFilters({
target_date: val,

View File

@ -43,17 +43,19 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
filters,
});
const filterDates = getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "none");
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
target_date: getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "this_week"),
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
});
};
// fetch widget stats
useEffect(() => {
const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "none");
fetchWidgetStats(workspaceSlug, dashboardId, {
widget_key: WIDGET_KEY,
target_date: getCustomDates(widgetDetails?.widget_filters.target_date ?? "this_week"),
...(filterDates.trim() !== "" ? { target_date: filterDates } : {}),
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@ -72,14 +74,14 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
startedCount > 0
? "started"
: unStartedCount > 0
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
? "unstarted"
: backlogCount > 0
? "backlog"
: completedCount > 0
? "completed"
: canceledCount > 0
? "cancelled"
: null;
setActiveStateGroup(stateGroup);
setDefaultStateGroup(stateGroup);
@ -128,21 +130,15 @@ export const IssuesByStateGroupWidget: React.FC<WidgetProps> = observer((props)
return (
<div className="bg-custom-background-100 rounded-xl border-[0.5px] border-custom-border-200 w-full py-6 hover:shadow-custom-shadow-4xl duration-300 overflow-hidden min-h-96 flex flex-col">
<div className="flex items-start justify-between gap-2 pl-7 pr-6">
<div>
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned by state
</Link>
<p className="mt-3 text-xs font-medium text-custom-text-300">
Filtered by{" "}
<span className="border-[0.5px] border-custom-border-300 rounded py-1 px-2 ml-0.5">Due date</span>
</p>
</div>
<div className="flex items-center justify-between gap-2 pl-7 pr-6">
<Link
href={`/${workspaceSlug}/workspace-views/assigned`}
className="text-lg font-semibold text-custom-text-300 hover:underline"
>
Assigned by state
</Link>
<DurationFilterDropdown
value={widgetDetails.widget_filters.target_date ?? "this_week"}
value={widgetDetails.widget_filters.target_date ?? "none"}
onChange={(val) =>
handleUpdateFilters({
target_date: val,

View File

@ -62,16 +62,18 @@ export const WorkspaceDashboardView = observer(() => {
{homeDashboardId && joinedProjectIds ? (
<>
{joinedProjectIds.length > 0 ? (
<div className="flex h-full w-full flex-col space-y-7 overflow-y-auto bg-custom-background-90 p-7">
<>
<IssuePeekOverview />
{currentUser && <UserGreetingsView user={currentUser} />}
{currentUser && !currentUser.is_tour_completed && (
<div className="fixed left-0 top-0 z-20 grid h-full w-full place-items-center bg-custom-backdrop bg-opacity-50 transition-opacity">
<TourRoot onComplete={handleTourCompleted} />
</div>
)}
<DashboardWidgets />
</div>
<div className="space-y-7 p-7 bg-custom-background-90 h-full w-full flex flex-col overflow-y-auto">
{currentUser && <UserGreetingsView user={currentUser} />}
{currentUser && !currentUser.is_tour_completed && (
<div className="fixed left-0 top-0 z-20 grid h-full w-full place-items-center bg-custom-backdrop bg-opacity-50 transition-opacity">
<TourRoot onComplete={handleTourCompleted} />
</div>
)}
<DashboardWidgets />
</div>
</>
) : (
<EmptyState
image={emptyStateImage}

View File

@ -121,21 +121,25 @@ export const DURATION_FILTER_OPTIONS: {
key: TDurationFilterOptions;
label: string;
}[] = [
{
key: "none",
label: "None",
},
{
key: "today",
label: "Today",
label: "Due today",
},
{
key: "this_week",
label: "This week",
label: " Due this week",
},
{
key: "this_month",
label: "This month",
label: "Due this month",
},
{
key: "this_year",
label: "This year",
label: "Due this year",
},
];
@ -152,7 +156,7 @@ export const PROJECT_BACKGROUND_COLORS = [
];
// assigned and created issues widgets tabs list
export const ISSUES_TABS_LIST: {
export const FILTERED_ISSUES_TABS_LIST: {
key: TIssuesListTypes;
label: string;
}[] = [
@ -170,7 +174,27 @@ export const ISSUES_TABS_LIST: {
},
];
// assigned and created issues widgets tabs list
export const UNFILTERED_ISSUES_TABS_LIST: {
key: TIssuesListTypes;
label: string;
}[] = [
{
key: "pending",
label: "Pending",
},
{
key: "completed",
label: "Marked completed",
},
];
export const ASSIGNED_ISSUES_EMPTY_STATES = {
pending: {
title: "Issues assigned to you that are pending\nwill show up here.",
darkImage: UpcomingIssuesDark,
lightImage: UpcomingIssuesLight,
},
upcoming: {
title: "Upcoming issues assigned to\nyou will show up here.",
darkImage: UpcomingIssuesDark,
@ -189,6 +213,11 @@ export const ASSIGNED_ISSUES_EMPTY_STATES = {
};
export const CREATED_ISSUES_EMPTY_STATES = {
pending: {
title: "Issues created by you that are pending\nwill show up here.",
darkImage: UpcomingIssuesDark,
lightImage: UpcomingIssuesLight,
},
upcoming: {
title: "Upcoming issues you created\nwill show up here.",
darkImage: UpcomingIssuesDark,

View File

@ -9,6 +9,8 @@ export const getCustomDates = (duration: TDurationFilterOptions): string => {
let firstDay, lastDay;
switch (duration) {
case "none":
return "";
case "today":
firstDay = renderFormattedPayloadDate(today);
lastDay = renderFormattedPayloadDate(today);
@ -32,7 +34,9 @@ export const getRedirectionFilters = (type: TIssuesListTypes): string => {
const today = renderFormattedPayloadDate(new Date());
const filterParams =
type === "upcoming"
type === "pending"
? "?state_group=backlog,unstarted,started"
: type === "upcoming"
? `?target_date=${today};after`
: type === "overdue"
? `?target_date=${today};before`