forked from github/plane
[WEB-601] feat: enhanced display filters grouping by cycles and modules in project issues (#3834)
* feat: implemented cycle and module for display filters groupBy and sunGroupBy in project issues list and kanban layouts * chore: Enabled drag ability for cycle and handled prepopulated data for quick add * chore: disbaled drag ability for cycle * chore: updated preloaded data * chore: updated module and cycle store router dependancy to prop dependancy
This commit is contained in:
parent
56805203f1
commit
9326fb0762
2
packages/types/src/issues.d.ts
vendored
2
packages/types/src/issues.d.ts
vendored
@ -203,6 +203,8 @@ export interface ViewFlags {
|
|||||||
|
|
||||||
export type GroupByColumnTypes =
|
export type GroupByColumnTypes =
|
||||||
| "project"
|
| "project"
|
||||||
|
| "cycle"
|
||||||
|
| "module"
|
||||||
| "state"
|
| "state"
|
||||||
| "state_detail.group"
|
| "state_detail.group"
|
||||||
| "priority"
|
| "priority"
|
||||||
|
2
packages/types/src/view-props.d.ts
vendored
2
packages/types/src/view-props.d.ts
vendored
@ -14,6 +14,8 @@ export type TIssueGroupByOptions =
|
|||||||
| "project"
|
| "project"
|
||||||
| "assignees"
|
| "assignees"
|
||||||
| "mentions"
|
| "mentions"
|
||||||
|
| "cycle"
|
||||||
|
| "module"
|
||||||
| null;
|
| null;
|
||||||
|
|
||||||
export type TIssueOrderByOptions =
|
export type TIssueOrderByOptions =
|
||||||
|
@ -152,6 +152,7 @@ export const CycleMobileHeader = () => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
ignoreGroupedFilters={["cycle"]}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -244,6 +244,7 @@ export const CycleIssuesHeader: React.FC = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
ignoreGroupedFilters={["cycle"]}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
|
|
||||||
|
@ -248,6 +248,7 @@ export const ModuleIssuesHeader: React.FC = observer(() => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
ignoreGroupedFilters={["module"]}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
FilterSubGroupBy,
|
FilterSubGroupBy,
|
||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
// types
|
// types
|
||||||
import { IIssueDisplayFilterOptions, IIssueDisplayProperties } from "@plane/types";
|
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssueGroupByOptions } from "@plane/types";
|
||||||
import { ILayoutDisplayFiltersOptions } from "constants/issue";
|
import { ILayoutDisplayFiltersOptions } from "constants/issue";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -20,6 +20,7 @@ type Props = {
|
|||||||
handleDisplayFiltersUpdate: (updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => void;
|
handleDisplayFiltersUpdate: (updatedDisplayFilter: Partial<IIssueDisplayFilterOptions>) => void;
|
||||||
handleDisplayPropertiesUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
handleDisplayPropertiesUpdate: (updatedDisplayProperties: Partial<IIssueDisplayProperties>) => void;
|
||||||
layoutDisplayFiltersOptions: ILayoutDisplayFiltersOptions | undefined;
|
layoutDisplayFiltersOptions: ILayoutDisplayFiltersOptions | undefined;
|
||||||
|
ignoreGroupedFilters?: Partial<TIssueGroupByOptions>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
||||||
@ -29,6 +30,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
handleDisplayFiltersUpdate,
|
handleDisplayFiltersUpdate,
|
||||||
handleDisplayPropertiesUpdate,
|
handleDisplayPropertiesUpdate,
|
||||||
layoutDisplayFiltersOptions,
|
layoutDisplayFiltersOptions,
|
||||||
|
ignoreGroupedFilters = [],
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) =>
|
const isDisplayFilterEnabled = (displayFilter: keyof IIssueDisplayFilterOptions) =>
|
||||||
@ -54,6 +56,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
group_by: val,
|
group_by: val,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
ignoreGroupedFilters={ignoreGroupedFilters}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@ -71,6 +74,7 @@ export const DisplayFiltersSelection: React.FC<Props> = observer((props) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
subGroupByOptions={layoutDisplayFiltersOptions?.display_filters.sub_group_by ?? []}
|
subGroupByOptions={layoutDisplayFiltersOptions?.display_filters.sub_group_by ?? []}
|
||||||
|
ignoreGroupedFilters={ignoreGroupedFilters}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { FilterHeader, FilterOption } from "components/issues";
|
import { FilterHeader, FilterOption } from "components/issues";
|
||||||
// types
|
// types
|
||||||
@ -12,10 +11,11 @@ type Props = {
|
|||||||
displayFilters: IIssueDisplayFilterOptions;
|
displayFilters: IIssueDisplayFilterOptions;
|
||||||
groupByOptions: TIssueGroupByOptions[];
|
groupByOptions: TIssueGroupByOptions[];
|
||||||
handleUpdate: (val: TIssueGroupByOptions) => void;
|
handleUpdate: (val: TIssueGroupByOptions) => void;
|
||||||
|
ignoreGroupedFilters: Partial<TIssueGroupByOptions>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FilterGroupBy: React.FC<Props> = observer((props) => {
|
export const FilterGroupBy: React.FC<Props> = observer((props) => {
|
||||||
const { displayFilters, groupByOptions, handleUpdate } = props;
|
const { displayFilters, groupByOptions, handleUpdate, ignoreGroupedFilters } = props;
|
||||||
|
|
||||||
const [previewEnabled, setPreviewEnabled] = useState(true);
|
const [previewEnabled, setPreviewEnabled] = useState(true);
|
||||||
|
|
||||||
@ -34,6 +34,7 @@ export const FilterGroupBy: React.FC<Props> = observer((props) => {
|
|||||||
{ISSUE_GROUP_BY_OPTIONS.filter((option) => groupByOptions.includes(option.key)).map((groupBy) => {
|
{ISSUE_GROUP_BY_OPTIONS.filter((option) => groupByOptions.includes(option.key)).map((groupBy) => {
|
||||||
if (displayFilters.layout === "kanban" && selectedSubGroupBy !== null && groupBy.key === selectedSubGroupBy)
|
if (displayFilters.layout === "kanban" && selectedSubGroupBy !== null && groupBy.key === selectedSubGroupBy)
|
||||||
return null;
|
return null;
|
||||||
|
if (ignoreGroupedFilters.includes(groupBy?.key)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FilterOption
|
<FilterOption
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { FilterHeader, FilterOption } from "components/issues";
|
import { FilterHeader, FilterOption } from "components/issues";
|
||||||
// types
|
// types
|
||||||
@ -12,10 +11,11 @@ type Props = {
|
|||||||
displayFilters: IIssueDisplayFilterOptions;
|
displayFilters: IIssueDisplayFilterOptions;
|
||||||
handleUpdate: (val: TIssueGroupByOptions) => void;
|
handleUpdate: (val: TIssueGroupByOptions) => void;
|
||||||
subGroupByOptions: TIssueGroupByOptions[];
|
subGroupByOptions: TIssueGroupByOptions[];
|
||||||
|
ignoreGroupedFilters: Partial<TIssueGroupByOptions>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FilterSubGroupBy: React.FC<Props> = observer((props) => {
|
export const FilterSubGroupBy: React.FC<Props> = observer((props) => {
|
||||||
const { displayFilters, handleUpdate, subGroupByOptions } = props;
|
const { displayFilters, handleUpdate, subGroupByOptions, ignoreGroupedFilters } = props;
|
||||||
|
|
||||||
const [previewEnabled, setPreviewEnabled] = useState(true);
|
const [previewEnabled, setPreviewEnabled] = useState(true);
|
||||||
|
|
||||||
@ -33,6 +33,7 @@ export const FilterSubGroupBy: React.FC<Props> = observer((props) => {
|
|||||||
<div>
|
<div>
|
||||||
{ISSUE_GROUP_BY_OPTIONS.filter((option) => subGroupByOptions.includes(option.key)).map((subGroupBy) => {
|
{ISSUE_GROUP_BY_OPTIONS.filter((option) => subGroupByOptions.includes(option.key)).map((subGroupBy) => {
|
||||||
if (selectedGroupBy !== null && subGroupBy.key === selectedGroupBy) return null;
|
if (selectedGroupBy !== null && subGroupBy.key === selectedGroupBy) return null;
|
||||||
|
if (ignoreGroupedFilters.includes(subGroupBy?.key)) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FilterOption
|
<FilterOption
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
// hooks
|
// hooks
|
||||||
import { useIssueDetail, useKanbanView, useLabel, useMember, useProject, useProjectState } from "hooks/store";
|
import {
|
||||||
|
useCycle,
|
||||||
|
useIssueDetail,
|
||||||
|
useKanbanView,
|
||||||
|
useLabel,
|
||||||
|
useMember,
|
||||||
|
useModule,
|
||||||
|
useProject,
|
||||||
|
useProjectState,
|
||||||
|
} from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { HeaderGroupByCard } from "./headers/group-by-card";
|
import { HeaderGroupByCard } from "./headers/group-by-card";
|
||||||
import { KanbanGroup } from "./kanban-group";
|
import { KanbanGroup } from "./kanban-group";
|
||||||
@ -79,14 +88,16 @@ const GroupByKanBan: React.FC<IGroupByKanBan> = observer((props) => {
|
|||||||
const member = useMember();
|
const member = useMember();
|
||||||
const project = useProject();
|
const project = useProject();
|
||||||
const label = useLabel();
|
const label = useLabel();
|
||||||
|
const cycle = useCycle();
|
||||||
|
const _module = useModule();
|
||||||
const projectState = useProjectState();
|
const projectState = useProjectState();
|
||||||
const { peekIssue } = useIssueDetail();
|
const { peekIssue } = useIssueDetail();
|
||||||
|
|
||||||
const list = getGroupByColumns(group_by as GroupByColumnTypes, project, label, projectState, member);
|
const list = getGroupByColumns(group_by as GroupByColumnTypes, project, cycle, _module, label, projectState, member);
|
||||||
|
|
||||||
if (!list) return null;
|
if (!list) return null;
|
||||||
|
|
||||||
const groupWithIssues = list.filter((_list) => (issueIds as TGroupedIssues)[_list.id]?.length > 0);
|
const groupWithIssues = list.filter((_list) => (issueIds as TGroupedIssues)?.[_list.id]?.length > 0);
|
||||||
|
|
||||||
const groupList = showEmptyGroup ? list : groupWithIssues;
|
const groupList = showEmptyGroup ? list : groupWithIssues;
|
||||||
|
|
||||||
|
@ -80,6 +80,10 @@ export const KanbanGroup = (props: IKanbanGroup) => {
|
|||||||
preloadedData = { ...preloadedData, state_id: groupValue };
|
preloadedData = { ...preloadedData, state_id: groupValue };
|
||||||
} else if (groupByKey === "priority") {
|
} else if (groupByKey === "priority") {
|
||||||
preloadedData = { ...preloadedData, priority: groupValue };
|
preloadedData = { ...preloadedData, priority: groupValue };
|
||||||
|
} else if (groupByKey === "cycle") {
|
||||||
|
preloadedData = { ...preloadedData, cycle_id: groupValue };
|
||||||
|
} else if (groupByKey === "module") {
|
||||||
|
preloadedData = { ...preloadedData, module_ids: [groupValue] };
|
||||||
} else if (groupByKey === "labels" && groupValue != "None") {
|
} else if (groupByKey === "labels" && groupValue != "None") {
|
||||||
preloadedData = { ...preloadedData, label_ids: [groupValue] };
|
preloadedData = { ...preloadedData, label_ids: [groupValue] };
|
||||||
} else if (groupByKey === "assignees" && groupValue != "None") {
|
} else if (groupByKey === "assignees" && groupValue != "None") {
|
||||||
@ -96,6 +100,10 @@ export const KanbanGroup = (props: IKanbanGroup) => {
|
|||||||
preloadedData = { ...preloadedData, state_id: subGroupValue };
|
preloadedData = { ...preloadedData, state_id: subGroupValue };
|
||||||
} else if (subGroupByKey === "priority") {
|
} else if (subGroupByKey === "priority") {
|
||||||
preloadedData = { ...preloadedData, priority: subGroupValue };
|
preloadedData = { ...preloadedData, priority: subGroupValue };
|
||||||
|
} else if (groupByKey === "cycle") {
|
||||||
|
preloadedData = { ...preloadedData, cycle_id: subGroupValue };
|
||||||
|
} else if (groupByKey === "module") {
|
||||||
|
preloadedData = { ...preloadedData, module_ids: [subGroupValue] };
|
||||||
} else if (subGroupByKey === "labels" && subGroupValue != "None") {
|
} else if (subGroupByKey === "labels" && subGroupValue != "None") {
|
||||||
preloadedData = { ...preloadedData, label_ids: [subGroupValue] };
|
preloadedData = { ...preloadedData, label_ids: [subGroupValue] };
|
||||||
} else if (subGroupByKey === "assignees" && subGroupValue != "None") {
|
} else if (subGroupByKey === "assignees" && subGroupValue != "None") {
|
||||||
|
@ -18,7 +18,7 @@ import {
|
|||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
import { EIssueActions } from "../types";
|
import { EIssueActions } from "../types";
|
||||||
import { useLabel, useMember, useProject, useProjectState } from "hooks/store";
|
import { useCycle, useLabel, useMember, useModule, useProject, useProjectState } from "hooks/store";
|
||||||
import { getGroupByColumns } from "../utils";
|
import { getGroupByColumns } from "../utils";
|
||||||
import { TCreateModalStoreTypes } from "constants/issue";
|
import { TCreateModalStoreTypes } from "constants/issue";
|
||||||
|
|
||||||
@ -217,10 +217,28 @@ export const KanBanSwimLanes: React.FC<IKanBanSwimLanes> = observer((props) => {
|
|||||||
const member = useMember();
|
const member = useMember();
|
||||||
const project = useProject();
|
const project = useProject();
|
||||||
const label = useLabel();
|
const label = useLabel();
|
||||||
|
const cycle = useCycle();
|
||||||
|
const _module = useModule();
|
||||||
const projectState = useProjectState();
|
const projectState = useProjectState();
|
||||||
|
|
||||||
const groupByList = getGroupByColumns(group_by as GroupByColumnTypes, project, label, projectState, member);
|
const groupByList = getGroupByColumns(
|
||||||
const subGroupByList = getGroupByColumns(sub_group_by as GroupByColumnTypes, project, label, projectState, member);
|
group_by as GroupByColumnTypes,
|
||||||
|
project,
|
||||||
|
cycle,
|
||||||
|
_module,
|
||||||
|
label,
|
||||||
|
projectState,
|
||||||
|
member
|
||||||
|
);
|
||||||
|
const subGroupByList = getGroupByColumns(
|
||||||
|
sub_group_by as GroupByColumnTypes,
|
||||||
|
project,
|
||||||
|
cycle,
|
||||||
|
_module,
|
||||||
|
label,
|
||||||
|
projectState,
|
||||||
|
member
|
||||||
|
);
|
||||||
|
|
||||||
if (!groupByList || !subGroupByList) return null;
|
if (!groupByList || !subGroupByList) return null;
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ import { useRef } from "react";
|
|||||||
import { IssueBlocksList, ListQuickAddIssueForm } from "components/issues";
|
import { IssueBlocksList, ListQuickAddIssueForm } from "components/issues";
|
||||||
import { HeaderGroupByCard } from "./headers/group-by-card";
|
import { HeaderGroupByCard } from "./headers/group-by-card";
|
||||||
// hooks
|
// hooks
|
||||||
import { useLabel, useMember, useProject, useProjectState } from "hooks/store";
|
import { useCycle, useLabel, useMember, useModule, useProject, useProjectState } from "hooks/store";
|
||||||
// types
|
// types
|
||||||
import {
|
import {
|
||||||
GroupByColumnTypes,
|
GroupByColumnTypes,
|
||||||
@ -65,10 +65,21 @@ const GroupByList: React.FC<IGroupByList> = (props) => {
|
|||||||
const project = useProject();
|
const project = useProject();
|
||||||
const label = useLabel();
|
const label = useLabel();
|
||||||
const projectState = useProjectState();
|
const projectState = useProjectState();
|
||||||
|
const cycle = useCycle();
|
||||||
|
const _module = useModule();
|
||||||
|
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
|
||||||
const groups = getGroupByColumns(group_by as GroupByColumnTypes, project, label, projectState, member, true);
|
const groups = getGroupByColumns(
|
||||||
|
group_by as GroupByColumnTypes,
|
||||||
|
project,
|
||||||
|
cycle,
|
||||||
|
_module,
|
||||||
|
label,
|
||||||
|
projectState,
|
||||||
|
member,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
if (!groups) return null;
|
if (!groups) return null;
|
||||||
|
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
import { Avatar, PriorityIcon, StateGroupIcon } from "@plane/ui";
|
import { Avatar, CycleGroupIcon, DiceIcon, PriorityIcon, StateGroupIcon } from "@plane/ui";
|
||||||
import { EIssueListRow, ISSUE_PRIORITIES } from "constants/issue";
|
// stores
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
|
||||||
import { IMemberRootStore } from "store/member";
|
import { IMemberRootStore } from "store/member";
|
||||||
import { IProjectStore } from "store/project/project.store";
|
import { IProjectStore } from "store/project/project.store";
|
||||||
import { IStateStore } from "store/state.store";
|
import { IStateStore } from "store/state.store";
|
||||||
import { GroupByColumnTypes, IGroupByColumn, IIssueListRow, TGroupedIssues, TUnGroupedIssues } from "@plane/types";
|
|
||||||
import { STATE_GROUPS } from "constants/state";
|
|
||||||
import { ILabelStore } from "store/label.store";
|
import { ILabelStore } from "store/label.store";
|
||||||
|
import { ICycleStore } from "store/cycle.store";
|
||||||
|
import { IModuleStore } from "store/module.store";
|
||||||
|
// helpers
|
||||||
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
|
// constants
|
||||||
|
import { STATE_GROUPS } from "constants/state";
|
||||||
|
import { ISSUE_PRIORITIES } from "constants/issue";
|
||||||
|
// types
|
||||||
|
import { GroupByColumnTypes, IGroupByColumn, TCycleGroups } from "@plane/types";
|
||||||
|
import { ContrastIcon } from "lucide-react";
|
||||||
|
|
||||||
export const getGroupByColumns = (
|
export const getGroupByColumns = (
|
||||||
groupBy: GroupByColumnTypes | null,
|
groupBy: GroupByColumnTypes | null,
|
||||||
project: IProjectStore,
|
project: IProjectStore,
|
||||||
|
cycle: ICycleStore,
|
||||||
|
module: IModuleStore,
|
||||||
label: ILabelStore,
|
label: ILabelStore,
|
||||||
projectState: IStateStore,
|
projectState: IStateStore,
|
||||||
member: IMemberRootStore,
|
member: IMemberRootStore,
|
||||||
@ -19,6 +28,10 @@ export const getGroupByColumns = (
|
|||||||
switch (groupBy) {
|
switch (groupBy) {
|
||||||
case "project":
|
case "project":
|
||||||
return getProjectColumns(project);
|
return getProjectColumns(project);
|
||||||
|
case "cycle":
|
||||||
|
return getCycleColumns(project, cycle);
|
||||||
|
case "module":
|
||||||
|
return getModuleColumns(project, module);
|
||||||
case "state":
|
case "state":
|
||||||
return getStateColumns(projectState);
|
return getStateColumns(projectState);
|
||||||
case "state_detail.group":
|
case "state_detail.group":
|
||||||
@ -55,6 +68,68 @@ const getProjectColumns = (project: IProjectStore): IGroupByColumn[] | undefined
|
|||||||
}) as any;
|
}) as any;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCycleColumns = (projectStore: IProjectStore, cycleStore: ICycleStore): IGroupByColumn[] | undefined => {
|
||||||
|
const { currentProjectDetails } = projectStore;
|
||||||
|
const { getProjectCycleIds, getCycleById } = cycleStore;
|
||||||
|
|
||||||
|
if (!currentProjectDetails || !currentProjectDetails?.id) return;
|
||||||
|
|
||||||
|
const cycleIds = currentProjectDetails?.id ? getProjectCycleIds(currentProjectDetails?.id) : undefined;
|
||||||
|
if (!cycleIds) return;
|
||||||
|
|
||||||
|
const cycles = [];
|
||||||
|
|
||||||
|
cycleIds.map((cycleId) => {
|
||||||
|
const cycle = getCycleById(cycleId);
|
||||||
|
if (cycle) {
|
||||||
|
const cycleStatus = cycle.status ? (cycle.status.toLocaleLowerCase() as TCycleGroups) : "draft";
|
||||||
|
cycles.push({
|
||||||
|
id: cycle.id,
|
||||||
|
name: cycle.name,
|
||||||
|
icon: <CycleGroupIcon cycleGroup={cycleStatus as TCycleGroups} className="h-3.5 w-3.5" />,
|
||||||
|
payload: { cycle_id: cycle.id },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
cycles.push({
|
||||||
|
id: "None",
|
||||||
|
name: "None",
|
||||||
|
icon: <ContrastIcon className="h-3.5 w-3.5" />,
|
||||||
|
});
|
||||||
|
|
||||||
|
return cycles as any;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getModuleColumns = (projectStore: IProjectStore, moduleStore: IModuleStore): IGroupByColumn[] | undefined => {
|
||||||
|
const { currentProjectDetails } = projectStore;
|
||||||
|
const { getProjectModuleIds, getModuleById } = moduleStore;
|
||||||
|
|
||||||
|
if (!currentProjectDetails || !currentProjectDetails?.id) return;
|
||||||
|
|
||||||
|
const moduleIds = currentProjectDetails?.id ? getProjectModuleIds(currentProjectDetails?.id) : undefined;
|
||||||
|
if (!moduleIds) return;
|
||||||
|
|
||||||
|
const modules = [];
|
||||||
|
|
||||||
|
moduleIds.map((moduleId) => {
|
||||||
|
const _module = getModuleById(moduleId);
|
||||||
|
if (_module)
|
||||||
|
modules.push({
|
||||||
|
id: _module.id,
|
||||||
|
name: _module.name,
|
||||||
|
icon: <DiceIcon className="w-3.5 h-3.5" />,
|
||||||
|
payload: { module_ids: [_module.id] },
|
||||||
|
});
|
||||||
|
}) as any;
|
||||||
|
modules.push({
|
||||||
|
id: "None",
|
||||||
|
name: "None",
|
||||||
|
icon: <DiceIcon className="w-3.5 h-3.5" />,
|
||||||
|
});
|
||||||
|
|
||||||
|
return modules as any;
|
||||||
|
};
|
||||||
|
|
||||||
const getStateColumns = (projectState: IStateStore): IGroupByColumn[] | undefined => {
|
const getStateColumns = (projectState: IStateStore): IGroupByColumn[] | undefined => {
|
||||||
const { projectStates } = projectState;
|
const { projectStates } = projectState;
|
||||||
if (!projectStates) return;
|
if (!projectStates) return;
|
||||||
|
@ -146,6 +146,7 @@ export const ModuleMobileHeader = () => {
|
|||||||
handleDisplayFiltersUpdate={handleDisplayFilters}
|
handleDisplayFiltersUpdate={handleDisplayFilters}
|
||||||
displayProperties={issueFilters?.displayProperties ?? {}}
|
displayProperties={issueFilters?.displayProperties ?? {}}
|
||||||
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
handleDisplayPropertiesUpdate={handleDisplayProperties}
|
||||||
|
ignoreGroupedFilters={["module"]}
|
||||||
/>
|
/>
|
||||||
</FiltersDropdown>
|
</FiltersDropdown>
|
||||||
</div>
|
</div>
|
||||||
|
@ -49,22 +49,6 @@ export const ISSUE_PRIORITIES: {
|
|||||||
{ key: "none", title: "None" },
|
{ key: "none", title: "None" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ISSUE_START_DATE_OPTIONS = [
|
|
||||||
{ key: "last_week", title: "Last Week" },
|
|
||||||
{ key: "2_weeks_from_now", title: "2 weeks from now" },
|
|
||||||
{ key: "1_month_from_now", title: "1 month from now" },
|
|
||||||
{ key: "2_months_from_now", title: "2 months from now" },
|
|
||||||
{ key: "custom", title: "Custom" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_DUE_DATE_OPTIONS = [
|
|
||||||
{ key: "last_week", title: "Last Week" },
|
|
||||||
{ key: "2_weeks_from_now", title: "2 weeks from now" },
|
|
||||||
{ key: "1_month_from_now", title: "1 month from now" },
|
|
||||||
{ key: "2_months_from_now", title: "2 months from now" },
|
|
||||||
{ key: "custom", title: "Custom" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_GROUP_BY_OPTIONS: {
|
export const ISSUE_GROUP_BY_OPTIONS: {
|
||||||
key: TIssueGroupByOptions;
|
key: TIssueGroupByOptions;
|
||||||
title: string;
|
title: string;
|
||||||
@ -73,6 +57,8 @@ export const ISSUE_GROUP_BY_OPTIONS: {
|
|||||||
{ key: "state_detail.group", title: "State Groups" },
|
{ key: "state_detail.group", title: "State Groups" },
|
||||||
{ key: "priority", title: "Priority" },
|
{ key: "priority", title: "Priority" },
|
||||||
{ key: "project", title: "Project" }, // required this on my issues
|
{ key: "project", title: "Project" }, // required this on my issues
|
||||||
|
{ key: "cycle", title: "Cycle" }, // required this on my issues
|
||||||
|
{ key: "module", title: "Module" }, // required this on my issues
|
||||||
{ key: "labels", title: "Labels" },
|
{ key: "labels", title: "Labels" },
|
||||||
{ key: "assignees", title: "Assignees" },
|
{ key: "assignees", title: "Assignees" },
|
||||||
{ key: "created_by", title: "Created By" },
|
{ key: "created_by", title: "Created By" },
|
||||||
@ -140,81 +126,6 @@ export const ISSUE_LAYOUTS: {
|
|||||||
{ key: "gantt_chart", title: "Gantt Chart Layout", icon: GanttChartSquare },
|
{ key: "gantt_chart", title: "Gantt Chart Layout", icon: GanttChartSquare },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ISSUE_LIST_FILTERS = [
|
|
||||||
{ key: "mentions", title: "Mentions" },
|
|
||||||
{ key: "priority", title: "Priority" },
|
|
||||||
{ key: "state", title: "State" },
|
|
||||||
{ key: "assignees", title: "Assignees" },
|
|
||||||
{ key: "created_by", title: "Created By" },
|
|
||||||
{ key: "labels", title: "Labels" },
|
|
||||||
{ key: "start_date", title: "Start Date" },
|
|
||||||
{ key: "due_date", title: "Due Date" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_KANBAN_FILTERS = [
|
|
||||||
{ key: "priority", title: "Priority" },
|
|
||||||
{ key: "state", title: "State" },
|
|
||||||
{ key: "assignees", title: "Assignees" },
|
|
||||||
{ key: "created_by", title: "Created By" },
|
|
||||||
{ key: "labels", title: "Labels" },
|
|
||||||
{ key: "start_date", title: "Start Date" },
|
|
||||||
{ key: "due_date", title: "Due Date" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_CALENDER_FILTERS = [
|
|
||||||
{ key: "priority", title: "Priority" },
|
|
||||||
{ key: "state", title: "State" },
|
|
||||||
{ key: "assignees", title: "Assignees" },
|
|
||||||
{ key: "created_by", title: "Created By" },
|
|
||||||
{ key: "labels", title: "Labels" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_SPREADSHEET_FILTERS = [
|
|
||||||
{ key: "priority", title: "Priority" },
|
|
||||||
{ key: "state", title: "State" },
|
|
||||||
{ key: "assignees", title: "Assignees" },
|
|
||||||
{ key: "created_by", title: "Created By" },
|
|
||||||
{ key: "labels", title: "Labels" },
|
|
||||||
{ key: "start_date", title: "Start Date" },
|
|
||||||
{ key: "due_date", title: "Due Date" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_GANTT_FILTERS = [
|
|
||||||
{ key: "priority", title: "Priority" },
|
|
||||||
{ key: "state", title: "State" },
|
|
||||||
{ key: "assignees", title: "Assignees" },
|
|
||||||
{ key: "created_by", title: "Created By" },
|
|
||||||
{ key: "labels", title: "Labels" },
|
|
||||||
{ key: "start_date", title: "Start Date" },
|
|
||||||
{ key: "due_date", title: "Due Date" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_LIST_DISPLAY_FILTERS = [
|
|
||||||
{ key: "group_by", title: "Group By" },
|
|
||||||
{ key: "order_by", title: "Order By" },
|
|
||||||
{ key: "issue_type", title: "Issue Type" },
|
|
||||||
{ key: "sub_issue", title: "Sub Issue" },
|
|
||||||
{ key: "show_empty_groups", title: "Show Empty Groups" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_KANBAN_DISPLAY_FILTERS = [
|
|
||||||
{ key: "group_by", title: "Group By" },
|
|
||||||
{ key: "order_by", title: "Order By" },
|
|
||||||
{ key: "issue_type", title: "Issue Type" },
|
|
||||||
{ key: "sub_issue", title: "Sub Issue" },
|
|
||||||
{ key: "show_empty_groups", title: "Show Empty Groups" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export const ISSUE_CALENDER_DISPLAY_FILTERS = [{ key: "issue_type", title: "Issue Type" }];
|
|
||||||
|
|
||||||
export const ISSUE_SPREADSHEET_DISPLAY_FILTERS = [{ key: "issue_type", title: "Issue Type" }];
|
|
||||||
|
|
||||||
export const ISSUE_GANTT_DISPLAY_FILTERS = [
|
|
||||||
{ key: "order_by", title: "Order By" },
|
|
||||||
{ key: "issue_type", title: "Issue Type" },
|
|
||||||
{ key: "sub_issue", title: "Sub Issue" },
|
|
||||||
];
|
|
||||||
|
|
||||||
export interface ILayoutDisplayFiltersOptions {
|
export interface ILayoutDisplayFiltersOptions {
|
||||||
filters: (keyof IIssueFilterOptions)[];
|
filters: (keyof IIssueFilterOptions)[];
|
||||||
display_properties: boolean;
|
display_properties: boolean;
|
||||||
@ -276,7 +187,17 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
],
|
],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state", "state_detail.group", "priority", "labels", "assignees", "created_by", null],
|
group_by: [
|
||||||
|
"state",
|
||||||
|
"cycle",
|
||||||
|
"module",
|
||||||
|
"state_detail.group",
|
||||||
|
"priority",
|
||||||
|
"labels",
|
||||||
|
"assignees",
|
||||||
|
"created_by",
|
||||||
|
null,
|
||||||
|
],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
@ -291,7 +212,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
filters: ["priority", "state_group", "cycle", "module", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "cycle", "module", "labels", "start_date", "target_date"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state_detail.group", "priority", "project", "labels", null],
|
group_by: ["state_detail.group", "cycle", "module", "priority", "project", "labels", null],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
@ -304,7 +225,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
filters: ["priority", "state_group", "cycle", "module", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "cycle", "module", "labels", "start_date", "target_date"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state_detail.group", "priority", "project", "labels"],
|
group_by: ["state_detail.group", "cycle", "module", "priority", "project", "labels"],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
@ -374,7 +295,7 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
],
|
],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state", "priority", "labels", "assignees", "created_by", null],
|
group_by: ["state", "priority", "cycle", "module", "labels", "assignees", "created_by", null],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
@ -398,8 +319,8 @@ export const ISSUE_DISPLAY_FILTERS_BY_LAYOUT: {
|
|||||||
],
|
],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
display_filters: {
|
display_filters: {
|
||||||
group_by: ["state", "priority", "labels", "assignees", "created_by"],
|
group_by: ["state", "priority", "cycle", "module", "labels", "assignees", "created_by"],
|
||||||
sub_group_by: ["state", "priority", "labels", "assignees", "created_by", null],
|
sub_group_by: ["state", "priority", "cycle", "module", "labels", "assignees", "created_by", null],
|
||||||
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority", "target_date"],
|
order_by: ["sort_order", "-created_at", "-updated_at", "start_date", "-priority", "target_date"],
|
||||||
type: [null, "active", "backlog"],
|
type: [null, "active", "backlog"],
|
||||||
},
|
},
|
||||||
|
@ -36,6 +36,8 @@ export type TIssueHelperStore = {
|
|||||||
|
|
||||||
const ISSUE_FILTER_DEFAULT_DATA: Record<TIssueDisplayFilterOptions, keyof TIssue> = {
|
const ISSUE_FILTER_DEFAULT_DATA: Record<TIssueDisplayFilterOptions, keyof TIssue> = {
|
||||||
project: "project_id",
|
project: "project_id",
|
||||||
|
cycle: "cycle_id",
|
||||||
|
module: "module_ids",
|
||||||
state: "state_id",
|
state: "state_id",
|
||||||
"state_detail.group": "state_group" as keyof TIssue, // state_detail.group is only being used for state_group display,
|
"state_detail.group": "state_group" as keyof TIssue, // state_detail.group is only being used for state_group display,
|
||||||
priority: "priority",
|
priority: "priority",
|
||||||
@ -157,6 +159,10 @@ export class IssueHelperStore implements TIssueHelperStore {
|
|||||||
return Object.keys(this.rootStore?.workSpaceMemberRolesMap || {});
|
return Object.keys(this.rootStore?.workSpaceMemberRolesMap || {});
|
||||||
case "project":
|
case "project":
|
||||||
return Object.keys(this.rootStore?.projectMap || {});
|
return Object.keys(this.rootStore?.projectMap || {});
|
||||||
|
case "cycle":
|
||||||
|
return Object.keys(this.rootStore?.cycleMap || {});
|
||||||
|
case "module":
|
||||||
|
return Object.keys(this.rootStore?.moduleMap || {});
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user