diff --git a/apps/web/ce/components/issues/issue-details/sidebar.tsx/date-alert.tsx b/apps/web/ce/components/issues/issue-details/sidebar.tsx/date-alert.tsx new file mode 100644 index 000000000..930d45949 --- /dev/null +++ b/apps/web/ce/components/issues/issue-details/sidebar.tsx/date-alert.tsx @@ -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) => <>; diff --git a/apps/web/ce/components/issues/issue-layouts/utils.tsx b/apps/web/ce/components/issues/issue-layouts/utils.tsx index 2d2a1deb8..82a26a00c 100644 --- a/apps/web/ce/components/issues/issue-layouts/utils.tsx +++ b/apps/web/ce/components/issues/issue-layouts/utils.tsx @@ -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; +}; diff --git a/apps/web/ce/store/issue/helpers/filter-utils.ts b/apps/web/ce/store/issue/helpers/filter-utils.ts new file mode 100644 index 000000000..eedd12624 --- /dev/null +++ b/apps/web/ce/store/issue/helpers/filter-utils.ts @@ -0,0 +1,3 @@ +import type { IIssueDisplayFilterOptions } from "@plane/types"; + +export const getEnabledDisplayFilters = (displayFilters: IIssueDisplayFilterOptions) => displayFilters; diff --git a/apps/web/core/components/core/modals/existing-issues-list-modal.tsx b/apps/web/core/components/core/modals/existing-issues-list-modal.tsx index d67ebb8d6..09e12fb16 100644 --- a/apps/web/core/components/core/modals/existing-issues-list-modal.tsx +++ b/apps/web/core/components/core/modals/existing-issues-list-modal.tsx @@ -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) => { 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) => { }; 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(); diff --git a/apps/web/core/components/issues/issue-detail/sidebar.tsx b/apps/web/core/components/issues/issue-detail/sidebar.tsx index 4c6fc3837..fd8e1c61d 100644 --- a/apps/web/core/components/issues/issue-detail/sidebar.tsx +++ b/apps/web/core/components/issues/issue-detail/sidebar.tsx @@ -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 = observer((props) => { {t("common.order_by.due_date")} - - 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 - /> +
+ + 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 && } +
{projectId && areEstimateEnabledByProjectId(projectId) && ( diff --git a/apps/web/core/components/issues/issue-layouts/filters/header/display-filters/group-by.tsx b/apps/web/core/components/issues/issue-layouts/filters/header/display-filters/group-by.tsx index 30c149835..c5a0838d8 100644 --- a/apps/web/core/components/issues/issue-layouts/filters/header/display-filters/group-by.tsx +++ b/apps/web/core/components/issues/issue-layouts/filters/header/display-filters/group-by.tsx @@ -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 = observer((props) => { const selectedGroupBy = displayFilters?.group_by ?? null; const selectedSubGroupBy = displayFilters?.sub_group_by ?? null; + const options = useGroupByOptions(groupByOptions); + return ( <> = observer((props) => { /> {previewEnabled && (
- {ISSUE_GROUP_BY_OPTIONS.filter((option) => groupByOptions.includes(option.key)).map((groupBy) => { + {options.map((groupBy) => { if ( displayFilters?.layout === "kanban" && selectedSubGroupBy !== null && diff --git a/apps/web/core/components/issues/peek-overview/properties.tsx b/apps/web/core/components/issues/peek-overview/properties.tsx index 34f5265dc..a38a0bad0 100644 --- a/apps/web/core/components/issues/peek-overview/properties.tsx +++ b/apps/web/core/components/issues/peek-overview/properties.tsx @@ -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 = observer((pro {t("common.order_by.due_date")}
- - 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 - /> +
+ + 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 && } +
{/* estimate */} diff --git a/apps/web/core/store/issue/helpers/issue-filter-helper.store.ts b/apps/web/core/store/issue/helpers/issue-filter-helper.store.ts index e99eb7c9c..b6095044c 100644 --- a/apps/web/core/store/issue/helpers/issue-filter-helper.store.ts +++ b/apps/web/core/store/issue/helpers/issue-filter-helper.store.ts @@ -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 diff --git a/apps/web/core/store/project/project.store.ts b/apps/web/core/store/project/project.store.ts index 1f4cd0802..3dce91b05 100644 --- a/apps/web/core/store/project/project.store.ts +++ b/apps/web/core/store/project/project.store.ts @@ -76,7 +76,7 @@ export class ProjectStore implements IProjectStore { fetchStatus: TFetchStatus = undefined; projectMap: Record = {}; projectAnalyticsCountMap: Record = {}; - openCollapsibleSection: ProjectOverviewCollapsible[] = []; + openCollapsibleSection: ProjectOverviewCollapsible[] = ["milestones"]; lastCollapsibleAction: ProjectOverviewCollapsible | null = null; // root store