mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: store changes on the filters and display filters
This commit is contained in:
parent
02380c730d
commit
a5fd6f0e8a
18
packages/types/src/view/filter.d.ts
vendored
18
packages/types/src/view/filter.d.ts
vendored
@ -1,9 +1,17 @@
|
|||||||
|
declare enum EViewLayouts {
|
||||||
|
LIST = "list",
|
||||||
|
KANBAN = "kanban",
|
||||||
|
CALENDAR = "calendar",
|
||||||
|
SPREADSHEET = "spreadsheet",
|
||||||
|
GANTT = "gantt",
|
||||||
|
}
|
||||||
|
|
||||||
export type TViewLayouts =
|
export type TViewLayouts =
|
||||||
| "list"
|
| EViewLayouts.LIST
|
||||||
| "kanban"
|
| EViewLayouts.KANBAN
|
||||||
| "calendar"
|
| EViewLayouts.CALENDAR
|
||||||
| "spreadsheet"
|
| EViewLayouts.SPREADSHEET
|
||||||
| "gantt";
|
| EViewLayouts.GANTT;
|
||||||
|
|
||||||
export type TViewDisplayFiltersGrouped =
|
export type TViewDisplayFiltersGrouped =
|
||||||
| "project"
|
| "project"
|
||||||
|
@ -154,7 +154,9 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
|
|
||||||
<Breadcrumbs.BreadcrumbItem
|
<Breadcrumbs.BreadcrumbItem
|
||||||
type="text"
|
type="text"
|
||||||
link={<BreadcrumbLink label="Issues" icon={<LayersIcon className="h-4 w-4 text-custom-text-300" />} />}
|
link={
|
||||||
|
<BreadcrumbLink label="Issues" icon={<LayersIcon className="h-4 w-4 text-custom-text-300" />} />
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Breadcrumbs>
|
</Breadcrumbs>
|
||||||
</div>
|
</div>
|
||||||
@ -203,7 +205,7 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
</div>
|
</div>
|
||||||
{currentProjectDetails?.inbox_view && inboxDetails && (
|
{currentProjectDetails?.inbox_view && inboxDetails && (
|
||||||
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxDetails?.id}`}>
|
<Link href={`/${workspaceSlug}/projects/${projectId}/inbox/${inboxDetails?.id}`}>
|
||||||
<span className="hidden md:block" >
|
<span className="hidden md:block">
|
||||||
<Button variant="neutral-primary" size="sm" className="relative">
|
<Button variant="neutral-primary" size="sm" className="relative">
|
||||||
Inbox
|
Inbox
|
||||||
{inboxDetails?.pending_issue_count > 0 && (
|
{inboxDetails?.pending_issue_count > 0 && (
|
||||||
@ -218,7 +220,12 @@ export const ProjectIssuesHeader: React.FC = observer(() => {
|
|||||||
)}
|
)}
|
||||||
{canUserCreateIssue && (
|
{canUserCreateIssue && (
|
||||||
<>
|
<>
|
||||||
<Button className="hidden md:block" onClick={() => setAnalyticsModal(true)} variant="neutral-primary" size="sm">
|
<Button
|
||||||
|
className="hidden md:block"
|
||||||
|
onClick={() => setAnalyticsModal(true)}
|
||||||
|
variant="neutral-primary"
|
||||||
|
size="sm"
|
||||||
|
>
|
||||||
Analytics
|
Analytics
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// hooks
|
||||||
|
import { useViewDetail, useViewFilter } from "hooks/store";
|
||||||
|
// components
|
||||||
|
import { ViewDisplayFiltersItem, ViewDisplayFilterSelection } from "..";
|
||||||
|
// types
|
||||||
|
import { TViewDisplayFilters, TViewTypes } from "@plane/types";
|
||||||
|
|
||||||
|
type TViewDisplayFiltersItemRoot = {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string | undefined;
|
||||||
|
viewId: string;
|
||||||
|
viewType: TViewTypes;
|
||||||
|
filterKey: keyof TViewDisplayFilters;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ViewDisplayFiltersItemRoot: FC<TViewDisplayFiltersItemRoot> = observer((props) => {
|
||||||
|
const { workspaceSlug, projectId, viewId, viewType, filterKey } = props;
|
||||||
|
// hooks
|
||||||
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
|
const viewFilterHelper = useViewFilter(workspaceSlug, projectId);
|
||||||
|
|
||||||
|
const filterPropertyIds = viewFilterHelper?.displayFilterIdsWithKey(filterKey) || [];
|
||||||
|
|
||||||
|
const handlePropertySelection = (_propertyId: string) => {
|
||||||
|
viewDetailStore?.setDisplayFilters({ [filterKey]: _propertyId });
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderElement = (_propertyId: string) =>
|
||||||
|
filterKey === "group_by"
|
||||||
|
? viewDetailStore?.appliedFilters?.display_filters?.["sub_group_by"] !== _propertyId
|
||||||
|
? true
|
||||||
|
: false
|
||||||
|
: filterKey === "sub_group_by"
|
||||||
|
? viewDetailStore?.appliedFilters?.display_filters?.["group_by"] !== _propertyId
|
||||||
|
? true
|
||||||
|
: false
|
||||||
|
: true;
|
||||||
|
|
||||||
|
if (filterPropertyIds.length <= 0)
|
||||||
|
return <div className="text-xs italic py-1 text-custom-text-300">No items are available.</div>;
|
||||||
|
return (
|
||||||
|
<div className="space-y-0.5">
|
||||||
|
{filterPropertyIds.map(
|
||||||
|
(propertyId) =>
|
||||||
|
renderElement(propertyId) && (
|
||||||
|
<button
|
||||||
|
key={`filterKey_${propertyId}`}
|
||||||
|
className="relative w-full flex items-center overflow-hidden gap-2.5 cursor-pointer p-1 py-1.5 rounded hover:bg-custom-background-80 transition-all group"
|
||||||
|
onClick={() => handlePropertySelection(propertyId)}
|
||||||
|
>
|
||||||
|
<ViewDisplayFilterSelection
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
viewId={viewId}
|
||||||
|
viewType={viewType}
|
||||||
|
filterKey={filterKey}
|
||||||
|
propertyId={propertyId}
|
||||||
|
/>
|
||||||
|
<ViewDisplayFiltersItem
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
filterKey={filterKey}
|
||||||
|
propertyId={propertyId}
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
27
web/components/view/display-filters/display-filter-item.tsx
Normal file
27
web/components/view/display-filters/display-filter-item.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import { FC, Fragment } from "react";
|
||||||
|
// hooks
|
||||||
|
import { useViewFilter } from "hooks/store";
|
||||||
|
// types
|
||||||
|
import { TViewDisplayFilters } from "@plane/types";
|
||||||
|
|
||||||
|
type TViewDisplayFiltersItem = {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string | undefined;
|
||||||
|
filterKey: keyof TViewDisplayFilters;
|
||||||
|
propertyId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ViewDisplayFiltersItem: FC<TViewDisplayFiltersItem> = (props) => {
|
||||||
|
const { workspaceSlug, projectId, filterKey, propertyId } = props;
|
||||||
|
// hooks
|
||||||
|
const viewFilterHelper = useViewFilter(workspaceSlug, projectId);
|
||||||
|
|
||||||
|
const propertyDetail = viewFilterHelper?.displayPropertyDetails(filterKey, propertyId) || undefined;
|
||||||
|
|
||||||
|
if (!propertyDetail) return <></>;
|
||||||
|
return (
|
||||||
|
<div className="text-xs block truncate line-clamp-1 text-custom-text-200 group-hover:text-custom-text-100">
|
||||||
|
{propertyDetail?.label || propertyId}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,38 @@
|
|||||||
|
import { FC } from "react";
|
||||||
|
import { Check } from "lucide-react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
// hooks
|
||||||
|
import { useViewDetail } from "hooks/store";
|
||||||
|
// types
|
||||||
|
import { TViewDisplayFilters, TViewTypes } from "@plane/types";
|
||||||
|
|
||||||
|
type TViewDisplayFilterSelection = {
|
||||||
|
workspaceSlug: string;
|
||||||
|
projectId: string | undefined;
|
||||||
|
viewId: string;
|
||||||
|
viewType: TViewTypes;
|
||||||
|
filterKey: keyof TViewDisplayFilters;
|
||||||
|
propertyId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ViewDisplayFilterSelection: FC<TViewDisplayFilterSelection> = observer((props) => {
|
||||||
|
const { workspaceSlug, projectId, viewId, viewType, filterKey, propertyId } = props;
|
||||||
|
|
||||||
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
|
|
||||||
|
const propertyIds = viewDetailStore?.appliedFilters?.display_filters?.[filterKey] || undefined;
|
||||||
|
|
||||||
|
const isSelected = propertyIds === propertyId || false;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`flex-shrink-0 w-3 h-3 flex justify-center items-center border rounded-full text-bold ${
|
||||||
|
isSelected
|
||||||
|
? "border-custom-primary-100 bg-custom-primary-100"
|
||||||
|
: "border-custom-border-400 bg-custom-background-100"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{isSelected && <Check size={14} />}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -7,28 +7,34 @@ import { MonitorDot } from "lucide-react";
|
|||||||
// hooks
|
// hooks
|
||||||
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
import useOutsideClickDetector from "hooks/use-outside-click-detector";
|
||||||
// components
|
// components
|
||||||
import { ViewDisplayPropertiesRoot } from "../";
|
import { ViewDisplayFiltersRoot } from "../";
|
||||||
// ui
|
// ui
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TViewTypes } from "@plane/types";
|
import { TViewTypes } from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType } from "constants/view";
|
||||||
|
|
||||||
type TViewDisplayFiltersDropdown = {
|
type NewType = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
displayDropdownText?: boolean;
|
displayDropdownText?: boolean;
|
||||||
dropdownPlacement?: Placement;
|
dropdownPlacement?: Placement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TViewDisplayFiltersDropdown = NewType;
|
||||||
|
|
||||||
export const ViewDisplayFiltersDropdown: FC<TViewDisplayFiltersDropdown> = observer((props) => {
|
export const ViewDisplayFiltersDropdown: FC<TViewDisplayFiltersDropdown> = observer((props) => {
|
||||||
const {
|
const {
|
||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
projectId,
|
projectId,
|
||||||
viewId,
|
viewId,
|
||||||
viewType,
|
viewType,
|
||||||
|
viewPageType,
|
||||||
children,
|
children,
|
||||||
displayDropdownText = true,
|
displayDropdownText = true,
|
||||||
dropdownPlacement = "bottom-start",
|
dropdownPlacement = "bottom-start",
|
||||||
@ -110,18 +116,14 @@ export const ViewDisplayFiltersDropdown: FC<TViewDisplayFiltersDropdown> = obser
|
|||||||
{...attributes.popper}
|
{...attributes.popper}
|
||||||
className="my-1 w-72 p-2 space-y-2 rounded bg-custom-background-100 border-[0.5px] border-custom-border-300 shadow-custom-shadow-rg focus:outline-none"
|
className="my-1 w-72 p-2 space-y-2 rounded bg-custom-background-100 border-[0.5px] border-custom-border-300 shadow-custom-shadow-rg focus:outline-none"
|
||||||
>
|
>
|
||||||
<div className="max-h-96 space-y-1 overflow-y-scroll">
|
<div className="max-h-[500px] space-y-0.5 overflow-y-scroll mb-2">
|
||||||
<div className="space-y-2">
|
<ViewDisplayFiltersRoot
|
||||||
<div className="text-sm font-medium text-custom-text-200">Properties</div>
|
workspaceSlug={workspaceSlug}
|
||||||
<ViewDisplayPropertiesRoot
|
projectId={projectId}
|
||||||
workspaceSlug={workspaceSlug}
|
viewId={viewId}
|
||||||
projectId={projectId}
|
viewType={viewType}
|
||||||
viewId={viewId}
|
viewPageType={viewPageType}
|
||||||
viewType={viewType}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="border border-red-500">Content</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Combobox.Options>
|
</Combobox.Options>
|
||||||
|
@ -1,17 +1,101 @@
|
|||||||
import { FC } from "react";
|
import { FC, useState } from "react";
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { ChevronUp, ChevronDown } from "lucide-react";
|
||||||
|
import filter from "lodash/filter";
|
||||||
|
import concat from "lodash/concat";
|
||||||
|
import uniq from "lodash/uniq";
|
||||||
|
// hooks
|
||||||
|
import { useViewDetail } from "hooks/store";
|
||||||
|
// components
|
||||||
|
import { ViewDisplayPropertiesRoot, ViewDisplayFiltersItemRoot } from "../";
|
||||||
|
// types
|
||||||
|
import { TViewDisplayFilters, TViewTypes } from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view";
|
||||||
|
|
||||||
type TViewDisplayFiltersRoot = {
|
type TViewDisplayFiltersRoot = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewDisplayFiltersRoot: FC<TViewDisplayFiltersRoot> = (props) => {
|
export const ViewDisplayFiltersRoot: FC<TViewDisplayFiltersRoot> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, viewId } = props;
|
const { workspaceSlug, projectId, viewId, viewType, viewPageType } = props;
|
||||||
|
// hooks
|
||||||
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
|
// state
|
||||||
|
const [filterVisibility, setFilterVisibility] = useState<(Partial<keyof TViewDisplayFilters> | "display_property")[]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
const handleFilterVisibility = (key: keyof TViewDisplayFilters | "display_property") => {
|
||||||
|
setFilterVisibility((prevData = []) => {
|
||||||
|
if (prevData.includes(key)) return filter(prevData, (item) => item !== key);
|
||||||
|
return uniq(concat(prevData, [key]));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const layout = viewDetailStore?.appliedFilters?.display_filters?.layout;
|
||||||
|
|
||||||
|
const filtersProperties = layout
|
||||||
|
? viewDefaultFilterParametersByViewTypeAndLayout(viewPageType, layout, "display_filters")
|
||||||
|
: [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div className="space-y-1 divide-y divide-custom-border-300">
|
||||||
<div>ViewDisplayFiltersRoot</div>
|
<div className="relative py-1 first:pt-0">
|
||||||
|
<div className="sticky top-0 z-20 flex justify-between items-center gap-2 bg-custom-background-100 select-none">
|
||||||
|
<div className="font-medium text-xs text-custom-text-300 capitalize py-1">Properties</div>
|
||||||
|
<div
|
||||||
|
className="flex-shrink-0 relative overflow-hidden w-5 h-5 rounded flex justify-center items-center cursor-pointer hover:bg-custom-background-80"
|
||||||
|
onClick={() => handleFilterVisibility("display_property")}
|
||||||
|
>
|
||||||
|
{!filterVisibility.includes("display_property") ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!filterVisibility.includes("display_property") && (
|
||||||
|
<div className="py-1">
|
||||||
|
<ViewDisplayPropertiesRoot
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
viewId={viewId}
|
||||||
|
viewType={viewType}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{filtersProperties.map((filterKey) => (
|
||||||
|
<div key={filterKey} className="relative py-1 last:pb-0">
|
||||||
|
<div className="sticky top-0 z-20 flex justify-between items-center gap-2 bg-custom-background-100 select-none">
|
||||||
|
<div className="font-medium text-xs text-custom-text-300 capitalize py-1">
|
||||||
|
{filterKey.replaceAll("_", " ")}
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="flex-shrink-0 relative overflow-hidden w-5 h-5 rounded flex justify-center items-center cursor-pointer hover:bg-custom-background-80"
|
||||||
|
onClick={() => handleFilterVisibility(filterKey)}
|
||||||
|
>
|
||||||
|
{!filterVisibility.includes(filterKey) ? <ChevronUp size={12} /> : <ChevronDown size={12} />}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{!filterVisibility.includes(filterKey) && (
|
||||||
|
<ViewDisplayFiltersItemRoot
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
viewId={viewId}
|
||||||
|
viewType={viewType}
|
||||||
|
filterKey={filterKey}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* extra options */}
|
||||||
|
<div>
|
||||||
|
<div>Show sub issues</div>
|
||||||
|
<div>Show Empty groups</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
});
|
||||||
|
@ -12,12 +12,14 @@ import { ViewFiltersRoot } from "../";
|
|||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TViewTypes } from "@plane/types";
|
import { TViewTypes } from "@plane/types";
|
||||||
|
import { EViewPageType } from "constants/view";
|
||||||
|
|
||||||
type TViewFiltersDropdown = {
|
type TViewFiltersDropdown = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
displayDropdownText?: boolean;
|
displayDropdownText?: boolean;
|
||||||
dropdownPlacement?: Placement;
|
dropdownPlacement?: Placement;
|
||||||
@ -29,6 +31,7 @@ export const ViewFiltersDropdown: FC<TViewFiltersDropdown> = observer((props) =>
|
|||||||
projectId,
|
projectId,
|
||||||
viewId,
|
viewId,
|
||||||
viewType,
|
viewType,
|
||||||
|
viewPageType,
|
||||||
children,
|
children,
|
||||||
displayDropdownText = true,
|
displayDropdownText = true,
|
||||||
dropdownPlacement = "bottom-start",
|
dropdownPlacement = "bottom-start",
|
||||||
@ -130,6 +133,7 @@ export const ViewFiltersDropdown: FC<TViewFiltersDropdown> = observer((props) =>
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
viewType={viewType}
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
dateCustomFilterToggle={dateCustomFilterToggle}
|
dateCustomFilterToggle={dateCustomFilterToggle}
|
||||||
setDateCustomFilterToggle={setDateCustomFilterToggle}
|
setDateCustomFilterToggle={setDateCustomFilterToggle}
|
||||||
/>
|
/>
|
||||||
|
@ -50,14 +50,14 @@ export const ViewFiltersEditDropdown: FC<TViewFiltersEditDropdown> = observer((p
|
|||||||
// dropdown options
|
// dropdown options
|
||||||
const dropdownOptions: TViewFilterEditDropdownOptions[] = useMemo(
|
const dropdownOptions: TViewFilterEditDropdownOptions[] = useMemo(
|
||||||
() => [
|
() => [
|
||||||
// {
|
{
|
||||||
// icon: PhotoFilterIcon,
|
icon: PhotoFilterIcon,
|
||||||
// key: "save_as_new",
|
key: "save_as_new",
|
||||||
// label: "Save as new view",
|
label: "Save as new view",
|
||||||
// onClick: () => {
|
onClick: () => {
|
||||||
// viewOperations.localViewCreateEdit(undefined, viewDetailStore?.filtersToUpdate);
|
viewOperations.localViewCreateEdit(undefined, viewDetailStore?.filtersToUpdate);
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
icon: RotateCcw,
|
icon: RotateCcw,
|
||||||
key: "reset_changes",
|
key: "reset_changes",
|
||||||
|
@ -10,19 +10,28 @@ import { useViewDetail } from "hooks/store";
|
|||||||
import { ViewFiltersItemRoot } from "../";
|
import { ViewFiltersItemRoot } from "../";
|
||||||
// types
|
// types
|
||||||
import { TViewFilters, TViewTypes } from "@plane/types";
|
import { TViewFilters, TViewTypes } from "@plane/types";
|
||||||
import { VIEW_DEFAULT_FILTER_PARAMETERS } from "constants/view";
|
import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view";
|
||||||
|
|
||||||
type TViewFiltersRoot = {
|
type TViewFiltersRoot = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
dateCustomFilterToggle: string | undefined;
|
dateCustomFilterToggle: string | undefined;
|
||||||
setDateCustomFilterToggle: (value: string | undefined) => void;
|
setDateCustomFilterToggle: (value: string | undefined) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewFiltersRoot: FC<TViewFiltersRoot> = observer((props) => {
|
export const ViewFiltersRoot: FC<TViewFiltersRoot> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, viewId, viewType, dateCustomFilterToggle, setDateCustomFilterToggle } = props;
|
const {
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
viewId,
|
||||||
|
viewType,
|
||||||
|
viewPageType,
|
||||||
|
dateCustomFilterToggle,
|
||||||
|
setDateCustomFilterToggle,
|
||||||
|
} = props;
|
||||||
// hooks
|
// hooks
|
||||||
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
// state
|
// state
|
||||||
@ -34,9 +43,11 @@ export const ViewFiltersRoot: FC<TViewFiltersRoot> = observer((props) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const layout = viewDetailStore?.appliedFilters?.display_filters?.layout || "spreadsheet";
|
const layout = viewDetailStore?.appliedFilters?.display_filters?.layout;
|
||||||
|
|
||||||
const filtersProperties = VIEW_DEFAULT_FILTER_PARAMETERS?.["all"]?.["spreadsheet"]?.filters || [];
|
const filtersProperties = layout
|
||||||
|
? viewDefaultFilterParametersByViewTypeAndLayout(viewPageType, layout, "filters")
|
||||||
|
: [];
|
||||||
|
|
||||||
if (!layout || filtersProperties.length <= 0) return <></>;
|
if (!layout || filtersProperties.length <= 0) return <></>;
|
||||||
return (
|
return (
|
||||||
@ -45,7 +56,7 @@ export const ViewFiltersRoot: FC<TViewFiltersRoot> = observer((props) => {
|
|||||||
<div key={filterKey} className="relative py-1 first:pt-0 last:pb-0">
|
<div key={filterKey} className="relative py-1 first:pt-0 last:pb-0">
|
||||||
<div className="sticky top-0 z-20 flex justify-between items-center gap-2 bg-custom-background-100 select-none">
|
<div className="sticky top-0 z-20 flex justify-between items-center gap-2 bg-custom-background-100 select-none">
|
||||||
<div className="font-medium text-xs text-custom-text-300 capitalize py-1">
|
<div className="font-medium text-xs text-custom-text-300 capitalize py-1">
|
||||||
{filterKey.replace("_", " ")}
|
{filterKey.replaceAll("_", " ")}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="flex-shrink-0 relative overflow-hidden w-5 h-5 rounded flex justify-center items-center cursor-pointer hover:bg-custom-background-80"
|
className="flex-shrink-0 relative overflow-hidden w-5 h-5 rounded flex justify-center items-center cursor-pointer hover:bg-custom-background-80"
|
||||||
|
@ -22,6 +22,9 @@ export * from "./filters/edit-dropdown";
|
|||||||
// view display filters
|
// view display filters
|
||||||
export * from "./display-filters/dropdown";
|
export * from "./display-filters/dropdown";
|
||||||
export * from "./display-filters/root";
|
export * from "./display-filters/root";
|
||||||
|
export * from "./display-filters/display-filter-item-root";
|
||||||
|
export * from "./display-filters/display-filter-item";
|
||||||
|
export * from "./display-filters/display-filter-selection";
|
||||||
|
|
||||||
// view display properties
|
// view display properties
|
||||||
export * from "./display-properties/root";
|
export * from "./display-properties/root";
|
||||||
|
@ -6,49 +6,57 @@ import { useViewDetail } from "hooks/store";
|
|||||||
// ui
|
// ui
|
||||||
import { Tooltip } from "@plane/ui";
|
import { Tooltip } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TViewLayouts, TViewTypes } from "@plane/types";
|
import { TViewTypes } from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EViewLayouts, EViewPageType, viewPageDefaultLayoutsByPageType } from "constants/view";
|
||||||
|
|
||||||
type TViewLayoutRoot = {
|
type TViewLayoutRoot = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
};
|
};
|
||||||
|
|
||||||
const LAYOUTS_DATA: { key: TViewLayouts; title: string; icon: LucideIcon }[] = [
|
const LAYOUTS_DATA: { key: EViewLayouts; title: string; icon: LucideIcon }[] = [
|
||||||
{ key: "list", title: "List Layout", icon: List },
|
{ key: EViewLayouts.LIST, title: "List Layout", icon: List },
|
||||||
{ key: "kanban", title: "Kanban Layout", icon: Kanban },
|
{ key: EViewLayouts.KANBAN, title: "Kanban Layout", icon: Kanban },
|
||||||
{ key: "calendar", title: "Calendar Layout", icon: Calendar },
|
{ key: EViewLayouts.CALENDAR, title: "Calendar Layout", icon: Calendar },
|
||||||
{ key: "spreadsheet", title: "Spreadsheet Layout", icon: Sheet },
|
{ key: EViewLayouts.SPREADSHEET, title: "Spreadsheet Layout", icon: Sheet },
|
||||||
{ key: "gantt", title: "Gantt Chart layout", icon: GanttChartSquare },
|
{ key: EViewLayouts.GANTT, title: "Gantt Chart layout", icon: GanttChartSquare },
|
||||||
];
|
];
|
||||||
|
|
||||||
export const ViewLayoutRoot: FC<TViewLayoutRoot> = observer((props) => {
|
export const ViewLayoutRoot: FC<TViewLayoutRoot> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, viewId, viewType } = props;
|
const { workspaceSlug, projectId, viewId, viewType, viewPageType } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
|
|
||||||
if (!viewDetailStore) return <></>;
|
const validLayouts = viewPageDefaultLayoutsByPageType(viewPageType);
|
||||||
|
|
||||||
|
if (!viewDetailStore || validLayouts.length <= 1) return <></>;
|
||||||
return (
|
return (
|
||||||
<div className="relative flex gap-0.5 items-center bg-custom-background-80 rounded p-1 shadow-custom-shadow-2xs">
|
<div className="relative flex gap-0.5 items-center bg-custom-background-80 rounded p-1 shadow-custom-shadow-2xs">
|
||||||
{LAYOUTS_DATA.map((layout) => (
|
{LAYOUTS_DATA.map((layout) => {
|
||||||
<Fragment key={layout.key}>
|
if (!validLayouts.includes(layout.key)) return <Fragment key={layout.key} />;
|
||||||
<Tooltip tooltipContent={layout.title} position="bottom">
|
return (
|
||||||
<div
|
<Fragment key={layout.key}>
|
||||||
className={`relative h-6 w-7 flex justify-center items-center overflow-hidden rounded transition-all cursor-pointer
|
<Tooltip tooltipContent={layout.title} position="bottom">
|
||||||
|
<div
|
||||||
|
className={`relative h-6 w-7 flex justify-center items-center overflow-hidden rounded transition-all cursor-pointer
|
||||||
${
|
${
|
||||||
viewDetailStore?.filtersToUpdate?.display_filters?.layout === layout.key
|
viewDetailStore?.filtersToUpdate?.display_filters?.layout === layout.key
|
||||||
? `bg-custom-background-100 shadow-custom-shadow-2xs`
|
? `bg-custom-background-100 shadow-custom-shadow-2xs`
|
||||||
: `hover:bg-custom-background-100`
|
: `hover:bg-custom-background-100`
|
||||||
}
|
}
|
||||||
`}
|
`}
|
||||||
onClick={() => viewDetailStore.setDisplayFilters({ layout: layout.key })}
|
onClick={() => viewDetailStore.setDisplayFilters({ layout: layout.key })}
|
||||||
>
|
>
|
||||||
<layout.icon size={12} />
|
<layout.icon size={12} />
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -23,7 +23,7 @@ import {
|
|||||||
// ui
|
// ui
|
||||||
import { Spinner } from "@plane/ui";
|
import { Spinner } from "@plane/ui";
|
||||||
// constants
|
// constants
|
||||||
import { viewLocalPayload } from "constants/view";
|
import { EViewPageType, viewLocalPayload } from "constants/view";
|
||||||
// types
|
// types
|
||||||
import { TViewOperations } from "./types";
|
import { TViewOperations } from "./types";
|
||||||
import { TView, TViewTypes } from "@plane/types";
|
import { TView, TViewTypes } from "@plane/types";
|
||||||
@ -33,6 +33,7 @@ type TGlobalViewRoot = {
|
|||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
baseRoute: string;
|
baseRoute: string;
|
||||||
workspaceViewTabOptions: { key: TViewTypes; title: string; href: string }[];
|
workspaceViewTabOptions: { key: TViewTypes; title: string; href: string }[];
|
||||||
};
|
};
|
||||||
@ -43,7 +44,7 @@ type TViewOperationsToggle = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, viewId, viewType, baseRoute, workspaceViewTabOptions } = props;
|
const { workspaceSlug, projectId, viewId, viewType, viewPageType, baseRoute, workspaceViewTabOptions } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const viewStore = useView(workspaceSlug, projectId, viewType);
|
const viewStore = useView(workspaceSlug, projectId, viewType);
|
||||||
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
@ -232,7 +233,13 @@ export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<ViewLayoutRoot workspaceSlug={workspaceSlug} projectId={projectId} viewId={viewId} viewType={viewType} />
|
<ViewLayoutRoot
|
||||||
|
workspaceSlug={workspaceSlug}
|
||||||
|
projectId={projectId}
|
||||||
|
viewId={viewId}
|
||||||
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
@ -241,6 +248,7 @@ export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
viewType={viewType}
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
displayDropdownText={false}
|
displayDropdownText={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@ -251,24 +259,29 @@ export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
viewType={viewType}
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
displayDropdownText={false}
|
displayDropdownText={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ViewEditDropdown
|
<div className="flex-shrink-0">
|
||||||
workspaceSlug={workspaceSlug}
|
<ViewEditDropdown
|
||||||
projectId={projectId}
|
workspaceSlug={workspaceSlug}
|
||||||
viewId={viewId}
|
projectId={projectId}
|
||||||
viewOperations={viewOperations}
|
viewId={viewId}
|
||||||
/>
|
viewOperations={viewOperations}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<ViewFiltersEditDropdown
|
<div className="flex-shrink-0">
|
||||||
workspaceSlug={workspaceSlug}
|
<ViewFiltersEditDropdown
|
||||||
projectId={projectId}
|
workspaceSlug={workspaceSlug}
|
||||||
viewId={viewId}
|
projectId={projectId}
|
||||||
viewType={viewType}
|
viewId={viewId}
|
||||||
viewOperations={viewOperations}
|
viewType={viewType}
|
||||||
/>
|
viewOperations={viewOperations}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@ -282,6 +295,7 @@ export const GlobalViewRoot: FC<TGlobalViewRoot> = observer((props) => {
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
viewId={viewOperationsToggle.viewId}
|
viewId={viewOperationsToggle.viewId}
|
||||||
viewType={viewType}
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
viewOperations={viewOperations}
|
viewOperations={viewOperations}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -11,17 +11,20 @@ import { Input, Button } from "@plane/ui";
|
|||||||
// types
|
// types
|
||||||
import { TViewTypes } from "@plane/types";
|
import { TViewTypes } from "@plane/types";
|
||||||
import { TViewOperations } from "../types";
|
import { TViewOperations } from "../types";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType } from "constants/view";
|
||||||
|
|
||||||
type TViewCreateEditForm = {
|
type TViewCreateEditForm = {
|
||||||
workspaceSlug: string;
|
workspaceSlug: string;
|
||||||
projectId: string | undefined;
|
projectId: string | undefined;
|
||||||
viewId: string;
|
viewId: string;
|
||||||
viewType: TViewTypes;
|
viewType: TViewTypes;
|
||||||
|
viewPageType: EViewPageType;
|
||||||
viewOperations: TViewOperations;
|
viewOperations: TViewOperations;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewCreateEditForm: FC<TViewCreateEditForm> = observer((props) => {
|
export const ViewCreateEditForm: FC<TViewCreateEditForm> = observer((props) => {
|
||||||
const { workspaceSlug, projectId, viewId, viewType, viewOperations } = props;
|
const { workspaceSlug, projectId, viewId, viewType, viewPageType, viewOperations } = props;
|
||||||
// hooks
|
// hooks
|
||||||
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
const viewDetailStore = useViewDetail(workspaceSlug, projectId, viewId, viewType);
|
||||||
const { getProjectById } = useProject();
|
const { getProjectById } = useProject();
|
||||||
@ -126,6 +129,7 @@ export const ViewCreateEditForm: FC<TViewCreateEditForm> = observer((props) => {
|
|||||||
projectId={projectId}
|
projectId={projectId}
|
||||||
viewId={viewId}
|
viewId={viewId}
|
||||||
viewType={viewType}
|
viewType={viewType}
|
||||||
|
viewPageType={viewPageType}
|
||||||
dropdownPlacement="right"
|
dropdownPlacement="right"
|
||||||
>
|
>
|
||||||
<div className="cursor-pointer relative rounded p-1.5 px-2 flex items-center gap-1 border border-custom-border-100 bg-custom-background-80">
|
<div className="cursor-pointer relative rounded p-1.5 px-2 flex items-center gap-1 border border-custom-border-100 bg-custom-background-80">
|
||||||
|
@ -49,49 +49,49 @@ export const ViewEditDropdown: FC<TViewEditDropdown> = observer((props) => {
|
|||||||
onClick: () => viewOperations.localViewCreateEdit(viewId),
|
onClick: () => viewOperations.localViewCreateEdit(viewId),
|
||||||
children: undefined,
|
children: undefined,
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// icon: Eye,
|
icon: Eye,
|
||||||
// key: "accessability",
|
key: "accessability",
|
||||||
// label: "Change Accessability",
|
label: "Change Accessability",
|
||||||
// onClick: () => {},
|
onClick: () => {},
|
||||||
// children: [
|
children: [
|
||||||
// {
|
{
|
||||||
// icon: Eye,
|
icon: Eye,
|
||||||
// key: "private",
|
key: "private",
|
||||||
// label: "Private",
|
label: "Private",
|
||||||
// onClick: () => viewOperations.create({}),
|
onClick: () => viewOperations.create({}),
|
||||||
// children: undefined,
|
children: undefined,
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// icon: Globe2,
|
icon: Globe2,
|
||||||
// key: "public",
|
key: "public",
|
||||||
// label: "Public",
|
label: "Public",
|
||||||
// onClick: () => viewOperations.create({}),
|
onClick: () => viewOperations.create({}),
|
||||||
// children: undefined,
|
children: undefined,
|
||||||
// },
|
},
|
||||||
// ],
|
],
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// icon: Copy,
|
icon: Copy,
|
||||||
// key: "duplicate",
|
key: "duplicate",
|
||||||
// label: "Duplicate view",
|
label: "Duplicate view",
|
||||||
// onClick: () => viewOperations.remove(viewId),
|
onClick: () => viewOperations.remove(viewId),
|
||||||
// children: undefined,
|
children: undefined,
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// icon: Link2,
|
icon: Link2,
|
||||||
// key: "copy_link",
|
key: "copy_link",
|
||||||
// label: "Copy view link",
|
label: "Copy view link",
|
||||||
// onClick: () => viewOperations.remove(viewId),
|
onClick: () => viewOperations.remove(viewId),
|
||||||
// children: undefined,
|
children: undefined,
|
||||||
// },
|
},
|
||||||
// {
|
{
|
||||||
// icon: Trash,
|
icon: Trash,
|
||||||
// key: "delete",
|
key: "delete",
|
||||||
// label: "Delete view",
|
label: "Delete view",
|
||||||
// onClick: () => viewOperations.remove(viewId),
|
onClick: () => viewOperations.remove(viewId),
|
||||||
// children: undefined,
|
children: undefined,
|
||||||
// },
|
},
|
||||||
],
|
],
|
||||||
[viewOperations, viewId]
|
[viewOperations, viewId]
|
||||||
);
|
);
|
||||||
|
@ -449,4 +449,4 @@ export const groupReactionEmojis = (reactions: any) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return _groupedEmojis;
|
return _groupedEmojis;
|
||||||
};
|
};
|
||||||
|
@ -1,40 +1,24 @@
|
|||||||
// types
|
// types
|
||||||
import { TStateGroups, TIssuePriorities, TViewFilters, TViewDisplayFilters, TViewLayouts } from "@plane/types";
|
import {
|
||||||
|
TStateGroups,
|
||||||
|
TIssuePriorities,
|
||||||
|
TViewFilters,
|
||||||
|
TViewDisplayFilters,
|
||||||
|
TViewDisplayFiltersGrouped,
|
||||||
|
TViewDisplayFiltersOrderBy,
|
||||||
|
TViewDisplayFiltersType,
|
||||||
|
} from "@plane/types";
|
||||||
|
|
||||||
// filters constants
|
// filters constants
|
||||||
export const STATE_GROUP_PROPERTY: {
|
export const STATE_GROUP_PROPERTY: Record<TStateGroups, { label: string; color: string }> = {
|
||||||
[key in TStateGroups]: {
|
backlog: { label: "Backlog", color: "#d9d9d9" },
|
||||||
label: string;
|
unstarted: { label: "Unstarted", color: "#3f76ff" },
|
||||||
color: string;
|
started: { label: "Started", color: "#f59e0b" },
|
||||||
};
|
completed: { label: "Completed", color: "#16a34a" },
|
||||||
} = {
|
cancelled: { label: "Canceled", color: "#dc2626" },
|
||||||
backlog: {
|
|
||||||
label: "Backlog",
|
|
||||||
color: "#d9d9d9",
|
|
||||||
},
|
|
||||||
unstarted: {
|
|
||||||
label: "Unstarted",
|
|
||||||
color: "#3f76ff",
|
|
||||||
},
|
|
||||||
started: {
|
|
||||||
label: "Started",
|
|
||||||
color: "#f59e0b",
|
|
||||||
},
|
|
||||||
completed: {
|
|
||||||
label: "Completed",
|
|
||||||
color: "#16a34a",
|
|
||||||
},
|
|
||||||
cancelled: {
|
|
||||||
label: "Canceled",
|
|
||||||
color: "#dc2626",
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PRIORITIES_PROPERTY: {
|
export const PRIORITIES_PROPERTY: Record<TIssuePriorities, { label: string }> = {
|
||||||
[key in TIssuePriorities]: {
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
} = {
|
|
||||||
urgent: { label: "Urgent" },
|
urgent: { label: "Urgent" },
|
||||||
high: { label: "High" },
|
high: { label: "High" },
|
||||||
medium: { label: "Medium" },
|
medium: { label: "Medium" },
|
||||||
@ -42,11 +26,7 @@ export const PRIORITIES_PROPERTY: {
|
|||||||
none: { label: "None" },
|
none: { label: "None" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DATE_PROPERTY: {
|
export const DATE_PROPERTY: Record<string, { label: string }> = {
|
||||||
[key in string]: {
|
|
||||||
label: string;
|
|
||||||
};
|
|
||||||
} = {
|
|
||||||
"1_weeks;after;fromnow": { label: "1 week from now" },
|
"1_weeks;after;fromnow": { label: "1 week from now" },
|
||||||
"2_weeks;after;fromnow": { label: "2 weeks from now" },
|
"2_weeks;after;fromnow": { label: "2 weeks from now" },
|
||||||
"1_months;after;fromnow": { label: "1 month from now" },
|
"1_months;after;fromnow": { label: "1 month from now" },
|
||||||
@ -55,77 +35,98 @@ export const DATE_PROPERTY: {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// display filter constants
|
// display filter constants
|
||||||
|
export const GROUP_BY_PROPERTY: Partial<Record<TViewDisplayFiltersGrouped | "null", { label: string }>> = {
|
||||||
|
state: { label: "states" },
|
||||||
|
priority: { label: "Priority" },
|
||||||
|
labels: { label: "labels" },
|
||||||
|
assignees: { label: "Assignees" },
|
||||||
|
created_by: { label: "Created By" },
|
||||||
|
cycles: { label: "Cycles" },
|
||||||
|
modules: { label: "Modules" },
|
||||||
|
null: { label: "None" },
|
||||||
|
};
|
||||||
|
|
||||||
// layout, filter, display filter and display properties permissions for views
|
export const ORDER_BY_PROPERTY: Partial<Record<TViewDisplayFiltersOrderBy, Record<string, string>>> = {
|
||||||
type TViewLayoutFilterProperties = {
|
sort_order: { label: "Manual" },
|
||||||
|
"-created_at": { label: "Last Created" },
|
||||||
|
"-updated_at": { label: "Last Updated" },
|
||||||
|
start_date: { label: "Start Date" },
|
||||||
|
target_date: { label: "Due Date" },
|
||||||
|
"-priority": { label: "Priority" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const TYPE_PROPERTY: Record<TViewDisplayFiltersType | "null", { label: string }> = {
|
||||||
|
null: { label: "All" },
|
||||||
|
active: { label: "Active issues" },
|
||||||
|
backlog: { label: "Backlog issues" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EXTRA_OPTIONS_PROPERTY: Record<string, { label: string }> = {
|
||||||
|
sub_issue: { label: "Sub Issues" },
|
||||||
|
show_empty_groups: { label: "Show Empty Groups" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum EViewPageType {
|
||||||
|
ALL = "all",
|
||||||
|
PROFILE = "profile",
|
||||||
|
PROJECT = "project",
|
||||||
|
ARCHIVED = "archived",
|
||||||
|
DRAFT = "draft",
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum EViewLayouts {
|
||||||
|
LIST = "list",
|
||||||
|
KANBAN = "kanban",
|
||||||
|
CALENDAR = "calendar",
|
||||||
|
SPREADSHEET = "spreadsheet",
|
||||||
|
GANTT = "gantt",
|
||||||
|
}
|
||||||
|
|
||||||
|
export type TViewLayoutFilterProperties = {
|
||||||
filters: Partial<keyof TViewFilters>[];
|
filters: Partial<keyof TViewFilters>[];
|
||||||
readonlyFilters?: Partial<keyof TViewFilters>[];
|
|
||||||
display_filters: Partial<keyof TViewDisplayFilters>[];
|
display_filters: Partial<keyof TViewDisplayFilters>[];
|
||||||
extra_options: ("sub_issue" | "show_empty_groups")[];
|
extra_options: ("sub_issue" | "show_empty_groups")[];
|
||||||
display_properties: boolean;
|
display_properties: boolean;
|
||||||
|
readonlyFilters?: Partial<keyof TViewFilters>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
type TViewLayoutFilters = {
|
export type TViewLayoutFilters = {
|
||||||
list: TViewLayoutFilterProperties;
|
layouts: Partial<EViewLayouts>[];
|
||||||
kanban: TViewLayoutFilterProperties;
|
[EViewLayouts.LIST]: TViewLayoutFilterProperties;
|
||||||
calendar: TViewLayoutFilterProperties;
|
[EViewLayouts.KANBAN]: TViewLayoutFilterProperties;
|
||||||
spreadsheet: TViewLayoutFilterProperties;
|
[EViewLayouts.CALENDAR]: TViewLayoutFilterProperties;
|
||||||
gantt: TViewLayoutFilterProperties;
|
[EViewLayouts.SPREADSHEET]: TViewLayoutFilterProperties;
|
||||||
|
[EViewLayouts.GANTT]: TViewLayoutFilterProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
type TFilterPermissions = {
|
export type TFilterPermissions = {
|
||||||
all: Omit<TViewLayoutFilters, "list" | "kanban" | "calendar" | "gantt"> & {
|
[EViewPageType.ALL]: Partial<TViewLayoutFilters>;
|
||||||
layouts: Omit<TViewLayouts, "list" | "kanban" | "calendar" | "gantt">[];
|
[EViewPageType.PROFILE]: Partial<TViewLayoutFilters>;
|
||||||
};
|
[EViewPageType.PROJECT]: TViewLayoutFilters;
|
||||||
profile: Omit<TViewLayoutFilters, "spreadsheet" | "calendar" | "gantt"> & {
|
[EViewPageType.ARCHIVED]: Partial<TViewLayoutFilters>;
|
||||||
layouts: Omit<TViewLayouts, "spreadsheet" | "calendar" | "gantt">[];
|
[EViewPageType.DRAFT]: Partial<TViewLayoutFilters>;
|
||||||
};
|
|
||||||
project: TViewLayoutFilters & {
|
|
||||||
layouts: TViewLayouts[];
|
|
||||||
};
|
|
||||||
archived: Omit<TViewLayoutFilters, "kanban" | "spreadsheet" | "calendar" | "gantt"> & {
|
|
||||||
layouts: Omit<TViewLayouts, "kanban" | "spreadsheet" | "calendar" | "gantt">[];
|
|
||||||
};
|
|
||||||
draft: Omit<TViewLayoutFilters, "spreadsheet" | "calendar" | "gantt"> & {
|
|
||||||
layouts: Omit<TViewLayouts, "kanban" | "spreadsheet" | "calendar" | "gantt">[];
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const ALL_FILTER_PERMISSIONS: TFilterPermissions["all"] = {
|
const ALL_FILTER_PERMISSIONS: TFilterPermissions["all"] = {
|
||||||
layouts: ["spreadsheet"],
|
layouts: [EViewLayouts.SPREADSHEET],
|
||||||
spreadsheet: {
|
[EViewLayouts.SPREADSHEET]: {
|
||||||
// filters: ["project", "priority", "state_group", "assignees", "created_by", "labels", "start_date", "target_date"],
|
filters: ["project", "priority", "state_group", "assignees", "created_by", "labels", "start_date", "target_date"],
|
||||||
filters: [
|
display_filters: ["type"],
|
||||||
"project",
|
// extra_options: [],
|
||||||
"module",
|
extra_options: ["sub_issue", "show_empty_groups"],
|
||||||
"cycle",
|
|
||||||
"priority",
|
|
||||||
"state",
|
|
||||||
"state_group",
|
|
||||||
"assignees",
|
|
||||||
"mentions",
|
|
||||||
"subscriber",
|
|
||||||
"created_by",
|
|
||||||
"labels",
|
|
||||||
"start_date",
|
|
||||||
"target_date",
|
|
||||||
],
|
|
||||||
// display_filters: ["type"],
|
|
||||||
display_filters: ["group_by", "sub_group_by", "order_by", "type"],
|
|
||||||
extra_options: [],
|
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const PROFILE_FILTER_PERMISSIONS: TFilterPermissions["profile"] = {
|
const PROFILE_FILTER_PERMISSIONS: TFilterPermissions["profile"] = {
|
||||||
layouts: ["list", "kanban"],
|
layouts: [EViewLayouts.LIST, EViewLayouts.KANBAN],
|
||||||
list: {
|
[EViewLayouts.LIST]: {
|
||||||
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
||||||
display_filters: ["group_by", "order_by", "type"],
|
display_filters: ["group_by", "order_by", "type"],
|
||||||
extra_options: [],
|
extra_options: [],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
kanban: {
|
[EViewLayouts.KANBAN]: {
|
||||||
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
filters: ["priority", "state_group", "labels", "start_date", "target_date"],
|
||||||
display_filters: ["group_by", "order_by", "type"],
|
display_filters: ["group_by", "order_by", "type"],
|
||||||
extra_options: [],
|
extra_options: [],
|
||||||
@ -134,8 +135,14 @@ const PROFILE_FILTER_PERMISSIONS: TFilterPermissions["profile"] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
||||||
layouts: ["list", "kanban", "spreadsheet", "calendar", "gantt"],
|
layouts: [
|
||||||
list: {
|
EViewLayouts.LIST,
|
||||||
|
EViewLayouts.KANBAN,
|
||||||
|
EViewLayouts.CALENDAR,
|
||||||
|
EViewLayouts.SPREADSHEET,
|
||||||
|
EViewLayouts.GANTT,
|
||||||
|
],
|
||||||
|
[EViewLayouts.LIST]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -152,7 +159,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
|||||||
extra_options: ["sub_issue", "show_empty_groups"],
|
extra_options: ["sub_issue", "show_empty_groups"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
kanban: {
|
[EViewLayouts.KANBAN]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -169,7 +176,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
|||||||
extra_options: ["sub_issue", "show_empty_groups"],
|
extra_options: ["sub_issue", "show_empty_groups"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
calendar: {
|
[EViewLayouts.CALENDAR]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -186,7 +193,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
|||||||
extra_options: ["sub_issue"],
|
extra_options: ["sub_issue"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
spreadsheet: {
|
[EViewLayouts.SPREADSHEET]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -203,8 +210,7 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
|||||||
extra_options: [],
|
extra_options: [],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
|
[EViewLayouts.GANTT]: {
|
||||||
gantt: {
|
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -224,8 +230,8 @@ const PROJECT_FILTER_PERMISSIONS: TFilterPermissions["project"] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const ARCHIVED_FILTER_PERMISSIONS: TFilterPermissions["archived"] = {
|
const ARCHIVED_FILTER_PERMISSIONS: TFilterPermissions["archived"] = {
|
||||||
layouts: ["list"],
|
layouts: [EViewLayouts.LIST],
|
||||||
list: {
|
[EViewLayouts.LIST]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -245,8 +251,8 @@ const ARCHIVED_FILTER_PERMISSIONS: TFilterPermissions["archived"] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = {
|
const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = {
|
||||||
layouts: ["list", "kanban"],
|
layouts: [EViewLayouts.LIST, EViewLayouts.KANBAN],
|
||||||
list: {
|
[EViewLayouts.LIST]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -263,7 +269,7 @@ const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = {
|
|||||||
extra_options: ["sub_issue", "show_empty_groups"],
|
extra_options: ["sub_issue", "show_empty_groups"],
|
||||||
display_properties: true,
|
display_properties: true,
|
||||||
},
|
},
|
||||||
kanban: {
|
[EViewLayouts.KANBAN]: {
|
||||||
filters: [
|
filters: [
|
||||||
"priority",
|
"priority",
|
||||||
"state",
|
"state",
|
||||||
@ -283,9 +289,19 @@ const DRAFT_FILTER_PERMISSIONS: TFilterPermissions["draft"] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const VIEW_DEFAULT_FILTER_PARAMETERS: TFilterPermissions = {
|
export const VIEW_DEFAULT_FILTER_PARAMETERS: TFilterPermissions = {
|
||||||
all: ALL_FILTER_PERMISSIONS,
|
[EViewPageType.ALL]: ALL_FILTER_PERMISSIONS,
|
||||||
profile: PROFILE_FILTER_PERMISSIONS,
|
[EViewPageType.PROFILE]: PROFILE_FILTER_PERMISSIONS,
|
||||||
project: PROJECT_FILTER_PERMISSIONS,
|
[EViewPageType.PROJECT]: PROJECT_FILTER_PERMISSIONS,
|
||||||
archived: ARCHIVED_FILTER_PERMISSIONS,
|
[EViewPageType.ARCHIVED]: ARCHIVED_FILTER_PERMISSIONS,
|
||||||
draft: DRAFT_FILTER_PERMISSIONS,
|
[EViewPageType.DRAFT]: DRAFT_FILTER_PERMISSIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const viewPageDefaultLayoutsByPageType = (_viewPageType: EViewPageType) =>
|
||||||
|
VIEW_DEFAULT_FILTER_PARAMETERS?.[_viewPageType]?.layouts || [];
|
||||||
|
|
||||||
|
export const viewDefaultFilterParametersByViewTypeAndLayout = <K extends keyof TViewLayoutFilterProperties>(
|
||||||
|
_viewPageType: EViewPageType,
|
||||||
|
_layout: EViewLayouts,
|
||||||
|
property: K
|
||||||
|
): TViewLayoutFilterProperties[K] =>
|
||||||
|
VIEW_DEFAULT_FILTER_PARAMETERS?.[_viewPageType]?.[_layout]?.[property] as TViewLayoutFilterProperties[K];
|
||||||
|
@ -13,9 +13,24 @@ import {
|
|||||||
StateGroupIcon,
|
StateGroupIcon,
|
||||||
} from "@plane/ui";
|
} from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import { TIssuePriorities, TStateGroups, TViewFilters } from "@plane/types";
|
import {
|
||||||
|
TIssuePriorities,
|
||||||
|
TStateGroups,
|
||||||
|
TViewFilters,
|
||||||
|
TViewDisplayFilters,
|
||||||
|
TViewDisplayFiltersGrouped,
|
||||||
|
TViewDisplayFiltersOrderBy,
|
||||||
|
TViewDisplayFiltersType,
|
||||||
|
} from "@plane/types";
|
||||||
// constants
|
// constants
|
||||||
import { STATE_GROUP_PROPERTY, PRIORITIES_PROPERTY, DATE_PROPERTY } from "constants/view/filters";
|
import {
|
||||||
|
STATE_GROUP_PROPERTY,
|
||||||
|
PRIORITIES_PROPERTY,
|
||||||
|
DATE_PROPERTY,
|
||||||
|
GROUP_BY_PROPERTY,
|
||||||
|
ORDER_BY_PROPERTY,
|
||||||
|
TYPE_PROPERTY,
|
||||||
|
} from "constants/view/filters";
|
||||||
// helpers
|
// helpers
|
||||||
import { renderEmoji } from "helpers/emoji.helper";
|
import { renderEmoji } from "helpers/emoji.helper";
|
||||||
import { renderFormattedDate } from "helpers/date-time.helper";
|
import { renderFormattedDate } from "helpers/date-time.helper";
|
||||||
@ -30,6 +45,11 @@ type TFilterPropertyDefaultDetails = {
|
|||||||
label: string;
|
label: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type TDisplayFilterPropertyDetails = {
|
||||||
|
icon: ReactNode;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const useViewFilter = (workspaceSlug: string, projectId: string | undefined) => {
|
export const useViewFilter = (workspaceSlug: string, projectId: string | undefined) => {
|
||||||
const { projectMap, getProjectById } = useProject();
|
const { projectMap, getProjectById } = useProject();
|
||||||
const { getProjectModuleIds, getModuleById } = useModule();
|
const { getProjectModuleIds, getModuleById } = useModule();
|
||||||
@ -326,9 +346,68 @@ export const useViewFilter = (workspaceSlug: string, projectId: string | undefin
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const displayFilterIdsWithKey = (displayFilterKey: keyof TViewDisplayFilters): string[] | undefined => {
|
||||||
|
if (!displayFilterKey) return undefined;
|
||||||
|
|
||||||
|
switch (displayFilterKey) {
|
||||||
|
case "group_by":
|
||||||
|
return Object.keys(GROUP_BY_PROPERTY) || undefined;
|
||||||
|
case "sub_group_by":
|
||||||
|
return Object.keys(GROUP_BY_PROPERTY) || undefined;
|
||||||
|
case "order_by":
|
||||||
|
return Object.keys(ORDER_BY_PROPERTY) || undefined;
|
||||||
|
case "type":
|
||||||
|
return Object.keys(TYPE_PROPERTY) || undefined;
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const displayPropertyDetails = (
|
||||||
|
displayFilterKey: keyof TViewDisplayFilters,
|
||||||
|
propertyId: string
|
||||||
|
): TDisplayFilterPropertyDetails | undefined => {
|
||||||
|
if (!displayFilterKey) return undefined;
|
||||||
|
|
||||||
|
switch (displayFilterKey) {
|
||||||
|
case "group_by":
|
||||||
|
const groupBy = GROUP_BY_PROPERTY?.[propertyId as TViewDisplayFiltersGrouped | "null"];
|
||||||
|
if (!groupBy) return undefined;
|
||||||
|
return {
|
||||||
|
icon: undefined,
|
||||||
|
label: groupBy.label,
|
||||||
|
};
|
||||||
|
case "sub_group_by":
|
||||||
|
const subGroupBy = GROUP_BY_PROPERTY?.[propertyId as TViewDisplayFiltersGrouped | "null"];
|
||||||
|
if (!subGroupBy) return undefined;
|
||||||
|
return {
|
||||||
|
icon: undefined,
|
||||||
|
label: subGroupBy.label,
|
||||||
|
};
|
||||||
|
case "order_by":
|
||||||
|
const orderBy = ORDER_BY_PROPERTY?.[propertyId as TViewDisplayFiltersOrderBy];
|
||||||
|
if (!orderBy) return undefined;
|
||||||
|
return {
|
||||||
|
icon: undefined,
|
||||||
|
label: orderBy.label,
|
||||||
|
};
|
||||||
|
case "type":
|
||||||
|
const type = TYPE_PROPERTY?.[propertyId as TViewDisplayFiltersType | "null"];
|
||||||
|
if (!type) return undefined;
|
||||||
|
return {
|
||||||
|
icon: undefined,
|
||||||
|
label: type.label,
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
filterIdsWithKey,
|
filterIdsWithKey,
|
||||||
propertyDefaultDetails,
|
propertyDefaultDetails,
|
||||||
propertyDetails,
|
propertyDetails,
|
||||||
|
displayFilterIdsWithKey,
|
||||||
|
displayPropertyDetails,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view";
|
|||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "lib/types";
|
import { NextPageWithLayout } from "lib/types";
|
||||||
// constants
|
// constants
|
||||||
import { VIEW_TYPES } from "constants/view";
|
import { EViewPageType, VIEW_TYPES } from "constants/view";
|
||||||
|
|
||||||
const ProjectPrivateViewPage: NextPageWithLayout = () => {
|
const ProjectPrivateViewPage: NextPageWithLayout = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -38,6 +38,7 @@ const ProjectPrivateViewPage: NextPageWithLayout = () => {
|
|||||||
projectId={projectId.toString()}
|
projectId={projectId.toString()}
|
||||||
viewId={viewId.toString()}
|
viewId={viewId.toString()}
|
||||||
viewType={VIEW_TYPES.PROJECT_PRIVATE_VIEWS}
|
viewType={VIEW_TYPES.PROJECT_PRIVATE_VIEWS}
|
||||||
|
viewPageType={EViewPageType.PROJECT}
|
||||||
baseRoute={`/${workspaceSlug?.toString()}/projects/${projectId}/views/private`}
|
baseRoute={`/${workspaceSlug?.toString()}/projects/${projectId}/views/private`}
|
||||||
workspaceViewTabOptions={workspaceViewTabOptions}
|
workspaceViewTabOptions={workspaceViewTabOptions}
|
||||||
/>
|
/>
|
||||||
|
@ -1,49 +1,16 @@
|
|||||||
import { ReactElement, useMemo } from "react";
|
import { ReactElement } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
// layouts
|
// layouts
|
||||||
import { AppLayout } from "layouts/app-layout";
|
import { AppLayout } from "layouts/app-layout";
|
||||||
// components
|
|
||||||
import { GlobalViewRoot } from "components/view";
|
|
||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "lib/types";
|
import { NextPageWithLayout } from "lib/types";
|
||||||
// constants
|
|
||||||
import { VIEW_TYPES } from "constants/view";
|
|
||||||
|
|
||||||
const ProjectPrivateViewPage: NextPageWithLayout = () => {
|
const ProjectPrivateViewPage: NextPageWithLayout = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, viewId } = router.query;
|
const { workspaceSlug, projectId, viewId } = router.query;
|
||||||
|
|
||||||
const workspaceViewTabOptions = useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
key: VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS,
|
|
||||||
title: "Private",
|
|
||||||
href: `/${workspaceSlug}/projects/${projectId}/views/private`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: VIEW_TYPES.WORKSPACE_PUBLIC_VIEWS,
|
|
||||||
title: "Public",
|
|
||||||
href: `/${workspaceSlug}/projects/${projectId}/views/public`,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[workspaceSlug, projectId]
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!workspaceSlug || !projectId || !viewId) return <></>;
|
if (!workspaceSlug || !projectId || !viewId) return <></>;
|
||||||
return (
|
return <div />;
|
||||||
<div className="h-full overflow-hidden bg-custom-background-100">
|
|
||||||
<div className="flex h-full w-full flex-col border-b border-custom-border-300">
|
|
||||||
<GlobalViewRoot
|
|
||||||
workspaceSlug={workspaceSlug.toString()}
|
|
||||||
projectId={projectId.toString()}
|
|
||||||
viewId={viewId.toString()}
|
|
||||||
viewType={VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS}
|
|
||||||
baseRoute={`/${workspaceSlug?.toString()}/projects/${projectId}/views/private`}
|
|
||||||
workspaceViewTabOptions={workspaceViewTabOptions}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ProjectPrivateViewPage.getLayout = function getLayout(page: ReactElement) {
|
ProjectPrivateViewPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view";
|
|||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "lib/types";
|
import { NextPageWithLayout } from "lib/types";
|
||||||
// constants
|
// constants
|
||||||
import { VIEW_TYPES } from "constants/view";
|
import { EViewPageType, VIEW_TYPES } from "constants/view";
|
||||||
|
|
||||||
const ProjectPublicViewPage: NextPageWithLayout = () => {
|
const ProjectPublicViewPage: NextPageWithLayout = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -38,6 +38,7 @@ const ProjectPublicViewPage: NextPageWithLayout = () => {
|
|||||||
projectId={undefined}
|
projectId={undefined}
|
||||||
viewId={viewId.toString()}
|
viewId={viewId.toString()}
|
||||||
viewType={VIEW_TYPES.PROJECT_PUBLIC_VIEWS}
|
viewType={VIEW_TYPES.PROJECT_PUBLIC_VIEWS}
|
||||||
|
viewPageType={EViewPageType.PROJECT}
|
||||||
baseRoute={`/${workspaceSlug?.toString()}/views/public`}
|
baseRoute={`/${workspaceSlug?.toString()}/views/public`}
|
||||||
workspaceViewTabOptions={workspaceViewTabOptions}
|
workspaceViewTabOptions={workspaceViewTabOptions}
|
||||||
/>
|
/>
|
||||||
|
@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view";
|
|||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "lib/types";
|
import { NextPageWithLayout } from "lib/types";
|
||||||
// constants
|
// constants
|
||||||
import { VIEW_TYPES } from "constants/view";
|
import { EViewPageType, VIEW_TYPES } from "constants/view";
|
||||||
|
|
||||||
const WorkspacePrivateViewPage: NextPageWithLayout = () => {
|
const WorkspacePrivateViewPage: NextPageWithLayout = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -38,6 +38,7 @@ const WorkspacePrivateViewPage: NextPageWithLayout = () => {
|
|||||||
projectId={undefined}
|
projectId={undefined}
|
||||||
viewId={viewId.toString()}
|
viewId={viewId.toString()}
|
||||||
viewType={VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS}
|
viewType={VIEW_TYPES.WORKSPACE_PRIVATE_VIEWS}
|
||||||
|
viewPageType={EViewPageType.ALL}
|
||||||
baseRoute={`/${workspaceSlug?.toString()}/views/private`}
|
baseRoute={`/${workspaceSlug?.toString()}/views/private`}
|
||||||
workspaceViewTabOptions={workspaceViewTabOptions}
|
workspaceViewTabOptions={workspaceViewTabOptions}
|
||||||
/>
|
/>
|
||||||
|
@ -7,7 +7,7 @@ import { GlobalViewRoot } from "components/view";
|
|||||||
// types
|
// types
|
||||||
import { NextPageWithLayout } from "lib/types";
|
import { NextPageWithLayout } from "lib/types";
|
||||||
// constants
|
// constants
|
||||||
import { VIEW_TYPES } from "constants/view";
|
import { EViewPageType, VIEW_TYPES } from "constants/view";
|
||||||
|
|
||||||
const WorkspacePublicViewPage: NextPageWithLayout = () => {
|
const WorkspacePublicViewPage: NextPageWithLayout = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -38,6 +38,7 @@ const WorkspacePublicViewPage: NextPageWithLayout = () => {
|
|||||||
projectId={undefined}
|
projectId={undefined}
|
||||||
viewId={viewId.toString()}
|
viewId={viewId.toString()}
|
||||||
viewType={VIEW_TYPES.WORKSPACE_PUBLIC_VIEWS}
|
viewType={VIEW_TYPES.WORKSPACE_PUBLIC_VIEWS}
|
||||||
|
viewPageType={EViewPageType.ALL}
|
||||||
baseRoute={`/${workspaceSlug?.toString()}/views/public`}
|
baseRoute={`/${workspaceSlug?.toString()}/views/public`}
|
||||||
workspaceViewTabOptions={workspaceViewTabOptions}
|
workspaceViewTabOptions={workspaceViewTabOptions}
|
||||||
/>
|
/>
|
||||||
|
@ -8,6 +8,8 @@ import {
|
|||||||
TViewFilterProps,
|
TViewFilterProps,
|
||||||
TViewFilterQueryParams,
|
TViewFilterQueryParams,
|
||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType, viewPageDefaultLayoutsByPageType } from "constants/view";
|
||||||
|
|
||||||
export class FiltersHelper {
|
export class FiltersHelper {
|
||||||
// computed filters
|
// computed filters
|
||||||
@ -29,21 +31,26 @@ export class FiltersHelper {
|
|||||||
|
|
||||||
// computed display filters
|
// computed display filters
|
||||||
computedDisplayFilters = (
|
computedDisplayFilters = (
|
||||||
|
viewPageType: EViewPageType,
|
||||||
displayFilters: TViewDisplayFilters,
|
displayFilters: TViewDisplayFilters,
|
||||||
defaultValues?: Partial<TViewDisplayFilters>
|
defaultValues?: Partial<TViewDisplayFilters>
|
||||||
): TViewDisplayFilters => ({
|
): TViewDisplayFilters => {
|
||||||
layout: defaultValues?.layout || displayFilters?.layout || "list",
|
const viewPageDefaultLayout = viewPageDefaultLayoutsByPageType(viewPageType)?.[0] || "list";
|
||||||
group_by: defaultValues?.group_by || displayFilters?.group_by || undefined,
|
|
||||||
sub_group_by: defaultValues?.sub_group_by || displayFilters?.sub_group_by || undefined,
|
return {
|
||||||
order_by: defaultValues?.order_by || displayFilters?.order_by || "sort_order",
|
layout: defaultValues?.layout || displayFilters?.layout || viewPageDefaultLayout,
|
||||||
type: defaultValues?.type || displayFilters?.type || undefined,
|
group_by: defaultValues?.group_by || displayFilters?.group_by || undefined,
|
||||||
sub_issue: defaultValues?.sub_issue || displayFilters?.sub_issue || false,
|
sub_group_by: defaultValues?.sub_group_by || displayFilters?.sub_group_by || undefined,
|
||||||
show_empty_groups: defaultValues?.show_empty_groups || displayFilters?.show_empty_groups || false,
|
order_by: defaultValues?.order_by || displayFilters?.order_by || "sort_order",
|
||||||
calendar: {
|
type: defaultValues?.type || displayFilters?.type || undefined,
|
||||||
show_weekends: defaultValues?.calendar?.show_weekends || displayFilters?.calendar?.show_weekends || false,
|
sub_issue: defaultValues?.sub_issue || displayFilters?.sub_issue || false,
|
||||||
layout: defaultValues?.calendar?.layout || displayFilters?.calendar?.layout || "month",
|
show_empty_groups: defaultValues?.show_empty_groups || displayFilters?.show_empty_groups || false,
|
||||||
},
|
calendar: {
|
||||||
});
|
show_weekends: defaultValues?.calendar?.show_weekends || displayFilters?.calendar?.show_weekends || false,
|
||||||
|
layout: defaultValues?.calendar?.layout || displayFilters?.calendar?.layout || "month",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// computed display properties
|
// computed display properties
|
||||||
computedDisplayProperties = (
|
computedDisplayProperties = (
|
||||||
|
@ -11,6 +11,8 @@ import {
|
|||||||
} from "services/view";
|
} from "services/view";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "store/root.store";
|
import { RootStore } from "store/root.store";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType } from "constants/view";
|
||||||
|
|
||||||
export class GlobalViewRootStore {
|
export class GlobalViewRootStore {
|
||||||
workspacePrivateViewStore: ViewRootStore;
|
workspacePrivateViewStore: ViewRootStore;
|
||||||
@ -59,25 +61,29 @@ export class GlobalViewRootStore {
|
|||||||
this.store,
|
this.store,
|
||||||
workspacePrivateDefaultViews,
|
workspacePrivateDefaultViews,
|
||||||
new WorkspacePrivateViewService(),
|
new WorkspacePrivateViewService(),
|
||||||
new WorkspaceFiltersService()
|
new WorkspaceFiltersService(),
|
||||||
|
EViewPageType.ALL
|
||||||
);
|
);
|
||||||
this.workspacePublicViewStore = new ViewRootStore(
|
this.workspacePublicViewStore = new ViewRootStore(
|
||||||
this.store,
|
this.store,
|
||||||
workspacePublicDefaultViews,
|
workspacePublicDefaultViews,
|
||||||
new WorkspacePublicViewService(),
|
new WorkspacePublicViewService(),
|
||||||
new WorkspaceFiltersService()
|
new WorkspaceFiltersService(),
|
||||||
|
EViewPageType.ALL
|
||||||
);
|
);
|
||||||
this.projectPrivateViewStore = new ViewRootStore(
|
this.projectPrivateViewStore = new ViewRootStore(
|
||||||
this.store,
|
this.store,
|
||||||
undefined,
|
undefined,
|
||||||
new ProjectPrivateViewService(),
|
new ProjectPrivateViewService(),
|
||||||
new ProjectFiltersService()
|
new ProjectFiltersService(),
|
||||||
|
EViewPageType.PROJECT
|
||||||
);
|
);
|
||||||
this.projectPublicViewStore = new ViewRootStore(
|
this.projectPublicViewStore = new ViewRootStore(
|
||||||
this.store,
|
this.store,
|
||||||
undefined,
|
undefined,
|
||||||
new ProjectPublicViewService(),
|
new ProjectPublicViewService(),
|
||||||
new ProjectFiltersService()
|
new ProjectFiltersService(),
|
||||||
|
EViewPageType.PROJECT
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ import { ViewStore } from "./view.store";
|
|||||||
// types
|
// types
|
||||||
import { TUserViewService, TViewService } from "services/view/types";
|
import { TUserViewService, TViewService } from "services/view/types";
|
||||||
import { TView } from "@plane/types";
|
import { TView } from "@plane/types";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType } from "constants/view";
|
||||||
|
|
||||||
export type TLoader = "init-loader" | "mutation-loader" | "submitting" | undefined;
|
export type TLoader = "init-loader" | "mutation-loader" | "submitting" | undefined;
|
||||||
|
|
||||||
@ -37,7 +39,8 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
private store: RootStore,
|
private store: RootStore,
|
||||||
private defaultViews: TView[] = [],
|
private defaultViews: TView[] = [],
|
||||||
private service: TViewService,
|
private service: TViewService,
|
||||||
private userService: TUserViewService
|
private userService: TUserViewService,
|
||||||
|
private viewPageType: EViewPageType
|
||||||
) {
|
) {
|
||||||
makeObservable(this, {
|
makeObservable(this, {
|
||||||
// observables
|
// observables
|
||||||
@ -70,7 +73,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
// actions
|
// actions
|
||||||
localViewCreate = async (view: TView) => {
|
localViewCreate = async (view: TView) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -84,7 +92,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
if (this.defaultViews && this.defaultViews.length > 0)
|
if (this.defaultViews && this.defaultViews.length > 0)
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.defaultViews?.forEach((view) => {
|
this.defaultViews?.forEach((view) => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -93,7 +106,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
views.forEach((view) => {
|
views.forEach((view) => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
this.loader = undefined;
|
this.loader = undefined;
|
||||||
});
|
});
|
||||||
@ -105,9 +123,13 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
const { workspaceSlug, projectId } = this.store.app.router;
|
const { workspaceSlug, projectId } = this.store.app.router;
|
||||||
if (!workspaceSlug || !viewId) return;
|
if (!workspaceSlug || !viewId) return;
|
||||||
|
|
||||||
|
// fetching display properties and display_filters
|
||||||
const userView = await this.userService.fetch(workspaceSlug, projectId);
|
const userView = await this.userService.fetch(workspaceSlug, projectId);
|
||||||
if (!userView) return;
|
if (!userView) return;
|
||||||
|
|
||||||
|
// fetching kanban display filters from local
|
||||||
|
|
||||||
|
// fetching display filters from local and from the view
|
||||||
if (["all-issues", "assigned", "created", "subscribed"].includes(viewId)) {
|
if (["all-issues", "assigned", "created", "subscribed"].includes(viewId)) {
|
||||||
const view = { ...this.viewById(viewId) };
|
const view = { ...this.viewById(viewId) };
|
||||||
if (!view) return;
|
if (!view) return;
|
||||||
@ -124,7 +146,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
view?.display_properties && (view.display_properties = userView.display_properties);
|
view?.display_properties && (view.display_properties = userView.display_properties);
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
@ -139,7 +166,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
if (!view) return;
|
if (!view) return;
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (data.id) this.remove(data.id);
|
if (data.id) this.remove(data.id);
|
||||||
@ -169,7 +201,12 @@ export class ViewRootStore implements TViewRootStore {
|
|||||||
if (!view) return;
|
if (!view) return;
|
||||||
|
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
if (view.id) set(this.viewMap, [view.id], new ViewStore(this.store, view, this.service, this.userService));
|
if (view.id)
|
||||||
|
set(
|
||||||
|
this.viewMap,
|
||||||
|
[view.id],
|
||||||
|
new ViewStore(this.store, view, this.service, this.userService, this.viewPageType)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} catch {}
|
} catch {}
|
||||||
};
|
};
|
||||||
|
@ -20,6 +20,8 @@ import {
|
|||||||
} from "@plane/types";
|
} from "@plane/types";
|
||||||
// helpers
|
// helpers
|
||||||
import { FiltersHelper } from "./helpers/filters_helpers";
|
import { FiltersHelper } from "./helpers/filters_helpers";
|
||||||
|
// constants
|
||||||
|
import { EViewPageType, viewDefaultFilterParametersByViewTypeAndLayout } from "constants/view";
|
||||||
|
|
||||||
type TLoader = "updating" | undefined;
|
type TLoader = "updating" | undefined;
|
||||||
|
|
||||||
@ -79,7 +81,8 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
private store: RootStore,
|
private store: RootStore,
|
||||||
_view: TView,
|
_view: TView,
|
||||||
private service: TViewService,
|
private service: TViewService,
|
||||||
private userService: TUserViewService
|
private userService: TUserViewService,
|
||||||
|
private viewPageType: EViewPageType
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
this.id = _view.id;
|
this.id = _view.id;
|
||||||
@ -89,7 +92,7 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
this.description = _view.description;
|
this.description = _view.description;
|
||||||
this.query = _view.query;
|
this.query = _view.query;
|
||||||
this.filters = this.computedFilters(_view.filters);
|
this.filters = this.computedFilters(_view.filters);
|
||||||
this.display_filters = this.computedDisplayFilters(_view.display_filters);
|
this.display_filters = this.computedDisplayFilters(this.viewPageType, _view.display_filters);
|
||||||
this.display_properties = this.computedDisplayProperties(_view.display_properties);
|
this.display_properties = this.computedDisplayProperties(_view.display_properties);
|
||||||
this.access = _view.access;
|
this.access = _view.access;
|
||||||
this.owned_by = _view.owned_by;
|
this.owned_by = _view.owned_by;
|
||||||
@ -108,7 +111,7 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
description: this.description,
|
description: this.description,
|
||||||
filters: this.computedFilters(_view.filters),
|
filters: this.computedFilters(_view.filters),
|
||||||
display_filters: this.computedDisplayFilters(_view.display_filters),
|
display_filters: this.computedDisplayFilters(this.viewPageType, _view.display_filters),
|
||||||
display_properties: this.computedDisplayProperties(_view.display_properties),
|
display_properties: this.computedDisplayProperties(_view.display_properties),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -164,7 +167,11 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
get appliedFilters() {
|
get appliedFilters() {
|
||||||
return {
|
return {
|
||||||
filters: this.computedFilters(this.filters, this.filtersToUpdate.filters),
|
filters: this.computedFilters(this.filters, this.filtersToUpdate.filters),
|
||||||
display_filters: this.computedDisplayFilters(this.display_filters, this.filtersToUpdate.display_filters),
|
display_filters: this.computedDisplayFilters(
|
||||||
|
this.viewPageType,
|
||||||
|
this.display_filters,
|
||||||
|
this.filtersToUpdate.display_filters
|
||||||
|
),
|
||||||
display_properties: this.computedDisplayProperties(
|
display_properties: this.computedDisplayProperties(
|
||||||
this.display_properties,
|
this.display_properties,
|
||||||
this.filtersToUpdate.display_properties
|
this.filtersToUpdate.display_properties
|
||||||
@ -173,9 +180,17 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get appliedFiltersQueryParams() {
|
get appliedFiltersQueryParams() {
|
||||||
const filters = this.appliedFilters;
|
const appliedFilters = this.appliedFilters;
|
||||||
if (!filters) return undefined;
|
if (!appliedFilters) return undefined;
|
||||||
return this.computeAppliedFiltersQueryParameters(filters, [])?.query || undefined;
|
|
||||||
|
const layout = appliedFilters?.display_filters?.layout;
|
||||||
|
const requiredFilterProperties = viewDefaultFilterParametersByViewTypeAndLayout(
|
||||||
|
this.viewPageType,
|
||||||
|
layout,
|
||||||
|
"filters"
|
||||||
|
);
|
||||||
|
|
||||||
|
return this.computeAppliedFiltersQueryParameters(appliedFilters, requiredFilterProperties)?.query || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isFiltersApplied() {
|
get isFiltersApplied() {
|
||||||
@ -247,12 +262,18 @@ export class ViewStore extends FiltersHelper implements TViewStore {
|
|||||||
set(this.filtersToUpdate, ["display_filters", _key], display_filters[_key]);
|
set(this.filtersToUpdate, ["display_filters", _key], display_filters[_key]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// update display properties globally
|
||||||
|
|
||||||
|
// updating display properties locally for kanban filters
|
||||||
};
|
};
|
||||||
|
|
||||||
setDisplayProperties = async (displayPropertyKey: keyof TViewDisplayProperties) => {
|
setDisplayProperties = async (displayPropertyKey: keyof TViewDisplayProperties) => {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
update(this.filtersToUpdate, ["display_properties", displayPropertyKey], (_value: boolean = true) => !_value);
|
update(this.filtersToUpdate, ["display_properties", displayPropertyKey], (_value: boolean = true) => !_value);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// update display properties globally
|
||||||
};
|
};
|
||||||
|
|
||||||
setIsEditable = (is_editable: boolean) => {
|
setIsEditable = (is_editable: boolean) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user