mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: add empty state for list and spreadsheet layouts (#2531)
* chore: add empty state for list and spreadsheet layouts * fix: build errors
This commit is contained in:
parent
8eaac60aa5
commit
050406b8a4
25
web/components/issues/issue-layouts/empty-states/cycle.tsx
Normal file
25
web/components/issues/issue-layouts/empty-states/cycle.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { EmptyState } from "components/common";
|
||||||
|
// assets
|
||||||
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
|
export const CycleEmptyState: React.FC = () => (
|
||||||
|
<div className="h-full w-full grid place-items-center">
|
||||||
|
<EmptyState
|
||||||
|
title="Cycle issues will appear here"
|
||||||
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
|
image={emptyIssue}
|
||||||
|
primaryButton={{
|
||||||
|
text: "New issue",
|
||||||
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
|
onClick: () => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,25 @@
|
|||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { EmptyState } from "components/common";
|
||||||
|
// assets
|
||||||
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
|
export const GlobalViewEmptyState: React.FC = () => (
|
||||||
|
<div className="h-full w-full grid place-items-center">
|
||||||
|
<EmptyState
|
||||||
|
title="View issues will appear here"
|
||||||
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
|
image={emptyIssue}
|
||||||
|
primaryButton={{
|
||||||
|
text: "New issue",
|
||||||
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
|
onClick: () => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,5 @@
|
|||||||
|
export * from "./cycle";
|
||||||
|
export * from "./global-view";
|
||||||
|
export * from "./module";
|
||||||
|
export * from "./project-view";
|
||||||
|
export * from "./project";
|
25
web/components/issues/issue-layouts/empty-states/module.tsx
Normal file
25
web/components/issues/issue-layouts/empty-states/module.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { EmptyState } from "components/common";
|
||||||
|
// assets
|
||||||
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
|
export const ModuleEmptyState: React.FC = () => (
|
||||||
|
<div className="h-full w-full grid place-items-center">
|
||||||
|
<EmptyState
|
||||||
|
title="Module issues will appear here"
|
||||||
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
|
image={emptyIssue}
|
||||||
|
primaryButton={{
|
||||||
|
text: "New issue",
|
||||||
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
|
onClick: () => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
@ -0,0 +1,25 @@
|
|||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { EmptyState } from "components/common";
|
||||||
|
// assets
|
||||||
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
|
export const ProjectViewEmptyState: React.FC = () => (
|
||||||
|
<div className="h-full w-full grid place-items-center">
|
||||||
|
<EmptyState
|
||||||
|
title="View issues will appear here"
|
||||||
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
|
image={emptyIssue}
|
||||||
|
primaryButton={{
|
||||||
|
text: "New issue",
|
||||||
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
|
onClick: () => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
25
web/components/issues/issue-layouts/empty-states/project.tsx
Normal file
25
web/components/issues/issue-layouts/empty-states/project.tsx
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import { PlusIcon } from "lucide-react";
|
||||||
|
// components
|
||||||
|
import { EmptyState } from "components/common";
|
||||||
|
// assets
|
||||||
|
import emptyIssue from "public/empty-state/issue.svg";
|
||||||
|
|
||||||
|
export const ProjectEmptyState: React.FC = () => (
|
||||||
|
<div className="h-full w-full grid place-items-center">
|
||||||
|
<EmptyState
|
||||||
|
title="Project issues will appear here"
|
||||||
|
description="Issues help you track individual pieces of work. With Issues, keep track of what's going on, who is working on it, and what's done."
|
||||||
|
image={emptyIssue}
|
||||||
|
primaryButton={{
|
||||||
|
text: "New issue",
|
||||||
|
icon: <PlusIcon className="h-3 w-3" strokeWidth={2} />,
|
||||||
|
onClick: () => {
|
||||||
|
const e = new KeyboardEvent("keydown", {
|
||||||
|
key: "c",
|
||||||
|
});
|
||||||
|
document.dispatchEvent(e);
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
@ -1,5 +1,6 @@
|
|||||||
// filters
|
// filters
|
||||||
export * from "./filters";
|
export * from "./filters";
|
||||||
|
export * from "./empty-states";
|
||||||
export * from "./quick-action-dropdowns";
|
export * from "./quick-action-dropdowns";
|
||||||
|
|
||||||
// layouts
|
// layouts
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export * from "./roots";
|
export * from "./roots";
|
||||||
export * from "./block";
|
export * from "./block";
|
||||||
|
export * from "./roots";
|
||||||
export * from "./blocks-list";
|
export * from "./blocks-list";
|
||||||
export * from "./inline-create-issue-form";
|
export * from "./inline-create-issue-form";
|
||||||
|
@ -68,7 +68,7 @@ export const ModuleListLayout: React.FC = observer(() => {
|
|||||||
: null;
|
: null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`relative w-full h-full bg-custom-background-90`}>
|
<div className="relative w-full h-full bg-custom-background-90">
|
||||||
<List
|
<List
|
||||||
issues={issues}
|
issues={issues}
|
||||||
group_by={group_by}
|
group_by={group_by}
|
||||||
|
@ -8,6 +8,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
import {
|
import {
|
||||||
CycleAppliedFiltersRoot,
|
CycleAppliedFiltersRoot,
|
||||||
CycleCalendarLayout,
|
CycleCalendarLayout,
|
||||||
|
CycleEmptyState,
|
||||||
CycleGanttLayout,
|
CycleGanttLayout,
|
||||||
CycleKanBanLayout,
|
CycleKanBanLayout,
|
||||||
CycleListLayout,
|
CycleListLayout,
|
||||||
@ -50,12 +51,17 @@ export const CycleLayoutRoot: React.FC = observer(() => {
|
|||||||
? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date)
|
? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date)
|
||||||
: "draft";
|
: "draft";
|
||||||
|
|
||||||
|
const issueCount = cycleIssueStore.getIssuesCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
|
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
|
||||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||||
{cycleStatus === "completed" && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
{cycleStatus === "completed" && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||||
<CycleAppliedFiltersRoot />
|
<CycleAppliedFiltersRoot />
|
||||||
|
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||||
|
<CycleEmptyState />
|
||||||
|
) : (
|
||||||
<div className="w-full h-full overflow-auto">
|
<div className="w-full h-full overflow-auto">
|
||||||
{activeLayout === "list" ? (
|
{activeLayout === "list" ? (
|
||||||
<CycleListLayout />
|
<CycleListLayout />
|
||||||
@ -69,6 +75,7 @@ export const CycleLayoutRoot: React.FC = observer(() => {
|
|||||||
<CycleSpreadsheetLayout />
|
<CycleSpreadsheetLayout />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
|||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// components
|
// components
|
||||||
import { GlobalViewsAppliedFiltersRoot, SpreadsheetView } from "components/issues";
|
import { GlobalViewEmptyState, GlobalViewsAppliedFiltersRoot, SpreadsheetView } from "components/issues";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueDisplayFilterOptions, TStaticViewTypes } from "types";
|
import { IIssue, IIssueDisplayFilterOptions, TStaticViewTypes } from "types";
|
||||||
|
|
||||||
@ -81,6 +81,9 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
|
|||||||
return (
|
return (
|
||||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||||
<GlobalViewsAppliedFiltersRoot />
|
<GlobalViewsAppliedFiltersRoot />
|
||||||
|
{issues?.length === 0 ? (
|
||||||
|
<GlobalViewEmptyState />
|
||||||
|
) : (
|
||||||
<div className="h-full w-full overflow-auto">
|
<div className="h-full w-full overflow-auto">
|
||||||
<SpreadsheetView
|
<SpreadsheetView
|
||||||
displayProperties={workspaceFilterStore.workspaceDisplayProperties}
|
displayProperties={workspaceFilterStore.workspaceDisplayProperties}
|
||||||
@ -94,6 +97,7 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
|
|||||||
disableUserActions={false}
|
disableUserActions={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -9,6 +9,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
|||||||
import {
|
import {
|
||||||
ModuleAppliedFiltersRoot,
|
ModuleAppliedFiltersRoot,
|
||||||
ModuleCalendarLayout,
|
ModuleCalendarLayout,
|
||||||
|
ModuleEmptyState,
|
||||||
ModuleGanttLayout,
|
ModuleGanttLayout,
|
||||||
ModuleKanBanLayout,
|
ModuleKanBanLayout,
|
||||||
ModuleListLayout,
|
ModuleListLayout,
|
||||||
@ -46,9 +47,14 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
|
|||||||
|
|
||||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||||
|
|
||||||
|
const issueCount = moduleIssueStore.getIssuesCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||||
<ModuleAppliedFiltersRoot />
|
<ModuleAppliedFiltersRoot />
|
||||||
|
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||||
|
<ModuleEmptyState />
|
||||||
|
) : (
|
||||||
<div className="h-full w-full overflow-auto">
|
<div className="h-full w-full overflow-auto">
|
||||||
{activeLayout === "list" ? (
|
{activeLayout === "list" ? (
|
||||||
<ModuleListLayout />
|
<ModuleListLayout />
|
||||||
@ -62,6 +68,7 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
|
|||||||
<ModuleSpreadsheetLayout />
|
<ModuleSpreadsheetLayout />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
KanBanLayout,
|
KanBanLayout,
|
||||||
ProjectAppliedFiltersRoot,
|
ProjectAppliedFiltersRoot,
|
||||||
ProjectSpreadsheetLayout,
|
ProjectSpreadsheetLayout,
|
||||||
|
ProjectEmptyState,
|
||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
|
|
||||||
export const ProjectLayoutRoot: React.FC = observer(() => {
|
export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||||
@ -30,9 +31,14 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
|||||||
|
|
||||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||||
|
|
||||||
|
const issueCount = issueStore.getIssuesCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||||
<ProjectAppliedFiltersRoot />
|
<ProjectAppliedFiltersRoot />
|
||||||
|
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||||
|
<ProjectEmptyState />
|
||||||
|
) : (
|
||||||
<div className="w-full h-full overflow-auto">
|
<div className="w-full h-full overflow-auto">
|
||||||
{activeLayout === "list" ? (
|
{activeLayout === "list" ? (
|
||||||
<ListLayout />
|
<ListLayout />
|
||||||
@ -46,6 +52,7 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
|||||||
<ProjectSpreadsheetLayout />
|
<ProjectSpreadsheetLayout />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
ModuleListLayout,
|
ModuleListLayout,
|
||||||
ProjectViewAppliedFiltersRoot,
|
ProjectViewAppliedFiltersRoot,
|
||||||
ProjectViewCalendarLayout,
|
ProjectViewCalendarLayout,
|
||||||
|
ProjectViewEmptyState,
|
||||||
ProjectViewGanttLayout,
|
ProjectViewGanttLayout,
|
||||||
ProjectViewSpreadsheetLayout,
|
ProjectViewSpreadsheetLayout,
|
||||||
} from "components/issues";
|
} from "components/issues";
|
||||||
@ -48,9 +49,14 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => {
|
|||||||
|
|
||||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||||
|
|
||||||
|
const issueCount = projectViewIssuesStore.getIssuesCount;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full w-full flex flex-col overflow-hidden">
|
<div className="relative h-full w-full flex flex-col overflow-hidden">
|
||||||
<ProjectViewAppliedFiltersRoot />
|
<ProjectViewAppliedFiltersRoot />
|
||||||
|
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||||
|
<ProjectViewEmptyState />
|
||||||
|
) : (
|
||||||
<div className="h-full w-full overflow-y-auto">
|
<div className="h-full w-full overflow-y-auto">
|
||||||
{activeLayout === "list" ? (
|
{activeLayout === "list" ? (
|
||||||
<ModuleListLayout />
|
<ModuleListLayout />
|
||||||
@ -64,6 +70,7 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => {
|
|||||||
<ProjectViewSpreadsheetLayout />
|
<ProjectViewSpreadsheetLayout />
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -6,15 +6,12 @@ import { IIssue } from "types";
|
|||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||||
|
import {
|
||||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
IIssueGroupWithSubGroupsStructure,
|
||||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
IIssueGroupedStructure,
|
||||||
export type IIssueGroupWithSubGroupsStructure = {
|
IIssueType,
|
||||||
[group_id: string]: {
|
IIssueUnGroupedStructure,
|
||||||
[sub_group_id: string]: IIssue[];
|
} from "store/issue";
|
||||||
};
|
|
||||||
};
|
|
||||||
export type IIssueUnGroupedStructure = IIssue[];
|
|
||||||
|
|
||||||
export interface IArchivedIssueStore {
|
export interface IArchivedIssueStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
|
@ -9,15 +9,12 @@ import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
|||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
import { IBlockUpdateData } from "components/gantt-chart";
|
import { IBlockUpdateData } from "components/gantt-chart";
|
||||||
|
import {
|
||||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
IIssueGroupWithSubGroupsStructure,
|
||||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
IIssueGroupedStructure,
|
||||||
export type IIssueGroupWithSubGroupsStructure = {
|
IIssueType,
|
||||||
[group_id: string]: {
|
IIssueUnGroupedStructure,
|
||||||
[sub_group_id: string]: IIssue[];
|
} from "store/issue";
|
||||||
};
|
|
||||||
};
|
|
||||||
export type IIssueUnGroupedStructure = IIssue[];
|
|
||||||
|
|
||||||
export interface ICycleIssueStore {
|
export interface ICycleIssueStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
@ -33,6 +30,7 @@ export interface ICycleIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: IIssueType | null;
|
getIssueType: IIssueType | null;
|
||||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||||
|
getIssuesCount: number;
|
||||||
// action
|
// action
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<any>;
|
fetchIssues: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<any>;
|
||||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||||
@ -73,6 +71,7 @@ export class CycleIssueStore implements ICycleIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: computed,
|
getIssueType: computed,
|
||||||
getIssues: computed,
|
getIssues: computed,
|
||||||
|
getIssuesCount: computed,
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
updateIssueStructure: action,
|
updateIssueStructure: action,
|
||||||
@ -130,6 +129,44 @@ export class CycleIssueStore implements ICycleIssueStore {
|
|||||||
return this.issues?.[cycleId]?.[issueType] || null;
|
return this.issues?.[cycleId]?.[issueType] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getIssuesCount() {
|
||||||
|
const issueType = this.getIssueType;
|
||||||
|
|
||||||
|
let issuesCount = 0;
|
||||||
|
|
||||||
|
if (issueType === "grouped") {
|
||||||
|
const issues = this.getIssues as IIssueGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((group_id) => {
|
||||||
|
issuesCount += issues[group_id].length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "groupWithSubGroups") {
|
||||||
|
const issues = this.getIssues as IIssueGroupWithSubGroupsStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((sub_group_id) => {
|
||||||
|
Object.keys(issues[sub_group_id]).map((group_id) => {
|
||||||
|
issuesCount += issues[sub_group_id][group_id].length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "ungrouped") {
|
||||||
|
const issues = this.getIssues as IIssueUnGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
issuesCount = issues.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return issuesCount;
|
||||||
|
}
|
||||||
|
|
||||||
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
||||||
const cycleId: string | null = this.rootStore?.cycle?.cycleId || null;
|
const cycleId: string | null = this.rootStore?.cycle?.cycleId || null;
|
||||||
const issueType = this.getIssueType;
|
const issueType = this.getIssueType;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { action, makeObservable, runInAction } from "mobx";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
import { IIssueType } from "./cycle_issue.store";
|
import { IIssueType } from "store/issue";
|
||||||
|
|
||||||
export interface ICycleIssueCalendarViewStore {
|
export interface ICycleIssueCalendarViewStore {
|
||||||
// actions
|
// actions
|
||||||
|
@ -6,15 +6,12 @@ import { IIssue } from "types";
|
|||||||
// services
|
// services
|
||||||
import { IssueService } from "services/issue";
|
import { IssueService } from "services/issue";
|
||||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||||
|
import {
|
||||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
IIssueGroupWithSubGroupsStructure,
|
||||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
IIssueGroupedStructure,
|
||||||
export type IIssueGroupWithSubGroupsStructure = {
|
IIssueType,
|
||||||
[group_id: string]: {
|
IIssueUnGroupedStructure,
|
||||||
[sub_group_id: string]: IIssue[];
|
} from "store/issue";
|
||||||
};
|
|
||||||
};
|
|
||||||
export type IIssueUnGroupedStructure = IIssue[];
|
|
||||||
|
|
||||||
export interface IDraftIssueStore {
|
export interface IDraftIssueStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
|
@ -31,6 +31,7 @@ export interface IIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: IIssueType | null;
|
getIssueType: IIssueType | null;
|
||||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||||
|
getIssuesCount: number;
|
||||||
// action
|
// action
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string) => Promise<any>;
|
fetchIssues: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||||
@ -68,6 +69,7 @@ export class IssueStore implements IIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: computed,
|
getIssueType: computed,
|
||||||
getIssues: computed,
|
getIssues: computed,
|
||||||
|
getIssuesCount: computed,
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
updateIssueStructure: action,
|
updateIssueStructure: action,
|
||||||
@ -120,6 +122,44 @@ export class IssueStore implements IIssueStore {
|
|||||||
return this.issues?.[projectId]?.[issueType] || null;
|
return this.issues?.[projectId]?.[issueType] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getIssuesCount() {
|
||||||
|
const issueType = this.getIssueType;
|
||||||
|
|
||||||
|
let issuesCount = 0;
|
||||||
|
|
||||||
|
if (issueType === "grouped") {
|
||||||
|
const issues = this.getIssues as IIssueGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((group_id) => {
|
||||||
|
issuesCount += issues[group_id].length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "groupWithSubGroups") {
|
||||||
|
const issues = this.getIssues as IIssueGroupWithSubGroupsStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((sub_group_id) => {
|
||||||
|
Object.keys(issues[sub_group_id]).map((group_id) => {
|
||||||
|
issuesCount += issues[sub_group_id][group_id].length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "ungrouped") {
|
||||||
|
const issues = this.getIssues as IIssueUnGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
issuesCount = issues.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return issuesCount;
|
||||||
|
}
|
||||||
|
|
||||||
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
||||||
const projectId: string | null = issue?.project;
|
const projectId: string | null = issue?.project;
|
||||||
const issueType = this.getIssueType;
|
const issueType = this.getIssueType;
|
||||||
|
@ -8,15 +8,12 @@ import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
|||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
import { IBlockUpdateData } from "components/gantt-chart";
|
import { IBlockUpdateData } from "components/gantt-chart";
|
||||||
|
import {
|
||||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
IIssueGroupWithSubGroupsStructure,
|
||||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
IIssueGroupedStructure,
|
||||||
export type IIssueGroupWithSubGroupsStructure = {
|
IIssueType,
|
||||||
[group_id: string]: {
|
IIssueUnGroupedStructure,
|
||||||
[sub_group_id: string]: IIssue[];
|
} from "store/issue";
|
||||||
};
|
|
||||||
};
|
|
||||||
export type IIssueUnGroupedStructure = IIssue[];
|
|
||||||
|
|
||||||
export interface IModuleIssueStore {
|
export interface IModuleIssueStore {
|
||||||
loader: boolean;
|
loader: boolean;
|
||||||
@ -32,6 +29,7 @@ export interface IModuleIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: IIssueType | null;
|
getIssueType: IIssueType | null;
|
||||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||||
|
getIssuesCount: number;
|
||||||
// action
|
// action
|
||||||
fetchIssues: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<any>;
|
fetchIssues: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<any>;
|
||||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||||
@ -76,6 +74,7 @@ export class ModuleIssueStore implements IModuleIssueStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: computed,
|
getIssueType: computed,
|
||||||
getIssues: computed,
|
getIssues: computed,
|
||||||
|
getIssuesCount: computed,
|
||||||
// actions
|
// actions
|
||||||
fetchIssues: action,
|
fetchIssues: action,
|
||||||
updateIssueStructure: action,
|
updateIssueStructure: action,
|
||||||
@ -132,6 +131,44 @@ export class ModuleIssueStore implements IModuleIssueStore {
|
|||||||
return this.issues?.[moduleId]?.[issueType] || null;
|
return this.issues?.[moduleId]?.[issueType] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getIssuesCount() {
|
||||||
|
const issueType = this.getIssueType;
|
||||||
|
|
||||||
|
let issuesCount = 0;
|
||||||
|
|
||||||
|
if (issueType === "grouped") {
|
||||||
|
const issues = this.getIssues as IIssueGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((group_id) => {
|
||||||
|
issuesCount += issues[group_id].length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "groupWithSubGroups") {
|
||||||
|
const issues = this.getIssues as IIssueGroupWithSubGroupsStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((sub_group_id) => {
|
||||||
|
Object.keys(issues[sub_group_id]).map((group_id) => {
|
||||||
|
issuesCount += issues[sub_group_id][group_id].length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "ungrouped") {
|
||||||
|
const issues = this.getIssues as IIssueUnGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
issuesCount = issues.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return issuesCount;
|
||||||
|
}
|
||||||
|
|
||||||
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
||||||
const moduleId: string | null = this.rootStore?.module?.moduleId;
|
const moduleId: string | null = this.rootStore?.module?.moduleId;
|
||||||
const issueType = this.getIssueType;
|
const issueType = this.getIssueType;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { action, makeObservable, runInAction } from "mobx";
|
import { action, makeObservable, runInAction } from "mobx";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
import { IIssueType } from "./module_issue.store";
|
import { IIssueType } from "store/issue";
|
||||||
|
|
||||||
export interface IModuleIssueCalendarViewStore {
|
export interface IModuleIssueCalendarViewStore {
|
||||||
// actions
|
// actions
|
||||||
|
@ -45,6 +45,7 @@ export interface IProjectViewIssuesStore {
|
|||||||
|
|
||||||
// computed
|
// computed
|
||||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||||
|
getIssuesCount: number;
|
||||||
getIssueType: IIssueType | null;
|
getIssueType: IIssueType | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,6 +87,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
|||||||
// computed
|
// computed
|
||||||
getIssueType: computed,
|
getIssueType: computed,
|
||||||
getIssues: computed,
|
getIssues: computed,
|
||||||
|
getIssuesCount: computed,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.rootStore = _rootStore;
|
this.rootStore = _rootStore;
|
||||||
@ -147,6 +149,44 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
|||||||
return this.viewIssues?.[viewId]?.[issueType] || null;
|
return this.viewIssues?.[viewId]?.[issueType] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get getIssuesCount() {
|
||||||
|
const issueType = this.rootStore.issue.getIssueType;
|
||||||
|
|
||||||
|
let issuesCount = 0;
|
||||||
|
|
||||||
|
if (issueType === "grouped") {
|
||||||
|
const issues = this.getIssues as IIssueGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((group_id) => {
|
||||||
|
issuesCount += issues[group_id].length;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "groupWithSubGroups") {
|
||||||
|
const issues = this.getIssues as IIssueGroupWithSubGroupsStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
Object.keys(issues).map((sub_group_id) => {
|
||||||
|
Object.keys(issues[sub_group_id]).map((group_id) => {
|
||||||
|
issuesCount += issues[sub_group_id][group_id].length;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (issueType === "ungrouped") {
|
||||||
|
const issues = this.getIssues as IIssueUnGroupedStructure;
|
||||||
|
|
||||||
|
if (!issues) return 0;
|
||||||
|
|
||||||
|
issuesCount = issues.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return issuesCount;
|
||||||
|
}
|
||||||
|
|
||||||
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
updateIssueStructure = async (group_id: string | null, sub_group_id: string | null, issue: IIssue) => {
|
||||||
const viewId: string | null = this.rootStore.projectViews.viewId;
|
const viewId: string | null = this.rootStore.projectViews.viewId;
|
||||||
const issueType = this.rootStore.issue.getIssueType;
|
const issueType = this.rootStore.issue.getIssueType;
|
||||||
|
Loading…
Reference in New Issue
Block a user