-
- {issueIds.length === 0 ? (
+
+ {!totalIssueCount ? (
0
- ? currentView !== "custom-view" && currentView !== "subscribed"
+ ? globalViewId !== "custom-view" && globalViewId !== "subscribed"
? () => {
setTrackElement("All issues empty state");
commandPaletteStore.toggleCreateIssueModal(true, EIssuesStoreType.PROJECT);
@@ -177,11 +188,12 @@ export const AllIssueLayoutRoot: React.FC = observer(() => {
displayProperties={issueFilters?.displayProperties ?? {}}
displayFilters={issueFilters?.displayFilters ?? {}}
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
- issueIds={issueIds}
+ issueIds={Array.isArray(issueIds) ? issueIds : []}
quickActions={renderQuickActions}
updateIssue={updateIssue}
canEditProperties={canEditProperties}
- viewId={globalViewId}
+ viewId={globalViewId.toString()}
+ onEndOfListTrigger={fetchNextPages}
/>
{/* peek overview */}
diff --git a/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx
index ae8ca400a..e692f2988 100644
--- a/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx
@@ -4,13 +4,7 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// mobx store
// components
-import {
- ArchivedIssueListLayout,
- ArchivedIssueAppliedFiltersRoot,
- ProjectArchivedEmptyState,
- IssuePeekOverview,
-} from "components/issues";
-import { ListLayoutLoader } from "components/ui";
+import { ArchivedIssueListLayout, ArchivedIssueAppliedFiltersRoot, IssuePeekOverview } from "components/issues";
import { EIssuesStoreType } from "constants/issue";
// ui
import { useIssues } from "hooks/store";
@@ -27,37 +21,19 @@ export const ArchivedIssueLayoutRoot: React.FC = observer(() => {
async () => {
if (workspaceSlug && projectId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader"
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
);
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return ;
- }
-
if (!workspaceSlug || !projectId) return <>>;
return (
-
- {issues?.groupedIssueIds?.length === 0 ? (
-
- ) : (
-
-
-
-
- )}
+
+
);
});
diff --git a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx
index ce0a9943e..59174b78f 100644
--- a/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/cycle-layout-root.tsx
@@ -1,6 +1,5 @@
-import React, { Fragment, useState } from "react";
+import React, { useState } from "react";
import isEmpty from "lodash/isEmpty";
-import size from "lodash/size";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
import useSWR from "swr";
@@ -10,19 +9,32 @@ import { TransferIssues, TransferIssuesModal } from "components/cycles";
import {
CycleAppliedFiltersRoot,
CycleCalendarLayout,
- CycleEmptyState,
CycleGanttLayout,
CycleKanBanLayout,
CycleListLayout,
CycleSpreadsheetLayout,
IssuePeekOverview,
} from "components/issues";
-import { ActiveLoader } from "components/ui";
// constants
-import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
+import { EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { useCycle, useIssues } from "hooks/store";
-// types
-import { IIssueFilterOptions } from "@plane/types";
+
+const CycleIssueLayout = (props: { activeLayout: EIssueLayoutTypes | undefined }) => {
+ switch (props.activeLayout) {
+ case EIssueLayoutTypes.LIST:
+ return ;
+ case EIssueLayoutTypes.KANBAN:
+ return ;
+ case EIssueLayoutTypes.CALENDAR:
+ return ;
+ case EIssueLayoutTypes.GANTT:
+ return ;
+ case EIssueLayoutTypes.SPREADSHEET:
+ return ;
+ default:
+ return null;
+ }
+};
export const CycleLayoutRoot: React.FC = observer(() => {
const router = useRouter();
@@ -40,12 +52,6 @@ export const CycleLayoutRoot: React.FC = observer(() => {
async () => {
if (workspaceSlug && projectId && cycleId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString(), cycleId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader",
- cycleId.toString()
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
@@ -56,37 +62,8 @@ export const CycleLayoutRoot: React.FC = observer(() => {
const cycleDetails = cycleId ? getCycleById(cycleId.toString()) : undefined;
const cycleStatus = cycleDetails?.status?.toLocaleLowerCase() ?? "draft";
- const userFilters = issuesFilter?.issueFilters?.filters;
-
- const issueFilterCount = size(
- Object.fromEntries(
- Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0)
- )
- );
-
- const handleClearAllFilters = () => {
- if (!workspaceSlug || !projectId || !cycleId) return;
- const newFilters: IIssueFilterOptions = {};
- Object.keys(userFilters ?? {}).forEach((key) => {
- newFilters[key as keyof IIssueFilterOptions] = [];
- });
- issuesFilter.updateFilters(
- workspaceSlug.toString(),
- projectId.toString(),
- EIssueFilterType.FILTERS,
- {
- ...newFilters,
- },
- cycleId.toString()
- );
- };
-
if (!workspaceSlug || !projectId || !cycleId) return <>>;
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return <>{activeLayout && }>;
- }
-
return (
<>
setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
@@ -99,36 +76,11 @@ export const CycleLayoutRoot: React.FC = observer(() => {
)}
- {issues?.groupedIssueIds?.length === 0 ? (
-
- 0}
- />
-
- ) : (
-
-
- {activeLayout === "list" ? (
-
- ) : activeLayout === "kanban" ? (
-
- ) : activeLayout === "calendar" ? (
-
- ) : activeLayout === "gantt_chart" ? (
-
- ) : activeLayout === "spreadsheet" ? (
-
- ) : null}
-
- {/* peek overview */}
-
-
- )}
+
+
+
+ {/* peek overview */}
+
>
);
diff --git a/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx b/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx
index 1a1602ad1..19d84b1b9 100644
--- a/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/draft-issue-layout-root.tsx
@@ -4,17 +4,25 @@ import { useRouter } from "next/router";
import useSWR from "swr";
// hooks
import { IssuePeekOverview } from "components/issues/peek-overview";
-import { ActiveLoader } from "components/ui";
-import { EIssuesStoreType } from "constants/issue";
+import { EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { useIssues } from "hooks/store";
// components
-import { ProjectDraftEmptyState } from "../empty-states";
import { DraftIssueAppliedFiltersRoot } from "../filters/applied-filters/roots/draft-issue";
import { DraftKanBanLayout } from "../kanban/roots/draft-issue-root";
import { DraftIssueListLayout } from "../list/roots/draft-issue-root";
// ui
// constants
+const DraftIssueLayout = (props: { activeLayout: EIssueLayoutTypes | undefined }) => {
+ switch (props.activeLayout) {
+ case EIssueLayoutTypes.LIST:
+ return
;
+ case EIssueLayoutTypes.KANBAN:
+ return
;
+ default:
+ return null;
+ }
+};
export const DraftIssueLayoutRoot: React.FC = observer(() => {
// router
const router = useRouter();
@@ -27,11 +35,6 @@ export const DraftIssueLayoutRoot: React.FC = observer(() => {
async () => {
if (workspaceSlug && projectId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader"
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
@@ -41,29 +44,14 @@ export const DraftIssueLayoutRoot: React.FC = observer(() => {
if (!workspaceSlug || !projectId) return <>>;
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return <>{activeLayout &&
}>;
- }
-
return (
-
- {issues?.groupedIssueIds?.length === 0 ? (
-
- ) : (
-
- {activeLayout === "list" ? (
-
- ) : activeLayout === "kanban" ? (
-
- ) : null}
- {/* issue peek overview */}
-
-
- )}
+
+
+ {/* issue peek overview */}
+
+
);
});
diff --git a/web/components/issues/issue-layouts/roots/module-layout-root.tsx b/web/components/issues/issue-layouts/roots/module-layout-root.tsx
index 268a2c60c..647e74a27 100644
--- a/web/components/issues/issue-layouts/roots/module-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/module-layout-root.tsx
@@ -1,5 +1,4 @@
-import React, { Fragment } from "react";
-import size from "lodash/size";
+import React from "react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
import useSWR from "swr";
@@ -9,18 +8,32 @@ import {
IssuePeekOverview,
ModuleAppliedFiltersRoot,
ModuleCalendarLayout,
- ModuleEmptyState,
ModuleGanttLayout,
ModuleKanBanLayout,
ModuleListLayout,
ModuleSpreadsheetLayout,
} from "components/issues";
-import { ActiveLoader } from "components/ui";
// constants
-import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
+import { EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { useIssues } from "hooks/store";
// types
-import { IIssueFilterOptions } from "@plane/types";
+
+const ModuleIssueLayout = (props: { activeLayout: EIssueLayoutTypes | undefined }) => {
+ switch (props.activeLayout) {
+ case EIssueLayoutTypes.LIST:
+ return
;
+ case EIssueLayoutTypes.KANBAN:
+ return
;
+ case EIssueLayoutTypes.CALENDAR:
+ return
;
+ case EIssueLayoutTypes.GANTT:
+ return
;
+ case EIssueLayoutTypes.SPREADSHEET:
+ return
;
+ default:
+ return null;
+ }
+};
export const ModuleLayoutRoot: React.FC = observer(() => {
// router
@@ -36,84 +49,23 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
async () => {
if (workspaceSlug && projectId && moduleId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString(), moduleId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader",
- moduleId.toString()
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
);
- const userFilters = issuesFilter?.issueFilters?.filters;
-
- const issueFilterCount = size(
- Object.fromEntries(
- Object.entries(userFilters ?? {}).filter(([, value]) => value && Array.isArray(value) && value.length > 0)
- )
- );
-
- const handleClearAllFilters = () => {
- if (!workspaceSlug || !projectId || !moduleId) return;
- const newFilters: IIssueFilterOptions = {};
- Object.keys(userFilters ?? {}).forEach((key) => {
- newFilters[key as keyof IIssueFilterOptions] = [];
- });
- issuesFilter.updateFilters(
- workspaceSlug.toString(),
- projectId.toString(),
- EIssueFilterType.FILTERS,
- {
- ...newFilters,
- },
- moduleId.toString()
- );
- };
-
if (!workspaceSlug || !projectId || !moduleId) return <>>;
const activeLayout = issuesFilter?.issueFilters?.displayFilters?.layout || undefined;
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return <>{activeLayout &&
}>;
- }
-
return (
-
- {issues?.groupedIssueIds?.length === 0 ? (
-
- 0}
- />
-
- ) : (
-
-
- {activeLayout === "list" ? (
-
- ) : activeLayout === "kanban" ? (
-
- ) : activeLayout === "calendar" ? (
-
- ) : activeLayout === "gantt_chart" ? (
-
- ) : activeLayout === "spreadsheet" ? (
-
- ) : null}
-
- {/* peek overview */}
-
-
- )}
+
+
+
+ {/* peek overview */}
+
);
});
diff --git a/web/components/issues/issue-layouts/roots/project-layout-root.tsx b/web/components/issues/issue-layouts/roots/project-layout-root.tsx
index a57d73b2c..f3ee870b1 100644
--- a/web/components/issues/issue-layouts/roots/project-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/project-layout-root.tsx
@@ -1,4 +1,4 @@
-import { FC, Fragment } from "react";
+import { FC } from "react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
import useSWR from "swr";
@@ -12,16 +12,31 @@ import {
KanBanLayout,
ProjectAppliedFiltersRoot,
ProjectSpreadsheetLayout,
- ProjectEmptyState,
IssuePeekOverview,
} from "components/issues";
// hooks
// helpers
-import { ActiveLoader } from "components/ui";
// constants
-import { EIssuesStoreType } from "constants/issue";
+import { EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { useIssues } from "hooks/store";
+const ProjectIssueLayout = (props: { activeLayout: EIssueLayoutTypes | undefined }) => {
+ switch (props.activeLayout) {
+ case EIssueLayoutTypes.LIST:
+ return
;
+ case EIssueLayoutTypes.KANBAN:
+ return
;
+ case EIssueLayoutTypes.CALENDAR:
+ return
;
+ case EIssueLayoutTypes.GANTT:
+ return
;
+ case EIssueLayoutTypes.SPREADSHEET:
+ return
;
+ default:
+ return null;
+ }
+};
+
export const ProjectLayoutRoot: FC = observer(() => {
// router
const router = useRouter();
@@ -34,11 +49,6 @@ export const ProjectLayoutRoot: FC = observer(() => {
async () => {
if (workspaceSlug && projectId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader"
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
@@ -48,42 +58,21 @@ export const ProjectLayoutRoot: FC = observer(() => {
if (!workspaceSlug || !projectId) return <>>;
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return <>{activeLayout &&
}>;
- }
-
return (
-
- {issues?.groupedIssueIds?.length === 0 ? (
-
- ) : (
-
-
- {/* mutation loader */}
- {issues?.loader === "mutation" && (
-
-
-
- )}
- {activeLayout === "list" ? (
-
- ) : activeLayout === "kanban" ? (
-
- ) : activeLayout === "calendar" ? (
-
- ) : activeLayout === "gantt_chart" ? (
-
- ) : activeLayout === "spreadsheet" ? (
-
- ) : null}
+
+ {/* mutation loader */}
+ {issues?.loader === "mutation" && (
+
+
+ )}
+
+
- {/* peek overview */}
-
-
- )}
+ {/* peek overview */}
+
);
});
diff --git a/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx b/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx
index d15e65865..052b77b4e 100644
--- a/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx
+++ b/web/components/issues/issue-layouts/roots/project-view-layout-root.tsx
@@ -1,4 +1,4 @@
-import React, { Fragment } from "react";
+import React from "react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
import useSWR from "swr";
@@ -8,18 +8,33 @@ import {
IssuePeekOverview,
ProjectViewAppliedFiltersRoot,
ProjectViewCalendarLayout,
- ProjectViewEmptyState,
ProjectViewGanttLayout,
ProjectViewKanBanLayout,
ProjectViewListLayout,
ProjectViewSpreadsheetLayout,
} from "components/issues";
-import { ActiveLoader } from "components/ui";
// constants
-import { EIssuesStoreType } from "constants/issue";
+import { EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { useIssues } from "hooks/store";
// types
+const ProjectViewIssueLayout = (props: { activeLayout: EIssueLayoutTypes | undefined }) => {
+ switch (props.activeLayout) {
+ case EIssueLayoutTypes.LIST:
+ return ;
+ case EIssueLayoutTypes.KANBAN:
+ return ;
+ case EIssueLayoutTypes.CALENDAR:
+ return ;
+ case EIssueLayoutTypes.GANTT:
+ return ;
+ case EIssueLayoutTypes.SPREADSHEET:
+ return ;
+ default:
+ return null;
+ }
+};
+
export const ProjectViewLayoutRoot: React.FC = observer(() => {
// router
const router = useRouter();
@@ -32,12 +47,6 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => {
async () => {
if (workspaceSlug && projectId && viewId) {
await issuesFilter?.fetchFilters(workspaceSlug.toString(), projectId.toString(), viewId.toString());
- await issues?.fetchIssues(
- workspaceSlug.toString(),
- projectId.toString(),
- issues?.groupedIssueIds ? "mutation" : "init-loader",
- viewId.toString()
- );
}
},
{ revalidateIfStale: false, revalidateOnFocus: false }
@@ -47,38 +56,15 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => {
if (!workspaceSlug || !projectId || !viewId) return <>>;
- if (issues?.loader === "init-loader" || !issues?.groupedIssueIds) {
- return <>{activeLayout && }>;
- }
-
return (
+
- {issues?.groupedIssueIds?.length === 0 ? (
-
- ) : (
-
-
- {activeLayout === "list" ? (
-
- ) : activeLayout === "kanban" ? (
-
- ) : activeLayout === "calendar" ? (
-
- ) : activeLayout === "gantt_chart" ? (
-
- ) : activeLayout === "spreadsheet" ? (
-
- ) : null}
-
-
- {/* peek overview */}
-
-
- )}
+ {/* peek overview */}
+
);
});
diff --git a/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx b/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
index 653cc28f2..6c2a85213 100644
--- a/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/base-spreadsheet-root.tsx
@@ -2,7 +2,7 @@ import { FC, useCallback } from "react";
import { observer } from "mobx-react-lite";
import { useRouter } from "next/router";
// hooks
-import { EIssueFilterType, EIssuesStoreType } from "constants/issue";
+import { EIssueFilterType, EIssueLayoutTypes, EIssuesStoreType } from "constants/issue";
import { EUserProjectRoles } from "constants/project";
import { useIssues, useUser } from "hooks/store";
import { useIssuesActions } from "hooks/use-issues-actions";
@@ -12,6 +12,8 @@ import { useIssuesActions } from "hooks/use-issues-actions";
import { TIssue, IIssueDisplayFilterOptions, TUnGroupedIssues } from "@plane/types";
import { IQuickActionProps } from "../list/list-view-types";
import { SpreadsheetView } from "./spreadsheet-view";
+import useSWR from "swr";
+import { IssueLayoutHOC } from "../issue-layout-HOC";
export type SpreadsheetStoreType =
| EIssuesStoreType.PROJECT
@@ -36,13 +38,30 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
membership: { currentProjectRole },
} = useUser();
const { issues, issuesFilter } = useIssues(storeType);
- const { updateIssue, removeIssue, removeIssueFromView, archiveIssue, restoreIssue, updateFilters } =
- useIssuesActions(storeType);
+ const {
+ fetchIssues,
+ fetchNextIssues,
+ updateIssue,
+ removeIssue,
+ removeIssueFromView,
+ archiveIssue,
+ restoreIssue,
+ updateFilters,
+ } = useIssuesActions(storeType);
// derived values
const { enableInlineEditing, enableQuickAdd, enableIssueCreation } = issues?.viewFlags || {};
// user role validation
const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER;
+ useSWR(
+ `ISSUE_SPREADSHEET_LAYOUT_${storeType}`,
+ () => fetchIssues("init-loader", { canGroup: false, perPageCount: 100 }),
+ {
+ revalidateOnFocus: false,
+ revalidateOnReconnect: false,
+ }
+ );
+
const canEditProperties = useCallback(
(projectId: string | undefined) => {
const isEditingAllowedBasedOnProject =
@@ -53,7 +72,7 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
[canEditPropertiesBasedOnProject, enableInlineEditing, isEditingAllowed]
);
- const issueIds = (issues.groupedIssueIds ?? []) as TUnGroupedIssues;
+ const issueIds = issues.groupedIssueIds?.["All Issues"]?.issueIds ?? [];
const handleDisplayFiltersUpdate = useCallback(
(updatedDisplayFilter: Partial) => {
@@ -83,19 +102,24 @@ export const BaseSpreadsheetRoot = observer((props: IBaseSpreadsheetRoot) => {
[isEditingAllowed, isCompletedCycle, removeIssue, updateIssue, removeIssueFromView, archiveIssue, restoreIssue]
);
+ if (!Array.isArray(issueIds)) return null;
+
return (
-
+
+
+
);
});
diff --git a/web/components/issues/issue-layouts/spreadsheet/issue-column.tsx b/web/components/issues/issue-layouts/spreadsheet/issue-column.tsx
index 825c2b31c..fd6614cec 100644
--- a/web/components/issues/issue-layouts/spreadsheet/issue-column.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/issue-column.tsx
@@ -14,7 +14,9 @@ type Props = {
issueDetail: TIssue;
disableUserActions: boolean;
property: keyof IIssueDisplayProperties;
- updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined;
+ updateIssue:
+ | ((projectId: string | undefined | null, issueId: string, data: Partial) => Promise)
+ | undefined;
isEstimateEnabled: boolean;
};
diff --git a/web/components/issues/issue-layouts/spreadsheet/issue-row.tsx b/web/components/issues/issue-layouts/spreadsheet/issue-row.tsx
index 8a8ce29f4..71c11379c 100644
--- a/web/components/issues/issue-layouts/spreadsheet/issue-row.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/issue-row.tsx
@@ -29,7 +29,9 @@ interface Props {
portalElement?: HTMLDivElement | null
) => React.ReactNode;
canEditProperties: (projectId: string | undefined) => boolean;
- updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined;
+ updateIssue:
+ | ((projectId: string | undefined | null, issueId: string, data: Partial) => Promise)
+ | undefined;
portalElement: React.MutableRefObject;
nestingLevel: number;
issueId: string;
@@ -115,7 +117,9 @@ interface IssueRowDetailsProps {
portalElement?: HTMLDivElement | null
) => React.ReactNode;
canEditProperties: (projectId: string | undefined) => boolean;
- updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined;
+ updateIssue:
+ | ((projectId: string | undefined | null, issueId: string, data: Partial) => Promise)
+ | undefined;
portalElement: React.MutableRefObject;
nestingLevel: number;
issueId: string;
@@ -163,7 +167,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
const handleToggleExpand = () => {
setExpanded((prevState) => {
- if (!prevState && workspaceSlug && issueDetail)
+ if (!prevState && workspaceSlug && issueDetail && issueDetail.project_id)
subIssuesStore.fetchSubIssues(workspaceSlug.toString(), issueDetail.project_id, issueDetail.id);
return !prevState;
});
@@ -182,7 +186,7 @@ const IssueRowDetails = observer((props: IssueRowDetailsProps) => {
);
if (!issueDetail) return null;
- const disableUserActions = !canEditProperties(issueDetail.project_id);
+ const disableUserActions = !canEditProperties(issueDetail.project_id ?? undefined);
return (
<>
diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-table.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-table.tsx
index 896d5a4dd..52de26d6a 100644
--- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-table.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-table.tsx
@@ -6,6 +6,7 @@ import { IIssueDisplayFilterOptions, IIssueDisplayProperties, TIssue } from "@pl
//components
import { SpreadsheetIssueRow } from "./issue-row";
import { SpreadsheetHeader } from "./spreadsheet-header";
+import { useIntersectionObserver } from "hooks/use-intersection-observer";
type Props = {
displayProperties: IIssueDisplayProperties;
@@ -18,10 +19,13 @@ type Props = {
customActionButton?: React.ReactElement,
portalElement?: HTMLDivElement | null
) => React.ReactNode;
- updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined;
+ updateIssue:
+ | ((projectId: string | undefined | null, issueId: string, data: Partial) => Promise)
+ | undefined;
canEditProperties: (projectId: string | undefined) => boolean;
portalElement: React.MutableRefObject;
containerRef: MutableRefObject;
+ onEndOfListTrigger: () => void;
};
export const SpreadsheetTable = observer((props: Props) => {
@@ -36,10 +40,12 @@ export const SpreadsheetTable = observer((props: Props) => {
updateIssue,
canEditProperties,
containerRef,
+ onEndOfListTrigger,
} = props;
// states
const isScrolled = useRef(false);
+ const intersectionRef = useRef(null);
const handleScroll = useCallback(() => {
if (!containerRef.current) return;
@@ -74,6 +80,28 @@ export const SpreadsheetTable = observer((props: Props) => {
};
}, [handleScroll, containerRef]);
+ // useEffect(() => {
+ // if (intersectionRef.current) {
+ // const observer = new IntersectionObserver(
+ // (entries) => {
+ // if (entries[0].isIntersecting) onEndOfListTrigger();
+ // },
+ // {
+ // root: containerRef?.current,
+ // rootMargin: `50% 0% 50% 0%`,
+ // }
+ // );
+ // observer.observe(intersectionRef.current);
+ // return () => {
+ // if (intersectionRef.current) {
+ // // eslint-disable-next-line react-hooks/exhaustive-deps
+ // observer.unobserve(intersectionRef.current);
+ // }
+ // };
+ // }
+ // }, [intersectionRef, containerRef]);
+ useIntersectionObserver(containerRef, intersectionRef, onEndOfListTrigger, `50% 0% 50% 0%`);
+
const handleKeyBoardNavigation = useTableKeyboardNavigation();
return (
@@ -102,6 +130,7 @@ export const SpreadsheetTable = observer((props: Props) => {
/>
))}
+ Loading...
);
});
diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx
index ed243d312..a2873776b 100644
--- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx
+++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-view.tsx
@@ -19,7 +19,9 @@ type Props = {
customActionButton?: React.ReactElement,
portalElement?: HTMLDivElement | null
) => React.ReactNode;
- updateIssue: ((projectId: string, issueId: string, data: Partial) => Promise) | undefined;
+ updateIssue:
+ | ((projectId: string | undefined | null, issueId: string, data: Partial) => Promise)
+ | undefined;
openIssuesListModal?: (() => void) | null;
quickAddCallback?: (
workspaceSlug: string,
@@ -29,6 +31,7 @@ type Props = {
) => Promise;
viewId?: string;
canEditProperties: (projectId: string | undefined) => boolean;
+ onEndOfListTrigger: () => void;
enableQuickCreateIssue?: boolean;
disableIssueCreation?: boolean;
};
@@ -46,6 +49,7 @@ export const SpreadsheetView: React.FC = observer((props) => {
canEditProperties,
enableQuickCreateIssue,
disableIssueCreation,
+ onEndOfListTrigger,
} = props;
// refs
const containerRef = useRef(null);
@@ -77,6 +81,7 @@ export const SpreadsheetView: React.FC = observer((props) => {
updateIssue={updateIssue}
canEditProperties={canEditProperties}
containerRef={containerRef}
+ onEndOfListTrigger={onEndOfListTrigger}
/>
diff --git a/web/components/issues/issue-layouts/utils.tsx b/web/components/issues/issue-layouts/utils.tsx
index ffe979a56..293fc5f43 100644
--- a/web/components/issues/issue-layouts/utils.tsx
+++ b/web/components/issues/issue-layouts/utils.tsx
@@ -47,7 +47,7 @@ export const getGroupByColumns = (
case "created_by":
return getCreatedByColumns(member) as any;
default:
- if (includeNone) return [{ id: `null`, name: `All Issues`, payload: {}, icon: undefined }];
+ if (includeNone) return [{ id: `All Issues`, name: `All Issues`, payload: {}, icon: undefined }];
}
};
diff --git a/web/components/issues/issues-mobile-header.tsx b/web/components/issues/issues-mobile-header.tsx
index e0263b8c8..1a9c79af9 100644
--- a/web/components/issues/issues-mobile-header.tsx
+++ b/web/components/issues/issues-mobile-header.tsx
@@ -6,11 +6,17 @@ import { CustomMenu } from "@plane/ui";
// icons
// constants
import { ProjectAnalyticsModal } from "components/analytics";
-import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "constants/issue";
+import {
+ EIssueFilterType,
+ EIssueLayoutTypes,
+ EIssuesStoreType,
+ ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
+ ISSUE_LAYOUTS,
+} from "constants/issue";
// hooks
import { useIssues, useLabel, useMember, useProject, useProjectState } from "hooks/store";
// layouts
-import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
+import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "./issue-layouts";
export const IssuesMobileHeader = () => {
@@ -38,7 +44,7 @@ export const IssuesMobileHeader = () => {
const activeLayout = issueFilters?.displayFilters?.layout;
const handleLayoutChange = useCallback(
- (layout: TIssueLayouts) => {
+ (layout: EIssueLayoutTypes) => {
if (!workspaceSlug || !projectId) return;
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout });
},
diff --git a/web/components/modules/module-mobile-header.tsx b/web/components/modules/module-mobile-header.tsx
index 4763639ed..7e63be058 100644
--- a/web/components/modules/module-mobile-header.tsx
+++ b/web/components/modules/module-mobile-header.tsx
@@ -4,9 +4,15 @@ import { Calendar, ChevronDown, Kanban, List } from "lucide-react";
import { CustomMenu } from "@plane/ui";
import { ProjectAnalyticsModal } from "components/analytics";
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown } from "components/issues";
-import { EIssueFilterType, EIssuesStoreType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT, ISSUE_LAYOUTS } from "constants/issue";
+import {
+ EIssueFilterType,
+ EIssueLayoutTypes,
+ EIssuesStoreType,
+ ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
+ ISSUE_LAYOUTS,
+} from "constants/issue";
import { useIssues, useLabel, useMember, useModule, useProjectState } from "hooks/store";
-import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
+import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
export const ModuleMobileHeader = () => {
const [analyticsModal, setAnalyticsModal] = useState(false);
@@ -34,7 +40,7 @@ export const ModuleMobileHeader = () => {
} = useMember();
const handleLayoutChange = useCallback(
- (layout: TIssueLayouts) => {
+ (layout: EIssueLayoutTypes) => {
if (!workspaceSlug || !projectId) return;
updateFilters(workspaceSlug, projectId, EIssueFilterType.DISPLAY_FILTERS, { layout: layout }, moduleId);
},
diff --git a/web/components/profile/profile-issues-filter.tsx b/web/components/profile/profile-issues-filter.tsx
index 491c00f3a..d6b4162dd 100644
--- a/web/components/profile/profile-issues-filter.tsx
+++ b/web/components/profile/profile-issues-filter.tsx
@@ -4,10 +4,15 @@ import { useRouter } from "next/router";
// components
import { DisplayFiltersSelection, FilterSelection, FiltersDropdown, LayoutSelection } from "components/issues";
// hooks
-import { EIssuesStoreType, EIssueFilterType, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
+import {
+ EIssuesStoreType,
+ EIssueFilterType,
+ ISSUE_DISPLAY_FILTERS_BY_LAYOUT,
+ EIssueLayoutTypes,
+} from "constants/issue";
import { useIssues, useLabel } from "hooks/store";
// constants
-import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions, TIssueLayouts } from "@plane/types";
+import { IIssueDisplayFilterOptions, IIssueDisplayProperties, IIssueFilterOptions } from "@plane/types";
export const ProfileIssuesFilter = observer(() => {
// router
@@ -25,7 +30,7 @@ export const ProfileIssuesFilter = observer(() => {
const activeLayout = issueFilters?.displayFilters?.layout;
const handleLayoutChange = useCallback(
- (layout: TIssueLayouts) => {
+ (layout: EIssueLayoutTypes) => {
if (!workspaceSlug || !userId) return;
updateFilters(
workspaceSlug.toString(),
@@ -94,7 +99,7 @@ export const ProfileIssuesFilter = observer(() => {
return (
handleLayoutChange(layout)}
selectedLayout={activeLayout}
/>
diff --git a/web/components/ui/loader/layouts/calendar-layout-loader.tsx b/web/components/ui/loader/layouts/calendar-layout-loader.tsx
index 6bb75d3c6..db7bc4066 100644
--- a/web/components/ui/loader/layouts/calendar-layout-loader.tsx
+++ b/web/components/ui/loader/layouts/calendar-layout-loader.tsx
@@ -28,7 +28,7 @@ export const CalendarLayoutLoader = () => (
-
+
{[...Array(5)].map((_, index) => (
))}
diff --git a/web/components/ui/loader/layouts/kanban-layout-loader.tsx b/web/components/ui/loader/layouts/kanban-layout-loader.tsx
index b949c1b73..f7419d772 100644
--- a/web/components/ui/loader/layouts/kanban-layout-loader.tsx
+++ b/web/components/ui/loader/layouts/kanban-layout-loader.tsx
@@ -1,16 +1,22 @@
+import { forwardRef } from "react";
+
+export const KanbanIssueBlockLoader = forwardRef((props, ref) => (
+
+));
+
export const KanbanLayoutLoader = ({ cardsInEachColumn = [2, 3, 2, 4, 3] }: { cardsInEachColumn?: number[] }) => (
{cardsInEachColumn.map((cardsInColumn, columnIndex) => (
-
+
-
{Array.from({ length: cardsInColumn }, (_, cardIndex) => (
-
+
))}
))}
diff --git a/web/components/ui/loader/layouts/list-layout-loader.tsx b/web/components/ui/loader/layouts/list-layout-loader.tsx
index 9b861cc97..2936f334e 100644
--- a/web/components/ui/loader/layouts/list-layout-loader.tsx
+++ b/web/components/ui/loader/layouts/list-layout-loader.tsx
@@ -1,7 +1,8 @@
+import { forwardRef } from "react";
import { getRandomInt, getRandomLength } from "../utils";
-const ListItemRow = () => (
-
+export const ListLoaderItemRow = forwardRef
((props, ref) => (
+
@@ -18,7 +19,7 @@ const ListItemRow = () => (
))}
-);
+));
const ListSection = ({ itemCount }: { itemCount: number }) => (
@@ -30,7 +31,7 @@ const ListSection = ({ itemCount }: { itemCount: number }) => (
{[...Array(itemCount)].map((_, index) => (
-
+
))}
diff --git a/web/components/ui/loader/utils.tsx b/web/components/ui/loader/utils.tsx
index 312df038e..3637626ed 100644
--- a/web/components/ui/loader/utils.tsx
+++ b/web/components/ui/loader/utils.tsx
@@ -1,35 +1,6 @@
-import {
- CalendarLayoutLoader,
- GanttLayoutLoader,
- KanbanLayoutLoader,
- ListLayoutLoader,
- SpreadsheetLayoutLoader,
-} from "./layouts";
-
export const getRandomInt = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min;
export const getRandomLength = (lengthArray: string[]) => {
const randomIndex = Math.floor(Math.random() * lengthArray.length);
return `${lengthArray[randomIndex]}`;
};
-
-interface Props {
- layout: string;
-}
-export const ActiveLoader: React.FC
= (props) => {
- const { layout } = props;
- switch (layout) {
- case "list":
- return ;
- case "kanban":
- return ;
- case "spreadsheet":
- return ;
- case "calendar":
- return ;
- case "gantt_chart":
- return ;
- default:
- return ;
- }
-};
diff --git a/web/constants/issue.ts b/web/constants/issue.ts
index d474d2a49..21bc8fb6a 100644
--- a/web/constants/issue.ts
+++ b/web/constants/issue.ts
@@ -6,7 +6,6 @@ import {
IIssueDisplayProperties,
TIssueExtraOptions,
TIssueGroupByOptions,
- TIssueLayouts,
TIssueOrderByOptions,
TIssuePriorities,
TIssueTypeFilters,
@@ -24,6 +23,14 @@ export enum EIssuesStoreType {
DEFAULT = "DEFAULT",
}
+export enum EIssueLayoutTypes {
+ LIST = "list",
+ KANBAN = "kanban",
+ CALENDAR = "calendar",
+ GANTT = "gantt_chart",
+ SPREADSHEET = "spreadsheet",
+}
+
export type TCreateModalStoreTypes =
| EIssuesStoreType.PROJECT
| EIssuesStoreType.PROJECT_VIEW
@@ -115,15 +122,15 @@ export const ISSUE_EXTRA_OPTIONS: {
];
export const ISSUE_LAYOUTS: {
- key: TIssueLayouts;
+ key: EIssueLayoutTypes;
title: string;
icon: any;
}[] = [
- { key: "list", title: "List Layout", icon: List },
- { key: "kanban", title: "Kanban Layout", icon: Kanban },
- { key: "calendar", title: "Calendar Layout", icon: Calendar },
- { key: "spreadsheet", title: "Spreadsheet Layout", icon: Sheet },
- { key: "gantt_chart", title: "Gantt Chart Layout", icon: GanttChartSquare },
+ { key: EIssueLayoutTypes.LIST, title: "List Layout", icon: List },
+ { key: EIssueLayoutTypes.KANBAN, title: "Kanban Layout", icon: Kanban },
+ { key: EIssueLayoutTypes.CALENDAR, title: "Calendar Layout", icon: Calendar },
+ { key: EIssueLayoutTypes.SPREADSHEET, title: "Spreadsheet Layout", icon: Sheet },
+ { key: EIssueLayoutTypes.GANTT, title: "Gantt Chart Layout", icon: GanttChartSquare },
];
export interface ILayoutDisplayFiltersOptions {
diff --git a/web/helpers/issue.helper.ts b/web/helpers/issue.helper.ts
index 3e6689151..7c8ba8554 100644
--- a/web/helpers/issue.helper.ts
+++ b/web/helpers/issue.helper.ts
@@ -4,17 +4,10 @@ import { v4 as uuidv4 } from "uuid";
// types
import { IGanttBlock } from "components/gantt-chart";
// constants
-import { ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
+import { EIssueLayoutTypes, ISSUE_DISPLAY_FILTERS_BY_LAYOUT } from "constants/issue";
import { STATE_GROUPS } from "constants/state";
import { orderArrayBy } from "helpers/array.helper";
-import {
- TIssue,
- TIssueGroupByOptions,
- TIssueLayouts,
- TIssueOrderByOptions,
- TIssueParams,
- TStateGroups,
-} from "@plane/types";
+import { TIssue, TIssueGroupByOptions, TIssueOrderByOptions, TIssueParams, TStateGroups } from "@plane/types";
type THandleIssuesMutation = (
formData: Partial,
@@ -89,7 +82,7 @@ export const handleIssuesMutation: THandleIssuesMutation = (
};
export const handleIssueQueryParamsByLayout = (
- layout: TIssueLayouts | undefined,
+ layout: EIssueLayoutTypes | undefined,
viewType: "my_issues" | "issues" | "profile_issues" | "archived_issues" | "draft_issues"
): TIssueParams[] | null => {
const queryParams: TIssueParams[] = [];
diff --git a/web/hooks/use-intersection-observer.ts b/web/hooks/use-intersection-observer.ts
new file mode 100644
index 000000000..aec2ab5ba
--- /dev/null
+++ b/web/hooks/use-intersection-observer.ts
@@ -0,0 +1,41 @@
+import { RefObject, useState, useEffect } from "react";
+
+export type UseIntersectionObserverProps = {
+ containerRef: RefObject | undefined;
+ elementRef: RefObject;
+ callback: () => void;
+ rootMargin?: string;
+};
+
+export const useIntersectionObserver = (
+ containerRef: RefObject | undefined,
+ elementRef: RefObject,
+ callback: (() => void) | undefined,
+ rootMargin?: string
+) => {
+ useEffect(() => {
+ if (elementRef.current) {
+ const observer = new IntersectionObserver(
+ ([entry]) => {
+ if (entry.isIntersecting) {
+ callback && callback();
+ }
+ },
+ {
+ root: containerRef?.current,
+ rootMargin,
+ }
+ );
+ observer.observe(elementRef.current);
+ return () => {
+ if (elementRef.current) {
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ observer.unobserve(elementRef.current);
+ }
+ };
+ }
+ // When i am passing callback as a dependency, it is causing infinite loop,
+ // Please make sure you fix this eslint lint disable error with caution
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [elementRef, containerRef, rootMargin, callback]);
+};
diff --git a/web/store/issue/archived/filter.store.ts b/web/store/issue/archived/filter.store.ts
index 1d169bb19..461477531 100644
--- a/web/store/issue/archived/filter.store.ts
+++ b/web/store/issue/archived/filter.store.ts
@@ -28,7 +28,7 @@ export interface IArchivedIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise;
@@ -210,8 +210,7 @@ export class ArchivedIssuesFilter extends IssueFilterHelperStore implements IArc
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.archivedIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
+ this.rootIssueStore.archivedIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
this.handleIssuesLocalFilters.set(EIssuesStoreType.ARCHIVED, type, workspaceSlug, projectId, undefined, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/archived/issue.store.ts b/web/store/issue/archived/issue.store.ts
index c3c753236..96bb4040e 100644
--- a/web/store/issue/archived/issue.store.ts
+++ b/web/store/issue/archived/issue.store.ts
@@ -26,6 +26,8 @@ export interface IArchivedIssues extends IBaseIssuesStore {
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise;
restoreIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise;
+
+ quickAddIssue: undefined;
}
export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
@@ -44,6 +46,9 @@ export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
makeObservable(this, {
// action
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
+
restoreIssue: action,
});
// filter store
@@ -61,7 +66,7 @@ export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
this.loader = loadType;
});
this.clear();
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.issueArchiveService.getArchivedIssues(workspaceSlug, projectId, params);
this.onfetchIssues(response, options);
@@ -73,11 +78,11 @@ export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
};
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchNexIssues(response);
@@ -113,4 +118,6 @@ export class ArchivedIssues extends BaseIssuesStore implements IArchivedIssues {
throw error;
}
};
+
+ quickAddIssue = undefined;
}
diff --git a/web/store/issue/cycle/filter.store.ts b/web/store/issue/cycle/filter.store.ts
index 27785616e..753413a27 100644
--- a/web/store/issue/cycle/filter.store.ts
+++ b/web/store/issue/cycle/filter.store.ts
@@ -28,7 +28,7 @@ export interface ICycleIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string, cycleId: string) => Promise;
@@ -222,13 +222,12 @@ export class CycleIssuesFilter extends IssueFilterHelperStore implements ICycleI
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.cycleIssues.fetchIssuesWithExistingPagination(
- workspaceSlug,
- projectId,
- "mutation",
- cycleId
- );
+ this.rootIssueStore.cycleIssues.fetchIssuesWithExistingPagination(
+ workspaceSlug,
+ projectId,
+ "mutation",
+ cycleId
+ );
await this.issueFilterService.patchCycleIssueFilters(workspaceSlug, projectId, cycleId, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/cycle/issue.store.ts b/web/store/issue/cycle/issue.store.ts
index 3a961c9e8..43e3fed35 100644
--- a/web/store/issue/cycle/issue.store.ts
+++ b/web/store/issue/cycle/issue.store.ts
@@ -80,11 +80,15 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
cycleId: observable.ref,
// action
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
addIssueToCycle: action,
removeIssueFromCycle: action,
transferIssuesFromCycle: action,
fetchActiveCycleIssues: action,
+
+ quickAddIssue: action,
});
// service
this.cycleService = new CycleService();
@@ -107,7 +111,7 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
this.cycleId = cycleId;
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.cycleService.getCycleIssues(workspaceSlug, projectId, cycleId, params);
this.onfetchIssues(response, options);
@@ -119,11 +123,11 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
};
fetchNextIssues = async (workspaceSlug: string, projectId: string, cycleId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.cycleService.getCycleIssues(workspaceSlug, projectId, cycleId, params);
this.onfetchNexIssues(response);
@@ -241,4 +245,6 @@ export class CycleIssues extends BaseIssuesStore implements ICycleIssues {
throw error;
}
};
+
+ quickAddIssue = this.issueQuickAdd;
}
diff --git a/web/store/issue/draft/filter.store.ts b/web/store/issue/draft/filter.store.ts
index bde6b3f76..fb92aa3e9 100644
--- a/web/store/issue/draft/filter.store.ts
+++ b/web/store/issue/draft/filter.store.ts
@@ -28,7 +28,7 @@ export interface IDraftIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise;
@@ -107,6 +107,10 @@ export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftI
paginationOptions.group_by = options.groupedBy;
}
+ if (options.after && options.before) {
+ paginationOptions["target_date"] = `${options.after};after,${options.before};before`;
+ }
+
return paginationOptions;
});
@@ -205,8 +209,7 @@ export class DraftIssuesFilter extends IssueFilterHelperStore implements IDraftI
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.draftIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
+ this.rootIssueStore.draftIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
this.handleIssuesLocalFilters.set(EIssuesStoreType.DRAFT, type, workspaceSlug, projectId, undefined, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/draft/issue.store.ts b/web/store/issue/draft/issue.store.ts
index e7d4b26c0..e4f7330ee 100644
--- a/web/store/issue/draft/issue.store.ts
+++ b/web/store/issue/draft/issue.store.ts
@@ -27,6 +27,8 @@ export interface IDraftIssues extends IBaseIssuesStore {
fetchNextIssues: (workspaceSlug: string, projectId: string) => Promise;
createIssue: (workspaceSlug: string, projectId: string, data: Partial) => Promise;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => Promise;
+
+ quickAddIssue: undefined;
}
export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
@@ -43,9 +45,8 @@ export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
makeObservable(this, {
// action
fetchIssues: action,
- createIssue: action,
- updateIssue: action,
- removeIssue: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
});
// filter store
this.issueFilterStore = issueFilterStore;
@@ -62,7 +63,7 @@ export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
this.loader = loadType;
});
this.clear();
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.issueDraftService.getDraftIssues(workspaceSlug, projectId, params);
this.onfetchIssues(response, options);
@@ -74,11 +75,11 @@ export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
};
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchNexIssues(response);
@@ -100,4 +101,6 @@ export class DraftIssues extends BaseIssuesStore implements IDraftIssues {
createIssue = this.createDraftIssue;
updateIssue = this.updateDraftIssue;
+
+ quickAddIssue = undefined;
}
diff --git a/web/store/issue/helpers/base-issues.store.ts b/web/store/issue/helpers/base-issues.store.ts
index 350e69c21..0f97a8e0e 100644
--- a/web/store/issue/helpers/base-issues.store.ts
+++ b/web/store/issue/helpers/base-issues.store.ts
@@ -24,7 +24,7 @@ import {
import { IIssueRootStore } from "../root.store";
import { IBaseIssueFilterStore } from "./issue-filter-helper.store";
// constants
-import { ISSUE_PRIORITIES } from "constants/issue";
+import { EIssueLayoutTypes, ISSUE_PRIORITIES } from "constants/issue";
import { STATE_GROUPS } from "constants/state";
// helpers
import { renderFormattedPayloadDate } from "helpers/date-time.helper";
@@ -44,6 +44,9 @@ export interface IBaseIssuesStore {
issueCount: number | undefined;
pageCount: number | undefined;
+ next_page_results: boolean;
+ prev_page_results: boolean;
+
groupedIssueCount: Record | undefined;
// computed
@@ -96,6 +99,9 @@ export class BaseIssuesStore implements IBaseIssuesStore {
issueCount: number | undefined = undefined;
pageCount: number | undefined = undefined;
+ next_page_results: boolean = true;
+ prev_page_results: boolean = false;
+
paginationOptions: IssuePaginationOptions | undefined = undefined;
isArchived: boolean;
@@ -119,6 +125,8 @@ export class BaseIssuesStore implements IBaseIssuesStore {
prevCursor: observable.ref,
issueCount: observable.ref,
pageCount: observable.ref,
+ next_page_results: observable.ref,
+ prev_page_results: observable.ref,
paginationOptions: observable,
// computed
@@ -134,7 +142,6 @@ export class BaseIssuesStore implements IBaseIssuesStore {
updateIssue: action,
removeIssue: action,
archiveIssue: action,
- quickAddIssue: action,
removeBulkIssues: action,
});
this.rootIssueStore = _rootStore;
@@ -155,6 +162,9 @@ export class BaseIssuesStore implements IBaseIssuesStore {
this.issueCount = issuesResponse.count;
this.pageCount = issuesResponse.total_pages;
+
+ this.next_page_results = issuesResponse.next_page_results;
+ this.prev_page_results = issuesResponse.prev_page_results;
};
get groupedIssueIds() {
@@ -172,22 +182,22 @@ export class BaseIssuesStore implements IBaseIssuesStore {
this.issues,
this.isArchived ? "archived" : "un-archived"
);
- if (!currentIssues) return {};
+ if (!currentIssues) return { "All Issues": { issueIds: [], issueCount: 0 } };
let groupedIssues: TGroupedIssues | TSubGroupedIssues | TUnGroupedIssues = {};
- if (layout === "list" && orderBy) {
+ if (layout === EIssueLayoutTypes.LIST && orderBy) {
if (groupBy) groupedIssues = this.groupedIssues(groupBy, orderBy, currentIssues, this.groupedIssueCount);
else groupedIssues = this.unGroupedIssues(orderBy, currentIssues, this.issueCount);
- } else if (layout === "kanban" && groupBy && orderBy) {
+ } else if (layout === EIssueLayoutTypes.KANBAN && groupBy && orderBy) {
if (subGroupBy)
groupedIssues = this.subGroupedIssues(subGroupBy, groupBy, orderBy, currentIssues, this.groupedIssueCount);
else groupedIssues = this.groupedIssues(groupBy, orderBy, currentIssues, this.groupedIssueCount);
- } else if (layout === "calendar")
+ } else if (layout === EIssueLayoutTypes.CALENDAR)
groupedIssues = this.groupedIssues("target_date", "target_date", currentIssues, this.groupedIssueCount, true);
- else if (layout === "spreadsheet")
+ else if (layout === EIssueLayoutTypes.SPREADSHEET)
groupedIssues = this.unGroupedIssues(orderBy ?? "-created_at", currentIssues, this.issueCount);
- else if (layout === "gantt_chart")
+ else if (layout === EIssueLayoutTypes.GANTT)
groupedIssues = this.unGroupedIssues(orderBy ?? "sort_order", currentIssues, this.issueCount);
return groupedIssues;
@@ -308,7 +318,7 @@ export class BaseIssuesStore implements IBaseIssuesStore {
}
}
- async quickAddIssue(workspaceSlug: string, projectId: string, data: TIssue) {
+ async issueQuickAdd(workspaceSlug: string, projectId: string, data: TIssue) {
if (!this.issues) this.issues = [];
try {
this.addIssue(data);
@@ -400,8 +410,8 @@ export class BaseIssuesStore implements IBaseIssuesStore {
}
for (const group of groupArray) {
- if (group && currentIssues[group]) currentIssues[group].issueIds.push(currentIssue.id);
- else if (group) currentIssues[group].issueIds = [currentIssue.id];
+ if (!currentIssues[group]) currentIssues[group] = { issueIds: [], issueCount: groupedIssueCount[group] };
+ if (group) currentIssues[group].issueIds.push(currentIssue.id);
}
}
diff --git a/web/store/issue/helpers/issue-filter-helper.store.ts b/web/store/issue/helpers/issue-filter-helper.store.ts
index 41222eeed..1af7ae5b5 100644
--- a/web/store/issue/helpers/issue-filter-helper.store.ts
+++ b/web/store/issue/helpers/issue-filter-helper.store.ts
@@ -209,19 +209,6 @@ export class IssueFilterHelperStore implements IIssueFilterHelperStore {
cycle: displayProperties?.cycle ?? true,
});
- /**
- * This Method returns true if the display properties changed requires a server side update
- * @param displayFilters
- * @returns
- */
- requiresServerUpdate = (displayFilters: IIssueDisplayFilterOptions) => {
- const SERVER_DISPLAY_FILTERS = ["sub_issue", "type"];
- const displayFilterKeys = Object.keys(displayFilters);
-
- return SERVER_DISPLAY_FILTERS.some((serverDisplayfilter: string) =>
- displayFilterKeys.includes(serverDisplayfilter)
- );
- };
handleIssuesLocalFilters = {
fetchFiltersFromStorage: () => {
diff --git a/web/store/issue/issue_calendar_view.store.ts b/web/store/issue/issue_calendar_view.store.ts
index 98181d730..ee2b79811 100644
--- a/web/store/issue/issue_calendar_view.store.ts
+++ b/web/store/issue/issue_calendar_view.store.ts
@@ -5,6 +5,7 @@ import { ICalendarPayload, ICalendarWeek } from "components/issues";
import { generateCalendarData } from "helpers/calendar.helper";
// types
import { getWeekNumberOfDate } from "helpers/date-time.helper";
+import { computedFn } from "mobx-utils";
export interface ICalendarStore {
calendarFilters: {
@@ -25,6 +26,7 @@ export interface ICalendarStore {
| undefined;
activeWeekNumber: number;
allDaysOfActiveWeek: ICalendarWeek | undefined;
+ getStartAndEndDate: (layout: "week" | "month") => { startDate: string; endDate: string } | undefined;
}
export class CalendarStore implements ICalendarStore {
@@ -82,6 +84,22 @@ export class CalendarStore implements ICalendarStore {
];
}
+ getStartAndEndDate = computedFn((layout: "week" | "month") => {
+ switch (layout) {
+ case "week":
+ if (!this.allDaysOfActiveWeek) return;
+ const dates = Object.keys(this.allDaysOfActiveWeek);
+ return { startDate: dates[0], endDate: dates[dates.length - 1] };
+ case "month":
+ if (!this.allWeeksOfActiveMonth) return;
+ const weeks = Object.keys(this.allWeeksOfActiveMonth);
+ const firstWeekDates = Object.keys(this.allWeeksOfActiveMonth[weeks[0]]);
+ const lastWeekDates = Object.keys(this.allWeeksOfActiveMonth[weeks[weeks.length - 1]]);
+
+ return { startDate: firstWeekDates[0], endDate: lastWeekDates[lastWeekDates.length - 1] };
+ }
+ });
+
updateCalendarFilters = (filters: Partial<{ activeMonthDate: Date; activeWeekDate: Date }>) => {
this.updateCalendarPayload(filters.activeMonthDate || filters.activeWeekDate || new Date());
diff --git a/web/store/issue/module/filter.store.ts b/web/store/issue/module/filter.store.ts
index a3359d16e..8dfb5cb25 100644
--- a/web/store/issue/module/filter.store.ts
+++ b/web/store/issue/module/filter.store.ts
@@ -28,7 +28,7 @@ export interface IModuleIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string, moduleId: string) => Promise;
@@ -221,13 +221,12 @@ export class ModuleIssuesFilter extends IssueFilterHelperStore implements IModul
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.moduleIssues.fetchIssuesWithExistingPagination(
- workspaceSlug,
- projectId,
- "mutation",
- moduleId
- );
+ this.rootIssueStore.moduleIssues.fetchIssuesWithExistingPagination(
+ workspaceSlug,
+ projectId,
+ "mutation",
+ moduleId
+ );
await this.issueFilterService.patchModuleIssueFilters(workspaceSlug, projectId, moduleId, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/module/issue.store.ts b/web/store/issue/module/issue.store.ts
index 156fe486b..56338b525 100644
--- a/web/store/issue/module/issue.store.ts
+++ b/web/store/issue/module/issue.store.ts
@@ -79,12 +79,16 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
moduleId: observable.ref,
// action
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
addIssuesToModule: action,
removeIssuesFromModule: action,
addModulesToIssue: action,
removeModulesFromIssue: action,
removeIssueFromModule: action,
+
+ quickAddIssue: action,
});
// filter store
this.issueFilterStore = issueFilterStore;
@@ -107,7 +111,7 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
this.moduleId = moduleId;
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
this.onfetchIssues(response, options);
@@ -119,11 +123,11 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
};
fetchNextIssues = async (workspaceSlug: string, projectId: string, moduleId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.moduleService.getModuleIssues(workspaceSlug, projectId, moduleId, params);
this.onfetchNexIssues(response);
@@ -295,4 +299,6 @@ export class ModuleIssues extends BaseIssuesStore implements IModuleIssues {
throw error;
}
};
+
+ quickAddIssue = this.issueQuickAdd;
}
diff --git a/web/store/issue/profile/filter.store.ts b/web/store/issue/profile/filter.store.ts
index 11b1dbd9d..991611853 100644
--- a/web/store/issue/profile/filter.store.ts
+++ b/web/store/issue/profile/filter.store.ts
@@ -30,7 +30,7 @@ export interface IProfileIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, userId: string) => Promise;
@@ -212,8 +212,7 @@ export class ProfileIssuesFilter extends IssueFilterHelperStore implements IProf
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.profileIssues.fetchIssuesWithExistingPagination(workspaceSlug, userId, "mutation");
+ this.rootIssueStore.profileIssues.fetchIssuesWithExistingPagination(workspaceSlug, userId, "mutation");
this.handleIssuesLocalFilters.set(EIssuesStoreType.PROFILE, type, workspaceSlug, userId, undefined, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/profile/issue.store.ts b/web/store/issue/profile/issue.store.ts
index 7d4ba0f21..8a43caed2 100644
--- a/web/store/issue/profile/issue.store.ts
+++ b/web/store/issue/profile/issue.store.ts
@@ -32,6 +32,8 @@ export interface IProfileIssues extends IBaseIssuesStore {
createIssue: (workspaceSlug: string, projectId: string, data: Partial) => Promise;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => Promise;
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise;
+
+ quickAddIssue: undefined;
}
export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
@@ -51,6 +53,8 @@ export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
// action
setViewId: action.bound,
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
});
// filter store
this.issueFilterStore = issueFilterStore;
@@ -91,7 +95,7 @@ export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
this.setViewId(view);
- let params = this.issueFilterStore?.getFilterParams(options);
+ let params = this.issueFilterStore?.getFilterParams(options, undefined);
params = {
...params,
assignees: undefined,
@@ -113,7 +117,7 @@ export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
};
fetchNextIssues = async (workspaceSlug: string, userId: string) => {
- if (!this.paginationOptions || !this.currentView) return;
+ if (!this.paginationOptions || !this.currentView || !this.next_page_results) return;
try {
this.loader = "pagination";
@@ -142,4 +146,6 @@ export class ProfileIssues extends BaseIssuesStore implements IProfileIssues {
if (!this.paginationOptions || !this.currentView) return;
return await this.fetchIssues(workspaceSlug, userId, loadType, this.paginationOptions, this.currentView);
};
+
+ quickAddIssue = undefined;
}
diff --git a/web/store/issue/project-views/filter.store.ts b/web/store/issue/project-views/filter.store.ts
index 9cfffde1e..6a5dad963 100644
--- a/web/store/issue/project-views/filter.store.ts
+++ b/web/store/issue/project-views/filter.store.ts
@@ -28,7 +28,7 @@ export interface IProjectViewIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string, viewId: string) => Promise;
@@ -216,12 +216,7 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.projectViewIssues.fetchIssuesWithExistingPagination(
- workspaceSlug,
- projectId,
- "mutation"
- );
+ this.rootIssueStore.projectViewIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
await this.issueFilterService.patchView(workspaceSlug, projectId, viewId, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/project-views/issue.store.ts b/web/store/issue/project-views/issue.store.ts
index 701d0c3d4..9c3ea1d50 100644
--- a/web/store/issue/project-views/issue.store.ts
+++ b/web/store/issue/project-views/issue.store.ts
@@ -44,6 +44,8 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs
makeObservable(this, {
// action
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
});
//filter store
this.issueFilterStore = issueFilterStore;
@@ -60,7 +62,7 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs
this.loader = loadType;
});
this.clear();
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchIssues(response, options);
@@ -72,11 +74,11 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs
};
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchNexIssues(response);
@@ -91,4 +93,6 @@ export class ProjectViewIssues extends BaseIssuesStore implements IProjectViewIs
if (!this.paginationOptions) return;
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
};
+
+ quickAddIssue = this.issueQuickAdd;
}
diff --git a/web/store/issue/project/filter.store.ts b/web/store/issue/project/filter.store.ts
index 78cec2c8c..8d286125e 100644
--- a/web/store/issue/project/filter.store.ts
+++ b/web/store/issue/project/filter.store.ts
@@ -28,7 +28,7 @@ export interface IProjectIssuesFilter extends IBaseIssueFilterStore {
//helper actions
getFilterParams: (
options: IssuePaginationOptions,
- cursor?: string
+ cursor: string | undefined
) => Partial>;
// action
fetchFilters: (workspaceSlug: string, projectId: string) => Promise;
@@ -107,6 +107,10 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj
paginationOptions.group_by = options.groupedBy;
}
+ if (options.after && options.before) {
+ paginationOptions["target_date"] = `${options.after};after,${options.before};before`;
+ }
+
return paginationOptions;
});
@@ -217,8 +221,7 @@ export class ProjectIssuesFilter extends IssueFilterHelperStore implements IProj
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
- this.rootIssueStore.projectIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
+ this.rootIssueStore.projectIssues.fetchIssuesWithExistingPagination(workspaceSlug, projectId, "mutation");
await this.issueFilterService.patchProjectIssueFilters(workspaceSlug, projectId, {
display_filters: _filters.displayFilters,
diff --git a/web/store/issue/project/issue.store.ts b/web/store/issue/project/issue.store.ts
index 42f9f20e4..a7a853784 100644
--- a/web/store/issue/project/issue.store.ts
+++ b/web/store/issue/project/issue.store.ts
@@ -47,6 +47,8 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
fetchIssues: action,
fetchNextIssues: action,
fetchIssuesWithExistingPagination: action,
+
+ quickAddIssue: action,
});
// filter store
this.issueFilterStore = issueFilterStore;
@@ -63,7 +65,7 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
this.loader = loadType;
});
this.clear();
- const params = this.issueFilterStore?.getFilterParams(options);
+ const params = this.issueFilterStore?.getFilterParams(options, undefined);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchIssues(response, options);
@@ -75,11 +77,11 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
};
fetchNextIssues = async (workspaceSlug: string, projectId: string) => {
- if (!this.paginationOptions) return;
+ if (!this.paginationOptions || !this.next_page_results) return;
try {
this.loader = "pagination";
- const params = this.issueFilterStore?.getFilterParams(this.paginationOptions);
+ const params = this.issueFilterStore?.getFilterParams(this.paginationOptions, this.nextCursor);
const response = await this.issueService.getIssues(workspaceSlug, projectId, params);
this.onfetchNexIssues(response);
@@ -98,4 +100,6 @@ export class ProjectIssues extends BaseIssuesStore implements IProjectIssues {
if (!this.paginationOptions) return;
return await this.fetchIssues(workspaceSlug, projectId, loadType, this.paginationOptions);
};
+
+ quickAddIssue = this.issueQuickAdd;
}
diff --git a/web/store/issue/workspace/filter.store.ts b/web/store/issue/workspace/filter.store.ts
index b1870dcd6..1791c7cfd 100644
--- a/web/store/issue/workspace/filter.store.ts
+++ b/web/store/issue/workspace/filter.store.ts
@@ -237,7 +237,6 @@ export class WorkspaceIssuesFilter extends IssueFilterHelperStore implements IWo
});
});
- if (this.requiresServerUpdate(updatedDisplayFilters))
this.rootIssueStore.workspaceIssues.fetchIssuesWithExistingPagination(workspaceSlug, viewId, "mutation");
if (["all-issues", "assigned", "created", "subscribed"].includes(viewId))
diff --git a/web/store/issue/workspace/issue.store.ts b/web/store/issue/workspace/issue.store.ts
index d1c8917de..31db275f1 100644
--- a/web/store/issue/workspace/issue.store.ts
+++ b/web/store/issue/workspace/issue.store.ts
@@ -24,9 +24,12 @@ export interface IWorkspaceIssues extends IBaseIssuesStore {
loadType: TLoader
) => Promise;
fetchNextIssues: (workspaceSlug: string, viewId: string) => Promise;
+
createIssue: (workspaceSlug: string, projectId: string, data: Partial) => Promise;
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial) => Promise;
archiveIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise;
+
+ quickAddIssue: undefined;
}
export class WorkspaceIssues extends BaseIssuesStore implements IWorkspaceIssues {
@@ -46,6 +49,8 @@ export class WorkspaceIssues extends BaseIssuesStore implements IWorkspaceIssues
makeObservable(this, {
// action
fetchIssues: action,
+ fetchNextIssues: action,
+ fetchIssuesWithExistingPagination: action,
});
// services
this.workspaceService = new WorkspaceService();
@@ -90,4 +95,6 @@ export class WorkspaceIssues extends BaseIssuesStore implements IWorkspaceIssues
if (!this.paginationOptions) return;
return await this.fetchIssues(workspaceSlug, viewId, loadType, this.paginationOptions);
};
+
+ quickAddIssue = undefined;
}