diff --git a/web/components/analytics/project-modal/modal.tsx b/web/components/analytics/project-modal/modal.tsx index a4b82c4b6..df61411f2 100644 --- a/web/components/analytics/project-modal/modal.tsx +++ b/web/components/analytics/project-modal/modal.tsx @@ -38,14 +38,12 @@ export const ProjectAnalyticsModal: React.FC = observer((props) => { >
{ + const [analyticsModal, setAnalyticsModal] = useState(false); + const { getCycleById } = useCycle(); + const layouts = [ + { key: "list", title: "List", icon: List }, + { key: "kanban", title: "Kanban", icon: Kanban }, + { key: "calendar", title: "Calendar", icon: Calendar }, + ]; + + const { workspaceSlug, projectId, cycleId } = router.query as { + workspaceSlug: string; + projectId: string; + cycleId: string; + }; + const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined; + // store hooks + const { + issuesFilter: { issueFilters, updateFilters }, + } = useIssues(EIssuesStoreType.CYCLE); + const activeLayout = issueFilters?.displayFilters?.layout; + + const handleLayoutChange = useCallback( + (layout: TIssueLayouts) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, cycleId); + }, + [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) 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, projectId, EIssueFilterType.FILTERS, { [key]: newValues }, cycleId); + }, + [workspaceSlug, projectId, cycleId, issueFilters, updateFilters] + ); + + const handleDisplayFilters = useCallback( + (updatedDisplayFilter: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter, cycleId); + }, + [workspaceSlug, projectId, cycleId, updateFilters] + ); + + const handleDisplayProperties = useCallback( + (property: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_PROPERTIES, property, cycleId); + }, + [workspaceSlug, projectId, cycleId, updateFilters] + ); + + return ( + <> + setAnalyticsModal(false)} + cycleDetails={cycleDetails ?? undefined} + /> +
+ Layout} + customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm" + closeOnSelect + > + {layouts.map((layout, index) => ( + { + handleLayoutChange(ISSUE_LAYOUTS[index].key); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ))} +
+
+ + Filters + + + } + > + + +
+
+ + Display + + + } + > + + +
+ + setAnalyticsModal(true)} + className="flex flex-grow justify-center text-custom-text-200 text-sm border-l border-custom-border-200" + > + Analytics + +
+ + ); +}; diff --git a/web/components/cycles/cycles-list-item.tsx b/web/components/cycles/cycles-list-item.tsx index 86de8d0c0..a6d467091 100644 --- a/web/components/cycles/cycles-list-item.tsx +++ b/web/components/cycles/cycles-list-item.tsx @@ -159,10 +159,10 @@ export const CyclesListItem: FC = (props) => { projectId={projectId} /> -
-
-
- +
+
+
+
{isCompleted ? ( progress === 100 ? ( @@ -176,95 +176,97 @@ export const CyclesListItem: FC = (props) => { {`${progress}%`} )} - +
-
- - - +
+ - {cycleDetails.name} + + {cycleDetails.name} +
-
- -
-
-
- {currentCycle && ( - - {currentCycle.value === "current" - ? `${daysLeft} ${daysLeft > 1 ? "days" : "day"} left` - : `${currentCycle.label}`} - - )} +
- {renderDate && ( - - {renderFormattedDate(startDate) ?? "_ _"} - {renderFormattedDate(endDate) ?? "_ _"} - - )} - - -
- {cycleDetails.assignees.length > 0 ? ( - - {cycleDetails.assignees.map((assignee) => ( - - ))} - - ) : ( - - - - )} + {currentCycle && ( +
+ {currentCycle.value === "current" + ? `${daysLeft} ${daysLeft > 1 ? "days" : "day"} left` + : `${currentCycle.label}`}
- - {isEditingAllowed && - (cycleDetails.is_favorite ? ( - - ) : ( - - ))} + )} +
+
+
+ {renderDate && `${renderFormattedDate(startDate) ?? `_ _`} - ${renderFormattedDate(endDate) ?? `_ _`}`} +
- - {!isCompleted && isEditingAllowed && ( +
+ +
+ {cycleDetails.assignees.length > 0 ? ( + + {cycleDetails.assignees.map((assignee) => ( + + ))} + + ) : ( + + + + )} +
+
+ + {isEditingAllowed && ( <> - - - - Edit cycle - - - - - - Delete cycle - - + {cycleDetails.is_favorite ? ( + + ) : ( + + )} + + + {!isCompleted && isEditingAllowed && ( + <> + + + + Edit cycle + + + + + + Delete cycle + + + + )} + + + + Copy cycle link + + + )} - - - - Copy cycle link - - - +
diff --git a/web/components/headers/cycle-issues.tsx b/web/components/headers/cycle-issues.tsx index 7cfc492f4..44f4f944d 100644 --- a/web/components/headers/cycle-issues.tsx +++ b/web/components/headers/cycle-issues.tsx @@ -23,7 +23,7 @@ import { BreadcrumbLink } from "components/common"; // ui import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui"; // icons -import { ArrowRight, Plus } from "lucide-react"; +import { ArrowRight, Plus, PanelRight } from "lucide-react"; // helpers import { truncateText } from "helpers/string.helper"; import { renderEmoji } from "helpers/emoji.helper"; @@ -32,6 +32,8 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // constants import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { EUserProjectRoles } from "constants/project"; +import { cn } from "helpers/common.helper"; +import { CycleMobileHeader } from "components/cycles/cycle-mobile-header"; const CycleDropdownOption: React.FC<{ cycleId: string }> = ({ cycleId }) => { // router @@ -147,117 +149,136 @@ export const CycleIssuesHeader: React.FC = observer(() => { onClose={() => setAnalyticsModal(false)} cycleDetails={cycleDetails ?? undefined} /> -
-
- - - - {currentProjectDetails?.name.charAt(0)} - - ) - } - /> - } +
+
+
+ + + + + + {currentProjectDetails?.name.charAt(0)} + + ) + } + /> + + ... + + } + /> + } + /> + } + /> + + + {cycleDetails?.name && truncateText(cycleDetails.name, 40)} + + } + className="ml-1.5 flex-shrink-0" + placement="bottom-start" + > + {currentProjectCycleIds?.map((cycleId) => ( + + ))} + + } + /> + +
+
+ handleLayoutChange(layout)} + selectedLayout={activeLayout} /> - } - /> - } - /> - - - {cycleDetails?.name && truncateText(cycleDetails.name, 40)} - - } - className="ml-1.5 flex-shrink-0" - placement="bottom-start" - > - {currentProjectCycleIds?.map((cycleId) => ( - - ))} - - } - /> - -
-
- handleLayoutChange(layout)} - selectedLayout={activeLayout} - /> - - - - - - + + + + + + - {canUserCreateIssue && ( - <> - - - - )} + {canUserCreateIssue && ( + <> + + + + )} + +
+
+ +
); }); + + diff --git a/web/components/headers/cycles.tsx b/web/components/headers/cycles.tsx index a9ad3a01f..a4bf963ab 100644 --- a/web/components/headers/cycles.tsx +++ b/web/components/headers/cycles.tsx @@ -1,22 +1,24 @@ -import { FC } from "react"; +import { FC, useCallback } from "react"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import { Plus } from "lucide-react"; +import { List, Plus } from "lucide-react"; // hooks import { useApplication, useEventTracker, useProject, useUser } from "hooks/store"; // ui -import { Breadcrumbs, Button, ContrastIcon } from "@plane/ui"; +import { Breadcrumbs, Button, ContrastIcon, CustomMenu } from "@plane/ui"; // helpers import { renderEmoji } from "helpers/emoji.helper"; import { EUserProjectRoles } from "constants/project"; // components import { SidebarHamburgerToggle } from "components/core/sidebar/sidebar-menu-hamburger-toggle"; import { BreadcrumbLink } from "components/common"; +import { TCycleLayout } from "@plane/types"; +import { CYCLE_VIEW_LAYOUTS } from "constants/cycle"; +import useLocalStorage from "hooks/use-local-storage"; export const CyclesHeader: FC = observer(() => { // router const router = useRouter(); - const { workspaceSlug } = router.query; // store hooks const { commandPalette: { toggleCreateCycleModal }, @@ -30,54 +32,96 @@ export const CyclesHeader: FC = observer(() => { const canUserCreateCycle = currentProjectRole && [EUserProjectRoles.ADMIN, EUserProjectRoles.MEMBER].includes(currentProjectRole); + const { workspaceSlug } = router.query as { + workspaceSlug: string; + }; + const { setValue: setCycleLayout } = useLocalStorage("cycle_layout", "list"); + + const handleCurrentLayout = useCallback( + (_layout: TCycleLayout) => { + setCycleLayout(_layout); + }, + [setCycleLayout] + ); + return ( -
-
- -
- - - {currentProjectDetails?.name.charAt(0)} - - ) - } - /> - } - /> - } />} - /> - +
+
+
+ +
+ + + {currentProjectDetails?.name.charAt(0)} + + ) + } + /> + } + /> + } />} + /> + +
+ {canUserCreateCycle && ( +
+ +
+ )} +
+
+ + + Layout + + } + customButtonClassName="flex flex-grow justify-center items-center text-custom-text-200 text-sm" + closeOnSelect + > + {CYCLE_VIEW_LAYOUTS.map((layout) => ( + { + // handleLayoutChange(ISSUE_LAYOUTS[index].key); + handleCurrentLayout(layout.key as TCycleLayout); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ))} +
- {canUserCreateCycle && ( -
- -
- )}
); }); diff --git a/web/components/headers/module-issues.tsx b/web/components/headers/module-issues.tsx index 70e4dbeea..6287223b0 100644 --- a/web/components/headers/module-issues.tsx +++ b/web/components/headers/module-issues.tsx @@ -23,7 +23,7 @@ import { BreadcrumbLink } from "components/common"; // ui import { Breadcrumbs, Button, CustomMenu, DiceIcon } from "@plane/ui"; // icons -import { ArrowRight, Plus } from "lucide-react"; +import { ArrowRight, PanelRight, Plus } from "lucide-react"; // helpers import { truncateText } from "helpers/string.helper"; import { renderEmoji } from "helpers/emoji.helper"; @@ -32,6 +32,8 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOption // constants import { EIssuesStoreType, EIssueFilterType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue"; import { EUserProjectRoles } from "constants/project"; +import { cn } from "helpers/common.helper"; +import { ModuleMobileHeader } from "components/modules/module-mobile-header"; const ModuleDropdownOption: React.FC<{ moduleId: string }> = ({ moduleId }) => { // router @@ -150,116 +152,127 @@ export const ModuleIssuesHeader: React.FC = observer(() => { onClose={() => setAnalyticsModal(false)} moduleDetails={moduleDetails ?? undefined} /> -
-
- - - - {currentProjectDetails?.name.charAt(0)} - - ) +
+
+
+ + + + + + {currentProjectDetails?.name.charAt(0)} + + ) + } + /> + + ... + + } + /> + } + /> + } + /> + + + {moduleDetails?.name && truncateText(moduleDetails.name, 40)} + + } + className="ml-1.5 flex-shrink-0" + placement="bottom-start" + > + {projectModuleIds?.map((moduleId) => ( + + ))} + + } + /> + +
+
+
+ handleLayoutChange(layout)} + selectedLayout={activeLayout} + /> + + - } - /> - } - /> - } - /> - - - {moduleDetails?.name && truncateText(moduleDetails.name, 40)} - + + + - {projectModuleIds?.map((moduleId) => ( - - ))} - - } - /> - -
-
- handleLayoutChange(layout)} - selectedLayout={activeLayout} - /> - - - - - - + displayFilters={issueFilters?.displayFilters ?? {}} + handleDisplayFiltersUpdate={handleDisplayFilters} + displayProperties={issueFilters?.displayProperties ?? {}} + handleDisplayPropertiesUpdate={handleDisplayProperties} + /> + +
- {canUserCreateIssue && ( - <> - - - - )} - + {canUserCreateIssue && ( + <> + + + + )} + +
+
); diff --git a/web/components/headers/project-issues.tsx b/web/components/headers/project-issues.tsx index 769d6c945..c819b25c3 100644 --- a/web/components/headers/project-issues.tsx +++ b/web/components/headers/project-issues.tsx @@ -2,7 +2,7 @@ import { useCallback, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; import { observer } from "mobx-react-lite"; -import { ArrowLeft, Briefcase, Circle, ExternalLink, Plus } from "lucide-react"; +import { Briefcase, Circle, ExternalLink, Plus } from "lucide-react"; // hooks import { useApplication, @@ -29,6 +29,7 @@ import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } f import { renderEmoji } from "helpers/emoji.helper"; import { EUserProjectRoles } from "constants/project"; import { useIssues } from "hooks/store/use-issues"; +import { IssuesMobileHeader } from "components/issues/issues-mobile-header"; export const ProjectIssuesHeader: React.FC = observer(() => { // states @@ -114,118 +115,111 @@ export const ProjectIssuesHeader: React.FC = observer(() => { onClose={() => setAnalyticsModal(false)} projectDetails={currentProjectDetails ?? undefined} /> -
-
- -
- +
+
+
+ +
+ + + {renderEmoji(currentProjectDetails.emoji)} + + ) : currentProjectDetails?.icon_prop ? ( +
+ {renderEmoji(currentProjectDetails.icon_prop)} +
+ ) : ( + + {currentProjectDetails?.name.charAt(0)} + + ) + ) : ( + + + + ) + } + /> + } + /> + + } />} + /> +
+
+ {currentProjectDetails?.is_deployed && deployUrl && ( + + + Public + + + )}
-
- - - {renderEmoji(currentProjectDetails.emoji)} - - ) : currentProjectDetails?.icon_prop ? ( -
- {renderEmoji(currentProjectDetails.icon_prop)} -
- ) : ( - - {currentProjectDetails?.name.charAt(0)} - - ) - ) : ( - - - - ) - } - /> +
+ handleLayoutChange(layout)} + selectedLayout={activeLayout} + /> + + + + + + + + {currentProjectDetails?.inbox_view && inboxDetails && ( + + + + + + )} - } />} - /> -
- {currentProjectDetails?.is_deployed && deployUrl && ( - - - Public - - - )} -
-
- handleLayoutChange(layout)} - selectedLayout={activeLayout} - /> - - - - - - - - {currentProjectDetails?.inbox_view && inboxDetails && ( - - - - - - )} - {canUserCreateIssue && ( <> -
+
+ +
); diff --git a/web/components/headers/projects.tsx b/web/components/headers/projects.tsx index 34e8ffa08..34b1a6ef8 100644 --- a/web/components/headers/projects.tsx +++ b/web/components/headers/projects.tsx @@ -23,7 +23,7 @@ export const ProjectsHeader = observer(() => { return (
-
+
@@ -34,12 +34,12 @@ export const ProjectsHeader = observer(() => {
-
+
{workspaceProjectIds && workspaceProjectIds?.length > 0 && ( -
- +
+ setSearchQuery(e.target.value)} placeholder="Search" @@ -54,6 +54,7 @@ export const ProjectsHeader = observer(() => { setTrackElement("Projects page"); commandPaletteStore.toggleCreateProjectModal(true); }} + className="items-center" > Add Project diff --git a/web/components/headers/workspace-analytics.tsx b/web/components/headers/workspace-analytics.tsx index 8bb4c9251..4d54dd965 100644 --- a/web/components/headers/workspace-analytics.tsx +++ b/web/components/headers/workspace-analytics.tsx @@ -16,15 +16,6 @@ export const WorkspaceAnalyticsHeader = () => { >
-
- -
{ href="https://plane.so/changelog" target="_blank" rel="noopener noreferrer" - className="flex flex-shrink-0 items-center gap-1.5 rounded bg-custom-background-80 px-3 py-1.5 text-xs font-medium" + className="flex flex-shrink-0 items-center gap-1.5 rounded bg-custom-background-80 px-3 py-1.5" > - {"What's new?"} + {"What's new?"} { width={16} alt="GitHub Logo" /> - Star us on GitHub + Star us on GitHub
diff --git a/web/components/issues/issue-layouts/filters/header/helpers/dropdown.tsx b/web/components/issues/issue-layouts/filters/header/helpers/dropdown.tsx index 425f53b46..33b86ada1 100644 --- a/web/components/issues/issue-layouts/filters/header/helpers/dropdown.tsx +++ b/web/components/issues/issue-layouts/filters/header/helpers/dropdown.tsx @@ -13,10 +13,11 @@ type Props = { placement?: Placement; disabled?: boolean; tabIndex?: number; + menuButton?: React.ReactNode; }; export const FiltersDropdown: React.FC = (props) => { - const { children, title = "Dropdown", placement, disabled = false, tabIndex } = props; + const { children, title = "Dropdown", placement, disabled = false, tabIndex, menuButton } = props; const [referenceElement, setReferenceElement] = useState(null); const [popperElement, setPopperElement] = useState(null); @@ -33,7 +34,9 @@ export const FiltersDropdown: React.FC = (props) => { return ( <> - : + } { + const layouts = [ + { key: "list", title: "List", icon: List }, + { key: "kanban", title: "Kanban", icon: Kanban }, + { key: "calendar", title: "Calendar", icon: Calendar }, + ]; + const [analyticsModal, setAnalyticsModal] = useState(false); + const { workspaceSlug, projectId } = router.query as { + workspaceSlug: string; + 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( + (layout: TIssueLayouts) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }); + }, + [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)) { + 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, projectId, EIssueFilterType.FILTERS, { [key]: newValues }); + }, + [workspaceSlug, projectId, issueFilters, updateFilters] + ); + + const handleDisplayFilters = useCallback( + (updatedDisplayFilter: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter); + }, + [workspaceSlug, projectId, updateFilters] + ); + + const handleDisplayProperties = useCallback( + (property: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_PROPERTIES, property); + }, + [workspaceSlug, projectId, updateFilters] + ); + + return ( + <> + setAnalyticsModal(false)} + projectDetails={currentProjectDetails ?? undefined} + /> +
+ Layout} + customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm" + closeOnSelect + > + {layouts.map((layout, index) => ( + { + handleLayoutChange(ISSUE_LAYOUTS[index].key); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ))} +
+
+ + Filters + + + } + > + + +
+
+ + Display + + + } + > + + +
+ + +
+ + ); +}; diff --git a/web/components/modules/module-mobile-header.tsx b/web/components/modules/module-mobile-header.tsx new file mode 100644 index 000000000..b08c443d2 --- /dev/null +++ b/web/components/modules/module-mobile-header.tsx @@ -0,0 +1,162 @@ +import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types"; +import { CustomMenu } from "@plane/ui"; +import { ProjectAnalyticsModal } from "components/analytics"; +import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues"; +import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "constants/issue"; +import { useIssues, useLabel, useMember, useModule, useProjectState } from "hooks/store"; +import { Calendar, ChevronDown, Kanban, List } from "lucide-react"; +import router from "next/router"; +import { useCallback, useState } from "react"; + +export const ModuleMobileHeader = () => { + const [analyticsModal, setAnalyticsModal] = useState(false); + const { getModuleById } = useModule(); + const layouts = [ + { key: "list", title: "List", icon: List }, + { key: "kanban", title: "Kanban", icon: Kanban }, + { key: "calendar", title: "Calendar", icon: Calendar }, + ]; + const { workspaceSlug, projectId, moduleId } = router.query as { + workspaceSlug: string; + projectId: string; + moduleId: string; + }; + const moduleDetails = moduleId ? getModuleById(moduleId.toString()) : undefined; + + const { + issuesFilter: { issueFilters, updateFilters }, + } = useIssues(EIssuesStoreType.MODULE); + const activeLayout = issueFilters?.displayFilters?.layout; + const { projectStates } = useProjectState(); + const { projectLabels } = useLabel(); + const { + project: { projectMemberIds }, + } = useMember(); + + const handleLayoutChange = useCallback( + (layout: TIssueLayouts) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, moduleId); + }, + [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)) { + 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, projectId, EIssueFilterType.FILTERS, { [key]: newValues }, moduleId); + }, + [workspaceSlug, projectId, moduleId, issueFilters, updateFilters] + ); + + const handleDisplayFilters = useCallback( + (updatedDisplayFilter: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, updatedDisplayFilter, moduleId); + }, + [workspaceSlug, projectId, moduleId, updateFilters] + ); + + const handleDisplayProperties = useCallback( + (property: Partial) => { + if (!workspaceSlug || !projectId) return; + updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_PROPERTIES, property, moduleId); + }, + [workspaceSlug, projectId, moduleId, updateFilters] + ); + + return ( + <> + setAnalyticsModal(false)} + moduleDetails={moduleDetails ?? undefined} + /> +
+ Layout} + customButtonClassName="flex flex-grow justify-center text-custom-text-200 text-sm" + closeOnSelect + > + {layouts.map((layout, index) => ( + { + handleLayoutChange(ISSUE_LAYOUTS[index].key); + }} + className="flex items-center gap-2" + > + +
{layout.title}
+
+ ))} +
+
+ + Filters + + + } + > + + +
+
+ + Display + + + } + > + + +
+ + +
+ + ); +}; diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx index 22ec70b31..0541dfce4 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/index.tsx @@ -108,14 +108,13 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { selectedIndex={CYCLE_TAB_LIST.findIndex((i) => i.key == cycleTab)} onChange={(i) => handleCurrentView(CYCLE_TAB_LIST[i]?.key ?? "active")} > -
+
{CYCLE_TAB_LIST.map((tab) => ( - `border-b-2 p-4 text-sm font-medium outline-none ${ - selected ? "border-custom-primary-100 text-custom-primary-100" : "border-transparent" + `border-b-2 p-4 text-sm font-medium outline-none ${selected ? "border-custom-primary-100 text-custom-primary-100" : "border-transparent" }` } > @@ -123,32 +122,32 @@ const ProjectCyclesPage: NextPageWithLayout = observer(() => { ))} - {cycleTab !== "active" && ( -
- {CYCLE_VIEW_LAYOUTS.map((layout) => { - if (layout.key === "gantt" && cycleTab === "draft") return null; +
+ {cycleTab !== "active" && ( +
+ {CYCLE_VIEW_LAYOUTS.map((layout) => { + if (layout.key === "gantt" && cycleTab === "draft") return null; - return ( - - - - ); - })} -
- )} + return ( + + + + ); + })} +
+ )} +