From 2e129682b7b9e66c6115efd18ecb2b6d1b29397d Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 8 Feb 2024 17:57:22 +0530 Subject: [PATCH] fix: incorrect dashboard tab (#3597) * fix: incorrect dashboard tab * chore: added comments for the helper functions * style: updated tabs list UI * chore: default widget filters changed * fix: build errors --------- Co-authored-by: NarayanBavisetti --- .../db/migrations/0059_auto_20240208_0957.py | 33 +++++++++++++++++++ packages/types/src/dashboard.d.ts | 8 ++--- .../dashboard/widgets/assigned-issues.tsx | 14 ++++---- .../dashboard/widgets/created-issues.tsx | 14 ++++---- .../widgets/issue-panels/tabs-list.tsx | 32 +++++++++--------- .../dashboard/widgets/issues-by-priority.tsx | 10 +++--- .../widgets/issues-by-state-group.tsx | 9 ++--- web/helpers/dashboard.helper.ts | 25 ++++++++++++++ 8 files changed, 102 insertions(+), 43 deletions(-) create mode 100644 apiserver/plane/db/migrations/0059_auto_20240208_0957.py diff --git a/apiserver/plane/db/migrations/0059_auto_20240208_0957.py b/apiserver/plane/db/migrations/0059_auto_20240208_0957.py new file mode 100644 index 0000000000..c4c43fa4bf --- /dev/null +++ b/apiserver/plane/db/migrations/0059_auto_20240208_0957.py @@ -0,0 +1,33 @@ +# Generated by Django 4.2.7 on 2024-02-08 09:57 + +from django.db import migrations + + +def widgets_filter_change(apps, schema_editor): + Widget = apps.get_model("db", "Widget") + widgets_to_update = [] + + # Define the filter dictionaries for each widget key + filters_mapping = { + "assigned_issues": {"duration": "none", "tab": "pending"}, + "created_issues": {"duration": "none", "tab": "pending"}, + "issues_by_state_groups": {"duration": "none"}, + "issues_by_priority": {"duration": "none"}, + } + + # Iterate over widgets and update filters if applicable + for widget in Widget.objects.all(): + if widget.key in filters_mapping: + widget.filters = filters_mapping[widget.key] + widgets_to_update.append(widget) + + # Bulk update the widgets + Widget.objects.bulk_update(widgets_to_update, ["filters"], batch_size=10) + +class Migration(migrations.Migration): + dependencies = [ + ('db', '0058_alter_moduleissue_issue_and_more'), + ] + operations = [ + migrations.RunPython(widgets_filter_change) + ] diff --git a/packages/types/src/dashboard.d.ts b/packages/types/src/dashboard.d.ts index 7cfa6aa856..407b5cd794 100644 --- a/packages/types/src/dashboard.d.ts +++ b/packages/types/src/dashboard.d.ts @@ -24,21 +24,21 @@ export type TDurationFilterOptions = // widget filters export type TAssignedIssuesWidgetFilters = { - target_date?: TDurationFilterOptions; + duration?: TDurationFilterOptions; tab?: TIssuesListTypes; }; export type TCreatedIssuesWidgetFilters = { - target_date?: TDurationFilterOptions; + duration?: TDurationFilterOptions; tab?: TIssuesListTypes; }; export type TIssuesByStateGroupsWidgetFilters = { - target_date?: TDurationFilterOptions; + duration?: TDurationFilterOptions; }; export type TIssuesByPriorityWidgetFilters = { - target_date?: TDurationFilterOptions; + duration?: TDurationFilterOptions; }; export type TWidgetFiltersFormData = diff --git a/web/components/dashboard/widgets/assigned-issues.tsx b/web/components/dashboard/widgets/assigned-issues.tsx index e2a54c05f6..ed6bac324d 100644 --- a/web/components/dashboard/widgets/assigned-issues.tsx +++ b/web/components/dashboard/widgets/assigned-issues.tsx @@ -13,7 +13,7 @@ import { WidgetProps, } from "components/dashboard/widgets"; // helpers -import { getCustomDates, getRedirectionFilters } from "helpers/dashboard.helper"; +import { getCustomDates, getRedirectionFilters, getTabKey } from "helpers/dashboard.helper"; // types import { TAssignedIssuesWidgetFilters, TAssignedIssuesWidgetResponse } from "@plane/types"; // constants @@ -30,8 +30,8 @@ export const AssignedIssuesWidget: React.FC = observer((props) => { // derived values const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); - const selectedTab = widgetDetails?.widget_filters.tab ?? "pending"; - const selectedDurationFilter = widgetDetails?.widget_filters.target_date ?? "none"; + const selectedDurationFilter = widgetDetails?.widget_filters.duration ?? "none"; + const selectedTab = getTabKey(selectedDurationFilter, widgetDetails?.widget_filters.tab); const handleUpdateFilters = async (filters: Partial) => { if (!widgetDetails) return; @@ -43,7 +43,7 @@ export const AssignedIssuesWidget: React.FC = observer((props) => { filters, }); - const filterDates = getCustomDates(filters.target_date ?? selectedDurationFilter); + const filterDates = getCustomDates(filters.duration ?? selectedDurationFilter); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, issue_type: filters.tab ?? selectedTab, @@ -86,19 +86,19 @@ export const AssignedIssuesWidget: React.FC = observer((props) => { // switch to pending tab if target date is changed to none if (val === "none" && selectedTab !== "completed") { - handleUpdateFilters({ target_date: val, tab: "pending" }); + handleUpdateFilters({ duration: 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, + duration: val, tab: "upcoming", }); return; } - handleUpdateFilters({ target_date: val }); + handleUpdateFilters({ duration: val }); }} /> diff --git a/web/components/dashboard/widgets/created-issues.tsx b/web/components/dashboard/widgets/created-issues.tsx index dcdff6685a..4ef5708c86 100644 --- a/web/components/dashboard/widgets/created-issues.tsx +++ b/web/components/dashboard/widgets/created-issues.tsx @@ -13,7 +13,7 @@ import { WidgetProps, } from "components/dashboard/widgets"; // helpers -import { getCustomDates, getRedirectionFilters } from "helpers/dashboard.helper"; +import { getCustomDates, getRedirectionFilters, getTabKey } from "helpers/dashboard.helper"; // types import { TCreatedIssuesWidgetFilters, TCreatedIssuesWidgetResponse } from "@plane/types"; // constants @@ -30,8 +30,8 @@ export const CreatedIssuesWidget: React.FC = observer((props) => { // derived values const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); - const selectedTab = widgetDetails?.widget_filters.tab ?? "pending"; - const selectedDurationFilter = widgetDetails?.widget_filters.target_date ?? "none"; + const selectedDurationFilter = widgetDetails?.widget_filters.duration ?? "none"; + const selectedTab = getTabKey(selectedDurationFilter, widgetDetails?.widget_filters.tab); const handleUpdateFilters = async (filters: Partial) => { if (!widgetDetails) return; @@ -43,7 +43,7 @@ export const CreatedIssuesWidget: React.FC = observer((props) => { filters, }); - const filterDates = getCustomDates(filters.target_date ?? selectedDurationFilter); + const filterDates = getCustomDates(filters.duration ?? selectedDurationFilter); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, issue_type: filters.tab ?? selectedTab, @@ -83,19 +83,19 @@ export const CreatedIssuesWidget: React.FC = observer((props) => { // switch to pending tab if target date is changed to none if (val === "none" && selectedTab !== "completed") { - handleUpdateFilters({ target_date: val, tab: "pending" }); + handleUpdateFilters({ duration: 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, + duration: val, tab: "upcoming", }); return; } - handleUpdateFilters({ target_date: val }); + handleUpdateFilters({ duration: val }); }} /> diff --git a/web/components/dashboard/widgets/issue-panels/tabs-list.tsx b/web/components/dashboard/widgets/issue-panels/tabs-list.tsx index 9ce00a03c5..306c2fdeb9 100644 --- a/web/components/dashboard/widgets/issue-panels/tabs-list.tsx +++ b/web/components/dashboard/widgets/issue-panels/tabs-list.tsx @@ -16,42 +16,40 @@ export const TabsList: React.FC = 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")); + const selectedTabIndex = tabsList.findIndex((tab) => tab.key === selectedTab); return (
{tabsList.map((tab) => ( diff --git a/web/components/dashboard/widgets/issues-by-priority.tsx b/web/components/dashboard/widgets/issues-by-priority.tsx index 97884bccc1..91e321b05f 100644 --- a/web/components/dashboard/widgets/issues-by-priority.tsx +++ b/web/components/dashboard/widgets/issues-by-priority.tsx @@ -73,8 +73,10 @@ export const IssuesByPriorityWidget: React.FC = observer((props) => const { dashboardId, workspaceSlug } = props; // store hooks const { fetchWidgetStats, getWidgetDetails, getWidgetStats, updateDashboardWidgetFilters } = useDashboard(); + // derived values const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); + const selectedDuration = widgetDetails?.widget_filters.duration ?? "none"; const handleUpdateFilters = async (filters: Partial) => { if (!widgetDetails) return; @@ -84,7 +86,7 @@ export const IssuesByPriorityWidget: React.FC = observer((props) => filters, }); - const filterDates = getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "none"); + const filterDates = getCustomDates(filters.duration ?? selectedDuration); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), @@ -92,7 +94,7 @@ export const IssuesByPriorityWidget: React.FC = observer((props) => }; useEffect(() => { - const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "none"); + const filterDates = getCustomDates(selectedDuration); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), @@ -139,10 +141,10 @@ export const IssuesByPriorityWidget: React.FC = observer((props) => Assigned by priority handleUpdateFilters({ - target_date: val, + duration: val, }) } /> diff --git a/web/components/dashboard/widgets/issues-by-state-group.tsx b/web/components/dashboard/widgets/issues-by-state-group.tsx index 2f7f6ffae8..a0eb6c70f8 100644 --- a/web/components/dashboard/widgets/issues-by-state-group.tsx +++ b/web/components/dashboard/widgets/issues-by-state-group.tsx @@ -34,6 +34,7 @@ export const IssuesByStateGroupWidget: React.FC = observer((props) // derived values const widgetDetails = getWidgetDetails(workspaceSlug, dashboardId, WIDGET_KEY); const widgetStats = getWidgetStats(workspaceSlug, dashboardId, WIDGET_KEY); + const selectedDuration = widgetDetails?.widget_filters.duration ?? "none"; const handleUpdateFilters = async (filters: Partial) => { if (!widgetDetails) return; @@ -43,7 +44,7 @@ export const IssuesByStateGroupWidget: React.FC = observer((props) filters, }); - const filterDates = getCustomDates(filters.target_date ?? widgetDetails.widget_filters.target_date ?? "none"); + const filterDates = getCustomDates(filters.duration ?? selectedDuration); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), @@ -52,7 +53,7 @@ export const IssuesByStateGroupWidget: React.FC = observer((props) // fetch widget stats useEffect(() => { - const filterDates = getCustomDates(widgetDetails?.widget_filters.target_date ?? "none"); + const filterDates = getCustomDates(selectedDuration); fetchWidgetStats(workspaceSlug, dashboardId, { widget_key: WIDGET_KEY, ...(filterDates.trim() !== "" ? { target_date: filterDates } : {}), @@ -138,10 +139,10 @@ export const IssuesByStateGroupWidget: React.FC = observer((props) Assigned by state handleUpdateFilters({ - target_date: val, + duration: val, }) } /> diff --git a/web/helpers/dashboard.helper.ts b/web/helpers/dashboard.helper.ts index 8003f15e32..90319a90b9 100644 --- a/web/helpers/dashboard.helper.ts +++ b/web/helpers/dashboard.helper.ts @@ -4,6 +4,10 @@ import { renderFormattedPayloadDate } from "./date-time.helper"; // types import { TDurationFilterOptions, TIssuesListTypes } from "@plane/types"; +/** + * @description returns date range based on the duration filter + * @param duration + */ export const getCustomDates = (duration: TDurationFilterOptions): string => { const today = new Date(); let firstDay, lastDay; @@ -30,6 +34,10 @@ export const getCustomDates = (duration: TDurationFilterOptions): string => { } }; +/** + * @description returns redirection filters for the issues list + * @param type + */ export const getRedirectionFilters = (type: TIssuesListTypes): string => { const today = renderFormattedPayloadDate(new Date()); @@ -44,3 +52,20 @@ export const getRedirectionFilters = (type: TIssuesListTypes): string => { return filterParams; }; + +/** + * @description returns the tab key based on the duration filter + * @param duration + * @param tab + */ +export const getTabKey = (duration: TDurationFilterOptions, tab: TIssuesListTypes | undefined): TIssuesListTypes => { + if (!tab) return "completed"; + + if (tab === "completed") return tab; + + if (duration === "none") return "pending"; + else { + if (["upcoming", "overdue"].includes(tab)) return tab; + else return "upcoming"; + } +};