forked from github/plane
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
|
||||
export * from "./filters";
|
||||
export * from "./empty-states";
|
||||
export * from "./quick-action-dropdowns";
|
||||
|
||||
// layouts
|
||||
|
@ -1,4 +1,5 @@
|
||||
export * from "./roots";
|
||||
export * from "./block";
|
||||
export * from "./roots";
|
||||
export * from "./blocks-list";
|
||||
export * from "./inline-create-issue-form";
|
||||
|
@ -68,7 +68,7 @@ export const ModuleListLayout: React.FC = observer(() => {
|
||||
: null;
|
||||
|
||||
return (
|
||||
<div className={`relative w-full h-full bg-custom-background-90`}>
|
||||
<div className="relative w-full h-full bg-custom-background-90">
|
||||
<List
|
||||
issues={issues}
|
||||
group_by={group_by}
|
||||
|
@ -8,6 +8,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import {
|
||||
CycleAppliedFiltersRoot,
|
||||
CycleCalendarLayout,
|
||||
CycleEmptyState,
|
||||
CycleGanttLayout,
|
||||
CycleKanBanLayout,
|
||||
CycleListLayout,
|
||||
@ -50,25 +51,31 @@ export const CycleLayoutRoot: React.FC = observer(() => {
|
||||
? getDateRangeStatus(cycleDetails?.start_date, cycleDetails?.end_date)
|
||||
: "draft";
|
||||
|
||||
const issueCount = cycleIssueStore.getIssuesCount;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TransferIssuesModal handleClose={() => setTransferIssuesModal(false)} isOpen={transferIssuesModal} />
|
||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||
{cycleStatus === "completed" && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||
<CycleAppliedFiltersRoot />
|
||||
<div className="w-full h-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<CycleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<CycleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<CycleCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<CycleGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<CycleSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||
<CycleEmptyState />
|
||||
) : (
|
||||
<div className="w-full h-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<CycleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<CycleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<CycleCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<CycleGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<CycleSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -5,7 +5,7 @@ import useSWR from "swr";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
// components
|
||||
import { GlobalViewsAppliedFiltersRoot, SpreadsheetView } from "components/issues";
|
||||
import { GlobalViewEmptyState, GlobalViewsAppliedFiltersRoot, SpreadsheetView } from "components/issues";
|
||||
// types
|
||||
import { IIssue, IIssueDisplayFilterOptions, TStaticViewTypes } from "types";
|
||||
|
||||
@ -81,19 +81,23 @@ export const GlobalViewLayoutRoot: React.FC<Props> = observer((props) => {
|
||||
return (
|
||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||
<GlobalViewsAppliedFiltersRoot />
|
||||
<div className="h-full w-full overflow-auto">
|
||||
<SpreadsheetView
|
||||
displayProperties={workspaceFilterStore.workspaceDisplayProperties}
|
||||
displayFilters={workspaceFilterStore.workspaceDisplayFilters}
|
||||
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
|
||||
issues={issues}
|
||||
members={workspaceStore.workspaceMembers ? workspaceStore.workspaceMembers.map((m) => m.member) : undefined}
|
||||
labels={workspaceStore.workspaceLabels ? workspaceStore.workspaceLabels : undefined}
|
||||
handleIssueAction={() => {}}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
disableUserActions={false}
|
||||
/>
|
||||
</div>
|
||||
{issues?.length === 0 ? (
|
||||
<GlobalViewEmptyState />
|
||||
) : (
|
||||
<div className="h-full w-full overflow-auto">
|
||||
<SpreadsheetView
|
||||
displayProperties={workspaceFilterStore.workspaceDisplayProperties}
|
||||
displayFilters={workspaceFilterStore.workspaceDisplayFilters}
|
||||
handleDisplayFilterUpdate={handleDisplayFiltersUpdate}
|
||||
issues={issues}
|
||||
members={workspaceStore.workspaceMembers ? workspaceStore.workspaceMembers.map((m) => m.member) : undefined}
|
||||
labels={workspaceStore.workspaceLabels ? workspaceStore.workspaceLabels : undefined}
|
||||
handleIssueAction={() => {}}
|
||||
handleUpdateIssue={handleUpdateIssue}
|
||||
disableUserActions={false}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -9,6 +9,7 @@ import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import {
|
||||
ModuleAppliedFiltersRoot,
|
||||
ModuleCalendarLayout,
|
||||
ModuleEmptyState,
|
||||
ModuleGanttLayout,
|
||||
ModuleKanBanLayout,
|
||||
ModuleListLayout,
|
||||
@ -46,22 +47,28 @@ export const ModuleLayoutRoot: React.FC = observer(() => {
|
||||
|
||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||
|
||||
const issueCount = moduleIssueStore.getIssuesCount;
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||
<ModuleAppliedFiltersRoot />
|
||||
<div className="h-full w-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ModuleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<ModuleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<ModuleCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<ModuleGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ModuleSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||
<ModuleEmptyState />
|
||||
) : (
|
||||
<div className="h-full w-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ModuleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<ModuleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<ModuleCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<ModuleGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ModuleSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
KanBanLayout,
|
||||
ProjectAppliedFiltersRoot,
|
||||
ProjectSpreadsheetLayout,
|
||||
ProjectEmptyState,
|
||||
} from "components/issues";
|
||||
|
||||
export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
@ -30,22 +31,28 @@ export const ProjectLayoutRoot: React.FC = observer(() => {
|
||||
|
||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||
|
||||
const issueCount = issueStore.getIssuesCount;
|
||||
|
||||
return (
|
||||
<div className="relative w-full h-full flex flex-col overflow-hidden">
|
||||
<ProjectAppliedFiltersRoot />
|
||||
<div className="w-full h-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<KanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<CalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<GanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ProjectSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||
<ProjectEmptyState />
|
||||
) : (
|
||||
<div className="w-full h-full overflow-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<KanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<CalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<GanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ProjectSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
ModuleListLayout,
|
||||
ProjectViewAppliedFiltersRoot,
|
||||
ProjectViewCalendarLayout,
|
||||
ProjectViewEmptyState,
|
||||
ProjectViewGanttLayout,
|
||||
ProjectViewSpreadsheetLayout,
|
||||
} from "components/issues";
|
||||
@ -48,22 +49,28 @@ export const ProjectViewLayoutRoot: React.FC = observer(() => {
|
||||
|
||||
const activeLayout = issueFilterStore.userDisplayFilters.layout;
|
||||
|
||||
const issueCount = projectViewIssuesStore.getIssuesCount;
|
||||
|
||||
return (
|
||||
<div className="relative h-full w-full flex flex-col overflow-hidden">
|
||||
<ProjectViewAppliedFiltersRoot />
|
||||
<div className="h-full w-full overflow-y-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ModuleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<ModuleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<ProjectViewCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<ProjectViewGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ProjectViewSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
{(activeLayout === "list" || activeLayout === "spreadsheet") && issueCount === 0 ? (
|
||||
<ProjectViewEmptyState />
|
||||
) : (
|
||||
<div className="h-full w-full overflow-y-auto">
|
||||
{activeLayout === "list" ? (
|
||||
<ModuleListLayout />
|
||||
) : activeLayout === "kanban" ? (
|
||||
<ModuleKanBanLayout />
|
||||
) : activeLayout === "calendar" ? (
|
||||
<ProjectViewCalendarLayout />
|
||||
) : activeLayout === "gantt_chart" ? (
|
||||
<ProjectViewGanttLayout />
|
||||
) : activeLayout === "spreadsheet" ? (
|
||||
<ProjectViewSpreadsheetLayout />
|
||||
) : null}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
@ -6,15 +6,12 @@ import { IIssue } from "types";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||
|
||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
||||
export type IIssueGroupWithSubGroupsStructure = {
|
||||
[group_id: string]: {
|
||||
[sub_group_id: string]: IIssue[];
|
||||
};
|
||||
};
|
||||
export type IIssueUnGroupedStructure = IIssue[];
|
||||
import {
|
||||
IIssueGroupWithSubGroupsStructure,
|
||||
IIssueGroupedStructure,
|
||||
IIssueType,
|
||||
IIssueUnGroupedStructure,
|
||||
} from "store/issue";
|
||||
|
||||
export interface IArchivedIssueStore {
|
||||
loader: boolean;
|
||||
|
@ -9,15 +9,12 @@ import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
import { IBlockUpdateData } from "components/gantt-chart";
|
||||
|
||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
||||
export type IIssueGroupWithSubGroupsStructure = {
|
||||
[group_id: string]: {
|
||||
[sub_group_id: string]: IIssue[];
|
||||
};
|
||||
};
|
||||
export type IIssueUnGroupedStructure = IIssue[];
|
||||
import {
|
||||
IIssueGroupWithSubGroupsStructure,
|
||||
IIssueGroupedStructure,
|
||||
IIssueType,
|
||||
IIssueUnGroupedStructure,
|
||||
} from "store/issue";
|
||||
|
||||
export interface ICycleIssueStore {
|
||||
loader: boolean;
|
||||
@ -33,6 +30,7 @@ export interface ICycleIssueStore {
|
||||
// computed
|
||||
getIssueType: IIssueType | null;
|
||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||
getIssuesCount: number;
|
||||
// action
|
||||
fetchIssues: (workspaceSlug: string, projectId: string, cycleId: string) => Promise<any>;
|
||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||
@ -73,6 +71,7 @@ export class CycleIssueStore implements ICycleIssueStore {
|
||||
// computed
|
||||
getIssueType: computed,
|
||||
getIssues: computed,
|
||||
getIssuesCount: computed,
|
||||
// actions
|
||||
fetchIssues: action,
|
||||
updateIssueStructure: action,
|
||||
@ -130,6 +129,44 @@ export class CycleIssueStore implements ICycleIssueStore {
|
||||
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) => {
|
||||
const cycleId: string | null = this.rootStore?.cycle?.cycleId || null;
|
||||
const issueType = this.getIssueType;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./cycle_issue.store";
|
||||
import { IIssueType } from "store/issue";
|
||||
|
||||
export interface ICycleIssueCalendarViewStore {
|
||||
// actions
|
||||
|
@ -6,15 +6,12 @@ import { IIssue } from "types";
|
||||
// services
|
||||
import { IssueService } from "services/issue";
|
||||
import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||
|
||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
||||
export type IIssueGroupWithSubGroupsStructure = {
|
||||
[group_id: string]: {
|
||||
[sub_group_id: string]: IIssue[];
|
||||
};
|
||||
};
|
||||
export type IIssueUnGroupedStructure = IIssue[];
|
||||
import {
|
||||
IIssueGroupWithSubGroupsStructure,
|
||||
IIssueGroupedStructure,
|
||||
IIssueType,
|
||||
IIssueUnGroupedStructure,
|
||||
} from "store/issue";
|
||||
|
||||
export interface IDraftIssueStore {
|
||||
loader: boolean;
|
||||
|
@ -31,6 +31,7 @@ export interface IIssueStore {
|
||||
// computed
|
||||
getIssueType: IIssueType | null;
|
||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||
getIssuesCount: number;
|
||||
// action
|
||||
fetchIssues: (workspaceSlug: string, projectId: string) => Promise<any>;
|
||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||
@ -68,6 +69,7 @@ export class IssueStore implements IIssueStore {
|
||||
// computed
|
||||
getIssueType: computed,
|
||||
getIssues: computed,
|
||||
getIssuesCount: computed,
|
||||
// actions
|
||||
fetchIssues: action,
|
||||
updateIssueStructure: action,
|
||||
@ -120,6 +122,44 @@ export class IssueStore implements IIssueStore {
|
||||
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) => {
|
||||
const projectId: string | null = issue?.project;
|
||||
const issueType = this.getIssueType;
|
||||
|
@ -8,15 +8,12 @@ import { sortArrayByDate, sortArrayByPriority } from "constants/kanban-helpers";
|
||||
// types
|
||||
import { IIssue } from "types";
|
||||
import { IBlockUpdateData } from "components/gantt-chart";
|
||||
|
||||
export type IIssueType = "grouped" | "groupWithSubGroups" | "ungrouped";
|
||||
export type IIssueGroupedStructure = { [group_id: string]: IIssue[] };
|
||||
export type IIssueGroupWithSubGroupsStructure = {
|
||||
[group_id: string]: {
|
||||
[sub_group_id: string]: IIssue[];
|
||||
};
|
||||
};
|
||||
export type IIssueUnGroupedStructure = IIssue[];
|
||||
import {
|
||||
IIssueGroupWithSubGroupsStructure,
|
||||
IIssueGroupedStructure,
|
||||
IIssueType,
|
||||
IIssueUnGroupedStructure,
|
||||
} from "store/issue";
|
||||
|
||||
export interface IModuleIssueStore {
|
||||
loader: boolean;
|
||||
@ -32,6 +29,7 @@ export interface IModuleIssueStore {
|
||||
// computed
|
||||
getIssueType: IIssueType | null;
|
||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||
getIssuesCount: number;
|
||||
// action
|
||||
fetchIssues: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<any>;
|
||||
updateIssueStructure: (group_id: string | null, sub_group_id: string | null, issue: IIssue) => void;
|
||||
@ -76,6 +74,7 @@ export class ModuleIssueStore implements IModuleIssueStore {
|
||||
// computed
|
||||
getIssueType: computed,
|
||||
getIssues: computed,
|
||||
getIssuesCount: computed,
|
||||
// actions
|
||||
fetchIssues: action,
|
||||
updateIssueStructure: action,
|
||||
@ -132,6 +131,44 @@ export class ModuleIssueStore implements IModuleIssueStore {
|
||||
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) => {
|
||||
const moduleId: string | null = this.rootStore?.module?.moduleId;
|
||||
const issueType = this.getIssueType;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { action, makeObservable, runInAction } from "mobx";
|
||||
// types
|
||||
import { RootStore } from "../root";
|
||||
import { IIssueType } from "./module_issue.store";
|
||||
import { IIssueType } from "store/issue";
|
||||
|
||||
export interface IModuleIssueCalendarViewStore {
|
||||
// actions
|
||||
|
@ -45,6 +45,7 @@ export interface IProjectViewIssuesStore {
|
||||
|
||||
// computed
|
||||
getIssues: IIssueGroupedStructure | IIssueGroupWithSubGroupsStructure | IIssueUnGroupedStructure | null;
|
||||
getIssuesCount: number;
|
||||
getIssueType: IIssueType | null;
|
||||
}
|
||||
|
||||
@ -86,6 +87,7 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||
// computed
|
||||
getIssueType: computed,
|
||||
getIssues: computed,
|
||||
getIssuesCount: computed,
|
||||
});
|
||||
|
||||
this.rootStore = _rootStore;
|
||||
@ -147,6 +149,44 @@ export class ProjectViewIssuesStore implements IProjectViewIssuesStore {
|
||||
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) => {
|
||||
const viewId: string | null = this.rootStore.projectViews.viewId;
|
||||
const issueType = this.rootStore.issue.getIssueType;
|
||||
|
Loading…
Reference in New Issue
Block a user