[WEB-4951] [WEB-4884] feat: work item filters revamp (#7810)
This commit is contained in:
parent
e6a7ca4c72
commit
9aef5d4aa9
160 changed files with 5879 additions and 4881 deletions
|
|
@ -14,19 +14,16 @@ import {
|
|||
EIssuesStoreType,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
TIssueLayouts,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
// ui
|
||||
import { CustomMenu } from "@plane/ui";
|
||||
// components
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { IssueLayoutIcon } from "@/components/issues/issue-layouts/layout-icon";
|
||||
// hooks
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
|
||||
export const ProfileIssuesMobileHeader = observer(() => {
|
||||
// plane i18n
|
||||
|
|
@ -37,14 +34,7 @@ export const ProfileIssuesMobileHeader = observer(() => {
|
|||
const {
|
||||
issuesFilter: { issueFilters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.PROFILE);
|
||||
|
||||
const { workspaceLabels } = useLabel();
|
||||
// derived values
|
||||
const states = undefined;
|
||||
// const members = undefined;
|
||||
// const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
// const states = undefined;
|
||||
const members = undefined;
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
|
|
@ -61,31 +51,6 @@ export const ProfileIssuesMobileHeader = observer(() => {
|
|||
[workspaceSlug, updateFilters, userId]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !userId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
undefined,
|
||||
EIssueFilterType.FILTERS,
|
||||
{ [key]: newValues },
|
||||
userId.toString()
|
||||
);
|
||||
},
|
||||
[workspaceSlug, issueFilters, updateFilters, userId]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !userId) return;
|
||||
|
|
@ -145,32 +110,6 @@ export const ProfileIssuesMobileHeader = observer(() => {
|
|||
);
|
||||
})}
|
||||
</CustomMenu>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title={t("common.filters")}
|
||||
placement="bottom-end"
|
||||
menuButton={
|
||||
<div className="flex flex-center text-sm text-custom-text-200">
|
||||
{t("common.filters")}
|
||||
<ChevronDown className="ml-2 h-4 w-4 text-custom-text-200" strokeWidth={2} />
|
||||
</div>
|
||||
}
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.profile_issues[activeLayout] : undefined
|
||||
}
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
states={states}
|
||||
labels={workspaceLabels}
|
||||
memberIds={members}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
</div>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title={t("common.display")}
|
||||
|
|
@ -184,7 +123,7 @@ export const ProfileIssuesMobileHeader = observer(() => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.profile_issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.profile_issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useCallback, useRef, useState } from "react";
|
|||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// icons
|
||||
import { ChartNoAxesColumn, ListFilter, PanelRight, SlidersHorizontal } from "lucide-react";
|
||||
import { ChartNoAxesColumn, PanelRight, SlidersHorizontal } from "lucide-react";
|
||||
// plane imports
|
||||
import {
|
||||
EIssueFilterType,
|
||||
|
|
@ -23,11 +23,10 @@ import {
|
|||
ICustomSearchSelectOption,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { Breadcrumbs, Button, BreadcrumbNavigationSearchDropdown, Header } from "@plane/ui";
|
||||
import { cn, isIssueFilterActive } from "@plane/utils";
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
|
||||
import { SwitcherLabel } from "@/components/common/switcher-label";
|
||||
|
|
@ -35,7 +34,6 @@ import { CycleQuickActions } from "@/components/cycles/quick-actions";
|
|||
import {
|
||||
DisplayFiltersSelection,
|
||||
FiltersDropdown,
|
||||
FilterSelection,
|
||||
LayoutSelection,
|
||||
MobileLayoutSelection,
|
||||
} from "@/components/issues/issue-layouts/filters";
|
||||
|
|
@ -43,10 +41,7 @@ import {
|
|||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
import { useCycle } from "@/hooks/store/use-cycle";
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import useLocalStorage from "@/hooks/use-local-storage";
|
||||
|
|
@ -75,11 +70,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||
const { currentProjectCycleIds, getCycleById } = useCycle();
|
||||
const { toggleCreateIssueModal } = useCommandPalette();
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const { projectStates } = useProjectState();
|
||||
const { projectLabels } = useLabel();
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
const { isMobile } = usePlatformOS();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
|
||||
|
|
@ -100,27 +90,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||
[workspaceSlug, projectId, cycleId, updateFilters]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { [key]: newValues }, cycleId);
|
||||
},
|
||||
[workspaceSlug, projectId, cycleId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
|
@ -239,27 +208,6 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||
activeLayout={activeLayout}
|
||||
/>
|
||||
</div>
|
||||
<FiltersDropdown
|
||||
title={t("common.filters")}
|
||||
placement="bottom-end"
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
miniIcon={<ListFilter className="size-3.5" />}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
<FiltersDropdown
|
||||
title={t("common.display")}
|
||||
placement="bottom-end"
|
||||
|
|
@ -267,7 +215,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -7,48 +7,39 @@ import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
|
|||
// plane imports
|
||||
import { EIssueFilterType, ISSUE_LAYOUTS, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import {
|
||||
EIssuesStoreType,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { EIssuesStoreType, IIssueDisplayFilterOptions, IIssueDisplayProperties, EIssueLayoutTypes } from "@plane/types";
|
||||
import { CustomMenu } from "@plane/ui";
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
// components
|
||||
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
|
||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { IssueLayoutIcon } from "@/components/issues/issue-layouts/layout-icon";
|
||||
// hooks
|
||||
import { useCycle } from "@/hooks/store/use-cycle";
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
|
||||
const SUPPORTED_LAYOUTS = [
|
||||
{ key: "list", titleTranslationKey: "issue.layouts.list", icon: List },
|
||||
{ key: "kanban", titleTranslationKey: "issue.layouts.kanban", icon: Kanban },
|
||||
{ key: "calendar", titleTranslationKey: "issue.layouts.calendar", icon: Calendar },
|
||||
];
|
||||
|
||||
export const CycleIssuesMobileHeader = () => {
|
||||
// i18n
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
const { getCycleById } = useCycle();
|
||||
const layouts = [
|
||||
{ key: "list", titleTranslationKey: "issue.layouts.list", icon: List },
|
||||
{ key: "kanban", titleTranslationKey: "issue.layouts.kanban", icon: Kanban },
|
||||
{ key: "calendar", titleTranslationKey: "issue.layouts.calendar", icon: Calendar },
|
||||
];
|
||||
|
||||
// router
|
||||
const { workspaceSlug, projectId, cycleId } = useParams();
|
||||
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
|
||||
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { getCycleById } = useCycle();
|
||||
const {
|
||||
issuesFilter: { issueFilters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.CYCLE);
|
||||
// derived values
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
|
|
@ -64,37 +55,6 @@ export const CycleIssuesMobileHeader = () => {
|
|||
[workspaceSlug, projectId, cycleId, updateFilters]
|
||||
);
|
||||
|
||||
const { projectStates } = useProjectState();
|
||||
const { projectLabels } = useLabel();
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
EIssueFilterType.FILTERS,
|
||||
{ [key]: newValues },
|
||||
cycleId.toString()
|
||||
);
|
||||
},
|
||||
[workspaceSlug, projectId, cycleId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||
|
|
@ -142,7 +102,7 @@ export const CycleIssuesMobileHeader = () => {
|
|||
customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm"
|
||||
closeOnSelect
|
||||
>
|
||||
{layouts.map((layout, index) => (
|
||||
{SUPPORTED_LAYOUTS.map((layout, index) => (
|
||||
<CustomMenu.MenuItem
|
||||
key={ISSUE_LAYOUTS[index].key}
|
||||
onClick={() => {
|
||||
|
|
@ -155,34 +115,6 @@ export const CycleIssuesMobileHeader = () => {
|
|||
</CustomMenu.MenuItem>
|
||||
))}
|
||||
</CustomMenu>
|
||||
<div className="flex flex-grow justify-center border-l border-custom-border-200 items-center text-custom-text-200 text-sm">
|
||||
<FiltersDropdown
|
||||
title={t("common.filters")}
|
||||
placement="bottom-end"
|
||||
menuButton={
|
||||
<span className="flex items-center text-custom-text-200 text-sm">
|
||||
{t("common.filters")}
|
||||
<ChevronDown className="text-custom-text-200 h-4 w-4 ml-2" />
|
||||
</span>
|
||||
}
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
</div>
|
||||
<div className="flex flex-grow justify-center border-l border-custom-border-200 items-center text-custom-text-200 text-sm">
|
||||
<FiltersDropdown
|
||||
title={t("common.display")}
|
||||
|
|
@ -196,7 +128,7 @@ export const CycleIssuesMobileHeader = () => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -7,28 +7,17 @@ import { ChevronDown } from "lucide-react";
|
|||
// plane imports
|
||||
import { EIssueFilterType, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import {
|
||||
EIssuesStoreType,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
import { EIssuesStoreType, IIssueDisplayFilterOptions, IIssueDisplayProperties, EIssueLayoutTypes } from "@plane/types";
|
||||
// components
|
||||
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
|
||||
import {
|
||||
DisplayFiltersSelection,
|
||||
FilterSelection,
|
||||
FiltersDropdown,
|
||||
MobileLayoutSelection,
|
||||
} from "@/components/issues/issue-layouts/filters";
|
||||
// hooks
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
|
||||
export const ProjectIssuesMobileHeader = observer(() => {
|
||||
// i18n
|
||||
|
|
@ -39,16 +28,11 @@ export const ProjectIssuesMobileHeader = observer(() => {
|
|||
projectId: string;
|
||||
};
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { projectStates } = useProjectState();
|
||||
const { projectLabels } = useLabel();
|
||||
|
||||
// store hooks
|
||||
const {
|
||||
issuesFilter: { issueFilters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.PROJECT);
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
|
|
@ -59,27 +43,6 @@ export const ProjectIssuesMobileHeader = observer(() => {
|
|||
[workspaceSlug, projectId, updateFilters]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { [key]: newValues });
|
||||
},
|
||||
[workspaceSlug, projectId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
|
@ -108,34 +71,6 @@ export const ProjectIssuesMobileHeader = observer(() => {
|
|||
layouts={[EIssueLayoutTypes.LIST, EIssueLayoutTypes.KANBAN, EIssueLayoutTypes.CALENDAR]}
|
||||
onChange={handleLayoutChange}
|
||||
/>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title={t("common.filters")}
|
||||
placement="bottom-end"
|
||||
menuButton={
|
||||
<span className="flex items-center text-sm text-custom-text-200">
|
||||
{t("common.filters")}
|
||||
<ChevronDown className="ml-2 h-4 w-4 text-custom-text-200" />
|
||||
</span>
|
||||
}
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
</div>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title={t("common.display")}
|
||||
|
|
@ -149,7 +84,7 @@ export const ProjectIssuesMobileHeader = observer(() => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { useCallback, useRef, useState } from "react";
|
|||
import { observer } from "mobx-react";
|
||||
import { useParams } from "next/navigation";
|
||||
// icons
|
||||
import { ChartNoAxesColumn, ListFilter, PanelRight, SlidersHorizontal } from "lucide-react";
|
||||
import { ChartNoAxesColumn, PanelRight, SlidersHorizontal } from "lucide-react";
|
||||
// plane imports
|
||||
import {
|
||||
EIssueFilterType,
|
||||
|
|
@ -21,18 +21,16 @@ import {
|
|||
ICustomSearchSelectOption,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { Breadcrumbs, Button, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
|
||||
import { cn, isIssueFilterActive } from "@plane/utils";
|
||||
import { cn } from "@plane/utils";
|
||||
// components
|
||||
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
|
||||
import { SwitcherLabel } from "@/components/common/switcher-label";
|
||||
import {
|
||||
DisplayFiltersSelection,
|
||||
FiltersDropdown,
|
||||
FilterSelection,
|
||||
LayoutSelection,
|
||||
MobileLayoutSelection,
|
||||
} from "@/components/issues/issue-layouts/filters";
|
||||
|
|
@ -41,11 +39,8 @@ import { ModuleQuickActions } from "@/components/modules";
|
|||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useModule } from "@/hooks/store/use-module";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { useIssuesActions } from "@/hooks/use-issues-actions";
|
||||
|
|
@ -74,21 +69,22 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||
const { toggleCreateIssueModal } = useCommandPalette();
|
||||
const { allowPermissions } = useUserPermissions();
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const { projectLabels } = useLabel();
|
||||
const { projectStates } = useProjectState();
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
|
||||
// local storage
|
||||
const { setValue, storedValue } = useLocalStorage("module_sidebar_collapsed", "false");
|
||||
|
||||
// derived values
|
||||
const isSidebarCollapsed = storedValue ? (storedValue === "true" ? true : false) : false;
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
|
||||
const canUserCreateIssue = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
const workItemsCount = getGroupIssueCount(undefined, undefined, false);
|
||||
|
||||
const toggleSidebar = () => {
|
||||
setValue(`${!isSidebarCollapsed}`);
|
||||
};
|
||||
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
if (!projectId) return;
|
||||
|
|
@ -97,27 +93,6 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||
[projectId, updateFilters]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!projectId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(projectId.toString(), EIssueFilterType.FILTERS, { [key]: newValues });
|
||||
},
|
||||
[projectId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!projectId) return;
|
||||
|
|
@ -134,15 +109,6 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||
[projectId, updateFilters]
|
||||
);
|
||||
|
||||
// derived values
|
||||
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
|
||||
const canUserCreateIssue = allowPermissions(
|
||||
[EUserPermissions.ADMIN, EUserPermissions.MEMBER],
|
||||
EUserPermissionsLevel.PROJECT
|
||||
);
|
||||
|
||||
const workItemsCount = getGroupIssueCount(undefined, undefined, false);
|
||||
|
||||
const switcherOptions = projectModuleIds
|
||||
?.map((id) => {
|
||||
const _module = id === moduleId ? moduleDetails : getModuleById(id);
|
||||
|
|
@ -230,27 +196,6 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||
activeLayout={activeLayout}
|
||||
/>
|
||||
</div>
|
||||
<FiltersDropdown
|
||||
title="Filters"
|
||||
placement="bottom-end"
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
miniIcon={<ListFilter className="size-3.5" />}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
<FiltersDropdown
|
||||
title="Display"
|
||||
placement="bottom-end"
|
||||
|
|
@ -258,7 +203,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -8,53 +8,43 @@ import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
|
|||
// plane imports
|
||||
import { EIssueFilterType, ISSUE_LAYOUTS, ISSUE_DISPLAY_FILTERS_BY_PAGE } from "@plane/constants";
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import {
|
||||
EIssuesStoreType,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { EIssuesStoreType, IIssueDisplayFilterOptions, IIssueDisplayProperties, EIssueLayoutTypes } from "@plane/types";
|
||||
import { CustomMenu } from "@plane/ui";
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
// components
|
||||
import { WorkItemsModal } from "@/components/analytics/work-items/modal";
|
||||
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { IssueLayoutIcon } from "@/components/issues/issue-layouts/layout-icon";
|
||||
// hooks
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useModule } from "@/hooks/store/use-module";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
|
||||
const SUPPORTED_LAYOUTS = [
|
||||
{ key: "list", i18n_title: "issue.layouts.list", icon: List },
|
||||
{ key: "kanban", i18n_title: "issue.layouts.kanban", icon: Kanban },
|
||||
{ key: "calendar", i18n_title: "issue.layouts.calendar", icon: Calendar },
|
||||
];
|
||||
|
||||
export const ModuleIssuesMobileHeader = observer(() => {
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { getModuleById } = useModule();
|
||||
const { t } = useTranslation();
|
||||
const layouts = [
|
||||
{ key: "list", i18n_title: "issue.layouts.list", icon: List },
|
||||
{ key: "kanban", i18n_title: "issue.layouts.kanban", icon: Kanban },
|
||||
{ key: "calendar", i18n_title: "issue.layouts.calendar", icon: Calendar },
|
||||
];
|
||||
// router
|
||||
const { workspaceSlug, projectId, moduleId } = useParams() as {
|
||||
workspaceSlug: string;
|
||||
projectId: string;
|
||||
moduleId: string;
|
||||
};
|
||||
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
|
||||
|
||||
// states
|
||||
const [analyticsModal, setAnalyticsModal] = useState(false);
|
||||
// plane hooks
|
||||
const { t } = useTranslation();
|
||||
// store hooks
|
||||
const { currentProjectDetails } = useProject();
|
||||
const { getModuleById } = useModule();
|
||||
const {
|
||||
issuesFilter: { issueFilters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.MODULE);
|
||||
// derived values
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const { projectStates } = useProjectState();
|
||||
const { projectLabels } = useLabel();
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined;
|
||||
|
||||
const handleLayoutChange = useCallback(
|
||||
(layout: EIssueLayoutTypes) => {
|
||||
|
|
@ -64,27 +54,6 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
|||
[workspaceSlug, projectId, moduleId, updateFilters]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { [key]: newValues }, moduleId);
|
||||
},
|
||||
[workspaceSlug, projectId, moduleId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
|
|
@ -118,7 +87,7 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
|||
customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm"
|
||||
closeOnSelect
|
||||
>
|
||||
{layouts.map((layout, index) => (
|
||||
{SUPPORTED_LAYOUTS.map((layout, index) => (
|
||||
<CustomMenu.MenuItem
|
||||
key={layout.key}
|
||||
onClick={() => {
|
||||
|
|
@ -131,34 +100,6 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
|||
</CustomMenu.MenuItem>
|
||||
))}
|
||||
</CustomMenu>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title="Filters"
|
||||
placement="bottom-end"
|
||||
menuButton={
|
||||
<span className="flex items-center text-sm text-custom-text-200">
|
||||
Filters
|
||||
<ChevronDown className="ml-2 h-4 w-4 text-custom-text-200" />
|
||||
</span>
|
||||
}
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
</div>
|
||||
<div className="flex flex-grow items-center justify-center border-l border-custom-border-200 text-sm text-custom-text-200">
|
||||
<FiltersDropdown
|
||||
title="Display"
|
||||
|
|
@ -172,7 +113,7 @@ export const ModuleIssuesMobileHeader = observer(() => {
|
|||
>
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -21,29 +21,19 @@ import {
|
|||
ICustomSearchSelectOption,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
// ui
|
||||
import { Breadcrumbs, Button, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
|
||||
// components
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
import { SwitcherIcon, SwitcherLabel } from "@/components/common/switcher-label";
|
||||
import {
|
||||
DisplayFiltersSelection,
|
||||
FiltersDropdown,
|
||||
FilterSelection,
|
||||
LayoutSelection,
|
||||
} from "@/components/issues/issue-layouts/filters";
|
||||
import { DisplayFiltersSelection, FiltersDropdown, LayoutSelection } from "@/components/issues/issue-layouts/filters";
|
||||
// constants
|
||||
import { ViewQuickActions } from "@/components/views/quick-actions";
|
||||
// hooks
|
||||
import { useCommandPalette } from "@/hooks/store/use-command-palette";
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useProject } from "@/hooks/store/use-project";
|
||||
import { useProjectState } from "@/hooks/store/use-project-state";
|
||||
import { useProjectView } from "@/hooks/store/use-project-view";
|
||||
import { useUserPermissions } from "@/hooks/store/user";
|
||||
// plane web
|
||||
|
|
@ -65,11 +55,6 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||
|
||||
const { currentProjectDetails, loader } = useProject();
|
||||
const { projectViewIds, getViewById } = useProjectView();
|
||||
const { projectStates } = useProjectState();
|
||||
const { projectLabels } = useLabel();
|
||||
const {
|
||||
project: { projectMemberIds },
|
||||
} = useMember();
|
||||
|
||||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
|
||||
|
|
@ -87,33 +72,6 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||
[workspaceSlug, projectId, viewId, updateFilters]
|
||||
);
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
projectId.toString(),
|
||||
EIssueFilterType.FILTERS,
|
||||
{ [key]: newValues },
|
||||
viewId.toString()
|
||||
);
|
||||
},
|
||||
[workspaceSlug, projectId, viewId, issueFilters, updateFilters]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
|
|
@ -217,33 +175,10 @@ export const ProjectViewIssuesHeader: React.FC = observer(() => {
|
|||
onChange={(layout) => handleLayoutChange(layout)}
|
||||
selectedLayout={activeLayout}
|
||||
/>
|
||||
|
||||
<FiltersDropdown
|
||||
title="Filters"
|
||||
placement="bottom-end"
|
||||
disabled={!canUserCreateIssue}
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
}
|
||||
projectId={projectId.toString()}
|
||||
labels={projectLabels}
|
||||
memberIds={projectMemberIds ?? undefined}
|
||||
states={projectStates}
|
||||
cycleViewDisabled={!currentProjectDetails?.cycle_view}
|
||||
moduleViewDisabled={!currentProjectDetails?.module_view}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
<FiltersDropdown title="Display" placement="bottom-end">
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues[activeLayout] : undefined
|
||||
activeLayout ? ISSUE_DISPLAY_FILTERS_BY_PAGE.issues.layoutOptions[activeLayout] : undefined
|
||||
}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import { useParams } from "next/navigation";
|
|||
import { DEFAULT_GLOBAL_VIEWS_LIST } from "@plane/constants";
|
||||
// components
|
||||
import { PageHead } from "@/components/core/page-title";
|
||||
import { GlobalViewsAppliedFiltersRoot } from "@/components/issues/issue-layouts/filters";
|
||||
import { AllIssueLayoutRoot } from "@/components/issues/issue-layouts/roots/all-issue-layout-root";
|
||||
// hooks
|
||||
import { useWorkspace } from "@/hooks/store/use-workspace";
|
||||
|
|
@ -29,14 +28,7 @@ const GlobalViewIssuesPage = observer(() => {
|
|||
return (
|
||||
<>
|
||||
<PageHead title={pageTitle} />
|
||||
<div className="h-full overflow-hidden bg-custom-background-100">
|
||||
<div className="flex h-full w-full flex-col border-b border-custom-border-300">
|
||||
{globalViewId && (
|
||||
<GlobalViewsAppliedFiltersRoot globalViewId={globalViewId.toString()} isLoading={isLoading} />
|
||||
)}
|
||||
<AllIssueLayoutRoot isDefaultView={!!defaultView} isLoading={isLoading} toggleLoading={toggleLoading} />
|
||||
</div>
|
||||
</div>
|
||||
<AllIssueLayoutRoot isDefaultView={!!defaultView} isLoading={isLoading} toggleLoading={toggleLoading} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -16,24 +16,20 @@ import {
|
|||
EIssuesStoreType,
|
||||
IIssueDisplayFilterOptions,
|
||||
IIssueDisplayProperties,
|
||||
IIssueFilterOptions,
|
||||
ICustomSearchSelectOption,
|
||||
EIssueLayoutTypes,
|
||||
} from "@plane/types";
|
||||
import { Breadcrumbs, Button, Header, BreadcrumbNavigationSearchDropdown } from "@plane/ui";
|
||||
import { isIssueFilterActive } from "@plane/utils";
|
||||
// components
|
||||
import { BreadcrumbLink } from "@/components/common/breadcrumb-link";
|
||||
import { SwitcherLabel } from "@/components/common/switcher-label";
|
||||
import { DisplayFiltersSelection, FiltersDropdown, FilterSelection } from "@/components/issues/issue-layouts/filters";
|
||||
import { DisplayFiltersSelection, FiltersDropdown } from "@/components/issues/issue-layouts/filters";
|
||||
import { DefaultWorkspaceViewQuickActions } from "@/components/workspace/views/default-view-quick-action";
|
||||
import { CreateUpdateWorkspaceViewModal } from "@/components/workspace/views/modal";
|
||||
import { WorkspaceViewQuickActions } from "@/components/workspace/views/quick-action";
|
||||
// hooks
|
||||
import { useGlobalView } from "@/hooks/store/use-global-view";
|
||||
import { useIssues } from "@/hooks/store/use-issues";
|
||||
import { useLabel } from "@/hooks/store/use-label";
|
||||
import { useMember } from "@/hooks/store/use-member";
|
||||
import { useAppRouter } from "@/hooks/use-app-router";
|
||||
import { GlobalViewLayoutSelection } from "@/plane-web/components/views/helper";
|
||||
|
||||
|
|
@ -48,10 +44,6 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
issuesFilter: { filters, updateFilters },
|
||||
} = useIssues(EIssuesStoreType.GLOBAL);
|
||||
const { getViewDetailsById, currentWorkspaceViews } = useGlobalView();
|
||||
const { workspaceLabels } = useLabel();
|
||||
const {
|
||||
workspace: { workspaceMemberIds },
|
||||
} = useMember();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const issueFilters = globalViewId ? filters[globalViewId.toString()] : undefined;
|
||||
|
|
@ -59,33 +51,6 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
const activeLayout = issueFilters?.displayFilters?.layout;
|
||||
const viewDetails = getViewDetailsById(globalViewId.toString());
|
||||
|
||||
const handleFiltersUpdate = useCallback(
|
||||
(key: keyof IIssueFilterOptions, value: string | string[]) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
const newValues = issueFilters?.filters?.[key] ?? [];
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
// this validation is majorly for the filter start_date, target_date custom
|
||||
value.forEach((val) => {
|
||||
if (!newValues.includes(val)) newValues.push(val);
|
||||
else newValues.splice(newValues.indexOf(val), 1);
|
||||
});
|
||||
} else {
|
||||
if (issueFilters?.filters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1);
|
||||
else newValues.push(value);
|
||||
}
|
||||
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
undefined,
|
||||
EIssueFilterType.FILTERS,
|
||||
{ [key]: newValues },
|
||||
globalViewId.toString()
|
||||
);
|
||||
},
|
||||
[workspaceSlug, issueFilters, updateFilters, globalViewId]
|
||||
);
|
||||
|
||||
const handleDisplayFilters = useCallback(
|
||||
(updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
|
|
@ -155,7 +120,7 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
) as ICustomSearchSelectOption[];
|
||||
const currentLayoutFilters = useMemo(() => {
|
||||
const layout = activeLayout ?? EIssueLayoutTypes.SPREADSHEET;
|
||||
return ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues[layout];
|
||||
return ISSUE_DISPLAY_FILTERS_BY_PAGE.my_issues.layoutOptions[layout];
|
||||
}, [activeLayout]);
|
||||
|
||||
return (
|
||||
|
|
@ -199,21 +164,6 @@ export const GlobalIssuesHeader = observer(() => {
|
|||
selectedLayout={activeLayout ?? EIssueLayoutTypes.SPREADSHEET}
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
/>
|
||||
<FiltersDropdown
|
||||
title={t("common.filters")}
|
||||
placement="bottom-end"
|
||||
isFiltersApplied={isIssueFilterActive(issueFilters)}
|
||||
>
|
||||
<FilterSelection
|
||||
layoutDisplayFiltersOptions={currentLayoutFilters}
|
||||
filters={issueFilters?.filters ?? {}}
|
||||
handleFiltersUpdate={handleFiltersUpdate}
|
||||
displayFilters={issueFilters?.displayFilters ?? {}}
|
||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||
labels={workspaceLabels ?? undefined}
|
||||
memberIds={workspaceMemberIds ?? undefined}
|
||||
/>
|
||||
</FiltersDropdown>
|
||||
<FiltersDropdown title={t("common.display")} placement="bottom-end">
|
||||
<DisplayFiltersSelection
|
||||
layoutDisplayFiltersOptions={currentLayoutFilters}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue