forked from github/plane
refactor: views & filter (#490)
* fix: not saving filters on views detail page * refactor: using issues endpoint to get issues in views detail page feat: showing toast alert on saving view
This commit is contained in:
parent
9a97c97336
commit
a830808f9d
@ -34,7 +34,7 @@ import { GROUP_BY_OPTIONS, ORDER_BY_OPTIONS, FILTER_ISSUE_OPTIONS } from "consta
|
||||
|
||||
export const IssuesFilterView: React.FC = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
const { workspaceSlug, projectId, viewId } = router.query;
|
||||
|
||||
const {
|
||||
issueView,
|
||||
@ -102,13 +102,16 @@ export const IssuesFilterView: React.FC = () => {
|
||||
<MultiLevelDropdown
|
||||
label="Filters"
|
||||
onSelect={(option) => {
|
||||
setFilters({
|
||||
...filters,
|
||||
[option.key]: [
|
||||
...((filters?.[option.key as keyof typeof filters] as any[]) ?? []),
|
||||
option.value,
|
||||
],
|
||||
});
|
||||
setFilters(
|
||||
{
|
||||
...filters,
|
||||
[option.key]: [
|
||||
...((filters?.[option.key as keyof typeof filters] as any[]) ?? []),
|
||||
option.value,
|
||||
],
|
||||
},
|
||||
!Boolean(viewId)
|
||||
);
|
||||
}}
|
||||
direction="left"
|
||||
options={[
|
||||
|
@ -12,6 +12,7 @@ import stateService from "services/state.service";
|
||||
import projectService from "services/project.service";
|
||||
import modulesService from "services/modules.service";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useIssuesView from "hooks/use-issues-view";
|
||||
// components
|
||||
import { AllLists, AllBoards } from "components/core";
|
||||
@ -81,6 +82,8 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
|
||||
const {
|
||||
groupedByIssues,
|
||||
issueView,
|
||||
@ -443,9 +446,12 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
onClick={() =>
|
||||
setFilters({
|
||||
state: filters.state?.filter((s: any) => s !== stateId),
|
||||
})
|
||||
setFilters(
|
||||
{
|
||||
state: filters.state?.filter((s: any) => s !== stateId),
|
||||
},
|
||||
!Boolean(viewId)
|
||||
)
|
||||
}
|
||||
>
|
||||
<XMarkIcon className="h-3 w-3" />
|
||||
@ -474,9 +480,14 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
onClick={() =>
|
||||
setFilters({
|
||||
priority: filters.priority?.filter((p: any) => p !== priority),
|
||||
})
|
||||
setFilters(
|
||||
{
|
||||
priority: filters.priority?.filter(
|
||||
(p: any) => p !== priority
|
||||
),
|
||||
},
|
||||
!Boolean(viewId)
|
||||
)
|
||||
}
|
||||
>
|
||||
<XMarkIcon className="h-3 w-3" />
|
||||
@ -497,11 +508,14 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
|
||||
<span
|
||||
className="cursor-pointer"
|
||||
onClick={() =>
|
||||
setFilters({
|
||||
assignees: filters.assignees?.filter(
|
||||
(p: any) => p !== memberId
|
||||
),
|
||||
})
|
||||
setFilters(
|
||||
{
|
||||
assignees: filters.assignees?.filter(
|
||||
(p: any) => p !== memberId
|
||||
),
|
||||
},
|
||||
!Boolean(viewId)
|
||||
)
|
||||
}
|
||||
>
|
||||
<XMarkIcon className="h-3 w-3" />
|
||||
@ -519,21 +533,27 @@ export const IssuesView: React.FC<Props> = ({ type = "issue", openIssuesListModa
|
||||
})}
|
||||
</div>
|
||||
|
||||
{Object.keys(filters).length > 0 &&
|
||||
nullFilters.length !== Object.keys(filters).length &&
|
||||
!viewId && (
|
||||
<PrimaryButton
|
||||
onClick={() =>
|
||||
{Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length && (
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
if (viewId) {
|
||||
setFilters({}, true);
|
||||
setToastAlert({
|
||||
title: "View updated",
|
||||
message: "Your view has been updated",
|
||||
type: "success",
|
||||
});
|
||||
} else
|
||||
setCreateViewModal({
|
||||
query: filters,
|
||||
})
|
||||
}
|
||||
className="flex items-center gap-2 text-sm"
|
||||
>
|
||||
<PlusIcon className="h-4 w-4" />
|
||||
Save view
|
||||
</PrimaryButton>
|
||||
)}
|
||||
});
|
||||
}}
|
||||
className="flex items-center gap-2 text-sm"
|
||||
>
|
||||
{!viewId && <PlusIcon className="h-4 w-4" />}
|
||||
Save view
|
||||
</PrimaryButton>
|
||||
)}
|
||||
</div>
|
||||
<DragDropContext onDragEnd={handleOnDragEnd}>
|
||||
<StrictModeDroppable droppableId="trashBox">
|
||||
|
@ -44,7 +44,7 @@ type ReducerActionType = {
|
||||
type ContextType = IssueViewProps & {
|
||||
setGroupByProperty: (property: "state" | "priority" | "labels" | null) => void;
|
||||
setOrderBy: (property: "created_at" | "updated_at" | "priority" | "sort_order") => void;
|
||||
setFilters: (filters: Partial<IIssueFilterOptions>) => void;
|
||||
setFilters: (filters: Partial<IIssueFilterOptions>, saveToServer?: boolean) => void;
|
||||
resetFilterToDefault: () => void;
|
||||
setNewFilterDefaultView: () => void;
|
||||
setIssueViewToKanban: () => void;
|
||||
@ -335,7 +335,7 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
);
|
||||
|
||||
const setFilters = useCallback(
|
||||
(property: Partial<IIssueFilterOptions>) => {
|
||||
(property: Partial<IIssueFilterOptions>, saveToServer = true) => {
|
||||
Object.keys(property).forEach((key) => {
|
||||
if (property[key as keyof typeof property]?.length === 0) {
|
||||
property[key as keyof typeof property] = null;
|
||||
@ -380,13 +380,14 @@ export const IssueViewContextProvider: React.FC<{ children: React.ReactNode }> =
|
||||
},
|
||||
};
|
||||
}, false);
|
||||
sendFilterDataToServer(workspaceSlug as string, projectId as string, viewId as string, {
|
||||
query_data: {
|
||||
...state.filters,
|
||||
...property,
|
||||
},
|
||||
});
|
||||
} else
|
||||
if (saveToServer)
|
||||
sendFilterDataToServer(workspaceSlug as string, projectId as string, viewId as string, {
|
||||
query_data: {
|
||||
...state.filters,
|
||||
...property,
|
||||
},
|
||||
});
|
||||
} else if (saveToServer)
|
||||
saveDataToServer(workspaceSlug as string, projectId as string, {
|
||||
...state,
|
||||
filters: {
|
||||
|
@ -38,7 +38,7 @@ const useIssuesView = () => {
|
||||
} = useContext(issueViewContext);
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query;
|
||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||
|
||||
const params: any = {
|
||||
order_by: orderBy,
|
||||
@ -66,14 +66,6 @@ const useIssuesView = () => {
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: viewIssues } = useSWR(
|
||||
workspaceSlug && projectId && viewId ? VIEW_ISSUES(viewId as string) : null,
|
||||
workspaceSlug && projectId && viewId
|
||||
? () =>
|
||||
viewsService.getViewIssues(workspaceSlug as string, projectId as string, viewId as string)
|
||||
: null
|
||||
);
|
||||
|
||||
const { data: cycleIssues } = useSWR(
|
||||
workspaceSlug && projectId && cycleId && params
|
||||
? CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params)
|
||||
@ -109,11 +101,11 @@ const useIssuesView = () => {
|
||||
[key: string]: IIssue[];
|
||||
}
|
||||
| undefined = useMemo(() => {
|
||||
const issuesToGroup = viewIssues ?? cycleIssues ?? moduleIssues ?? projectIssues;
|
||||
const issuesToGroup = cycleIssues ?? moduleIssues ?? projectIssues;
|
||||
|
||||
if (Array.isArray(issuesToGroup)) return { allIssues: issuesToGroup };
|
||||
else return issuesToGroup;
|
||||
}, [projectIssues, cycleIssues, moduleIssues, viewIssues]);
|
||||
}, [projectIssues, cycleIssues, moduleIssues]);
|
||||
|
||||
return {
|
||||
groupedByIssues,
|
||||
|
Loading…
Reference in New Issue
Block a user