mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
save all filters and properties for views (#4728)
This commit is contained in:
parent
de8da176d3
commit
fb2b4ae303
@ -19,7 +19,7 @@ import { EUserProjectRoles } from "@/constants/project";
|
|||||||
// helpers
|
// helpers
|
||||||
import { replaceUnderscoreIfSnakeCase } from "@/helpers/string.helper";
|
import { replaceUnderscoreIfSnakeCase } from "@/helpers/string.helper";
|
||||||
// hooks
|
// hooks
|
||||||
import { useAppRouter, useUser } from "@/hooks/store";
|
import { useUser } from "@/hooks/store";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
appliedFilters: IIssueFilterOptions;
|
appliedFilters: IIssueFilterOptions;
|
||||||
@ -36,7 +36,6 @@ const dateFilters = ["start_date", "target_date"];
|
|||||||
export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
||||||
const { appliedFilters, handleClearAllFilters, handleRemoveFilter, labels, states, alwaysAllowEditing } = props;
|
const { appliedFilters, handleClearAllFilters, handleRemoveFilter, labels, states, alwaysAllowEditing } = props;
|
||||||
// store hooks
|
// store hooks
|
||||||
const { moduleId, cycleId } = useAppRouter();
|
|
||||||
const {
|
const {
|
||||||
membership: { currentProjectRole },
|
membership: { currentProjectRole },
|
||||||
} = useUser();
|
} = useUser();
|
||||||
@ -108,14 +107,14 @@ export const AppliedFiltersList: React.FC<Props> = observer((props) => {
|
|||||||
values={value}
|
values={value}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{filterKey === "cycle" && !cycleId && (
|
{filterKey === "cycle" && (
|
||||||
<AppliedCycleFilters
|
<AppliedCycleFilters
|
||||||
editable={isEditingAllowed}
|
editable={isEditingAllowed}
|
||||||
handleRemove={(val) => handleRemoveFilter("cycle", val)}
|
handleRemove={(val) => handleRemoveFilter("cycle", val)}
|
||||||
values={value}
|
values={value}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{filterKey === "module" && !moduleId && (
|
{filterKey === "module" && (
|
||||||
<AppliedModuleFilters
|
<AppliedModuleFilters
|
||||||
editable={isEditingAllowed}
|
editable={isEditingAllowed}
|
||||||
handleRemove={(val) => handleRemoveFilter("module", val)}
|
handleRemove={(val) => handleRemoveFilter("module", val)}
|
||||||
|
@ -2,7 +2,7 @@ import { observer } from "mobx-react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { IIssueFilterOptions } from "@plane/types";
|
import { IIssueFilterOptions } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
|
import { AppliedFiltersList } from "@/components/issues";
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
||||||
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
|
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
|
||||||
// components
|
// components
|
||||||
@ -76,8 +76,6 @@ export const ArchivedIssueAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
labels={projectLabels ?? []}
|
labels={projectLabels ?? []}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SaveFilterView workspaceSlug={workspaceSlug} projectId={projectId} filterParams={appliedFilters} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -74,7 +74,7 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// return if no filters are applied
|
// return if no filters are applied
|
||||||
if (Object.keys(appliedFilters).length === 0 || !workspaceSlug || !projectId) return null;
|
if (Object.keys(appliedFilters).length === 0 || !workspaceSlug || !projectId || !cycleId) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between p-4 gap-2.5">
|
<div className="flex justify-between p-4 gap-2.5">
|
||||||
@ -89,7 +89,11 @@ export const CycleAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
<SaveFilterView
|
<SaveFilterView
|
||||||
workspaceSlug={workspaceSlug.toString()}
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
projectId={projectId.toString()}
|
projectId={projectId.toString()}
|
||||||
filterParams={appliedFilters}
|
filterParams={{
|
||||||
|
filters: { ...appliedFilters, cycle: [cycleId?.toString()] },
|
||||||
|
display_filters: issueFilters?.displayFilters,
|
||||||
|
display_properties: issueFilters?.displayProperties,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@ import { observer } from "mobx-react";
|
|||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { IIssueFilterOptions } from "@plane/types";
|
import { IIssueFilterOptions } from "@plane/types";
|
||||||
// hooks
|
// hooks
|
||||||
import { AppliedFiltersList, SaveFilterView } from "@/components/issues";
|
import { AppliedFiltersList } from "@/components/issues";
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
||||||
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
|
import { useIssues, useLabel, useProjectState } from "@/hooks/store";
|
||||||
// components
|
// components
|
||||||
@ -71,8 +71,6 @@ export const DraftIssueAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
labels={projectLabels ?? []}
|
labels={projectLabels ?? []}
|
||||||
states={projectStates}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SaveFilterView workspaceSlug={workspaceSlug} projectId={projectId} filterParams={appliedFilters} />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -73,7 +73,7 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// return if no filters are applied
|
// return if no filters are applied
|
||||||
if (!workspaceSlug || !projectId || Object.keys(appliedFilters).length === 0) return null;
|
if (!workspaceSlug || !projectId || !moduleId || Object.keys(appliedFilters).length === 0) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-between p-4 gap-2.5">
|
<div className="flex justify-between p-4 gap-2.5">
|
||||||
@ -88,7 +88,11 @@ export const ModuleAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
<SaveFilterView
|
<SaveFilterView
|
||||||
workspaceSlug={workspaceSlug.toString()}
|
workspaceSlug={workspaceSlug.toString()}
|
||||||
projectId={projectId.toString()}
|
projectId={projectId.toString()}
|
||||||
filterParams={appliedFilters}
|
filterParams={{
|
||||||
|
filters: { ...appliedFilters, module: [moduleId.toString()] },
|
||||||
|
display_filters: issueFilters?.displayFilters,
|
||||||
|
display_properties: issueFilters?.displayProperties,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -77,7 +77,15 @@ export const ProjectAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
states={projectStates}
|
states={projectStates}
|
||||||
/>
|
/>
|
||||||
{isEditingAllowed && (
|
{isEditingAllowed && (
|
||||||
<SaveFilterView workspaceSlug={workspaceSlug} projectId={projectId} filterParams={appliedFilters} />
|
<SaveFilterView
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
filterParams={{
|
||||||
|
filters: appliedFilters,
|
||||||
|
display_filters: issueFilters?.displayFilters,
|
||||||
|
display_properties: issueFilters?.displayProperties,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import isEmpty from "lodash/isEmpty";
|
import isEmpty from "lodash/isEmpty";
|
||||||
import isEqual from "lodash/isEqual";
|
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { IIssueFilterOptions } from "@plane/types";
|
import { IIssueFilterOptions } from "@plane/types";
|
||||||
@ -8,6 +7,7 @@ import { Button } from "@plane/ui";
|
|||||||
import { AppliedFiltersList } from "@/components/issues";
|
import { AppliedFiltersList } from "@/components/issues";
|
||||||
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
import { EIssueFilterType, EIssuesStoreType } from "@/constants/issue";
|
||||||
import { useIssues, useLabel, useProjectState, useProjectView } from "@/hooks/store";
|
import { useIssues, useLabel, useProjectState, useProjectView } from "@/hooks/store";
|
||||||
|
import { getAreFiltersEqual } from "../../../utils";
|
||||||
// components
|
// components
|
||||||
// ui
|
// ui
|
||||||
// types
|
// types
|
||||||
@ -79,7 +79,7 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const areFiltersEqual = isEqual(appliedFilters ?? {}, viewDetails?.filters ?? {});
|
const areFiltersEqual = getAreFiltersEqual(appliedFilters, issueFilters, viewDetails);
|
||||||
|
|
||||||
// return if no filters are applied
|
// return if no filters are applied
|
||||||
if (isEmpty(appliedFilters) && areFiltersEqual) return null;
|
if (isEmpty(appliedFilters) && areFiltersEqual) return null;
|
||||||
@ -91,6 +91,12 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => {
|
|||||||
filters: {
|
filters: {
|
||||||
...(appliedFilters ?? {}),
|
...(appliedFilters ?? {}),
|
||||||
},
|
},
|
||||||
|
display_filters: {
|
||||||
|
...issueFilters?.displayFilters,
|
||||||
|
},
|
||||||
|
display_properties: {
|
||||||
|
...issueFilters?.displayProperties,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { FC, useState } from "react";
|
import { FC, useState } from "react";
|
||||||
|
import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
|
||||||
import { Button } from "@plane/ui";
|
import { Button } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { CreateUpdateProjectViewModal } from "@/components/views";
|
import { CreateUpdateProjectViewModal } from "@/components/views";
|
||||||
@ -6,7 +7,11 @@ import { CreateUpdateProjectViewModal } from "@/components/views";
|
|||||||
interface ISaveFilterView {
|
interface ISaveFilterView {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
filterParams: any;
|
filterParams: {
|
||||||
|
filters: IIssueFilterOptions;
|
||||||
|
display_filters?: IIssueDisplayFilterOptions;
|
||||||
|
display_properties?: IIssueDisplayProperties;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SaveFilterView: FC<ISaveFilterView> = (props) => {
|
export const SaveFilterView: FC<ISaveFilterView> = (props) => {
|
||||||
@ -19,7 +24,7 @@ export const SaveFilterView: FC<ISaveFilterView> = (props) => {
|
|||||||
<CreateUpdateProjectViewModal
|
<CreateUpdateProjectViewModal
|
||||||
workspaceSlug={workspaceSlug}
|
workspaceSlug={workspaceSlug}
|
||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
preLoadedData={{ filters: { ...filterParams } }}
|
preLoadedData={{ ...filterParams }}
|
||||||
isOpen={viewModal}
|
isOpen={viewModal}
|
||||||
onClose={() => setViewModal(false)}
|
onClose={() => setViewModal(false)}
|
||||||
/>
|
/>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
|
import { extractInstruction } from "@atlaskit/pragmatic-drag-and-drop-hitbox/tree-item";
|
||||||
import clone from "lodash/clone";
|
import clone from "lodash/clone";
|
||||||
import concat from "lodash/concat";
|
import concat from "lodash/concat";
|
||||||
|
import isEqual from "lodash/isEqual";
|
||||||
import pull from "lodash/pull";
|
import pull from "lodash/pull";
|
||||||
import uniq from "lodash/uniq";
|
import uniq from "lodash/uniq";
|
||||||
import scrollIntoView from "smooth-scroll-into-view-if-needed";
|
import scrollIntoView from "smooth-scroll-into-view-if-needed";
|
||||||
@ -13,6 +14,9 @@ import {
|
|||||||
IPragmaticDropPayload,
|
IPragmaticDropPayload,
|
||||||
TIssue,
|
TIssue,
|
||||||
TIssueGroupByOptions,
|
TIssueGroupByOptions,
|
||||||
|
IIssueFilterOptions,
|
||||||
|
IIssueFilters,
|
||||||
|
IProjectView,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
// ui
|
// ui
|
||||||
import { Avatar, CycleGroupIcon, DiceIcon, PriorityIcon, StateGroupIcon } from "@plane/ui";
|
import { Avatar, CycleGroupIcon, DiceIcon, PriorityIcon, StateGroupIcon } from "@plane/ui";
|
||||||
@ -535,3 +539,19 @@ export const handleGroupDragDrop = async (
|
|||||||
return await updateIssueOnDrop(sourceIssue.project_id, sourceIssue.id, updatedIssue, issueUpdates);
|
return await updateIssueOnDrop(sourceIssue.project_id, sourceIssue.id, updatedIssue, issueUpdates);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This Method compares filters and returns a boolean based on which and updateView button is shown
|
||||||
|
* @param appliedFilters
|
||||||
|
* @param issueFilters
|
||||||
|
* @param viewDetails
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const getAreFiltersEqual = (
|
||||||
|
appliedFilters: IIssueFilterOptions | undefined,
|
||||||
|
issueFilters: IIssueFilters | undefined,
|
||||||
|
viewDetails: IProjectView | null
|
||||||
|
) =>
|
||||||
|
isEqual(appliedFilters ?? {}, viewDetails?.filters ?? {}) &&
|
||||||
|
isEqual(issueFilters?.displayFilters ?? {}, viewDetails?.display_filters ?? {}) &&
|
||||||
|
isEqual(issueFilters?.displayProperties ?? {}, viewDetails?.display_properties ?? {});
|
||||||
|
@ -94,6 +94,8 @@ export const ProjectViewForm: React.FC<Props> = observer((props) => {
|
|||||||
description: formData.description,
|
description: formData.description,
|
||||||
logo_props: formData.logo_props,
|
logo_props: formData.logo_props,
|
||||||
filters: formData.filters,
|
filters: formData.filters,
|
||||||
|
display_filters: formData.display_filters,
|
||||||
|
display_properties: formData.display_properties,
|
||||||
} as IProjectView);
|
} as IProjectView);
|
||||||
|
|
||||||
reset({
|
reset({
|
||||||
|
Loading…
Reference in New Issue
Block a user