mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
[WEB-469] chore: selected filter sorting added in filter dropdown (#3869)
* chore: selected filter sorting added in filter dropdown * chore: handleClearAllFilters function updated * chore: filter dropdown sorting updated * chore: filter dropdown sorting updated * chore: filter dropdown sorting updated --------- Co-authored-by: gurusainath <gurusainath007@gmail.com>
This commit is contained in:
parent
47a7f60611
commit
7b88a2a88c
@ -32,7 +32,7 @@ export const ProjectArchivedEmptyState: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
issuesFilter.updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, {
|
||||
...newFilters,
|
||||
|
@ -31,7 +31,7 @@ export const ProjectDraftEmptyState: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
issuesFilter.updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, {
|
||||
...newFilters,
|
||||
|
@ -34,7 +34,7 @@ export const ProjectEmptyState: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
issuesFilter.updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, {
|
||||
...newFilters,
|
||||
|
@ -56,7 +56,7 @@ export const ArchivedIssueAppliedFiltersRoot: React.FC = observer(() => {
|
||||
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
|
||||
updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, {
|
||||
|
@ -62,7 +62,7 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -53,7 +53,7 @@ export const DraftIssueAppliedFiltersRoot: React.FC = observer(() => {
|
||||
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
|
||||
updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, { ...newFilters });
|
||||
|
@ -76,7 +76,7 @@ export const GlobalViewsAppliedFiltersRoot = observer((props: Props) => {
|
||||
if (!workspaceSlug || !globalViewId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -61,7 +61,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -57,7 +57,7 @@ export const ProfileIssuesAppliedFiltersRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !userId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(workspaceSlug.toString(), undefined, EIssueFilterType.FILTERS, { ...newFilters }, userId.toString());
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(workspaceSlug.toString(), projectId.toString(), EIssueFilterType.FILTERS, { ...newFilters });
|
||||
};
|
||||
|
@ -67,7 +67,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId || !viewId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// hooks
|
||||
import { Avatar, Loader } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
import { useMember } from "hooks/store";
|
||||
// components
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
// ui
|
||||
import { Avatar, Loader } from "@plane/ui";
|
||||
|
||||
type Props = {
|
||||
appliedFilters: string[] | null;
|
||||
@ -24,15 +25,23 @@ export const FilterAssignees: React.FC<Props> = observer((props: Props) => {
|
||||
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
|
||||
const filteredOptions = memberIds?.filter(
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (memberIds || []).filter((memberId) =>
|
||||
getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
return sortBy(filteredOptions, [
|
||||
(memberId) => !(appliedFilters ?? []).includes(memberId),
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
const handleViewToggle = () => {
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -44,10 +53,10 @@ export const FilterAssignees: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
{sortedOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
const member = getUserDetails(memberId);
|
||||
|
||||
if (!member) return null;
|
||||
@ -61,13 +70,13 @@ export const FilterAssignees: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// hooks
|
||||
import { Avatar, Loader } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
@ -22,16 +23,25 @@ export const FilterCreatedBy: React.FC<Props> = observer((props: Props) => {
|
||||
// store hooks
|
||||
const { getUserDetails } = useMember();
|
||||
|
||||
const filteredOptions = memberIds?.filter(
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (memberIds || []).filter((memberId) =>
|
||||
getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
return sortBy(filteredOptions, [
|
||||
(memberId) => !(appliedFilters ?? []).includes(memberId),
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -43,10 +53,10 @@ export const FilterCreatedBy: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
{sortedOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
const member = getUserDetails(memberId);
|
||||
|
||||
if (!member) return null;
|
||||
@ -60,13 +70,13 @@ export const FilterCreatedBy: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import sortBy from "lodash/sortBy";
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
@ -31,16 +31,24 @@ export const FilterCycle: React.FC<Props> = observer((props) => {
|
||||
const cycleIds = projectId ? getProjectCycleIds(projectId) : undefined;
|
||||
const cycles = cycleIds?.map((projectId) => getCycleById(projectId)!) ?? null;
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
const filteredOptions = sortBy(
|
||||
cycles?.filter((cycle) => cycle.name.toLowerCase().includes(searchQuery.toLowerCase())),
|
||||
(cycle) => cycle.name.toLowerCase()
|
||||
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (cycles || []).filter((cycle) =>
|
||||
cycle.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
return sortBy(filteredOptions, [
|
||||
(cycle) => !appliedFilters?.includes(cycle.id),
|
||||
(cycle) => cycle.name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
const handleViewToggle = () => {
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
const cycleStatus = (status: TCycleGroups) => (status ? status.toLocaleLowerCase() : "draft") as TCycleGroups;
|
||||
@ -54,10 +62,10 @@ export const FilterCycle: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((cycle) => (
|
||||
{sortedOptions.slice(0, itemsToRender).map((cycle) => (
|
||||
<FilterOption
|
||||
key={cycle.id}
|
||||
isChecked={appliedFilters?.includes(cycle.id) ? true : false}
|
||||
@ -69,13 +77,13 @@ export const FilterCycle: React.FC<Props> = observer((props) => {
|
||||
activePulse={cycleStatus(cycle?.status) === "current" ? true : false}
|
||||
/>
|
||||
))}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// components
|
||||
import { Loader } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
@ -26,13 +27,23 @@ export const FilterLabels: React.FC<Props> = observer((props) => {
|
||||
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
|
||||
const filteredOptions = labels?.filter((label) => label.name.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (labels || []).filter((label) =>
|
||||
label.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
return sortBy(filteredOptions, [
|
||||
(label) => !(appliedFilters ?? []).includes(label.id),
|
||||
(label) => label.name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -44,10 +55,10 @@ export const FilterLabels: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((label) => (
|
||||
{sortedOptions.slice(0, itemsToRender).map((label) => (
|
||||
<FilterOption
|
||||
key={label?.id}
|
||||
isChecked={appliedFilters?.includes(label?.id) ? true : false}
|
||||
@ -56,13 +67,13 @@ export const FilterLabels: React.FC<Props> = observer((props) => {
|
||||
title={label.name}
|
||||
/>
|
||||
))}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// hooks
|
||||
import { Loader, Avatar } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
@ -24,15 +25,23 @@ export const FilterMentions: React.FC<Props> = observer((props: Props) => {
|
||||
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
|
||||
const filteredOptions = memberIds?.filter(
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (memberIds || []).filter((memberId) =>
|
||||
getUserDetails(memberId)?.display_name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
return sortBy(filteredOptions, [
|
||||
(memberId) => !(appliedFilters ?? []).includes(memberId),
|
||||
(memberId) => getUserDetails(memberId)?.display_name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
const handleViewToggle = () => {
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -44,10 +53,10 @@ export const FilterMentions: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
{sortedOptions.slice(0, itemsToRender).map((memberId) => {
|
||||
const member = getUserDetails(memberId);
|
||||
|
||||
if (!member) return null;
|
||||
@ -61,13 +70,13 @@ export const FilterMentions: React.FC<Props> = observer((props: Props) => {
|
||||
/>
|
||||
);
|
||||
})}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import sortBy from "lodash/sortBy";
|
||||
import { observer } from "mobx-react";
|
||||
// components
|
||||
@ -29,16 +29,24 @@ export const FilterModule: React.FC<Props> = observer((props) => {
|
||||
const moduleIds = projectId ? getProjectModuleIds(projectId) : undefined;
|
||||
const modules = moduleIds?.map((projectId) => getModuleById(projectId)!) ?? null;
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
const filteredOptions = sortBy(
|
||||
modules?.filter((module) => module.name.toLowerCase().includes(searchQuery.toLowerCase())),
|
||||
(module) => module.name.toLowerCase()
|
||||
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (modules || []).filter((module) =>
|
||||
module.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
return sortBy(filteredOptions, [
|
||||
(module) => !appliedFilters?.includes(module.id),
|
||||
(module) => module.name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
const handleViewToggle = () => {
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -50,10 +58,10 @@ export const FilterModule: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((cycle) => (
|
||||
{sortedOptions.slice(0, itemsToRender).map((cycle) => (
|
||||
<FilterOption
|
||||
key={cycle.id}
|
||||
isChecked={appliedFilters?.includes(cycle.id) ? true : false}
|
||||
@ -62,13 +70,13 @@ export const FilterModule: React.FC<Props> = observer((props) => {
|
||||
title={cycle.name}
|
||||
/>
|
||||
))}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// components
|
||||
import { Loader } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
@ -26,13 +27,23 @@ export const FilterProjects: React.FC<Props> = observer((props) => {
|
||||
// derived values
|
||||
const projects = workspaceProjectIds?.map((projectId) => getProjectById(projectId)!) ?? null;
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
const filteredOptions = projects?.filter((project) => project.name.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (projects || []).filter((project) =>
|
||||
project.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
);
|
||||
return sortBy(filteredOptions, [
|
||||
(project) => !(appliedFilters ?? []).includes(project.id),
|
||||
(project) => project.name.toLowerCase(),
|
||||
]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -44,10 +55,10 @@ export const FilterProjects: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((project) => (
|
||||
{sortedOptions.slice(0, itemsToRender).map((project) => (
|
||||
<FilterOption
|
||||
key={`project-${project.id}`}
|
||||
isChecked={appliedFilters?.includes(project.id) ? true : false}
|
||||
@ -60,13 +71,13 @@ export const FilterProjects: React.FC<Props> = observer((props) => {
|
||||
title={project.name}
|
||||
/>
|
||||
))}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import sortBy from "lodash/sortBy";
|
||||
// components
|
||||
import { StateGroupIcon } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import sortBy from "lodash/sortBy";
|
||||
// components
|
||||
import { Loader, StateGroupIcon } from "@plane/ui";
|
||||
import { FilterHeader, FilterOption } from "components/issues";
|
||||
@ -22,13 +23,18 @@ export const FilterState: React.FC<Props> = observer((props) => {
|
||||
|
||||
const appliedFiltersCount = appliedFilters?.length ?? 0;
|
||||
|
||||
const filteredOptions = states?.filter((s) => s.name.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||
const sortedOptions = useMemo(() => {
|
||||
const filteredOptions = (states ?? []).filter((s) => s.name.toLowerCase().includes(searchQuery.toLowerCase()));
|
||||
|
||||
return sortBy(filteredOptions, [(s) => !(appliedFilters ?? []).includes(s.id), (s) => s.name.toLowerCase()]);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [searchQuery]);
|
||||
|
||||
const handleViewToggle = () => {
|
||||
if (!filteredOptions) return;
|
||||
if (!sortedOptions) return;
|
||||
|
||||
if (itemsToRender === filteredOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(filteredOptions.length);
|
||||
if (itemsToRender === sortedOptions.length) setItemsToRender(5);
|
||||
else setItemsToRender(sortedOptions.length);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -40,10 +46,10 @@ export const FilterState: React.FC<Props> = observer((props) => {
|
||||
/>
|
||||
{previewEnabled && (
|
||||
<div>
|
||||
{filteredOptions ? (
|
||||
filteredOptions.length > 0 ? (
|
||||
{sortedOptions ? (
|
||||
sortedOptions.length > 0 ? (
|
||||
<>
|
||||
{filteredOptions.slice(0, itemsToRender).map((state) => (
|
||||
{sortedOptions.slice(0, itemsToRender).map((state) => (
|
||||
<FilterOption
|
||||
key={state.id}
|
||||
isChecked={appliedFilters?.includes(state.id) ? true : false}
|
||||
@ -52,13 +58,13 @@ export const FilterState: React.FC<Props> = observer((props) => {
|
||||
title={state.name}
|
||||
/>
|
||||
))}
|
||||
{filteredOptions.length > 5 && (
|
||||
{sortedOptions.length > 5 && (
|
||||
<button
|
||||
type="button"
|
||||
className="ml-8 text-xs font-medium text-custom-primary-100"
|
||||
onClick={handleViewToggle}
|
||||
>
|
||||
{itemsToRender === filteredOptions.length ? "View less" : "View all"}
|
||||
{itemsToRender === sortedOptions.length ? "View less" : "View all"}
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
|
@ -68,7 +68,7 @@ export const CycleLayoutRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId || !cycleId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
issuesFilter.updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -59,7 +59,7 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
|
||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||
const newFilters: IIssueFilterOptions = {};
|
||||
Object.keys(userFilters ?? {}).forEach((key) => {
|
||||
newFilters[key as keyof IIssueFilterOptions] = null;
|
||||
newFilters[key as keyof IIssueFilterOptions] = [];
|
||||
});
|
||||
issuesFilter.updateFilters(
|
||||
workspaceSlug.toString(),
|
||||
|
Loading…
Reference in New Issue
Block a user