[WEB-5296]chore: grouping filter refactor (#8034)

This commit is contained in:
Vamsi Krishna
2025-10-29 20:36:28 +05:30
committed by GitHub
parent 0e8128594b
commit 710138f3a1
9 changed files with 98 additions and 52 deletions
@@ -0,0 +1,9 @@
import type { TIssue } from "@plane/types";
export type TDateAlertProps = {
date: string;
workItem: TIssue;
projectId: string;
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const DateAlert = (props: TDateAlertProps) => <></>;
@@ -1,6 +1,7 @@
import type { FC } from "react";
import { CalendarDays, LayersIcon, Link2, Paperclip } from "lucide-react";
// types
import { ISSUE_GROUP_BY_OPTIONS } from "@plane/constants";
import type { ISvgIcons } from "@plane/propel/icons";
import {
CycleIcon,
@@ -13,7 +14,13 @@ import {
PriorityPropertyIcon,
StartDatePropertyIcon,
} from "@plane/propel/icons";
import type { IGroupByColumn, IIssueDisplayProperties, TGetColumns, TSpreadsheetColumn } from "@plane/types";
import type {
IGroupByColumn,
IIssueDisplayProperties,
TGetColumns,
TIssueGroupByOptions,
TSpreadsheetColumn,
} from "@plane/types";
// components
import {
SpreadsheetAssigneeColumn,
@@ -96,3 +103,13 @@ export const SPREADSHEET_COLUMNS: { [key in keyof IIssueDisplayProperties]: TSpr
updated_on: SpreadsheetUpdatedOnColumn,
attachment_count: SpreadsheetAttachmentColumn,
};
export const useGroupByOptions = (
options: TIssueGroupByOptions[]
): {
key: TIssueGroupByOptions;
titleTranslationKey: string;
}[] => {
const groupByOptions = ISSUE_GROUP_BY_OPTIONS.filter((option) => options.includes(option.key));
return groupByOptions;
};
@@ -0,0 +1,3 @@
import type { IIssueDisplayFilterOptions } from "@plane/types";
export const getEnabledDisplayFilters = (displayFilters: IIssueDisplayFilterOptions) => displayFilters;
@@ -1,6 +1,6 @@
"use client";
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useRef } from "react";
import { Rocket, Search } from "lucide-react";
import { Combobox, Dialog, Transition } from "@headlessui/react";
// i18n
@@ -66,12 +66,14 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
const { isMobile } = usePlatformOS();
const debouncedSearchTerm: string = useDebounce(searchTerm, 500);
const { baseTabIndex } = getTabIndex(undefined, isMobile);
const hasInitializedSelection = useRef(false);
const handleClose = () => {
onClose();
setSearchTerm("");
setSelectedIssues([]);
setIsWorkspaceLevel(false);
hasInitializedSelection.current = false;
};
const onSubmit = async () => {
@@ -118,10 +120,11 @@ export const ExistingIssuesListModal: React.FC<Props> = (props) => {
};
useEffect(() => {
if (selectedWorkItemIds) {
if (isOpen && !hasInitializedSelection.current && selectedWorkItemIds && issues.length > 0) {
setSelectedIssues(issues.filter((issue) => selectedWorkItemIds.includes(issue.id)));
hasInitializedSelection.current = true;
}
}, [isOpen, selectedWorkItemIds]);
}, [isOpen, issues, selectedWorkItemIds]);
useEffect(() => {
handleSearch();
@@ -36,6 +36,7 @@ import { useProjectState } from "@/hooks/store/use-project-state";
// components
import { WorkItemAdditionalSidebarProperties } from "@/plane-web/components/issues/issue-details/additional-properties";
import { IssueParentSelectRoot } from "@/plane-web/components/issues/issue-details/parent-select-root";
import { DateAlert } from "@/plane-web/components/issues/issue-details/sidebar.tsx/date-alert";
import { IssueWorklogProperty } from "@/plane-web/components/issues/worklog/property";
import { IssueCycleSelect } from "./cycle-select";
import { IssueLabel } from "./label";
@@ -186,28 +187,31 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
<DueDatePropertyIcon className="h-4 w-4 flex-shrink-0" />
<span>{t("common.order_by.due_date")}</span>
</div>
<DateDropdown
placeholder={t("issue.add.due_date")}
value={issue.target_date}
onChange={(val) =>
issueOperations.update(workspaceSlug, projectId, issueId, {
target_date: val ? renderFormattedPayloadDate(val) : null,
})
}
minDate={minDate ?? undefined}
disabled={!isEditable}
buttonVariant="transparent-with-text"
className="group w-3/5 flex-grow"
buttonContainerClassName="w-full text-left"
buttonClassName={cn("text-sm", {
"text-custom-text-400": !issue.target_date,
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
})}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
// TODO: add this logic
// showPlaceholderIcon
/>
<div className="flex items-center gap-2">
<DateDropdown
placeholder={t("issue.add.due_date")}
value={issue.target_date}
onChange={(val) =>
issueOperations.update(workspaceSlug, projectId, issueId, {
target_date: val ? renderFormattedPayloadDate(val) : null,
})
}
minDate={minDate ?? undefined}
disabled={!isEditable}
buttonVariant="transparent-with-text"
className="group w-3/5 flex-grow"
buttonContainerClassName="w-full text-left"
buttonClassName={cn("text-sm", {
"text-custom-text-400": !issue.target_date,
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
})}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
// TODO: add this logic
// showPlaceholderIcon
/>
{issue.target_date && <DateAlert date={issue.target_date} workItem={issue} projectId={projectId} />}
</div>
</div>
{projectId && areEstimateEnabledByProjectId(projectId) && (
@@ -1,10 +1,10 @@
import React, { useState } from "react";
import { observer } from "mobx-react";
import { ISSUE_GROUP_BY_OPTIONS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import type { IIssueDisplayFilterOptions, TIssueGroupByOptions } from "@plane/types";
// components
import { FilterHeader, FilterOption } from "@/components/issues/issue-layouts/filters";
import { useGroupByOptions } from "@/plane-web/components/issues/issue-layouts/utils";
type Props = {
displayFilters: IIssueDisplayFilterOptions | undefined;
@@ -22,6 +22,8 @@ export const FilterGroupBy: React.FC<Props> = observer((props) => {
const selectedGroupBy = displayFilters?.group_by ?? null;
const selectedSubGroupBy = displayFilters?.sub_group_by ?? null;
const options = useGroupByOptions(groupByOptions);
return (
<>
<FilterHeader
@@ -31,7 +33,7 @@ export const FilterGroupBy: React.FC<Props> = observer((props) => {
/>
{previewEnabled && (
<div>
{ISSUE_GROUP_BY_OPTIONS.filter((option) => groupByOptions.includes(option.key)).map((groupBy) => {
{options.map((groupBy) => {
if (
displayFilters?.layout === "kanban" &&
selectedSubGroupBy !== null &&
@@ -34,6 +34,7 @@ import { useProjectState } from "@/hooks/store/use-project-state";
// plane web components
import { WorkItemAdditionalSidebarProperties } from "@/plane-web/components/issues/issue-details/additional-properties";
import { IssueParentSelectRoot } from "@/plane-web/components/issues/issue-details/parent-select-root";
import { DateAlert } from "@/plane-web/components/issues/issue-details/sidebar.tsx/date-alert";
import { IssueWorklogProperty } from "@/plane-web/components/issues/worklog/property";
import type { TIssueOperations } from "../issue-detail";
import { IssueCycleSelect } from "../issue-detail/cycle-select";
@@ -189,28 +190,31 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
<DueDatePropertyIcon className="h-4 w-4 flex-shrink-0" />
<span>{t("common.order_by.due_date")}</span>
</div>
<DateDropdown
value={issue.target_date}
onChange={(val) =>
issueOperations.update(workspaceSlug, projectId, issueId, {
target_date: val ? renderFormattedPayloadDate(val) : null,
})
}
placeholder={t("issue.add.due_date")}
buttonVariant="transparent-with-text"
minDate={minDate ?? undefined}
disabled={disabled}
className="w-3/4 flex-grow group"
buttonContainerClassName="w-full text-left"
buttonClassName={cn("text-sm", {
"text-custom-text-400": !issue.target_date,
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
})}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
// TODO: add this logic
// showPlaceholderIcon
/>
<div className="flex items-center gap-2">
<DateDropdown
value={issue.target_date}
onChange={(val) =>
issueOperations.update(workspaceSlug, projectId, issueId, {
target_date: val ? renderFormattedPayloadDate(val) : null,
})
}
placeholder={t("issue.add.due_date")}
buttonVariant="transparent-with-text"
minDate={minDate ?? undefined}
disabled={disabled}
className="w-3/4 flex-grow group"
buttonContainerClassName="w-full text-left"
buttonClassName={cn("text-sm", {
"text-custom-text-400": !issue.target_date,
"text-red-500": shouldHighlightIssueDueDate(issue.target_date, stateDetails?.group),
})}
hideIcon
clearIconClassName="h-3 w-3 hidden group-hover:inline !text-custom-text-100"
// TODO: add this logic
// showPlaceholderIcon
/>
{issue.target_date && <DateAlert date={issue.target_date} workItem={issue} projectId={projectId} />}
</div>
</div>
{/* estimate */}
@@ -24,6 +24,7 @@ import { EIssueLayoutTypes } from "@plane/types";
import { getComputedDisplayFilters, getComputedDisplayProperties } from "@plane/utils";
// lib
import { storage } from "@/lib/local-storage";
import { getEnabledDisplayFilters } from "@/plane-web/store/issue/helpers/filter-utils";
interface ILocalStoreIssueFilters {
key: EIssuesStoreType;
@@ -176,7 +177,10 @@ export class IssueFilterHelperStore implements IIssueFilterHelperStore {
computedDisplayFilters = (
displayFilters: IIssueDisplayFilterOptions,
defaultValues?: IIssueDisplayFilterOptions
): IIssueDisplayFilterOptions => getComputedDisplayFilters(displayFilters, defaultValues);
): IIssueDisplayFilterOptions => {
const computedFilters = getComputedDisplayFilters(displayFilters, defaultValues);
return getEnabledDisplayFilters(computedFilters);
};
/**
* @description This method is used to apply the display properties on the issues
+1 -1
View File
@@ -76,7 +76,7 @@ export class ProjectStore implements IProjectStore {
fetchStatus: TFetchStatus = undefined;
projectMap: Record<string, TProject> = {};
projectAnalyticsCountMap: Record<string, TProjectAnalyticsCount> = {};
openCollapsibleSection: ProjectOverviewCollapsible[] = [];
openCollapsibleSection: ProjectOverviewCollapsible[] = ["milestones"];
lastCollapsibleAction: ProjectOverviewCollapsible | null = null;
// root store