mirror of
https://github.com/makeplane/plane.git
synced 2026-07-12 21:40:18 +02:00
[WEB-2268] feat: persisted filters for project grouping (#899)
* feat: persisted filters for project grouping * fix: css
This commit is contained in:
@@ -21,9 +21,19 @@ type Props = {
|
||||
currentWorkspace: IWorkspace;
|
||||
cta?: React.ReactNode;
|
||||
dateClassname?: string;
|
||||
containerClass?: string;
|
||||
};
|
||||
const Attributes: React.FC<Props> = observer((props) => {
|
||||
const { project, isArchived, handleUpdateProject, workspaceSlug, currentWorkspace, cta, dateClassname } = props;
|
||||
const {
|
||||
project,
|
||||
isArchived,
|
||||
handleUpdateProject,
|
||||
workspaceSlug,
|
||||
currentWorkspace,
|
||||
cta,
|
||||
dateClassname,
|
||||
containerClass = "",
|
||||
} = props;
|
||||
const projectMembersIds = project.members?.map((member) => member.member_id);
|
||||
|
||||
const { getUserDetails } = useMember();
|
||||
@@ -41,7 +51,7 @@ const Attributes: React.FC<Props> = observer((props) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
return (
|
||||
<div className="flex gap-2 flex-wrap p-2 " data-prevent-nprogress>
|
||||
<div className={cn("flex gap-2 flex-wrap p-2", containerClass)} data-prevent-nprogress>
|
||||
<div className="h-5 my-auto" onFocus={handleEventPropagation} onClick={handleEventPropagation}>
|
||||
<StateDropdown
|
||||
value={project.state_id || ""}
|
||||
|
||||
@@ -46,7 +46,7 @@ export const ProjectBlock = observer((props: ProjectBlockProps) => {
|
||||
<div
|
||||
ref={projectRef}
|
||||
className={cn(
|
||||
"group/list-block min-h-11 relative flex flex-col gap-x-3 bg-custom-background-100 hover:bg-custom-background-90 p-3 pl-1.5 text-sm transition-colors border border-transparent border-b border-b-custom-border-200 md:py-1",
|
||||
"group/list-block min-h-[52px] relative flex flex-col gap-2 bg-custom-background-100 hover:bg-custom-background-90 p-3 px-4 py-4 text-sm transition-colors border border-transparent border-b border-b-custom-border-200 md:py-0",
|
||||
{
|
||||
"bg-custom-background-80": isCurrentBlockDragging,
|
||||
"md:flex-row md:items-center": isSidebarCollapsed,
|
||||
@@ -64,10 +64,10 @@ export const ProjectBlock = observer((props: ProjectBlockProps) => {
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full truncate">
|
||||
<div className="flex flex-grow items-center gap-0.5 truncate p-2 pb-0 lg:pb-2">
|
||||
<div className="flex flex-grow items-center gap-0.5 truncate pb-0 md:pt-2 lg:py-2">
|
||||
<div className="flex items-center gap-1">
|
||||
<div className="h-8 w-8 flex-shrink-0 grid place-items-center rounded bg-custom-background-90 mr-2">
|
||||
<Logo logo={projectDetails.logo_props} size={18} />
|
||||
<div className="h-6 w-6 flex-shrink-0 grid place-items-center rounded bg-custom-background-90 mr-2">
|
||||
<Logo logo={projectDetails.logo_props} size={14} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -83,7 +83,7 @@ export const ProjectBlock = observer((props: ProjectBlockProps) => {
|
||||
className={cn("w-full truncate cursor-pointer text-sm text-custom-text-100", {})}
|
||||
>
|
||||
<Tooltip tooltipContent={projectDetails.name} isMobile={isMobile} position="top-left">
|
||||
<p className="truncate">{projectDetails.name}</p>
|
||||
<p className="truncate mr-2">{projectDetails.name}</p>
|
||||
</Tooltip>
|
||||
</Link>
|
||||
) : (
|
||||
@@ -98,7 +98,7 @@ export const ProjectBlock = observer((props: ProjectBlockProps) => {
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={cn("block border border-custom-border-300 rounded h-full m-auto", {
|
||||
className={cn("block border border-custom-border-300 rounded h-full m-2", {
|
||||
"md:hidden": isSidebarCollapsed,
|
||||
"lg:hidden": !isSidebarCollapsed,
|
||||
})}
|
||||
@@ -115,6 +115,7 @@ export const ProjectBlock = observer((props: ProjectBlockProps) => {
|
||||
workspaceSlug={workspaceSlug.toString()}
|
||||
currentWorkspace={currentWorkspace}
|
||||
cta={filters?.scope === EProjectScope.ALL_PROJECTS && <JoinButton project={projectDetails as TProject} />}
|
||||
containerClass="px-0 py-0 md:pb-4 lg:py-2"
|
||||
/>
|
||||
<div
|
||||
className={cn("hidden", {
|
||||
|
||||
@@ -70,7 +70,7 @@ export const ListGroup = observer((props: Props) => {
|
||||
|
||||
return groupedProjectIds.length > 0 ? (
|
||||
<div ref={groupRef} className={cn(`relative flex flex-shrink-0 flex-col border-[1px] border-transparent`)}>
|
||||
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pl-2 pr-3 py-1">
|
||||
<div className="sticky top-0 z-[2] w-full flex-shrink-0 border-b border-custom-border-200 bg-custom-background-90 pl-4 pr-3 py-1">
|
||||
<HeaderGroupByCard
|
||||
groupID={group}
|
||||
icon={details?.icon}
|
||||
|
||||
@@ -40,17 +40,19 @@ export interface IProjectFilterStore extends IProjectFilterHelper {
|
||||
// helpers actions
|
||||
// actions
|
||||
initWorkspaceFilters: (workspaceSlug: string, scope?: EProjectScope) => void;
|
||||
updateScope: (workspaceSlug: string, scope: TProjectScope) => void;
|
||||
updateLayout: (workspaceSlug: string, layout: TProjectLayouts) => void;
|
||||
updateScope: (workspaceSlug: string, scope: TProjectScope, setLocalStorage?: boolean) => void;
|
||||
updateLayout: (workspaceSlug: string, layout: TProjectLayouts, setLocalStorage?: boolean) => void;
|
||||
updateAttributes: <T extends keyof TProjectAttributes>(
|
||||
workspaceSlug: string,
|
||||
key: T,
|
||||
values: TProjectAttributes[T]
|
||||
values: TProjectAttributes[T],
|
||||
setLocalStorage?: boolean
|
||||
) => void;
|
||||
updateDisplayFilters: <T extends keyof TProjectDisplayFilters>(
|
||||
workspaceSlug: string,
|
||||
key: T,
|
||||
values: TProjectDisplayFilters[T]
|
||||
values: TProjectDisplayFilters[T],
|
||||
setLocalStorage?: boolean
|
||||
) => void;
|
||||
bulkUpdateDisplayFilters: (workspaceSlug: string, values: Partial<TProjectDisplayFilters>) => void;
|
||||
updateSearchQuery: (query: string | undefined) => void;
|
||||
@@ -215,22 +217,19 @@ export class ProjectFilterStore extends ProjectFilterHelper implements IProjectF
|
||||
);
|
||||
|
||||
if (!this.layoutMap[workspaceSlug]) {
|
||||
this.updateLayout(workspaceSlug, savedFilters.layout || EProjectLayouts.GALLERY);
|
||||
}
|
||||
if (!this.layoutMap[workspaceSlug]) {
|
||||
this.updateLayout(workspaceSlug, savedFilters.layout || EProjectLayouts.GALLERY);
|
||||
this.updateLayout(workspaceSlug, savedFilters?.layout || EProjectLayouts.GALLERY, false);
|
||||
}
|
||||
if (!this.attributesMap[workspaceSlug]) {
|
||||
this.updateAttributes(workspaceSlug, "priority", []);
|
||||
this.updateAttributes(workspaceSlug, "state", []);
|
||||
this.updateAttributes(workspaceSlug, "lead", []);
|
||||
this.updateAttributes(workspaceSlug, "members", []);
|
||||
this.updateAttributes(workspaceSlug, "access", []);
|
||||
this.updateAttributes(workspaceSlug, "priority", savedFilters?.attributes?.priority || [], false);
|
||||
this.updateAttributes(workspaceSlug, "state", savedFilters?.attributes?.state || [], false);
|
||||
this.updateAttributes(workspaceSlug, "lead", savedFilters?.attributes?.lead || [], false);
|
||||
this.updateAttributes(workspaceSlug, "members", savedFilters?.attributes?.members || [], false);
|
||||
this.updateAttributes(workspaceSlug, "access", savedFilters?.attributes?.access || [], false);
|
||||
}
|
||||
if (!this.displayFiltersMap[workspaceSlug]) {
|
||||
this.updateDisplayFilters(workspaceSlug, "group_by", "states");
|
||||
this.updateDisplayFilters(workspaceSlug, "sort_by", "manual");
|
||||
this.updateDisplayFilters(workspaceSlug, "sort_order", "asc");
|
||||
this.updateDisplayFilters(workspaceSlug, "group_by", savedFilters?.display_filters?.group_by || "states", false);
|
||||
this.updateDisplayFilters(workspaceSlug, "sort_by", savedFilters?.display_filters?.sort_by || "manual", false);
|
||||
this.updateDisplayFilters(workspaceSlug, "sort_order", savedFilters?.display_filters?.sort_order || "asc", false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -240,9 +239,9 @@ export class ProjectFilterStore extends ProjectFilterHelper implements IProjectF
|
||||
* @param { TProjectScope } scope
|
||||
* @returns { void }
|
||||
*/
|
||||
updateScope = (workspaceSlug: string, scope: TProjectScope): void => {
|
||||
updateScope = (workspaceSlug: string, scope: TProjectScope, setLocalStorage = true): void => {
|
||||
set(this.scopeMap, workspaceSlug, scope);
|
||||
this.handleProjectLocalFilters.set("scope", workspaceSlug, { scope });
|
||||
setLocalStorage && this.handleProjectLocalFilters.set("scope", workspaceSlug, { scope });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -251,9 +250,9 @@ export class ProjectFilterStore extends ProjectFilterHelper implements IProjectF
|
||||
* @param { TProjectLayouts } layout
|
||||
* @returns { void }
|
||||
*/
|
||||
updateLayout = (workspaceSlug: string, layout: TProjectLayouts): void => {
|
||||
updateLayout = (workspaceSlug: string, layout: TProjectLayouts, setLocalStorage = true): void => {
|
||||
set(this.layoutMap, workspaceSlug, layout);
|
||||
this.handleProjectLocalFilters.set("layout", workspaceSlug, { layout });
|
||||
setLocalStorage && this.handleProjectLocalFilters.set("layout", workspaceSlug, { layout });
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -266,9 +265,14 @@ export class ProjectFilterStore extends ProjectFilterHelper implements IProjectF
|
||||
updateAttributes = <T extends keyof TProjectAttributes>(
|
||||
workspaceSlug: string,
|
||||
key: T,
|
||||
values: TProjectAttributes[T]
|
||||
values: TProjectAttributes[T],
|
||||
setLocalStorage = true
|
||||
): void => {
|
||||
set(this.attributesMap, [workspaceSlug, key], values);
|
||||
setLocalStorage &&
|
||||
this.handleProjectLocalFilters.set("attributes", workspaceSlug, {
|
||||
attributes: { ...this.attributesMap[workspaceSlug], [key]: values },
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -281,9 +285,14 @@ export class ProjectFilterStore extends ProjectFilterHelper implements IProjectF
|
||||
updateDisplayFilters = <T extends keyof TProjectDisplayFilters>(
|
||||
workspaceSlug: string,
|
||||
key: T,
|
||||
values: TProjectDisplayFilters[T]
|
||||
values: TProjectDisplayFilters[T],
|
||||
setLocalStorage = true
|
||||
): void => {
|
||||
set(this.displayFiltersMap, [workspaceSlug, key], values);
|
||||
setLocalStorage &&
|
||||
this.handleProjectLocalFilters.set("display_filters", workspaceSlug, {
|
||||
display_filters: { ...this.displayFiltersMap[workspaceSlug], [key]: values },
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user