forked from github/plane
chore: filter render UI and Functionality implementation
This commit is contained in:
parent
28ce96aaca
commit
3c9e62d308
6
web/components/issue-layouts/calendar/index.tsx
Normal file
6
web/components/issue-layouts/calendar/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const IssueCalendarViewRoot = () => {
|
||||||
|
console.log();
|
||||||
|
return <div>IssueCalendarViewRoot</div>;
|
||||||
|
};
|
@ -37,35 +37,33 @@ export const DisplayFiltersSelection = observer(() => {
|
|||||||
?.extra_options?.[issueFilterStore?.issueLayout].access;
|
?.extra_options?.[issueFilterStore?.issueLayout].access;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full overflow-hidden select-none relative flex flex-col">
|
<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 border-b border-custom-border-200">
|
<div className="flex-shrink-0 p-2 text-sm">Search container</div>
|
||||||
Search container
|
<div className="w-full h-full overflow-hidden overflow-y-auto relative pb-2 divide-y divide-custom-border-200">
|
||||||
</div>
|
|
||||||
<div className="w-full h-full overflow-hidden overflow-y-auto relative pb-2">
|
|
||||||
{/* display properties */}
|
{/* display properties */}
|
||||||
{handleDisplayPropertiesSectionVisibility && (
|
{handleDisplayPropertiesSectionVisibility && (
|
||||||
<div className="pb-2 px-2 border-b border-custom-border-200">
|
<div className="pb-2 px-2">
|
||||||
<FilterDisplayProperties />
|
<FilterDisplayProperties />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* group by */}
|
{/* group by */}
|
||||||
{handleDisplayFilterSectionVisibility("group_by") && (
|
{handleDisplayFilterSectionVisibility("group_by") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterGroupBy />
|
<FilterGroupBy />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* order by */}
|
{/* order by */}
|
||||||
{handleDisplayFilterSectionVisibility("order_by") && (
|
{handleDisplayFilterSectionVisibility("order_by") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterOrderBy />
|
<FilterOrderBy />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* issue type */}
|
{/* issue type */}
|
||||||
{handleDisplayFilterSectionVisibility("issue_type") && (
|
{handleDisplayFilterSectionVisibility("issue_type") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterIssueType />
|
<FilterIssueType />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
88
web/components/issue-layouts/filters-preview/assignees.tsx
Normal file
88
web/components/issue-layouts/filters-preview/assignees.tsx
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
export const MemberIcons = ({
|
||||||
|
display_name,
|
||||||
|
avatar,
|
||||||
|
}: {
|
||||||
|
display_name: string;
|
||||||
|
avatar: string | null;
|
||||||
|
}) => (
|
||||||
|
<div className="flex-shrink-0 rounded-sm overflow-hidden w-[16px] h-[16px] flex justify-center items-center">
|
||||||
|
{avatar ? (
|
||||||
|
<img src={avatar} alt={display_name || ""} className="" />
|
||||||
|
) : (
|
||||||
|
<div className="text-xs w-full h-full flex justify-center items-center capitalize font-medium bg-gray-700 text-white">
|
||||||
|
{(display_name ?? "U")[0]}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const FilterAssignees = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "assignees", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.assignees != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`Assignees (${
|
||||||
|
issueFilterStore?.userFilters?.filters?.assignees?.length || 0
|
||||||
|
})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.projectMembers &&
|
||||||
|
issueFilterStore?.projectMembers.length > 0 &&
|
||||||
|
issueFilterStore?.projectMembers.map(
|
||||||
|
(_member) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.assignees != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.assignees.includes(
|
||||||
|
_member?.member?.id
|
||||||
|
) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={`assignees-${_member?.member?.id}`}
|
||||||
|
icon={
|
||||||
|
<MemberIcons
|
||||||
|
display_name={_member?.member.display_name}
|
||||||
|
avatar={_member?.member.avatar}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
title={`${_member?.member?.display_name}`}
|
||||||
|
onClick={() => handleFilter("assignees", _member?.member?.id)}
|
||||||
|
className="border border-custom-border-100 bg-custom-background-100"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
72
web/components/issue-layouts/filters-preview/created-by.tsx
Normal file
72
web/components/issue-layouts/filters-preview/created-by.tsx
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { MemberIcons } from "./assignees";
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
export const FilterCreatedBy = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "created_by", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.created_by != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`Created By (${
|
||||||
|
issueFilterStore?.userFilters?.filters?.created_by?.length || 0
|
||||||
|
})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.projectMembers &&
|
||||||
|
issueFilterStore?.projectMembers.length > 0 &&
|
||||||
|
issueFilterStore?.projectMembers.map(
|
||||||
|
(_member) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.created_by != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.created_by.includes(
|
||||||
|
_member?.member?.id
|
||||||
|
) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={`create-by-${_member?.member?.id}`}
|
||||||
|
title={`${_member?.member?.display_name}`}
|
||||||
|
icon={
|
||||||
|
<MemberIcons
|
||||||
|
display_name={_member?.member.display_name}
|
||||||
|
avatar={_member?.member.avatar}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={() => handleFilter("created_by", _member?.member?.id)}
|
||||||
|
className="border border-custom-border-100 bg-custom-background-100"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,17 @@
|
|||||||
|
// lucide icons
|
||||||
|
import { X } from "lucide-react";
|
||||||
|
|
||||||
|
interface IFilterPreviewClear {
|
||||||
|
onClick?: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FilterPreviewClear = ({ onClick }: IFilterPreviewClear) => (
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => {
|
||||||
|
if (onClick) onClick();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<X width={12} strokeWidth={2} />
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,32 @@
|
|||||||
|
import { FilterPreviewClear } from "./clear";
|
||||||
|
|
||||||
|
interface IFilterPreviewContent {
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
title?: string;
|
||||||
|
onClick?: () => void;
|
||||||
|
className?: string;
|
||||||
|
style?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FilterPreviewContent = ({
|
||||||
|
icon,
|
||||||
|
title,
|
||||||
|
onClick,
|
||||||
|
className,
|
||||||
|
style,
|
||||||
|
}: IFilterPreviewContent) => (
|
||||||
|
<div
|
||||||
|
className={`flex-shrink-0 flex items-center gap-1.5 rounded-full px-[8px] transition-all ${className}`}
|
||||||
|
style={style ? style : {}}
|
||||||
|
>
|
||||||
|
<div className="flex-shrink-0">{icon}</div>
|
||||||
|
<div className="text-xs w-full whitespace-nowrap font-medium">{title}</div>
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear
|
||||||
|
onClick={() => {
|
||||||
|
if (onClick) onClick();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,12 @@
|
|||||||
|
interface IFilterPreviewHeader {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const FilterPreviewHeader = ({ title }: IFilterPreviewHeader) => {
|
||||||
|
console.log();
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between gap-2">
|
||||||
|
<div className="text-gray-500 text-xs text-custom-text-300 font-medium">{title}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
92
web/components/issue-layouts/filters-preview/index copy.tsx
Normal file
92
web/components/issue-layouts/filters-preview/index copy.tsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPriority } from "./priority";
|
||||||
|
import { FilterState } from "./state";
|
||||||
|
import { FilterStateGroup } from "./state-group";
|
||||||
|
import { FilterAssignees } from "./assignees";
|
||||||
|
import { FilterCreatedBy } from "./created-by";
|
||||||
|
import { FilterLabels } from "./labels";
|
||||||
|
import { FilterStartDate } from "./start-date";
|
||||||
|
import { FilterTargetDate } from "./target-date";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// default data
|
||||||
|
import { issueFilterVisibilityData } from "store/issue-views/issue_data";
|
||||||
|
|
||||||
|
export const FilterSelection = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilterSectionVisibility = (section_key: string) =>
|
||||||
|
issueFilterStore?.issueView &&
|
||||||
|
issueFilterStore?.issueLayout &&
|
||||||
|
issueFilterVisibilityData[
|
||||||
|
issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"
|
||||||
|
]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key);
|
||||||
|
|
||||||
|
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">
|
||||||
|
{/* priority */}
|
||||||
|
{handleFilterSectionVisibility("priority") && (
|
||||||
|
<div className="pb-1 px-2">
|
||||||
|
<FilterPriority />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* state group */}
|
||||||
|
{handleFilterSectionVisibility("state_group") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterStateGroup />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* state */}
|
||||||
|
{handleFilterSectionVisibility("state") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterState />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* assignees */}
|
||||||
|
{handleFilterSectionVisibility("assignees") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterAssignees />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* created_by */}
|
||||||
|
{handleFilterSectionVisibility("created_by") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterCreatedBy />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* labels */}
|
||||||
|
{handleFilterSectionVisibility("labels") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterLabels />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* start_date */}
|
||||||
|
{handleFilterSectionVisibility("start_date") && (
|
||||||
|
<div className="py-1 px-2">
|
||||||
|
<FilterStartDate />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* due_date */}
|
||||||
|
{handleFilterSectionVisibility("due_date") && (
|
||||||
|
<div className="pt-1 px-2">
|
||||||
|
<FilterTargetDate />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
68
web/components/issue-layouts/filters-preview/index.tsx
Normal file
68
web/components/issue-layouts/filters-preview/index.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPriority } from "./priority";
|
||||||
|
import { FilterState } from "./state";
|
||||||
|
import { FilterStateGroup } from "./state-group";
|
||||||
|
import { FilterAssignees } from "./assignees";
|
||||||
|
import { FilterCreatedBy } from "./created-by";
|
||||||
|
import { FilterLabels } from "./labels";
|
||||||
|
import { FilterStartDate } from "./start-date";
|
||||||
|
import { FilterTargetDate } from "./target-date";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// default data
|
||||||
|
import { issueFilterVisibilityData } from "store/issue-views/issue_data";
|
||||||
|
|
||||||
|
export const FilterPreview = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilterSectionVisibility = (section_key: string) =>
|
||||||
|
issueFilterStore?.issueView &&
|
||||||
|
issueFilterStore?.issueLayout &&
|
||||||
|
issueFilterVisibilityData[
|
||||||
|
issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"
|
||||||
|
]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key);
|
||||||
|
|
||||||
|
const validateFiltersAvailability =
|
||||||
|
issueFilterStore?.userFilters?.filters != null &&
|
||||||
|
Object.keys(issueFilterStore?.userFilters?.filters).length > 0 &&
|
||||||
|
Object.keys(issueFilterStore?.userFilters?.filters)
|
||||||
|
.map((key) => issueFilterStore?.userFilters?.filters?.[key]?.length)
|
||||||
|
.filter((v) => v != undefined || v != null).length > 0;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{validateFiltersAvailability && (
|
||||||
|
<div className="w-full h-full overflow-hidden overflow-y-auto relative max-h-[500px] flex flex-wrap p-2 border-b border-custom-border-80 shadow-sm">
|
||||||
|
{/* priority */}
|
||||||
|
{handleFilterSectionVisibility("priority") && <FilterPriority />}
|
||||||
|
|
||||||
|
{/* state group */}
|
||||||
|
{handleFilterSectionVisibility("state_group") && <FilterStateGroup />}
|
||||||
|
|
||||||
|
{/* state */}
|
||||||
|
{handleFilterSectionVisibility("state") && <FilterState />}
|
||||||
|
|
||||||
|
{/* assignees */}
|
||||||
|
{handleFilterSectionVisibility("assignees") && <FilterAssignees />}
|
||||||
|
|
||||||
|
{/* created_by */}
|
||||||
|
{handleFilterSectionVisibility("created_by") && <FilterCreatedBy />}
|
||||||
|
|
||||||
|
{/* labels */}
|
||||||
|
{handleFilterSectionVisibility("labels") && <FilterLabels />}
|
||||||
|
|
||||||
|
{/* start_date */}
|
||||||
|
{handleFilterSectionVisibility("start_date") && <FilterStartDate />}
|
||||||
|
|
||||||
|
{/* due_date */}
|
||||||
|
{handleFilterSectionVisibility("due_date") && <FilterTargetDate />}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
75
web/components/issue-layouts/filters-preview/labels.tsx
Normal file
75
web/components/issue-layouts/filters-preview/labels.tsx
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
const LabelIcons = ({ color }: { color: string }) => (
|
||||||
|
<div className="flex-shrink-0 rounded-sm overflow-hidden w-[20px] h-[20px] flex justify-center items-center">
|
||||||
|
<div className={`w-[12px] h-[12px] rounded-full`} style={{ backgroundColor: color }} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export const FilterLabels = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const stateStyles = (color: any) => ({ color: color, backgroundColor: `${color}20` });
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "labels", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleLabels =
|
||||||
|
issueFilterStore.issueView && issueFilterStore.issueView === "my_issues"
|
||||||
|
? issueFilterStore?.workspaceLabels
|
||||||
|
: issueFilterStore?.projectLabels;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.labels != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`Labels (${issueFilterStore?.userFilters?.filters?.labels?.length || 0})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{handleLabels &&
|
||||||
|
handleLabels.length > 0 &&
|
||||||
|
handleLabels.map(
|
||||||
|
(_label) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.labels != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.labels.includes(_label?.id) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_label?.id}
|
||||||
|
onClick={() => handleFilter("labels", _label?.id)}
|
||||||
|
icon={<LabelIcons color={_label.color} />}
|
||||||
|
title={_label.name}
|
||||||
|
style={stateStyles(_label.color)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
79
web/components/issue-layouts/filters-preview/priority.tsx
Normal file
79
web/components/issue-layouts/filters-preview/priority.tsx
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import React from "react";
|
||||||
|
// lucide icons
|
||||||
|
import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
const PriorityIcons = ({ priority }: { priority: string }) => {
|
||||||
|
if (priority === "urgent") return <AlertCircle size={12} strokeWidth={2} />;
|
||||||
|
if (priority === "high") return <SignalHigh size={12} strokeWidth={4} />;
|
||||||
|
if (priority === "medium") return <SignalMedium size={12} strokeWidth={4} />;
|
||||||
|
if (priority === "low") return <SignalLow size={12} strokeWidth={4} />;
|
||||||
|
return <Ban size={12} strokeWidth={2} />;
|
||||||
|
};
|
||||||
|
|
||||||
|
const classNamesStyling = (priority: string) => {
|
||||||
|
if (priority == "urgent") return "bg-red-500/20 text-red-500";
|
||||||
|
if (priority == "high") return "bg-orange-500/20 text-orange-500 !-pt-[30px]";
|
||||||
|
if (priority == "medium") return "bg-orange-500/20 text-orange-500 -pt-2";
|
||||||
|
if (priority == "low") return "bg-green-500/20 text-green-500 -pt-2";
|
||||||
|
return "bg-gray-500/10 text-gray-500";
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FilterPriority = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "priority", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.priority != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`Priority (${issueFilterStore?.userFilters?.filters?.priority?.length || 0})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.issueRenderFilters?.priority &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.priority.length > 0 &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.priority.map(
|
||||||
|
(_priority) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.priority != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.priority.includes(_priority?.key) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_priority?.key}
|
||||||
|
icon={<PriorityIcons priority={_priority.key} />}
|
||||||
|
title={_priority.title}
|
||||||
|
className={classNamesStyling(_priority?.key)}
|
||||||
|
onClick={() => handleFilter("priority", _priority?.key)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
56
web/components/issue-layouts/filters-preview/start-date.tsx
Normal file
56
web/components/issue-layouts/filters-preview/start-date.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
export const FilterStartDate = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "start_date", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.start_date != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader title={`Start Date`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.issueRenderFilters?.start_date &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.start_date.length > 0 &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.start_date.map((_startDate) => (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_startDate?.key}
|
||||||
|
title={_startDate.title}
|
||||||
|
className="border border-custom-border-100 bg-custom-background-100"
|
||||||
|
onClick={() => handleFilter("start_date", _startDate?.key)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
159
web/components/issue-layouts/filters-preview/state-group.tsx
Normal file
159
web/components/issue-layouts/filters-preview/state-group.tsx
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
StateGroupBacklogIcon,
|
||||||
|
StateGroupCancelledIcon,
|
||||||
|
StateGroupCompletedIcon,
|
||||||
|
StateGroupStartedIcon,
|
||||||
|
StateGroupUnstartedIcon,
|
||||||
|
} from "components/icons";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// constants
|
||||||
|
import { STATE_GROUP_COLORS } from "constants/state";
|
||||||
|
|
||||||
|
export const StateGroupIcons = ({
|
||||||
|
stateGroup,
|
||||||
|
color = null,
|
||||||
|
}: {
|
||||||
|
stateGroup: string;
|
||||||
|
color?: string | null;
|
||||||
|
}) => {
|
||||||
|
if (stateGroup === "cancelled")
|
||||||
|
return (
|
||||||
|
<StateGroupCancelledIcon
|
||||||
|
width={"12px"}
|
||||||
|
height={"12px"}
|
||||||
|
color={color ? color : STATE_GROUP_COLORS[stateGroup]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
if (stateGroup === "completed")
|
||||||
|
return (
|
||||||
|
<StateGroupCompletedIcon
|
||||||
|
width={"12px"}
|
||||||
|
height={"12px"}
|
||||||
|
color={color ? color : STATE_GROUP_COLORS[stateGroup]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
if (stateGroup === "started")
|
||||||
|
return (
|
||||||
|
<StateGroupStartedIcon
|
||||||
|
width={"12px"}
|
||||||
|
height={"12px"}
|
||||||
|
color={color ? color : STATE_GROUP_COLORS[stateGroup]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
if (stateGroup === "unstarted")
|
||||||
|
return (
|
||||||
|
<StateGroupUnstartedIcon
|
||||||
|
width={"12px"}
|
||||||
|
height={"12px"}
|
||||||
|
color={color ? color : STATE_GROUP_COLORS[stateGroup]}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
if (stateGroup === "backlog")
|
||||||
|
return (
|
||||||
|
<div className="flex-shrink-0 rounded-sm overflow-hidden w-[20px] h-[20px] flex justify-center items-center">
|
||||||
|
<StateGroupBacklogIcon
|
||||||
|
width={"12px"}
|
||||||
|
height={"12px"}
|
||||||
|
color={color ? color : STATE_GROUP_COLORS[stateGroup]}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return <></>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const stateStyles = (stateGroup: string, color: any) => {
|
||||||
|
if (stateGroup === "cancelled") {
|
||||||
|
return {
|
||||||
|
color: color ? color : STATE_GROUP_COLORS[stateGroup],
|
||||||
|
backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (stateGroup === "completed") {
|
||||||
|
return {
|
||||||
|
color: color ? color : STATE_GROUP_COLORS[stateGroup],
|
||||||
|
backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (stateGroup === "started") {
|
||||||
|
return {
|
||||||
|
color: color ? color : STATE_GROUP_COLORS[stateGroup],
|
||||||
|
backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (stateGroup === "unstarted") {
|
||||||
|
return {
|
||||||
|
color: color ? color : STATE_GROUP_COLORS[stateGroup],
|
||||||
|
backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (stateGroup === "backlog") {
|
||||||
|
return {
|
||||||
|
color: color ? color : STATE_GROUP_COLORS[stateGroup],
|
||||||
|
backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const FilterStateGroup = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "state_group", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.state_group != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`State Group (${
|
||||||
|
issueFilterStore?.userFilters?.filters?.state_group?.length || 0
|
||||||
|
})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.issueRenderFilters?.state_group &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.state_group.length > 0 &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.state_group.map(
|
||||||
|
(_stateGroup) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.state_group != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.state_group.includes(
|
||||||
|
_stateGroup?.key
|
||||||
|
) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_stateGroup?.key}
|
||||||
|
icon={<StateGroupIcons stateGroup={_stateGroup.key} />}
|
||||||
|
title={_stateGroup.title}
|
||||||
|
style={stateStyles(_stateGroup?.key, null)}
|
||||||
|
onClick={() => handleFilter("state_group", _stateGroup?.key)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
68
web/components/issue-layouts/filters-preview/state.tsx
Normal file
68
web/components/issue-layouts/filters-preview/state.tsx
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { StateGroupIcons, stateStyles } from "./state-group";
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
// store default data
|
||||||
|
import { issueStateGroupKeys } from "store/issue-views/issue_data";
|
||||||
|
|
||||||
|
export const FilterState = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "state", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.state != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader
|
||||||
|
title={`State (${issueFilterStore?.userFilters?.filters?.state?.length || 0})`}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueStateGroupKeys.map(
|
||||||
|
(_stateGroup) =>
|
||||||
|
issueFilterStore?.projectStates &&
|
||||||
|
issueFilterStore?.projectStates[_stateGroup] &&
|
||||||
|
issueFilterStore?.projectStates[_stateGroup].length > 0 &&
|
||||||
|
issueFilterStore?.projectStates[_stateGroup].map(
|
||||||
|
(_state: any) =>
|
||||||
|
issueFilterStore?.userFilters?.filters?.state != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.state.includes(_state?.id) && (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_state?.id}
|
||||||
|
icon={<StateGroupIcons stateGroup={_stateGroup} color={_state?.color} />}
|
||||||
|
title={_state?.name}
|
||||||
|
style={stateStyles(_state?.group, _state?.color)}
|
||||||
|
onClick={() => handleFilter("state", _state?.id)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
56
web/components/issue-layouts/filters-preview/target-date.tsx
Normal file
56
web/components/issue-layouts/filters-preview/target-date.tsx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import React from "react";
|
||||||
|
// components
|
||||||
|
import { FilterPreviewHeader } from "./helpers/header";
|
||||||
|
import { FilterPreviewContent } from "./helpers/content";
|
||||||
|
import { FilterPreviewClear } from "./helpers/clear";
|
||||||
|
// mobx react lite
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
export const FilterTargetDate = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
|
const handleFilter = (key: string, value: string) => {
|
||||||
|
let _value =
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key] != null &&
|
||||||
|
issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value);
|
||||||
|
_value = _value && _value.length > 0 ? _value : null;
|
||||||
|
|
||||||
|
issueFilterStore.handleUserFilter("filters", key, _value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearFilter = () => {
|
||||||
|
issueFilterStore.handleUserFilter("filters", "target_date", null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{issueFilterStore?.userFilters?.filters?.target_date != null && (
|
||||||
|
<div className="border border-custom-border-200 bg-custom-background-80 rounded-full overflow-hidden flex items-center gap-2 px-2 py-1">
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewHeader title={`Target Date`} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative flex items-center flex-wrap gap-2">
|
||||||
|
{issueFilterStore?.issueRenderFilters?.due_date &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.due_date.length > 0 &&
|
||||||
|
issueFilterStore?.issueRenderFilters?.due_date.map((_targetDate) => (
|
||||||
|
<FilterPreviewContent
|
||||||
|
key={_targetDate?.key}
|
||||||
|
title={_targetDate.title}
|
||||||
|
className="border border-custom-border-100 bg-custom-background-100"
|
||||||
|
onClick={() => handleFilter("target_date", _targetDate?.key)}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreviewClear onClick={clearFilter} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
@ -22,61 +22,60 @@ export const FilterSelection = observer(() => {
|
|||||||
|
|
||||||
const handleFilterSectionVisibility = (section_key: string) =>
|
const handleFilterSectionVisibility = (section_key: string) =>
|
||||||
issueFilterStore?.issueView &&
|
issueFilterStore?.issueView &&
|
||||||
|
issueFilterStore?.issueLayout &&
|
||||||
issueFilterVisibilityData[
|
issueFilterVisibilityData[
|
||||||
issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"
|
issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"
|
||||||
].filters.includes(section_key);
|
]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full overflow-hidden select-none relative flex flex-col">
|
<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 border-b border-custom-border-200">
|
<div className="flex-shrink-0 p-2 text-sm ">Search container</div>
|
||||||
Search container
|
<div className="w-full h-full overflow-hidden overflow-y-auto relative pb-2 divide-y divide-custom-border-200">
|
||||||
</div>
|
|
||||||
<div className="w-full h-full overflow-hidden overflow-y-auto relative pb-2">
|
|
||||||
{/* priority */}
|
{/* priority */}
|
||||||
{handleFilterSectionVisibility("priority") && (
|
{handleFilterSectionVisibility("priority") && (
|
||||||
<div className="pb-1 px-2 border-b border-custom-border-200">
|
<div className="pb-1 px-2">
|
||||||
<FilterPriority />
|
<FilterPriority />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* state group */}
|
{/* state group */}
|
||||||
{handleFilterSectionVisibility("state_group") && (
|
{handleFilterSectionVisibility("state_group") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterStateGroup />
|
<FilterStateGroup />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* state */}
|
{/* state */}
|
||||||
{handleFilterSectionVisibility("state") && (
|
{handleFilterSectionVisibility("state") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterState />
|
<FilterState />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* assignees */}
|
{/* assignees */}
|
||||||
{handleFilterSectionVisibility("assignees") && (
|
{handleFilterSectionVisibility("assignees") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterAssignees />
|
<FilterAssignees />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* created_by */}
|
{/* created_by */}
|
||||||
{handleFilterSectionVisibility("created_by") && (
|
{handleFilterSectionVisibility("created_by") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterCreatedBy />
|
<FilterCreatedBy />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* labels */}
|
{/* labels */}
|
||||||
{handleFilterSectionVisibility("labels") && (
|
{handleFilterSectionVisibility("labels") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterLabels />
|
<FilterLabels />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* start_date */}
|
{/* start_date */}
|
||||||
{handleFilterSectionVisibility("start_date") && (
|
{handleFilterSectionVisibility("start_date") && (
|
||||||
<div className="py-1 px-2 border-b border-custom-border-200">
|
<div className="py-1 px-2">
|
||||||
<FilterStartDate />
|
<FilterStartDate />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
6
web/components/issue-layouts/gantt/index.tsx
Normal file
6
web/components/issue-layouts/gantt/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const IssueGanttViewRoot = () => {
|
||||||
|
console.log();
|
||||||
|
return <div>IssueGanttViewRoot</div>;
|
||||||
|
};
|
@ -37,7 +37,7 @@ export const IssueDropdown = ({ children, title = "Dropdown" }: IIssueDropdown)
|
|||||||
leaveFrom="opacity-100 translate-y-0"
|
leaveFrom="opacity-100 translate-y-0"
|
||||||
leaveTo="opacity-0 translate-y-1"
|
leaveTo="opacity-0 translate-y-1"
|
||||||
>
|
>
|
||||||
<Popover.Panel className="absolute right-0 z-10 mt-1 w-[300px] h-[700px]">
|
<Popover.Panel className="absolute right-0 z-10 mt-1 w-[300px] h-[600px]">
|
||||||
<div className="w-full h-full overflow-hidden rounded border border-custom-border-200 bg-custom-background-100 shadow-xl">
|
<div className="w-full h-full overflow-hidden rounded border border-custom-border-200 bg-custom-background-100 shadow-xl">
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -52,22 +52,21 @@ export const LayoutSelection = observer(() => {
|
|||||||
issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey);
|
issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("----");
|
// console.log("----");
|
||||||
console.log("my_user_id", issueFilterStore.myUserId);
|
// console.log("my_user_id", issueFilterStore.myUserId);
|
||||||
console.log("workspace_id", issueFilterStore.workspaceId);
|
// console.log("workspace_id", issueFilterStore.workspaceId);
|
||||||
console.log("project_id", issueFilterStore.projectId);
|
// console.log("project_id", issueFilterStore.projectId);
|
||||||
console.log("module_id", issueFilterStore.moduleId);
|
// console.log("module_id", issueFilterStore.moduleId);
|
||||||
console.log("cycle_id", issueFilterStore.cycleId);
|
// console.log("cycle_id", issueFilterStore.cycleId);
|
||||||
console.log("view_id", issueFilterStore.viewId);
|
// console.log("view_id", issueFilterStore.viewId);
|
||||||
|
|
||||||
console.log("issue_view", issueFilterStore.issueView);
|
// console.log("issue_view", issueFilterStore.issueView);
|
||||||
console.log("issue_layout", issueFilterStore.issueLayout);
|
// console.log("issue_layout", issueFilterStore.issueLayout);
|
||||||
|
|
||||||
console.log("user_filters", issueFilterStore.userFilters);
|
// console.log("user_filters", issueFilterStore.userFilters);
|
||||||
console.log("issues", issueStore.issues);
|
// console.log("issues", issueStore.issues);
|
||||||
console.log("issues", issueStore.getIssues);
|
// console.log("issues", issueStore.getIssues);
|
||||||
|
// console.log("----");
|
||||||
console.log("----");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative flex items-center p-1 rounded gap-1 bg-custom-background-80">
|
<div className="relative flex items-center p-1 rounded gap-1 bg-custom-background-80">
|
||||||
|
6
web/components/issue-layouts/list/index.tsx
Normal file
6
web/components/issue-layouts/list/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const IssueListViewRoot = () => {
|
||||||
|
console.log();
|
||||||
|
return <div>IssueListViewRoot</div>;
|
||||||
|
};
|
@ -1,17 +1,30 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
// components
|
// components
|
||||||
import { IssueKanBanViewRoot } from "./kanban";
|
|
||||||
import { LayoutSelection } from "./layout-selection";
|
import { LayoutSelection } from "./layout-selection";
|
||||||
import { IssueDropdown } from "./helpers/dropdown";
|
import { IssueDropdown } from "./helpers/dropdown";
|
||||||
import { FilterSelection } from "./filters";
|
import { FilterSelection } from "./filters";
|
||||||
import { DisplayFiltersSelection } from "./display-filters";
|
import { DisplayFiltersSelection } from "./display-filters";
|
||||||
|
|
||||||
export const IssuesRoot = () => {
|
import { FilterPreview } from "./filters-preview";
|
||||||
console.log("issue root");
|
|
||||||
|
import { IssueListViewRoot } from "./list";
|
||||||
|
import { IssueKanBanViewRoot } from "./kanban";
|
||||||
|
import { IssueCalendarViewRoot } from "./calendar";
|
||||||
|
import { IssueSpreadsheetViewRoot } from "./spreadsheet";
|
||||||
|
import { IssueGanttViewRoot } from "./gantt";
|
||||||
|
// mobx
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// mobx store
|
||||||
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
|
import { RootStore } from "store/root";
|
||||||
|
|
||||||
|
export const IssuesRoot = observer(() => {
|
||||||
|
const store: RootStore = useMobxStore();
|
||||||
|
const { issueFilters: issueFilterStore } = store;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full h-full relative flex flex-col overflow-hidden">
|
<div className="w-full h-full relative flex flex-col overflow-hidden">
|
||||||
<div className="flex-shrink-0 h-[60px] border-b border-gray-200">
|
<div className="flex-shrink-0 h-[60px] border-b border-custom-border-80 shadow-sm">
|
||||||
<div className="w-full h-full p-2 px-5 relative flex justify-between items-center gap-2">
|
<div className="w-full h-full p-2 px-5 relative flex justify-between items-center gap-2">
|
||||||
<div>
|
<div>
|
||||||
<div>Filter Header</div>
|
<div>Filter Header</div>
|
||||||
@ -27,10 +40,16 @@ export const IssuesRoot = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-shrink-0 border-b border-gray-200">Hello</div>
|
<div className="flex-shrink-0">
|
||||||
|
<FilterPreview />
|
||||||
|
</div>
|
||||||
<div className="w-full h-full relative overflow-hidden">
|
<div className="w-full h-full relative overflow-hidden">
|
||||||
<IssueKanBanViewRoot />
|
{issueFilterStore?.issueLayout === "list" && <IssueListViewRoot />}
|
||||||
|
{issueFilterStore?.issueLayout === "kanban" && <IssueKanBanViewRoot />}
|
||||||
|
{issueFilterStore?.issueLayout === "calendar" && <IssueCalendarViewRoot />}
|
||||||
|
{issueFilterStore?.issueLayout === "spreadsheet" && <IssueSpreadsheetViewRoot />}
|
||||||
|
{issueFilterStore?.issueLayout === "gantt_chart" && <IssueGanttViewRoot />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
6
web/components/issue-layouts/spreadsheet/index.tsx
Normal file
6
web/components/issue-layouts/spreadsheet/index.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
export const IssueSpreadsheetViewRoot = () => {
|
||||||
|
console.log();
|
||||||
|
return <div>IssueSpreadsheetViewRoot</div>;
|
||||||
|
};
|
@ -1,6 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
// next imports
|
// next imports
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
|
// swr
|
||||||
|
// import useSWR from "swr";
|
||||||
// components
|
// components
|
||||||
import { IssuesRoot } from "components/issue-layouts/root";
|
import { IssuesRoot } from "components/issue-layouts/root";
|
||||||
// mobx store
|
// mobx store
|
||||||
@ -14,6 +16,10 @@ const KanBanViewRoot = () => {
|
|||||||
const store: RootStore = useMobxStore();
|
const store: RootStore = useMobxStore();
|
||||||
const { issueView: issueViewStore } = store;
|
const { issueView: issueViewStore } = store;
|
||||||
|
|
||||||
|
// useSWR(`REVALIDATE_MY_ISSUES`, async () => {
|
||||||
|
// if (workspace_slug) await issueViewStore.getMyIssuesAsync(workspace_slug);
|
||||||
|
// });
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
console.log("request init--->");
|
console.log("request init--->");
|
||||||
const init = async () => await issueViewStore.getMyIssuesAsync(workspace_slug);
|
const init = async () => await issueViewStore.getMyIssuesAsync(workspace_slug);
|
||||||
|
@ -48,22 +48,29 @@ export interface IIssueViewStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssues: IIssues | null | undefined;
|
getIssues: IIssues | null | undefined;
|
||||||
// actions
|
// actions
|
||||||
getMyIssuesAsync: (workspaceId: string) => null | Promise<any>;
|
getMyIssuesAsync: (workspaceId: string, fetchFilterToggle: boolean) => null | Promise<any>;
|
||||||
getProjectIssuesAsync: (workspaceId: string, projectId: string) => null | Promise<any>;
|
getProjectIssuesAsync: (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
fetchFilterToggle: boolean
|
||||||
|
) => null | Promise<any>;
|
||||||
getIssuesForModulesAsync: (
|
getIssuesForModulesAsync: (
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string
|
moduleId: string,
|
||||||
|
fetchFilterToggle: boolean
|
||||||
) => null | Promise<any>;
|
) => null | Promise<any>;
|
||||||
getIssuesForCyclesAsync: (
|
getIssuesForCyclesAsync: (
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
cycleId: string
|
cycleId: string,
|
||||||
|
fetchFilterToggle: boolean
|
||||||
) => null | Promise<any>;
|
) => null | Promise<any>;
|
||||||
getIssuesForViewsAsync: (
|
getIssuesForViewsAsync: (
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
viewId: string
|
viewId: string,
|
||||||
|
fetchFilterToggle: boolean
|
||||||
) => null | Promise<any>;
|
) => null | Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,11 +151,12 @@ class IssueViewStore implements IIssueViewStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// fetching my issues
|
// fetching my issues
|
||||||
getMyIssuesAsync = async (workspaceId: string) => {
|
getMyIssuesAsync = async (workspaceId: string, fetchFilterToggle: boolean = true) => {
|
||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
if (fetchFilterToggle)
|
||||||
await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId);
|
await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId);
|
||||||
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -190,11 +198,16 @@ class IssueViewStore implements IIssueViewStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// fetching project issues
|
// fetching project issues
|
||||||
getProjectIssuesAsync = async (workspaceId: string, projectId: string) => {
|
getProjectIssuesAsync = async (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
fetchFilterToggle: boolean = true
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
if (fetchFilterToggle)
|
||||||
await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId);
|
await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId);
|
||||||
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
@ -246,11 +259,17 @@ class IssueViewStore implements IIssueViewStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// fetching project issues for modules
|
// fetching project issues for modules
|
||||||
getIssuesForModulesAsync = async (workspaceId: string, projectId: string, moduleId: string) => {
|
getIssuesForModulesAsync = async (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
fetchFilterToggle: boolean = true
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
if (fetchFilterToggle)
|
||||||
await this.rootStore.issueFilters.getProjectIssueModuleFilters(
|
await this.rootStore.issueFilters.getProjectIssueModuleFilters(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
projectId,
|
projectId,
|
||||||
@ -310,11 +329,17 @@ class IssueViewStore implements IIssueViewStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// fetching project issues for cycles
|
// fetching project issues for cycles
|
||||||
getIssuesForCyclesAsync = async (workspaceId: string, projectId: string, cycleId: string) => {
|
getIssuesForCyclesAsync = async (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
cycleId: string,
|
||||||
|
fetchFilterToggle: boolean = true
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
|
if (fetchFilterToggle)
|
||||||
await this.rootStore.issueFilters.getProjectIssueCyclesFilters(
|
await this.rootStore.issueFilters.getProjectIssueCyclesFilters(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
projectId,
|
projectId,
|
||||||
@ -374,12 +399,22 @@ class IssueViewStore implements IIssueViewStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// fetching project issues for views
|
// fetching project issues for views
|
||||||
getIssuesForViewsAsync = async (workspaceId: string, projectId: string, viewId: string) => {
|
getIssuesForViewsAsync = async (
|
||||||
|
workspaceId: string,
|
||||||
|
projectId: string,
|
||||||
|
viewId: string,
|
||||||
|
fetchFilterToggle: boolean = true
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
this.loader = true;
|
this.loader = true;
|
||||||
this.error = null;
|
this.error = null;
|
||||||
|
|
||||||
await this.rootStore.issueFilters.getProjectIssueViewsFilters(workspaceId, projectId, viewId);
|
if (fetchFilterToggle)
|
||||||
|
await this.rootStore.issueFilters.getProjectIssueViewsFilters(
|
||||||
|
workspaceId,
|
||||||
|
projectId,
|
||||||
|
viewId
|
||||||
|
);
|
||||||
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
const filteredParams = this.rootStore.issueFilters.getComputedFilters(
|
||||||
workspaceId,
|
workspaceId,
|
||||||
projectId,
|
projectId,
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { renderDateFormat } from "helpers/date-time.helper";
|
||||||
|
|
||||||
export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled";
|
export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled";
|
||||||
export const issueStateGroupKeys: TStateGroup[] = [
|
export const issueStateGroupKeys: TStateGroup[] = [
|
||||||
"backlog",
|
"backlog",
|
||||||
@ -87,7 +89,10 @@ export const extraProperties: { key: string; title: string }[] = [
|
|||||||
export const issueFilterVisibilityData: any = {
|
export const issueFilterVisibilityData: any = {
|
||||||
my_issues: {
|
my_issues: {
|
||||||
layout: ["list", "kanban"],
|
layout: ["list", "kanban"],
|
||||||
filters: ["priority", "state_group", "labels", "start_date", "due_date"],
|
filters: {
|
||||||
|
list: ["priority", "state_group", "labels", "start_date", "due_date"],
|
||||||
|
kanban: ["priority", "state_group", "labels", "start_date", "due_date"],
|
||||||
|
},
|
||||||
display_properties: {
|
display_properties: {
|
||||||
list: true,
|
list: true,
|
||||||
kanban: true,
|
kanban: true,
|
||||||
@ -109,7 +114,29 @@ export const issueFilterVisibilityData: any = {
|
|||||||
},
|
},
|
||||||
others: {
|
others: {
|
||||||
layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"],
|
layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"],
|
||||||
filters: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"],
|
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: {
|
display_properties: {
|
||||||
list: true,
|
list: true,
|
||||||
kanban: true,
|
kanban: true,
|
||||||
@ -148,3 +175,31 @@ export const issueFilterVisibilityData: any = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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`;
|
||||||
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { observable, action, computed, makeObservable, runInAction } from "mobx";
|
import { observable, action, computed, makeObservable, runInAction, autorun } from "mobx";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
// services
|
// services
|
||||||
@ -24,6 +24,22 @@ import {
|
|||||||
|
|
||||||
export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles";
|
export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles";
|
||||||
export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart";
|
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 {
|
export interface IIssueFilter {
|
||||||
priority: string[] | undefined;
|
priority: string[] | undefined;
|
||||||
@ -649,6 +665,32 @@ class IssueFilterStore implements IIssueFilterStore {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
computedFilter = (filters: any, filteredParams: any) => {
|
computedFilter = (filters: any, filteredParams: any) => {
|
||||||
@ -699,8 +741,11 @@ class IssueFilterStore implements IIssueFilterStore {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// start date and target date we have to construct the format here
|
// 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
|
||||||
|
|
||||||
let filteredParams: any = {};
|
let filteredParams: TIssueParams[] = [];
|
||||||
if (_layout === "list")
|
if (_layout === "list")
|
||||||
filteredParams = [
|
filteredParams = [
|
||||||
"priority",
|
"priority",
|
||||||
@ -727,10 +772,11 @@ class IssueFilterStore implements IIssueFilterStore {
|
|||||||
"labels",
|
"labels",
|
||||||
"start_date",
|
"start_date",
|
||||||
"target_date",
|
"target_date",
|
||||||
"type",
|
|
||||||
"group_by",
|
"group_by",
|
||||||
"order_by",
|
"order_by",
|
||||||
|
"type",
|
||||||
"sub_issue",
|
"sub_issue",
|
||||||
|
"show_empty_groups",
|
||||||
];
|
];
|
||||||
if (_layout === "calendar")
|
if (_layout === "calendar")
|
||||||
filteredParams = [
|
filteredParams = [
|
||||||
@ -756,7 +802,7 @@ class IssueFilterStore implements IIssueFilterStore {
|
|||||||
"start_date",
|
"start_date",
|
||||||
"target_date",
|
"target_date",
|
||||||
"type",
|
"type",
|
||||||
"sub_issues",
|
"sub_issue",
|
||||||
];
|
];
|
||||||
if (_layout === "gantt_chart")
|
if (_layout === "gantt_chart")
|
||||||
filteredParams = [
|
filteredParams = [
|
||||||
@ -769,14 +815,12 @@ class IssueFilterStore implements IIssueFilterStore {
|
|||||||
"target_date",
|
"target_date",
|
||||||
"order_by",
|
"order_by",
|
||||||
"type",
|
"type",
|
||||||
"sub_issue_id",
|
"sub_issue",
|
||||||
"start_target_date",
|
"start_target_date",
|
||||||
];
|
];
|
||||||
|
|
||||||
filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams);
|
||||||
|
|
||||||
// remove few attributes from the object when we are in workspace issues
|
|
||||||
|
|
||||||
return filteredRouteParams;
|
return filteredRouteParams;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user