forked from github/plane
fix: dashboard issues widget tab rendering bug (#3795)
This commit is contained in:
parent
e1ef830f39
commit
8b6206f28b
@ -67,6 +67,7 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
|
||||
const filterParams = getRedirectionFilters(selectedTab);
|
||||
const tabsList = selectedDurationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
|
||||
const selectedTabIndex = tabsList.findIndex((tab) => tab.key === selectedTab);
|
||||
|
||||
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||
|
||||
@ -84,30 +85,25 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
onChange={(val) => {
|
||||
if (val === selectedDurationFilter) return;
|
||||
|
||||
let newTab = selectedTab;
|
||||
// switch to pending tab if target date is changed to none
|
||||
if (val === "none" && selectedTab !== "completed") {
|
||||
handleUpdateFilters({ duration: val, tab: "pending" });
|
||||
return;
|
||||
}
|
||||
if (val === "none" && selectedTab !== "completed") newTab = "pending";
|
||||
// switch to upcoming tab if target date is changed to other than none
|
||||
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") {
|
||||
handleUpdateFilters({
|
||||
duration: val,
|
||||
tab: "upcoming",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") newTab = "upcoming";
|
||||
|
||||
handleUpdateFilters({ duration: val });
|
||||
handleUpdateFilters({
|
||||
duration: val,
|
||||
tab: newTab,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Tab.Group
|
||||
as="div"
|
||||
selectedIndex={tabsList.findIndex((tab) => tab.key === selectedTab)}
|
||||
selectedIndex={selectedTabIndex}
|
||||
onChange={(i) => {
|
||||
const selectedTab = tabsList[i];
|
||||
handleUpdateFilters({ tab: selectedTab?.key ?? "pending" });
|
||||
const newSelectedTab = tabsList[i];
|
||||
handleUpdateFilters({ tab: newSelectedTab?.key ?? "completed" });
|
||||
}}
|
||||
className="h-full flex flex-col"
|
||||
>
|
||||
@ -115,18 +111,21 @@ export const AssignedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
|
||||
</div>
|
||||
<Tab.Panels as="div" className="h-full">
|
||||
{tabsList.map((tab) => (
|
||||
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
|
||||
<WidgetIssuesList
|
||||
issues={widgetStats.issues}
|
||||
tab={tab.key}
|
||||
totalIssues={widgetStats.count}
|
||||
type="assigned"
|
||||
workspaceSlug={workspaceSlug}
|
||||
isLoading={fetching}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
))}
|
||||
{tabsList.map((tab) => {
|
||||
if (tab.key !== selectedTab) return null;
|
||||
|
||||
return (
|
||||
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col" static>
|
||||
<WidgetIssuesList
|
||||
tab={tab.key}
|
||||
type="assigned"
|
||||
workspaceSlug={workspaceSlug}
|
||||
widgetStats={widgetStats}
|
||||
isLoading={fetching}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
);
|
||||
})}
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
|
@ -64,6 +64,7 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
|
||||
const filterParams = getRedirectionFilters(selectedTab);
|
||||
const tabsList = selectedDurationFilter === "none" ? UNFILTERED_ISSUES_TABS_LIST : FILTERED_ISSUES_TABS_LIST;
|
||||
const selectedTabIndex = tabsList.findIndex((tab) => tab.key === selectedTab);
|
||||
|
||||
if (!widgetDetails || !widgetStats) return <WidgetLoader widgetKey={WIDGET_KEY} />;
|
||||
|
||||
@ -81,30 +82,25 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
onChange={(val) => {
|
||||
if (val === selectedDurationFilter) return;
|
||||
|
||||
let newTab = selectedTab;
|
||||
// switch to pending tab if target date is changed to none
|
||||
if (val === "none" && selectedTab !== "completed") {
|
||||
handleUpdateFilters({ duration: val, tab: "pending" });
|
||||
return;
|
||||
}
|
||||
if (val === "none" && selectedTab !== "completed") newTab = "pending";
|
||||
// switch to upcoming tab if target date is changed to other than none
|
||||
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") {
|
||||
handleUpdateFilters({
|
||||
duration: val,
|
||||
tab: "upcoming",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (val !== "none" && selectedDurationFilter === "none" && selectedTab !== "completed") newTab = "upcoming";
|
||||
|
||||
handleUpdateFilters({ duration: val });
|
||||
handleUpdateFilters({
|
||||
duration: val,
|
||||
tab: newTab,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Tab.Group
|
||||
as="div"
|
||||
selectedIndex={tabsList.findIndex((tab) => tab.key === selectedTab)}
|
||||
selectedIndex={selectedTabIndex}
|
||||
onChange={(i) => {
|
||||
const selectedTab = tabsList[i];
|
||||
handleUpdateFilters({ tab: selectedTab.key ?? "pending" });
|
||||
const newSelectedTab = tabsList[i];
|
||||
handleUpdateFilters({ tab: newSelectedTab.key ?? "completed" });
|
||||
}}
|
||||
className="h-full flex flex-col"
|
||||
>
|
||||
@ -112,18 +108,21 @@ export const CreatedIssuesWidget: React.FC<WidgetProps> = observer((props) => {
|
||||
<TabsList durationFilter={selectedDurationFilter} selectedTab={selectedTab} />
|
||||
</div>
|
||||
<Tab.Panels as="div" className="h-full">
|
||||
{tabsList.map((tab) => (
|
||||
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col">
|
||||
<WidgetIssuesList
|
||||
issues={widgetStats.issues}
|
||||
tab={tab.key}
|
||||
totalIssues={widgetStats.count}
|
||||
type="created"
|
||||
workspaceSlug={workspaceSlug}
|
||||
isLoading={fetching}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
))}
|
||||
{tabsList.map((tab) => {
|
||||
if (tab.key !== selectedTab) return null;
|
||||
|
||||
return (
|
||||
<Tab.Panel key={tab.key} as="div" className="h-full flex flex-col" static>
|
||||
<WidgetIssuesList
|
||||
tab={tab.key}
|
||||
type="created"
|
||||
workspaceSlug={workspaceSlug}
|
||||
widgetStats={widgetStats}
|
||||
isLoading={fetching}
|
||||
/>
|
||||
</Tab.Panel>
|
||||
);
|
||||
})}
|
||||
</Tab.Panels>
|
||||
</Tab.Group>
|
||||
</div>
|
||||
|
@ -19,19 +19,18 @@ import { Loader, getButtonStyling } from "@plane/ui";
|
||||
import { cn } from "helpers/common.helper";
|
||||
import { getRedirectionFilters } from "helpers/dashboard.helper";
|
||||
// types
|
||||
import { TIssue, TIssuesListTypes } from "@plane/types";
|
||||
import { TAssignedIssuesWidgetResponse, TCreatedIssuesWidgetResponse, TIssue, TIssuesListTypes } from "@plane/types";
|
||||
|
||||
export type WidgetIssuesListProps = {
|
||||
isLoading: boolean;
|
||||
issues: TIssue[];
|
||||
tab: TIssuesListTypes;
|
||||
totalIssues: number;
|
||||
type: "assigned" | "created";
|
||||
widgetStats: TAssignedIssuesWidgetResponse | TCreatedIssuesWidgetResponse;
|
||||
workspaceSlug: string;
|
||||
};
|
||||
|
||||
export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
const { isLoading, issues, tab, totalIssues, type, workspaceSlug } = props;
|
||||
const { isLoading, tab, type, widgetStats, workspaceSlug } = props;
|
||||
// store hooks
|
||||
const { setPeekIssue } = useIssueDetail();
|
||||
|
||||
@ -59,6 +58,8 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
},
|
||||
};
|
||||
|
||||
const issuesList = widgetStats.issues;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="h-full">
|
||||
@ -69,7 +70,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
<Loader.Item height="25px" />
|
||||
<Loader.Item height="25px" />
|
||||
</Loader>
|
||||
) : issues.length > 0 ? (
|
||||
) : issuesList.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">
|
||||
<h6
|
||||
@ -80,7 +81,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
>
|
||||
Issues
|
||||
<span className="flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 text-xs font-medium rounded-xl px-3 flex items-center text-center justify-center">
|
||||
{totalIssues}
|
||||
{widgetStats.count}
|
||||
</span>
|
||||
</h6>
|
||||
{["upcoming", "pending"].includes(tab) && <h6 className="text-center">Due date</h6>}
|
||||
@ -89,7 +90,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
{type === "created" && <h6 className="text-center">Assigned to</h6>}
|
||||
</div>
|
||||
<div className="px-4 pb-3 mt-2">
|
||||
{issues.map((issue) => {
|
||||
{issuesList.map((issue) => {
|
||||
const IssueListItem = ISSUE_LIST_ITEM[type][tab];
|
||||
|
||||
if (!IssueListItem) return null;
|
||||
@ -112,7 +113,7 @@ export const WidgetIssuesList: React.FC<WidgetIssuesListProps> = (props) => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{issues.length > 0 && (
|
||||
{!isLoading && issuesList.length > 0 && (
|
||||
<Link
|
||||
href={`/${workspaceSlug}/workspace-views/${type}/${filterParams}`}
|
||||
className={cn(
|
||||
|
Loading…
Reference in New Issue
Block a user