chore: store fixes and static data setup

This commit is contained in:
sriramveeraghanta 2023-09-20 23:39:55 +05:30
parent e96bc77215
commit 6d52801ea7
23 changed files with 568 additions and 2005 deletions

View File

@ -27,7 +27,7 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper";
// types
import { Properties, TIssueViewOptions } from "types";
// constants
import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "constants/issue";
import { ISSUE_GROUP_BY_OPTIONS, ISSUE_ORDER_BY_OPTIONS, ISSUE_FILTER_OPTIONS } from "constants/issue";
const issueViewOptions: { type: TIssueViewOptions; Icon: any }[] = [
{
@ -69,19 +69,10 @@ export const IssuesFilterView: React.FC = () => {
const isArchivedIssues = router.pathname.includes("archived-issues");
const isDraftIssues = router.pathname.includes("draft-issues");
const {
displayFilters,
setDisplayFilters,
filters,
setFilters,
resetFilterToDefault,
setNewFilterDefaultView,
} = useIssuesView();
const { displayFilters, setDisplayFilters, filters, setFilters, resetFilterToDefault, setNewFilterDefaultView } =
useIssuesView();
const [properties, setProperties] = useIssuesProperties(
workspaceSlug as string,
projectId as string
);
const [properties, setProperties] = useIssuesProperties(workspaceSlug as string, projectId as string);
const { isEstimateActive } = useEstimateOption();
@ -92,9 +83,7 @@ export const IssuesFilterView: React.FC = () => {
{issueViewOptions.map((option) => (
<Tooltip
key={option.type}
tooltipContent={
<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>
}
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>}
position="bottom"
>
<button
@ -122,9 +111,7 @@ export const IssuesFilterView: React.FC = () => {
{issueViewForDraftIssues.map((option) => (
<Tooltip
key={option.type}
tooltipContent={
<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>
}
tooltipContent={<span className="capitalize">{replaceUnderscoreIfSnakeCase(option.type)} View</span>}
position="bottom"
>
<button
@ -164,9 +151,7 @@ export const IssuesFilterView: React.FC = () => {
if (valueExists)
setFilters(
{
[option.key]: ((filters[key] ?? []) as any[])?.filter(
(val) => val !== option.value
),
[option.key]: ((filters[key] ?? []) as any[])?.filter((val) => val !== option.value),
},
!Boolean(viewId)
);
@ -187,9 +172,7 @@ export const IssuesFilterView: React.FC = () => {
<>
<Popover.Button
className={`group flex items-center gap-2 rounded-md border border-custom-border-200 px-3 py-1.5 text-xs hover:bg-custom-sidebar-background-90 hover:text-custom-sidebar-text-100 focus:outline-none duration-300 ${
open
? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100"
: "text-custom-sidebar-text-200"
open ? "bg-custom-sidebar-background-90 text-custom-sidebar-text-100" : "text-custom-sidebar-text-200"
}`}
>
Display
@ -216,24 +199,24 @@ export const IssuesFilterView: React.FC = () => {
<div className="w-28">
<CustomMenu
label={
GROUP_BY_OPTIONS.find(
(option) => option.key === displayFilters.group_by
)?.name ?? "Select"
ISSUE_GROUP_BY_OPTIONS.find((option) => option.key === displayFilters.group_by)
?.title ?? "Select"
}
className="!w-full"
buttonClassName="w-full"
>
{GROUP_BY_OPTIONS.map((option) => {
if (displayFilters.layout === "kanban" && option.key === null)
return null;
{ISSUE_GROUP_BY_OPTIONS.map((option) => {
if (displayFilters.layout === "kanban" && option.key === null) return null;
if (option.key === "project") return null;
return (
<CustomMenu.MenuItem
key={option.key}
onClick={() => setDisplayFilters({ group_by: option.key })}
onClick={() => {
// setDisplayFilters({ group_by: option.key })
}}
>
{option.name}
{option.title}
</CustomMenu.MenuItem>
);
})}
@ -241,79 +224,71 @@ export const IssuesFilterView: React.FC = () => {
</div>
</div>
)}
{displayFilters.layout !== "calendar" &&
displayFilters.layout !== "spreadsheet" && (
<div className="flex items-center justify-between">
<h4 className="text-custom-text-200">Order by</h4>
<div className="w-28">
<CustomMenu
label={
ORDER_BY_OPTIONS.find(
(option) => option.key === displayFilters.order_by
)?.name ?? "Select"
}
className="!w-full"
buttonClassName="w-full"
>
{ORDER_BY_OPTIONS.map((option) =>
displayFilters.group_by === "priority" &&
option.key === "priority" ? null : (
<CustomMenu.MenuItem
key={option.key}
onClick={() => {
setDisplayFilters({ order_by: option.key });
}}
>
{option.name}
</CustomMenu.MenuItem>
)
)}
</CustomMenu>
</div>
{displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && (
<div className="flex items-center justify-between">
<h4 className="text-custom-text-200">Order by</h4>
<div className="w-28">
<CustomMenu
label={
ISSUE_ORDER_BY_OPTIONS.find((option) => option.key === displayFilters.order_by)?.title ??
"Select"
}
className="!w-full"
buttonClassName="w-full"
>
{ISSUE_ORDER_BY_OPTIONS.map((option) =>
displayFilters.group_by === "priority" && option.key === "priority" ? null : (
<CustomMenu.MenuItem
key={option.key}
onClick={() => {
// setDisplayFilters({ order_by: option.key });
}}
>
{option.title}
</CustomMenu.MenuItem>
)
)}
</CustomMenu>
</div>
)}
</div>
)}
<div className="flex items-center justify-between">
<h4 className="text-custom-text-200">Issue type</h4>
<div className="w-28">
<CustomMenu
label={
FILTER_ISSUE_OPTIONS.find(
(option) => option.key === displayFilters.type
)?.name ?? "Select"
ISSUE_FILTER_OPTIONS.find((option) => option.key === displayFilters.type)?.title ?? "Select"
}
className="!w-full"
buttonClassName="w-full"
>
{FILTER_ISSUE_OPTIONS.map((option) => (
{ISSUE_FILTER_OPTIONS.map((option) => (
<CustomMenu.MenuItem
key={option.key}
onClick={() =>
setDisplayFilters({
type: option.key,
})
}
onClick={() => {
// setDisplayFilters({
// type: option.key,
// })
}}
>
{option.name}
{option.title}
</CustomMenu.MenuItem>
))}
</CustomMenu>
</div>
</div>
{displayFilters.layout !== "calendar" &&
displayFilters.layout !== "spreadsheet" && (
<div className="flex items-center justify-between">
<h4 className="text-custom-text-200">Show sub-issues</h4>
<div className="w-28">
<ToggleSwitch
value={displayFilters.sub_issue ?? true}
onChange={() =>
setDisplayFilters({ sub_issue: !displayFilters.sub_issue })
}
/>
</div>
{displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && (
<div className="flex items-center justify-between">
<h4 className="text-custom-text-200">Show sub-issues</h4>
<div className="w-28">
<ToggleSwitch
value={displayFilters.sub_issue ?? true}
onChange={() => setDisplayFilters({ sub_issue: !displayFilters.sub_issue })}
/>
</div>
)}
</div>
)}
{displayFilters.layout !== "calendar" &&
displayFilters.layout !== "spreadsheet" &&
displayFilters.layout !== "gantt_chart" && (
@ -358,16 +333,11 @@ export const IssuesFilterView: React.FC = () => {
if (
displayFilters.layout === "spreadsheet" &&
(key === "attachment_count" ||
key === "link" ||
key === "sub_issue_count")
(key === "attachment_count" || key === "link" || key === "sub_issue_count")
)
return null;
if (
displayFilters.layout !== "spreadsheet" &&
(key === "created_on" || key === "updated_on")
)
if (displayFilters.layout !== "spreadsheet" && (key === "created_on" || key === "updated_on"))
return null;
return (

View File

@ -36,7 +36,7 @@ import {
} from "@heroicons/react/24/outline";
import { LayerDiagonalIcon } from "components/icons";
// helpers
import { handleIssuesMutation } from "constants/issue";
import { handleIssuesMutation } from "helpers/issue.helper";
import { copyTextToClipboard } from "helpers/string.helper";
// types
import { ICurrentUserResponse, IIssue, IIssueViewProps, ISubIssueResponse, UserAuth } from "types";

View File

@ -34,7 +34,7 @@ import {
import { LayerDiagonalIcon } from "components/icons";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
import { handleIssuesMutation } from "constants/issue";
import { handleIssuesMutation } from "helpers/issue.helper";
// types
import {
ICurrentUserResponse,

View File

@ -3,7 +3,7 @@ import { useRouter } from "next/router";
// headless ui
import { Dialog, Transition } from "@headlessui/react";
// services
import CSVIntegrationService from "services/csv.services";
import { CSVIntegrationService } from "services/csv.services";
// hooks
import useToast from "hooks/use-toast";
// ui

View File

@ -6,15 +6,16 @@ import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { ISSUE_DISPLAY_PROPERTIES } from "constants/issue";
export const FilterDisplayProperties = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleDisplayProperties = (key: string, value: boolean) => {
issueFilterStore.handleUserFilter("display_properties", key, !value);
// issueFilterStore.handleUserFilter("display_properties", key, !value);
};
return (
@ -26,26 +27,24 @@ export const FilterDisplayProperties = observer(() => {
/>
{previewEnabled && (
<div className="space-y-[2px] pt-1 px-1 flex items-center whitespace-nowrap gap-2 flex-wrap">
{issueFilterStore?.issueRenderFilters?.display_properties &&
issueFilterStore?.issueRenderFilters?.display_properties.length > 0 &&
issueFilterStore?.issueRenderFilters?.display_properties.map((_displayProperties) => (
<div
key={_displayProperties?.key}
className={`cursor-pointer rounded-sm transition-all text-xs border p-0.5 px-1.5 ${
issueFilterStore?.userFilters?.display_properties?.[_displayProperties?.key]
? `bg-custom-primary-200 border-custom-primary-200 text-white`
: `hover:bg-custom-border-100 border-custom-border-100`
}`}
onClick={() =>
handleDisplayProperties(
_displayProperties?.key,
issueFilterStore?.userFilters?.display_properties?.[_displayProperties?.key]
)
}
>
{_displayProperties?.title}
</div>
))}
{ISSUE_DISPLAY_PROPERTIES.map((displayProperty) => (
<div
key={displayProperty?.key}
className={`cursor-pointer rounded-sm transition-all text-xs border p-0.5 px-1.5 ${
issueFilterStore?.userDisplayProperties?.[displayProperty?.key]
? `bg-custom-primary-200 border-custom-primary-200 text-white`
: `hover:bg-custom-border-100 border-custom-border-100`
}`}
onClick={() => {
handleDisplayProperties(
displayProperty?.key,
issueFilterStore?.userDisplayProperties?.[displayProperty?.key]
);
}}
>
{displayProperty?.title}
</div>
))}
</div>
)}
</div>

View File

@ -7,25 +7,27 @@ import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { ISSUE_EXTRA_PROPERTIES } from "constants/issue";
// default data
import { issueFilterVisibilityData } from "store/helpers/issue-data";
// import { issueFilterVisibilityData } from "helpers/issue.helper";
export const FilterExtraOptions = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleExtraOptions = (key: string, value: boolean) => {
issueFilterStore.handleUserFilter("display_filters", key, !value);
// issueFilterStore.handleUserFilter("display_filters", key, !value);
};
const handleExtraOptionsSectionVisibility = (key: string) =>
issueFilterStore?.issueView &&
issueFilterStore?.issueLayout &&
issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[
issueFilterStore?.issueLayout
].values?.includes(key);
const handleExtraOptionsSectionVisibility = (key: string) => {
// issueFilterStore?.issueView &&
// issueFilterStore?.issueLayout &&
// issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[
// issueFilterStore?.issueLayout
// ].values?.includes(key);
};
return (
<div>
@ -36,24 +38,16 @@ export const FilterExtraOptions = observer(() => {
/>
{previewEnabled && (
<div className="space-y-[2px] pt-1">
{issueFilterStore?.issueRenderFilters?.extra_properties &&
issueFilterStore?.issueRenderFilters?.extra_properties.length > 0 &&
issueFilterStore?.issueRenderFilters?.extra_properties.map(
(_extraProperties) =>
handleExtraOptionsSectionVisibility(_extraProperties?.key) && (
<FilterOption
key={_extraProperties?.key}
isChecked={issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key] ? true : false}
onClick={() =>
handleExtraOptions(
_extraProperties?.key,
issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key]
)
}
title={_extraProperties.title}
/>
)
)}
{ISSUE_EXTRA_PROPERTIES.map((_extraProperties) => (
<FilterOption
key={_extraProperties?.key}
isChecked={issueFilterStore?.userDisplayFilters?.[_extraProperties?.key] ? true : false}
onClick={() =>
handleExtraOptions(_extraProperties?.key, issueFilterStore?.userDisplayFilters?.[_extraProperties?.key])
}
title={_extraProperties.title}
/>
))}
</div>
)}
</div>

View File

@ -7,15 +7,16 @@ import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { ISSUE_GROUP_BY_OPTIONS } from "constants/issue";
export const FilterGroupBy = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleGroupBy = (key: string, value: string) => {
issueFilterStore.handleUserFilter("display_filters", key, value);
// issueFilterStore.handleUserFilter("display_filters", key, value);
};
return (
@ -27,17 +28,15 @@ export const FilterGroupBy = observer(() => {
/>
{previewEnabled && (
<div className="space-y-[2px] pt-1">
{issueFilterStore?.issueRenderFilters?.group_by &&
issueFilterStore?.issueRenderFilters?.group_by.length > 0 &&
issueFilterStore?.issueRenderFilters?.group_by.map((_groupBy) => (
<FilterOption
key={_groupBy?.key}
isChecked={issueFilterStore?.userFilters?.display_filters?.group_by === _groupBy?.key ? true : false}
onClick={() => handleGroupBy("group_by", _groupBy?.key)}
title={_groupBy.title}
multiple={false}
/>
))}
{ISSUE_GROUP_BY_OPTIONS.map((_groupBy) => (
<FilterOption
key={_groupBy?.key}
isChecked={issueFilterStore?.userDisplayFilters?.group_by === _groupBy?.key ? true : false}
onClick={() => handleGroupBy("group_by", _groupBy?.key)}
title={_groupBy.title}
multiple={false}
/>
))}
</div>
)}
</div>

View File

@ -11,70 +11,71 @@ import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
// default data
import { issueFilterVisibilityData } from "store/helpers/issue-data";
// import { issueFilterVisibilityData } from "store/helpers/issue-data";
export const DisplayFiltersSelection = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const handleDisplayPropertiesSectionVisibility =
issueFilterStore?.issueView &&
issueFilterStore?.issueLayout &&
issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]
?.display_properties?.[issueFilterStore?.issueLayout];
// const handleDisplayPropertiesSectionVisibility =
// issueFilterStore?.issueView &&
// issueFilterStore?.issueLayout &&
// issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]
// ?.display_properties?.[issueFilterStore?.issueLayout];
const handleDisplayFilterSectionVisibility = (section_key: string) =>
issueFilterStore?.issueView &&
issueFilterStore?.issueLayout &&
issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.display_filters?.[
issueFilterStore?.issueLayout
].includes(section_key);
const handleDisplayFilterSectionVisibility = (section_key: string) => {
// issueFilterStore?.issueView &&
// issueFilterStore?.issueLayout &&
// issueFilterVisibilityData[
// issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"
// ]?.display_filters?.[issueFilterStore?.issueLayout].includes(section_key);
};
const handleExtraOptionsSectionVisibility =
issueFilterStore?.issueView &&
issueFilterStore?.issueLayout &&
issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[
issueFilterStore?.issueLayout
].access;
// const handleExtraOptionsSectionVisibility =
// issueFilterStore?.issueView &&
// issueFilterStore?.issueLayout &&
// issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[
// issueFilterStore?.issueLayout
// ].access;
return (
<div className="w-full h-full overflow-hidden select-none relative flex flex-col divide-y divide-custom-border-200">
<div className="flex-shrink-0 p-2 text-sm">Search container</div>
<div className="w-full h-full overflow-hidden overflow-y-auto relative pb-2 divide-y divide-custom-border-200">
{/* display properties */}
{handleDisplayPropertiesSectionVisibility && (
{/* {handleDisplayPropertiesSectionVisibility && (
<div className="pb-2 px-2">
<FilterDisplayProperties />
</div>
)}
)} */}
{/* group by */}
{handleDisplayFilterSectionVisibility("group_by") && (
{/* {handleDisplayFilterSectionVisibility("group_by") && (
<div className="py-1 px-2">
<FilterGroupBy />
</div>
)}
)} */}
{/* order by */}
{handleDisplayFilterSectionVisibility("order_by") && (
{/* {handleDisplayFilterSectionVisibility("order_by") && (
<div className="py-1 px-2">
<FilterOrderBy />
</div>
)}
)} */}
{/* issue type */}
{handleDisplayFilterSectionVisibility("issue_type") && (
{/* {handleDisplayFilterSectionVisibility("issue_type") && (
<div className="py-1 px-2">
<FilterIssueType />
</div>
)}
)} */}
{/* Options */}
{handleExtraOptionsSectionVisibility && (
{/* {handleExtraOptionsSectionVisibility && (
<div className="pt-1 px-2">
<FilterExtraOptions />
</div>
)}
)} */}
</div>
</div>
);

View File

@ -1,21 +1,21 @@
import React from "react";
import { observer } from "mobx-react-lite";
// components
import { FilterHeader } from "../helpers/filter-header";
import { FilterOption } from "../helpers/filter-option";
// mobx react lite
import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { ISSUE_FILTER_OPTIONS } from "constants/issue";
export const FilterIssueType = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleIssueType = (key: string, value: string) => {
issueFilterStore.handleUserFilter("display_filters", key, value);
// issueFilterStore.handleUserFilter("display_filters", key, value);
};
return (
@ -27,17 +27,15 @@ export const FilterIssueType = observer(() => {
/>
{previewEnabled && (
<div className="space-y-[2px] pt-1">
{issueFilterStore?.issueRenderFilters?.issue_type &&
issueFilterStore?.issueRenderFilters?.issue_type.length > 0 &&
issueFilterStore?.issueRenderFilters?.issue_type.map((_issueType) => (
<FilterOption
key={_issueType?.key}
isChecked={issueFilterStore?.userFilters?.display_filters?.type === _issueType?.key ? true : false}
onClick={() => handleIssueType("type", _issueType?.key)}
title={_issueType.title}
multiple={false}
/>
))}
{ISSUE_FILTER_OPTIONS.map((_issueType) => (
<FilterOption
key={_issueType?.key}
isChecked={issueFilterStore?.userDisplayFilters?.type === _issueType?.key ? true : false}
onClick={() => handleIssueType("type", _issueType?.key)}
title={_issueType.title}
multiple={false}
/>
))}
</div>
)}
</div>

View File

@ -7,15 +7,16 @@ import { observer } from "mobx-react-lite";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
import { RootStore } from "store/root";
import { ISSUE_ORDER_BY_OPTIONS } from "constants/issue";
export const FilterOrderBy = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleOrderBy = (key: string, value: string) => {
issueFilterStore.handleUserFilter("display_filters", key, value);
// issueFilterStore.handleUserFilter("display_filters", key, value);
};
return (
@ -27,17 +28,15 @@ export const FilterOrderBy = observer(() => {
/>
{previewEnabled && (
<div className="space-y-[2px] pt-1">
{issueFilterStore?.issueRenderFilters?.order_by &&
issueFilterStore?.issueRenderFilters?.order_by.length > 0 &&
issueFilterStore?.issueRenderFilters?.order_by.map((_orderBy) => (
<FilterOption
key={_orderBy?.key}
isChecked={issueFilterStore?.userFilters?.display_filters?.order_by === _orderBy?.key ? true : false}
onClick={() => handleOrderBy("order_by", _orderBy?.key)}
title={_orderBy.title}
multiple={false}
/>
))}
{ISSUE_ORDER_BY_OPTIONS.map((_orderBy) => (
<FilterOption
key={_orderBy?.key}
isChecked={issueFilterStore?.userDisplayFilters?.order_by === _orderBy?.key ? true : false}
onClick={() => handleOrderBy("order_by", _orderBy?.key)}
title={_orderBy.title}
multiple={false}
/>
))}
</div>
)}
</div>

View File

@ -22,19 +22,19 @@ export const MemberIcons = ({ display_name, avatar }: { display_name: string; av
export const FilterAssignees = observer(() => {
const store: RootStore = useMobxStore();
const { issueFilters: issueFilterStore } = store;
const { issueFilter: issueFilterStore } = store;
const [previewEnabled, setPreviewEnabled] = React.useState(true);
const handleFilter = (key: string, value: string) => {
let _value =
issueFilterStore?.userFilters?.filters?.[key] != null
? issueFilterStore?.userFilters?.filters?.[key].includes(value)
? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value)
: [...issueFilterStore?.userFilters?.filters?.[key], value]
: [value];
_value = _value && _value.length > 0 ? _value : null;
issueFilterStore.handleUserFilter("filters", key, _value);
// let _value =
// issueFilterStore?.userFilters?.filters?.[key] != null
// ? issueFilterStore?.userFilters?.filters?.[key].includes(value)
// ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value)
// : [...issueFilterStore?.userFilters?.filters?.[key], value]
// : [value];
// _value = _value && _value.length > 0 ? _value : null;
// issueFilterStore.handleUserFilter("filters", key, _value);
};
return (

View File

@ -1,121 +1,182 @@
export const GROUP_BY_OPTIONS: Array<{
name: string;
key: TIssueGroupByOptions;
}> = [
{ name: "States", key: "state" },
{ name: "State Groups", key: "state_detail.group" },
{ name: "Priority", key: "priority" },
{ name: "Project", key: "project" },
{ name: "Labels", key: "labels" },
{ name: "Assignees", key: "assignees" },
{ name: "Created by", key: "created_by" },
{ name: "None", key: null },
export const ISSUE_PRIORITIES = [
{ key: "urgent", title: "Urgent" },
{ key: "high", title: "High" },
{ key: "medium", title: "Medium" },
{ key: "low", title: "Low" },
{ key: "none", title: "None" },
];
export const ORDER_BY_OPTIONS: Array<{
name: string;
key: TIssueOrderByOptions;
}> = [
{ name: "Manual", key: "sort_order" },
{ name: "Last created", key: "-created_at" },
{ name: "Last updated", key: "-updated_at" },
{ name: "Start date", key: "start_date" },
{ name: "Priority", key: "priority" },
export const ISSUE_STATE_GROUPS = [
{ key: "backlog", title: "Backlog" },
{ key: "unstarted", title: "Unstarted" },
{ key: "started", title: "Started" },
{ key: "completed", title: "Completed" },
{ key: "cancelled", title: "Cancelled" },
];
export const FILTER_ISSUE_OPTIONS: Array<{
name: string;
key: "active" | "backlog" | null;
}> = [
{
name: "All",
key: null,
},
{
name: "Active Issues",
key: "active",
},
{
name: "Backlog Issues",
key: "backlog",
},
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" },
];
import { orderArrayBy } from "helpers/array.helper";
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
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" },
];
type THandleIssuesMutation = (
formData: Partial<IIssue>,
oldGroupTitle: string,
selectedGroupBy: TIssueGroupByOptions,
issueIndex: number,
orderBy: TIssueOrderByOptions,
prevData?:
| {
[key: string]: IIssue[];
}
| IIssue[]
) =>
| {
[key: string]: IIssue[];
}
| IIssue[]
| undefined;
export const ISSUE_GROUP_BY_OPTIONS = [
{ key: "state", title: "States" },
{ key: "state_detail.group", title: "State Groups" },
{ key: "priority", title: "Priority" },
{ key: "project", title: "Project" }, // required this on my issues
{ key: "labels", title: "Labels" },
{ key: "assignees", title: "Assignees" },
{ key: "created_by", title: "Created By" },
];
export const handleIssuesMutation: THandleIssuesMutation = (
formData,
oldGroupTitle,
selectedGroupBy,
issueIndex,
orderBy,
prevData
) => {
if (!prevData) return prevData;
export const ISSUE_ORDER_BY_OPTIONS = [
{ key: "sort_order", title: "Manual" },
{ key: "created_at", title: "Last Created" },
{ key: "updated_at", title: "Last Updated" },
{ key: "start_date", title: "Start Date" },
{ key: "priority", title: "Priority" },
];
if (Array.isArray(prevData)) {
const updatedIssue = {
...prevData[issueIndex],
...formData,
assignees: formData?.assignees_list ?? prevData[issueIndex]?.assignees,
labels: formData?.labels_list ?? prevData[issueIndex]?.labels,
};
export const ISSUE_FILTER_OPTIONS = [
{ key: "all", title: "All" },
{ key: "active", title: "Active Issues" },
{ key: "backlog", title: "Backlog Issues" },
// { key: "draft", title: "Draft Issues" },
];
prevData.splice(issueIndex, 1, updatedIssue);
export const ISSUE_DISPLAY_PROPERTIES = [
{ key: "assignee", title: "Assignee" },
{ key: "start_date", title: "Start Date" },
{ key: "due_date", title: "Due Date" },
{ key: "key", title: "ID" },
{ key: "labels", title: "Labels" },
{ key: "priority", title: "Priority" },
{ key: "state", title: "State" },
{ key: "sub_issue_count", title: "Sub Issue Count" },
{ key: "attachment_count", title: "Attachment Count" },
{ key: "link", title: "Link" },
{ key: "estimate", title: "Estimate" },
];
return [...prevData];
} else {
const oldGroup = prevData[oldGroupTitle ?? ""] ?? [];
export const ISSUE_EXTRA_PROPERTIES = [
{ key: "sub_issue", title: "Show sub-issues" }, // in spreadsheet its always false
{ key: "show_empty_groups", title: "Show empty states" }, // filter on front-end
{ key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after
{ key: "start_target_date", title: "Start target Date" }, // gantt always be true
];
let newGroup: IIssue[] = [];
export const ISSUE_LAYOUTS = [
{ key: "list", title: "List View" },
{ key: "kanban", title: "Kanban View" },
{ key: "calendar", title: "Calendar View" },
{ key: "spreadsheet", title: "Spreadsheet View" },
{ key: "gantt_chart", title: "Gantt Chart View" },
];
if (selectedGroupBy === "priority") newGroup = prevData[formData.priority ?? ""] ?? [];
else if (selectedGroupBy === "state") newGroup = prevData[formData.state ?? ""] ?? [];
export const ISSUE_LIST_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" },
];
const updatedIssue = {
...oldGroup[issueIndex],
...formData,
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees,
labels: formData?.labels_list ?? oldGroup[issueIndex]?.labels,
};
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" },
];
if (selectedGroupBy !== Object.keys(formData)[0])
return {
...prevData,
[oldGroupTitle ?? ""]: orderArrayBy(
oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)),
orderBy
),
};
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" },
];
const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state;
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" },
];
return {
...prevData,
[oldGroupTitle ?? ""]: orderArrayBy(
oldGroup.filter((i) => i.id !== updatedIssue.id),
orderBy
),
[groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy),
};
}
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 const ISSUE_EXTRA_DISPLAY_PROPERTIES = {
list: {
access: true,
values: ["show_empty_groups", "sub_issue"],
},
kanban: {
access: true,
values: ["show_empty_groups", "sub_issue"],
},
calendar: {
access: false,
values: [],
},
spreadsheet: {
access: false,
values: [],
},
gantt_chart: {
access: true,
values: ["sub_issue"],
},
};

199
web/helpers/issue.helper.ts Normal file
View File

@ -0,0 +1,199 @@
import { orderArrayBy } from "helpers/array.helper";
import { renderDateFormat } from "helpers/date-time.helper";
// types
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
type THandleIssuesMutation = (
formData: Partial<IIssue>,
oldGroupTitle: string,
selectedGroupBy: TIssueGroupByOptions,
issueIndex: number,
orderBy: TIssueOrderByOptions,
prevData?:
| {
[key: string]: IIssue[];
}
| IIssue[]
) =>
| {
[key: string]: IIssue[];
}
| IIssue[]
| undefined;
export const handleIssuesMutation: THandleIssuesMutation = (
formData,
oldGroupTitle,
selectedGroupBy,
issueIndex,
orderBy,
prevData
) => {
if (!prevData) return prevData;
if (Array.isArray(prevData)) {
const updatedIssue = {
...prevData[issueIndex],
...formData,
assignees: formData?.assignees_list ?? prevData[issueIndex]?.assignees,
labels: formData?.labels_list ?? prevData[issueIndex]?.labels,
};
prevData.splice(issueIndex, 1, updatedIssue);
return [...prevData];
} else {
const oldGroup = prevData[oldGroupTitle ?? ""] ?? [];
let newGroup: IIssue[] = [];
if (selectedGroupBy === "priority") newGroup = prevData[formData.priority ?? ""] ?? [];
else if (selectedGroupBy === "state") newGroup = prevData[formData.state ?? ""] ?? [];
const updatedIssue = {
...oldGroup[issueIndex],
...formData,
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees,
labels: formData?.labels_list ?? oldGroup[issueIndex]?.labels,
};
if (selectedGroupBy !== Object.keys(formData)[0])
return {
...prevData,
[oldGroupTitle ?? ""]: orderArrayBy(
oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)),
orderBy
),
};
const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state;
return {
...prevData,
[oldGroupTitle ?? ""]: orderArrayBy(
oldGroup.filter((i) => i.id !== updatedIssue.id),
orderBy
),
[groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy),
};
}
};
export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart";
export type TIssueParams =
| "priority"
| "state_group"
| "state"
| "assignees"
| "created_by"
| "labels"
| "start_date"
| "target_date"
| "group_by"
| "order_by"
| "type"
| "sub_issue"
| "show_empty_groups"
| "calendar_date_range"
| "start_target_date";
export const handleIssueQueryParamsByLayout = (_layout: TIssueLayouts | undefined): TIssueParams[] | null => {
if (_layout === "list")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"group_by",
"order_by",
"type",
"sub_issue",
"show_empty_groups",
];
if (_layout === "kanban")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"group_by",
"order_by",
"type",
"sub_issue",
"show_empty_groups",
];
if (_layout === "calendar")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"type",
"calendar_date_range",
];
if (_layout === "spreadsheet")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"type",
"sub_issue",
];
if (_layout === "gantt_chart")
return [
"priority",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"order_by",
"type",
"sub_issue",
"start_target_date",
];
return null;
};
export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => {
if (key === "last_week")
return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat(
new Date()
)};before`;
if (key === "2_weeks_from_now")
return `${renderDateFormat(new Date())};after,
${renderDateFormat(new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000))};before`;
if (key === "1_month_from_now")
return `${renderDateFormat(new Date())};after,${renderDateFormat(
new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate())
)};before`;
if (key === "2_months_from_now")
return `${renderDateFormat(new Date())};after,${renderDateFormat(
new Date(new Date().getFullYear(), new Date().getMonth() + 2, new Date().getDate())
)};before`;
if (key === "custom" && start_date && target_date)
return `${renderDateFormat(start_date)};after,${renderDateFormat(target_date)};before`;
};

View File

@ -34,5 +34,5 @@ export class JiraImporterService extends APIService {
});
}
}
export default JiraImporterService;
const jiraService = new JiraImporterService();
export default jiraService;

View File

@ -1,257 +0,0 @@
import { renderDateFormat } from "helpers/date-time.helper";
// types
import { TIssueLayouts, TIssueParams } from "../issue_filters.legacy";
export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled";
export const priorities: { key: string; title: string }[] = [
{ key: "urgent", title: "Urgent" },
{ key: "high", title: "High" },
{ key: "medium", title: "Medium" },
{ key: "low", title: "Low" },
{ key: "none", title: "None" },
];
export const stateGroups: { key: TStateGroup; title: string }[] = [
{ key: "backlog", title: "Backlog" },
{ key: "unstarted", title: "Unstarted" },
{ key: "started", title: "Started" },
{ key: "completed", title: "Completed" },
{ key: "cancelled", title: "Cancelled" },
];
export const startDateOptions: { key: string; title: string }[] = [
{ 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 dueDateOptions: { key: string; title: string }[] = [
{ 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 groupByOptions: { key: string; title: string }[] = [
{ key: "state", title: "States" },
{ key: "state_detail.group", title: "State Groups" },
{ key: "priority", title: "Priority" },
{ key: "project", title: "Project" }, // required this on my issues
{ key: "labels", title: "Labels" },
{ key: "assignees", title: "Assignees" },
{ key: "created_by", title: "Created By" },
];
export const orderByOptions: { key: string; title: string }[] = [
{ key: "sort_order", title: "Manual" },
{ key: "created_at", title: "Last Created" },
{ key: "updated_at", title: "Last Updated" },
{ key: "start_date", title: "Start Date" },
{ key: "priority", title: "Priority" },
];
export const issueTypes: { key: string; title: string }[] = [
{ key: "all", title: "All" },
{ key: "active", title: "Active Issues" },
{ key: "backlog", title: "Backlog Issues" },
];
export const displayProperties: { key: string; title: string }[] = [
{ key: "assignee", title: "Assignee" },
{ key: "start_date", title: "Start Date" },
{ key: "due_date", title: "Due Date" },
{ key: "key", title: "ID" },
{ key: "labels", title: "Labels" },
{ key: "priority", title: "Priority" },
{ key: "state", title: "State" },
{ key: "sub_issue_count", title: "Sub Issue Count" },
{ key: "attachment_count", title: "Attachment Count" },
{ key: "link", title: "Link" },
{ key: "estimate", title: "Estimate" },
];
export const extraProperties: { key: string; title: string }[] = [
{ key: "sub_issue", title: "Show sub-issues" }, // in spreadsheet its always false
{ key: "show_empty_groups", title: "Show empty states" }, // filter on front-end
{ key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after
{ key: "start_target_date", title: "Start target Date" }, // gantt always be true
];
export const issueFilterVisibilityData: any = {
my_issues: {
layout: ["list", "kanban"],
filters: {
list: ["priority", "state_group", "labels", "start_date", "due_date"],
kanban: ["priority", "state_group", "labels", "start_date", "due_date"],
},
display_properties: {
list: true,
kanban: true,
},
display_filters: {
list: ["group_by", "order_by", "issue_type"],
kanban: ["group_by", "order_by", "issue_type"],
},
extra_options: {
list: {
access: true,
values: ["show_empty_groups"],
},
kanban: {
access: true,
values: ["show_empty_groups"],
},
},
},
issues: {
layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"],
filters: {
list: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"],
kanban: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"],
calendar: ["priority", "state", "assignees", "created_by", "labels"],
spreadsheet: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"],
gantt_chart: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"],
},
display_properties: {
list: true,
kanban: true,
calendar: true,
spreadsheet: true,
gantt_chart: false,
},
display_filters: {
list: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"],
kanban: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"],
calendar: ["issue_type"],
spreadsheet: ["issue_type"],
gantt_chart: ["order_by", "issue_type", "sub_issue"],
},
extra_options: {
list: {
access: true,
values: ["show_empty_groups", "sub_issue"],
},
kanban: {
access: true,
values: ["show_empty_groups", "sub_issue"],
},
calendar: {
access: false,
values: [],
},
spreadsheet: {
access: false,
values: [],
},
gantt_chart: {
access: true,
values: ["sub_issue"],
},
},
},
};
export const handleIssueQueryParamsByLayout = (_layout: TIssueLayouts | undefined): TIssueParams[] | null => {
if (_layout === "list")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"group_by",
"order_by",
"type",
"sub_issue",
"show_empty_groups",
];
if (_layout === "kanban")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"group_by",
"order_by",
"type",
"sub_issue",
"show_empty_groups",
];
if (_layout === "calendar")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"type",
"calendar_date_range",
];
if (_layout === "spreadsheet")
return [
"priority",
"state_group",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"type",
"sub_issue",
];
if (_layout === "gantt_chart")
return [
"priority",
"state",
"assignees",
"created_by",
"labels",
"start_date",
"target_date",
"order_by",
"type",
"sub_issue",
"start_target_date",
];
return null;
};
export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => {
if (key === "last_week")
return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat(
new Date()
)};before`;
if (key === "2_weeks_from_now")
return `${renderDateFormat(new Date())};after,
${renderDateFormat(new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000))};before`;
if (key === "1_month_from_now")
return `${renderDateFormat(new Date())};after,${renderDateFormat(
new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate())
)};before`;
if (key === "2_months_from_now")
return `${renderDateFormat(new Date())};after,${renderDateFormat(
new Date(new Date().getFullYear(), new Date().getMonth() + 2, new Date().getDate())
)};before`;
if (key === "custom" && start_date && target_date)
return `${renderDateFormat(start_date)};after,${renderDateFormat(target_date)};before`;
};

View File

@ -1,5 +1,6 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
import { IIssue } from "types";
import { RootStore } from "./root";
export interface IIssueStore {
loader: boolean;
@ -16,13 +17,16 @@ class IssueStore implements IIssueStore {
};
} = {};
constructor() {
rootStore;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observable
loader: observable.ref,
error: observable.ref,
issues: observable.ref,
});
this.rootStore = _rootStore;
}
fetchIssuesWithParams() {}

View File

@ -1,847 +0,0 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "./root";
// services
import { WorkspaceService } from "services/workspace.service";
import { ProjectIssuesServices } from "services/issue.service";
import { ProjectStateServices } from "services/project_state.service";
import { ProjectServices } from "services/project.service";
import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service";
import { ProjectCycleServices } from "services/cycles.service";
import { ViewService } from "services/views.service";
// default data
import {
priorities,
stateGroups,
startDateOptions,
dueDateOptions,
groupByOptions,
orderByOptions,
issueTypes,
displayProperties,
extraProperties,
handleIssueQueryParamsByLayout,
} from "./helpers/issue-data";
export type TIssueViews = "issues" | "modules" | "views" | "cycles";
export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart";
export type TIssueParams =
| "priority"
| "state_group"
| "state"
| "assignees"
| "created_by"
| "labels"
| "start_date"
| "target_date"
| "group_by"
| "order_by"
| "type"
| "sub_issue"
| "show_empty_groups"
| "calendar_date_range"
| "start_target_date";
export interface IIssueFilter {
priority: string[] | undefined;
state_group: string[] | undefined;
state: string[] | undefined;
assignees: string[] | undefined;
created_by: string[] | undefined;
labels: string[] | undefined;
start_date: string[] | undefined;
target_date: string[] | undefined;
[key: string]: any;
}
export interface IIssueDisplayFilters {
group_by: undefined | string;
order_by: undefined | string;
type: string | undefined;
sub_issue: boolean;
show_empty_groups: boolean;
layout: TIssueLayouts;
calendar_date_range: string | undefined; // only for calendar
start_target_date: boolean;
[key: string]: any;
}
export interface IIssueDisplayProperties {
assignee: boolean;
attachment_count: boolean;
created_on: boolean;
due_date: boolean;
estimate: boolean;
key: boolean;
labels: boolean;
link: boolean;
priority: boolean;
start_date: boolean;
state: boolean;
sub_issue_count: boolean;
updated_on: boolean;
[key: string]: any;
}
export interface IIssueFilters {
// project_id
[key: string]: {
issues: {
// project_id
[key: string]: {
filters: IIssueFilter;
};
};
cycles: {
// cycle_id
[key: string]: {
filters: IIssueFilter;
};
};
modules: {
// module_id
[key: string]: {
filters: IIssueFilter;
};
};
views: {
// view_id
[key: string]: {
filters: IIssueFilter;
};
};
display_filters: IIssueDisplayFilters;
display_properties_id: string;
display_properties: IIssueDisplayProperties;
};
}
export interface IIssueFilterStore {
// static data
priorities: { key: string; title: string }[];
stateGroups: { key: string; title: string }[];
startDateOptions: { key: string; title: string }[];
dueDateOptions: { key: string; title: string }[];
groupByOptions: { key: string; title: string }[];
orderByOptions: { key: string; title: string }[];
issueTypes: { key: string; title: string }[];
displayProperties: { key: string; title: string }[];
extraProperties: { key: string; title: string }[];
loader: boolean;
error: any | null;
// current workspace and project id
issueView: TIssueViews | null;
issueFilters: IIssueFilters;
// actions
// getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise<any>;
// updateWorkspaceMyIssuesFilters: (workspaceId: string, data: any) => Promise<any>;
getProjectDisplayProperties: (workspaceId: string, projectId: string) => Promise<any>;
updateProjectDisplayProperties: (
workspaceId: string,
projectId: string,
display_properties_id: string,
data: any
) => Promise<any>;
getProjectDisplayFilters: (workspaceId: string, projectId: string) => Promise<any>;
updateProjectDisplayFilters: (workspaceId: string, projectId: string, data: any) => Promise<any>;
getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise<any>;
getProjectIssueModuleFilters: (workspaceId: string, projectId: string, moduleId: string) => Promise<any>;
updateProjectIssueModuleFilters: (
workspaceId: string,
projectId: string,
moduleId: string,
data: any
) => Promise<any>;
getProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string) => Promise<any>;
updateProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string, data: any) => Promise<any>;
getProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string) => Promise<any>;
updateProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string, data: any) => Promise<any>;
}
class IssueFilterStore implements IIssueFilterStore {
// static data
priorities: { key: string; title: string }[] = priorities;
stateGroups: { key: string; title: string }[] = stateGroups;
startDateOptions: { key: string; title: string }[] = startDateOptions;
dueDateOptions: { key: string; title: string }[] = dueDateOptions;
groupByOptions: { key: string; title: string }[] = groupByOptions;
orderByOptions: { key: string; title: string }[] = orderByOptions;
issueTypes: { key: string; title: string }[] = issueTypes;
displayProperties: { key: string; title: string }[] = displayProperties;
extraProperties: { key: string; title: string }[] = extraProperties;
loader: boolean = false;
error: any | null = null;
// workspaceId: string | null = null;
// projectId: string | null = null;
// moduleId: string | null = null;
// cycleId: string | null = null;
// viewId: string | null = null;
issueView: TIssueViews | null = null;
issueFilters: IIssueFilters = {};
// root store
rootStore;
// service
workspaceService;
issueService;
stateService;
projectService;
moduleService;
cycleService;
viewService;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observable
loader: observable,
error: observable,
issueView: observable,
issueFilters: observable.ref,
// computed
issueLayout: computed,
userFilters: computed,
// actions
getComputedFilters: action,
handleIssueFilter: action,
// getWorkspaceMyIssuesFilters: action,
// updateWorkspaceMyIssuesFilters: action,
getProjectDisplayFilters: action,
updateProjectDisplayFilters: action,
getProjectDisplayProperties: action,
updateProjectDisplayProperties: action,
getProjectIssueFilters: action,
getProjectIssueModuleFilters: action,
updateProjectIssueModuleFilters: action,
getProjectIssueCyclesFilters: action,
updateProjectIssueCyclesFilters: action,
getProjectIssueViewsFilters: action,
updateProjectIssueViewsFilters: action,
});
this.rootStore = _rootStore;
this.workspaceService = new WorkspaceService();
this.issueService = new ProjectIssuesServices();
this.stateService = new ProjectStateServices();
this.projectService = new ProjectServices();
this.moduleService = new ProjectModuleServices();
this.cycleService = new ProjectCycleServices();
this.viewService = new ViewService();
}
// computed
get issueLayout() {
// if (!this.projectId) return null;
// if (!this.projectId)
// return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout || null;
// if (this.projectId)
// return (
// this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters
// ?.layout || null
// );
return null;
}
get userFilters() {
const projectId = this.rootStore?.project?.projectId;
const moduleId = this.rootStore?.module?.moduleId;
const cycleId = this.rootStore?.cycle?.cycleId;
const viewId = this.rootStore?.view?.viewId;
const _issueView = this.issueView;
if (!projectId || !_issueView) return null;
const currentIssueViewId: string | null =
_issueView === "issues" && projectId
? projectId
: _issueView === "modules" && moduleId
? moduleId
: _issueView === "cycles" && cycleId
? cycleId
: _issueView === "cycles" && viewId
? viewId
: null;
if (!currentIssueViewId) return null;
const _issueFilters: {
filters: IIssueFilter | null;
display_filters: IIssueDisplayFilters;
display_properties_id: string;
display_properties: IIssueDisplayProperties;
} = {
filters: this.issueFilters?.[projectId]?.[_issueView]?.[currentIssueViewId]?.filters,
display_filters: this.issueFilters?.[projectId]?.display_filters,
display_properties_id: this.issueFilters?.[projectId]?.display_properties_id,
display_properties: this.issueFilters?.[projectId]?.display_properties,
};
return _issueFilters;
}
computedFilter = (filters: any, filteredParams: any) => {
const computedFilters: any = {};
Object.keys(filters).map((key) => {
if (filters[key] != undefined && filteredParams.includes(key))
computedFilters[key] =
typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(",");
});
return computedFilters;
};
getComputedFilters = (
_workspaceId: string | null,
_projectId: string | null,
_moduleId: string | null,
_cycleId: string | null,
_viewId: string | null,
_issueView: TIssueViews
) => {
this.issueView = _issueView;
const _layout = this.userFilters?.display_filters?.layout;
let filteredRouteParams: any = {
priority: this.userFilters?.filters?.priority || undefined,
state_group: this.userFilters?.filters?.state_group || undefined,
state: this.userFilters?.filters?.state || undefined,
assignees: this.userFilters?.filters?.assignees || undefined,
created_by: this.userFilters?.filters?.created_by || undefined,
labels: this.userFilters?.filters?.labels || undefined,
start_date: this.userFilters?.filters?.start_date || undefined,
target_date: this.userFilters?.filters?.target_date || undefined,
group_by: this.userFilters?.display_filters?.group_by || "state",
order_by: this.userFilters?.display_filters?.order_by || "-created_at",
type: this.userFilters?.display_filters?.type || undefined,
sub_issue: this.userFilters?.display_filters?.sub_issue || true,
show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true,
calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined,
start_target_date: this.userFilters?.display_filters?.start_target_date || true,
};
// start date and target date we have to construct the format here
// in calendar view calendar_date_range send as target_date
// in spreadsheet sub issue is false for sure
// in gantt start_target_date is true for sure
const filteredParams: TIssueParams[] | null = handleIssueQueryParamsByLayout(_layout);
if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
return filteredRouteParams;
};
handleIssueFilter = (
filter_type: "filters" | "display_filters" | "display_properties" | "display_properties_id",
value: any
) => {
const projectId = this.rootStore?.project?.projectId;
const moduleId = this.rootStore?.module?.moduleId;
const cycleId = this.rootStore?.cycle?.cycleId;
const viewId = this.rootStore?.view?.viewId;
const _issueView = this.issueView;
console.log("filter_type", filter_type);
console.log("value", value);
if (!_issueView || !projectId || !moduleId || !cycleId || !viewId) return null;
// let _issueFilters: IIssueFilters = {
// ...this.issueFilters,
// [workspaceId]: {
// ...this.issueFilters?.[workspaceId],
// },
// };
// console.log("_issueFilters", _issueFilters);
// if (this.issueView === "my_issues")
// this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false);
// if (this.issueView === "issues")
// this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false);
// if (this.issueView === "modules" && this.moduleId)
// this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false);
// if (this.issueView === "cycles" && this.cycleId)
// this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false);
// if (this.issueView === "views" && this.viewId)
// this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false);
};
// services
// getWorkspaceMyIssuesFilters = async (workspaceId: string) => {
// try {
// this.loader = true;
// this.error = null;
// const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId);
// if (issuesFiltersResponse) {
// const _issuesFiltersResponse: any = {
// ...this.issueFilters,
// [workspaceId]: {
// ...this?.issueFilters?.[workspaceId],
// my_issue_properties: {
// ...this?.issueFilters?.[workspaceId]?.my_issue_properties,
// filters: {
// priority: issuesFiltersResponse?.view_props?.filters?.priority ?? null,
// state: issuesFiltersResponse?.view_props?.filters?.state ?? null,
// state_group: issuesFiltersResponse?.view_props?.filters?.state_group ?? null,
// assignees: issuesFiltersResponse?.view_props?.filters?.assignees ?? null,
// created_by: issuesFiltersResponse?.view_props?.filters?.created_by ?? null,
// labels: issuesFiltersResponse?.view_props?.filters?.labels ?? null,
// start_date: issuesFiltersResponse?.view_props?.filters?.start_date ?? null,
// target_date: issuesFiltersResponse?.view_props?.filters?.target_date ?? null,
// subscriber: issuesFiltersResponse?.view_props?.filters?.subscriber ?? null,
// },
// display_filters: {
// group_by: issuesFiltersResponse?.view_props?.display_filters?.group_by ?? null,
// order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null,
// type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null,
// sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false,
// show_empty_groups: issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false,
// layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list",
// calendar_date_range: issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false,
// start_target_date: issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true,
// },
// display_properties: {
// assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false,
// attachment_count: issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false,
// created_on: issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false,
// due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false,
// estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false,
// key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false,
// labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false,
// link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false,
// priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false,
// start_date: issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false,
// state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false,
// sub_issue_count: issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false,
// updated_on: issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false,
// },
// },
// },
// };
// runInAction(() => {
// this.issueFilters = _issuesFiltersResponse;
// this.loader = false;
// this.error = null;
// });
// }
// return issuesFiltersResponse;
// } catch (error) {
// console.warn("error in fetching workspace level filters", error);
// this.loader = false;
// this.error = null;
//
// }
// };
// updateWorkspaceMyIssuesFilters = async (workspaceId: string, data: any) => {
// try {
// this.loader = true;
// this.error = null;
// const payload = {
// view_props: data,
// };
// const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView(workspaceId, payload);
// if (issuesFiltersResponse) {
// runInAction(() => {
// this.loader = false;
// this.error = null;
// });
// }
// } catch (error) {
// console.warn("error in fetching workspace level issue filters", error);
// this.loader = false;
// this.error = null;
//
// }
// };
getProjectDisplayProperties = async (workspaceId: string, projectId: string) => {
try {
this.loader = true;
this.error = null;
await this.rootStore.user.setCurrentUser();
const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId);
if (issuesDisplayPropertiesResponse) {
const _issuesDisplayPropertiesResponse: any = {
...this.issueFilters,
[projectId]: {
...this?.issueFilters?.[projectId],
display_properties_id: issuesDisplayPropertiesResponse?.id,
display_properties: {
...issuesDisplayPropertiesResponse?.properties,
},
},
};
runInAction(() => {
this.issueFilters = _issuesDisplayPropertiesResponse;
this.loader = false;
this.error = null;
});
}
return issuesDisplayPropertiesResponse;
} catch (error) {
console.warn("error in fetching project level display properties", error);
this.loader = false;
this.error = null;
}
};
updateProjectDisplayProperties = async (
workspaceId: string,
projectId: string,
display_properties_id: string,
data: any
) => {
try {
this.loader = true;
this.error = null;
const payload = {
properties: data,
user: this.rootStore?.user?.currentUser?.id,
};
const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties(
workspaceId,
projectId,
display_properties_id,
payload
);
if (issuesDisplayPropertiesResponse) {
runInAction(() => {
this.loader = false;
this.error = null;
});
}
return issuesDisplayPropertiesResponse;
} catch (error) {
console.warn("error in fetching project level display properties", error);
this.loader = false;
this.error = null;
}
};
getProjectDisplayFilters = async (workspaceId: string, projectId: string) => {
try {
this.loader = true;
this.error = null;
const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe(workspaceId, projectId);
if (issuesDisplayFiltersResponse) {
const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters };
const _displayFilters = { ...issuesDisplayFiltersResponse?.view_props?.display_filters };
const _issuesDisplayFiltersResponse: any = {
...this.issueFilters,
[projectId]: {
...this?.issueFilters?.[projectId],
issues: {
...this?.issueFilters?.[projectId]?.issues,
filters: _filters,
},
display_filters: _displayFilters,
},
};
console.log("_issuesDisplayFiltersResponse", _issuesDisplayFiltersResponse);
runInAction(() => {
this.issueFilters = _issuesDisplayFiltersResponse;
this.loader = false;
this.error = null;
});
}
return issuesDisplayFiltersResponse;
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
updateProjectDisplayFilters = async (workspaceId: string, projectId: string, data: any) => {
try {
this.loader = true;
this.error = null;
const payload: any = {
view_props: data,
};
const issuesFiltersResponse = await this.projectService.setProjectView(workspaceId, projectId, payload);
if (issuesFiltersResponse) {
runInAction(() => {
this.loader = false;
this.error = null;
});
}
return issuesFiltersResponse;
} catch (error) {
this.getProjectDisplayFilters(workspaceId, projectId);
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
getProjectIssueFilters = async (workspaceId: string, projectId: string) => {
try {
await this.getProjectDisplayProperties(workspaceId, projectId);
await this.getProjectDisplayFilters(workspaceId, projectId);
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
}
};
getProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string) => {
try {
this.loader = true;
this.error = null;
await this.getProjectIssueFilters(workspaceId, projectId);
const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails(workspaceId, projectId, moduleId);
if (issuesFiltersModuleResponse) {
const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters };
const _issuesFiltersModuleResponse = {
...this.issueFilters,
[projectId]: {
...this?.issueFilters?.[projectId],
modules: {
...this?.issueFilters?.[projectId]?.modules,
[moduleId]: {
...this?.issueFilters?.[projectId]?.modules?.[moduleId],
filters: {
priority: _filters?.priority ?? undefined,
state: _filters?.state ?? undefined,
state_group: _filters?.state_group ?? undefined,
assignees: _filters?.assignees ?? undefined,
created_by: _filters?.created_by ?? undefined,
labels: _filters?.labels ?? undefined,
start_date: _filters?.start_date ?? undefined,
target_date: _filters?.target_date ?? undefined,
},
},
},
},
};
runInAction(() => {
this.issueFilters = _issuesFiltersModuleResponse as any;
this.loader = false;
this.error = null;
});
}
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
updateProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string, data: any) => {
try {
this.loader = true;
this.error = null;
const payload = {
view_props: { filters: data },
};
const issuesFiltersModuleResponse = await this.moduleService.patchModule(
workspaceId,
projectId,
moduleId,
payload,
undefined // TODO: replace this with user
);
if (issuesFiltersModuleResponse) {
runInAction(() => {
this.loader = false;
this.error = null;
});
}
} catch (error) {
this.getProjectIssueModuleFilters(workspaceId, projectId, moduleId);
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
getProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string) => {
try {
this.loader = true;
this.error = null;
await this.getProjectIssueFilters(workspaceId, projectId);
const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails(workspaceId, projectId, cycleId);
if (issuesFiltersCycleResponse) {
const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters };
const _issuesFiltersCycleResponse = {
...this.issueFilters,
[projectId]: {
...this?.issueFilters?.[projectId],
cycles: {
...this?.issueFilters?.[projectId]?.cycles,
[cycleId]: {
...this?.issueFilters?.[projectId]?.modules?.[cycleId],
filters: {
priority: _filters?.priority ?? undefined,
state: _filters?.state ?? undefined,
state_group: _filters?.state_group ?? undefined,
assignees: _filters?.assignees ?? undefined,
created_by: _filters?.created_by ?? undefined,
labels: _filters?.labels ?? undefined,
start_date: _filters?.start_date ?? undefined,
target_date: _filters?.target_date ?? undefined,
},
},
},
},
};
runInAction(() => {
this.issueFilters = _issuesFiltersCycleResponse as any;
this.loader = false;
this.error = null;
});
}
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
updateProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string, data: any) => {
try {
this.loader = true;
this.error = null;
const payload = {
view_props: { filters: data },
};
const issuesFiltersCycleResponse = await this.cycleService.patchCycle(
workspaceId,
projectId,
cycleId,
payload,
undefined // TODO: replace this with user
);
if (issuesFiltersCycleResponse) {
runInAction(() => {
this.loader = false;
this.error = null;
});
}
} catch (error) {
this.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId);
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
getProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string) => {
try {
this.loader = true;
this.error = null;
await this.getProjectIssueFilters(workspaceId, projectId);
const issuesFiltersViewResponse = await this.viewService.getViewDetails(workspaceId, projectId, viewId);
if (issuesFiltersViewResponse) {
const _filters = { ...issuesFiltersViewResponse?.query_data } as any;
const _issuesFiltersViewResponse = {
...this.issueFilters,
[projectId]: {
...this?.issueFilters?.[projectId],
views: {
...this?.issueFilters?.[projectId]?.views,
[viewId]: {
...this?.issueFilters?.[projectId]?.modules?.[viewId],
filters: {
priority: _filters?.priority ?? undefined,
state: _filters?.state ?? undefined,
state_group: _filters?.state_group ?? undefined,
assignees: _filters?.assignees ?? undefined,
created_by: _filters?.created_by ?? undefined,
labels: _filters?.labels ?? undefined,
start_date: _filters?.start_date ?? undefined,
target_date: _filters?.target_date ?? undefined,
},
},
},
},
};
runInAction(() => {
this.issueFilters = _issuesFiltersViewResponse as any;
this.loader = false;
this.error = null;
});
}
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
updateProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string, data: any) => {
try {
this.loader = true;
this.error = null;
const payload = {
query_data: data,
};
const issuesFiltersViewResponse = await this.viewService.patchView(
workspaceId,
projectId,
viewId,
payload,
undefined // TODO: replace this with user
);
if (issuesFiltersViewResponse) {
runInAction(() => {
this.loader = false;
this.error = null;
});
}
return issuesFiltersViewResponse;
} catch (error) {
console.warn("error in fetching workspace level issue filters", error);
this.loader = false;
this.error = null;
}
};
}
export default IssueFilterStore;

View File

@ -2,11 +2,19 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"
// types
import { RootStore } from "./root";
export interface IIssueFilterStore {}
export interface IIssueFilterStore {
loader: boolean;
error: any | null;
userDisplayProperties: any;
userDisplayFilters: any;
}
class IssueFilterStore implements IIssueFilterStore {
loader: boolean = false;
error: any | null = null;
// observables
userDisplayProperties: any = {};
userDisplayFilters: any = {};
// root store
rootStore;
@ -14,6 +22,8 @@ class IssueFilterStore implements IIssueFilterStore {
makeObservable(this, {
loader: observable.ref,
error: observable.ref,
userDisplayProperties: observable.ref,
userDisplayFilters: observable.ref,
});
this.rootStore = _rootStore;

View File

@ -1,417 +0,0 @@
import { observable, action, computed, makeObservable, runInAction } from "mobx";
// types
import { RootStore } from "./root";
// services
import { UserService } from "services/user.service";
import { IssueServices } from "services/issue.service";
import { ModuleService } from "services/modules.service";
import { CycleService } from "services/cycles.service";
// types
import { TIssueLayouts, TIssueViews } from "./issue_filters.legacy";
export interface IIssues {
[key: string]: any;
}
export interface IIssuesLayout {
list: IIssues[];
kanban: IIssues[];
calendar: IIssues[];
spreadsheet: IIssues[];
gantt_chart: IIssues[];
}
export interface IIssueState {
[key: string]: {
// project_id: layout_view
issues: {
[key: string]: IIssuesLayout; // project_id: layout_key: ...issues, It's always one project id here
};
cycles: {
[key: string]: IIssuesLayout; // cycle_id: layout_key: ...issues
};
modules: {
[key: string]: IIssuesLayout; // module_id: layout_key: ...issues
};
views: {
[key: string]: IIssuesLayout; // view_id: layout_key: ...issues
};
};
}
export interface IIssueStore {
loader: boolean;
error: any | null;
issues: IIssueState;
// computed
getIssues: IIssues | null | undefined;
// actions
updateIssues: (data: any) => void;
getProjectIssuesAsync: (workspaceId: string, projectId: string, fetchFilterToggle?: boolean) => null | Promise<any>;
getIssuesForModulesAsync: (
workspaceId: string,
projectId: string,
moduleId: string,
fetchFilterToggle: boolean
) => null | Promise<any>;
getIssuesForCyclesAsync: (
workspaceId: string,
projectId: string,
cycleId: string,
fetchFilterToggle: boolean
) => null | Promise<any>;
getIssuesForViewsAsync: (
workspaceId: string,
projectId: string,
viewId: string,
fetchFilterToggle: boolean
) => null | Promise<any>;
}
class IssueStore implements IIssueStore {
loader: boolean = false;
error: any | null = null;
issues: IIssueState = {};
// root store
rootStore;
// service
issueService;
userService;
modulesService;
cyclesService;
constructor(_rootStore: RootStore) {
makeObservable(this, {
// observable
loader: observable,
error: observable,
issues: observable.ref,
// computed
getIssues: computed,
// action
updateIssues: action,
getProjectIssuesAsync: action,
getIssuesForModulesAsync: action,
getIssuesForCyclesAsync: action,
getIssuesForViewsAsync: action,
});
this.rootStore = _rootStore;
this.issueService = new IssueServices();
this.userService = new UserService();
this.modulesService = new ModuleService();
this.cyclesService = new CycleService();
}
// computed
get getIssues() {
if (this.issues != null) {
const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView;
const projectId: string | null = this.rootStore.project.projectId;
const moduleId: string | null = this.rootStore.module.moduleId;
const cycleId: string | null = this.rootStore.cycle.cycleId;
const viewId: string | null = this.rootStore.view.viewId;
const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout;
if (!issueView || !projectId) return null;
const currentViewIdIndex: string | null =
issueView === "issues" && projectId
? projectId
: issueView === "modules" && moduleId
? moduleId
: issueView === "cycles" && cycleId
? cycleId
: issueView === "cycles" && viewId
? viewId
: null;
if (!issueLayout || !currentViewIdIndex) return null;
return this.issues[projectId][issueView][currentViewIdIndex][issueLayout];
}
return null;
}
updateIssues = (data: any) => {
const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView;
const projectId: string | null = this.rootStore.project.projectId;
const moduleId: string | null = this.rootStore.module.moduleId;
const cycleId: string | null = this.rootStore.cycle.cycleId;
const viewId: string | null = this.rootStore.view.viewId;
const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout;
const { groupId, issueId, issueData } = data as {
groupId?: any;
issueId: string | null;
issueData: any;
};
if (!issueView || !projectId) return null;
const currentViewIdIndex: string | null =
issueView === "issues" && projectId
? projectId
: issueView === "modules" && moduleId
? moduleId
: issueView === "cycles" && cycleId
? cycleId
: issueView === "cycles" && viewId
? viewId
: null;
if (!issueLayout || !currentViewIdIndex) return null;
let _issues = this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout];
if (groupId && groupId != null && ["list", "kanban"].includes(issueLayout)) {
_issues = {
..._issues,
[groupId]:
_issues?.[groupId] && _issues?.[groupId].length > 0
? _issues?.[groupId]?.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item }))
: [],
};
} else {
_issues = {
..._issues,
..._issues.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item })),
};
}
this.issues = {
...this.issues,
[projectId]: {
...this?.issues?.[projectId],
[issueView]: {
...this?.issues?.[projectId]?.[issueView],
[currentViewIdIndex]: {
...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex],
[issueLayout]: {
...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout],
..._issues,
},
},
},
},
};
};
// fetching project issues
getProjectIssuesAsync = async (workspaceId: string, projectId: string, fetchFilterToggle: boolean = true) => {
try {
this.loader = true;
this.error = null;
if (fetchFilterToggle) await this.rootStore.issueFilter.getProjectIssueFilters(workspaceId, projectId);
// const filteredParams = this.rootStore.issueFilter.getComputedFilters(
// workspaceId,
// projectId,
// null,
// null,
// null,
// "issues"
// );
// const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams);
// if (issuesResponse) {
// const _issueResponse: any = {
// ...this.issues,
// [projectId]: {
// ...this?.issues?.[projectId],
// issues: {
// ...this?.issues?.[projectId]?.issues,
// [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse,
// },
// },
// };
// runInAction(() => {
// this.issues = _issueResponse;
// this.loader = false;
// this.error = null;
// });
// }
// return issuesResponse;
} catch (error) {
console.warn("error in fetching the project issues", error);
this.loader = false;
this.error = null;
return error;
}
};
// fetching project issues for modules
getIssuesForModulesAsync = async (
workspaceId: string,
projectId: string,
moduleId: string,
fetchFilterToggle: boolean = true
) => {
try {
this.loader = true;
this.error = null;
if (fetchFilterToggle)
await this.rootStore.issueFilter.getProjectIssueModuleFilters(workspaceId, projectId, moduleId);
const filteredParams = this.rootStore.issueFilter.getComputedFilters(
workspaceId,
projectId,
moduleId,
null,
null,
"modules"
);
const issuesResponse = await this.modulesService.getModuleIssuesWithParams(
workspaceId,
projectId,
moduleId,
filteredParams
);
if (issuesResponse) {
const _issueResponse: any = {
...this.issues,
[projectId]: {
...this?.issues?.[projectId],
modules: {
...this?.issues?.[projectId]?.modules,
[moduleId]: {
...this?.issues?.[projectId]?.modules?.[moduleId],
[this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse,
},
},
},
};
runInAction(() => {
this.issues = _issueResponse;
this.loader = false;
this.error = null;
});
}
return issuesResponse;
} catch (error) {
console.warn("error in fetching the project module issues", error);
this.loader = false;
this.error = null;
return error;
}
};
// fetching project issues for cycles
getIssuesForCyclesAsync = async (
workspaceId: string,
projectId: string,
cycleId: string,
fetchFilterToggle: boolean = true
) => {
try {
this.loader = true;
this.error = null;
if (fetchFilterToggle)
await this.rootStore.issueFilter.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId);
const filteredParams = this.rootStore.issueFilter.getComputedFilters(
workspaceId,
projectId,
null,
cycleId,
null,
"cycles"
);
const issuesResponse = await this.cyclesService.getCycleIssuesWithParams(
workspaceId,
projectId,
cycleId,
filteredParams
);
if (issuesResponse) {
const _issueResponse: any = {
...this.issues,
[projectId]: {
...this?.issues?.[projectId],
cycles: {
...this?.issues?.[projectId]?.cycles,
[cycleId]: {
...this?.issues?.[projectId]?.cycles?.[cycleId],
[this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse,
},
},
},
};
runInAction(() => {
this.issues = _issueResponse;
this.loader = false;
this.error = null;
});
}
return issuesResponse;
} catch (error) {
console.warn("error in fetching the project cycles issues", error);
this.loader = false;
this.error = null;
return error;
}
};
// fetching project issues for views
getIssuesForViewsAsync = async (
workspaceId: string,
projectId: string,
viewId: string,
fetchFilterToggle: boolean = true
) => {
try {
this.loader = true;
this.error = null;
if (fetchFilterToggle)
await this.rootStore.issueFilter.getProjectIssueViewsFilters(workspaceId, projectId, viewId);
const filteredParams = this.rootStore.issueFilter.getComputedFilters(
workspaceId,
projectId,
null,
null,
viewId,
"views"
);
const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams);
if (issuesResponse) {
const _issueResponse: any = {
...this.issues,
[projectId]: {
...this?.issues?.[projectId],
views: {
...this?.issues?.[projectId]?.views,
[viewId]: {
...this?.issues?.[projectId]?.views?.[viewId],
[this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse,
},
},
},
};
runInAction(() => {
this.issues = _issueResponse;
this.loader = false;
this.error = null;
});
}
return issuesResponse;
} catch (error) {
console.warn("error in fetching the project view issues", error);
this.loader = false;
this.error = null;
return error;
}
};
}
export default IssueStore;

View File

@ -1,150 +0,0 @@
// mobx
import { action, observable, runInAction, makeAutoObservable } from "mobx";
// services
import issueService from "services/issue.service";
// types
import type { ICurrentUserResponse, IIssue } from "types";
class IssuesStore {
issues: { [key: string]: IIssue } = {};
isIssuesLoading: boolean = false;
rootStore: any | null = null;
constructor(_rootStore: any | null = null) {
makeAutoObservable(this, {
issues: observable.ref,
loadIssues: action,
getIssueById: action,
isIssuesLoading: observable,
createIssue: action,
updateIssue: action,
deleteIssue: action,
});
this.rootStore = _rootStore;
}
/**
* @description Fetch all issues of a project and hydrate issues field
*/
loadIssues = async (workspaceSlug: string, projectId: string) => {
this.isIssuesLoading = true;
try {
const issuesResponse: IIssue[] = (await issueService.getIssuesWithParams(workspaceSlug, projectId)) as IIssue[];
const issues: { [kye: string]: IIssue } = {};
issuesResponse.forEach((issue) => {
issues[issue.id] = issue;
});
runInAction(() => {
this.issues = issues;
this.isIssuesLoading = false;
});
} catch (error) {
this.isIssuesLoading = false;
console.error("Fetching issues error", error);
}
};
getIssueById = async (workspaceSlug: string, projectId: string, issueId: string): Promise<IIssue> => {
if (this.issues[issueId]) return this.issues[issueId];
try {
const issueResponse: IIssue = await issueService.retrieve(workspaceSlug, projectId, issueId);
const issues = {
...this.issues,
[issueId]: { ...issueResponse },
};
runInAction(() => {
this.issues = issues;
});
return issueResponse;
} catch (error) {
throw error;
}
};
createIssue = async (
workspaceSlug: string,
projectId: string,
issueForm: IIssue,
user: ICurrentUserResponse
): Promise<IIssue> => {
try {
const issueResponse = await issueService.createIssues(workspaceSlug, projectId, issueForm, user);
const issues = {
...this.issues,
[issueResponse.id]: { ...issueResponse },
};
runInAction(() => {
this.issues = issues;
});
return issueResponse;
} catch (error) {
console.error("Creating issue error", error);
throw error;
}
};
updateIssue = async (
workspaceSlug: string,
projectId: string,
issueId: string,
issueForm: Partial<IIssue>,
user: ICurrentUserResponse
) => {
// keep a copy of the issue in the store
const originalIssue = { ...this.issues[issueId] };
// immediately update the issue in the store
const updatedIssue = { ...this.issues[issueId], ...issueForm };
if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list;
try {
runInAction(() => {
this.issues[issueId] = { ...updatedIssue };
});
// make a patch request to update the issue
const issueResponse: IIssue = await issueService.patchIssue(workspaceSlug, projectId, issueId, issueForm, user);
const updatedIssues = { ...this.issues };
updatedIssues[issueId] = { ...issueResponse };
runInAction(() => {
this.issues = updatedIssues;
});
} catch (error) {
// if there is an error, revert the changes
runInAction(() => {
this.issues[issueId] = originalIssue;
});
return error;
}
};
deleteIssue = async (workspaceSlug: string, projectId: string, issueId: string, user: ICurrentUserResponse) => {
const issues = { ...this.issues };
delete issues[issueId];
try {
runInAction(() => {
this.issues = issues;
});
issueService.deleteIssue(workspaceSlug, projectId, issueId, user);
} catch (error) {
console.error("Deleting issue error", error);
}
};
}
export default IssuesStore;

View File

@ -4,8 +4,8 @@ import { enableStaticRendering } from "mobx-react-lite";
import UserStore from "./user";
import ThemeStore from "./theme";
import ProjectPublishStore, { IProjectPublishStore } from "./project_publish";
import IssueStore, { IIssueStore } from "./issue_store.legacy";
import DraftIssuesStore from "./draft_issue";
import IssueStore, { IIssueStore } from "./issue";
import DraftIssuesStore from "./issue_draft";
import WorkspaceStore, { IWorkspaceStore } from "./workspace";
import ProjectStore, { IProjectStore } from "./project";
import ModuleStore, { IModuleStore } from "./modules";
@ -13,7 +13,7 @@ import CycleStore, { ICycleStore } from "./cycles";
import ViewStore, { IViewStore } from "./views";
import IssueFilterStore, { IIssueFilterStore } from "./issue_filters";
import IssueViewDetailStore from "./issue_detail";
import IssueKanBanViewStore from "./kanban-view";
import IssueKanBanViewStore from "./kanban_view";
enableStaticRendering(typeof window === "undefined");