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