From 8d86087feeae29d9614991657bb02aa9299bf1ca Mon Sep 17 00:00:00 2001 From: gurusainath Date: Mon, 4 Sep 2023 13:07:55 +0530 Subject: [PATCH 001/102] chore: kanban refactoring --- .../core/views/board-view/all-boards.tsx | 2 + web/components/kanban-layout/index.tsx | 11 +++ web/store/kanban.ts | 82 +++++++++++++++++++ web/store/root.ts | 3 + 4 files changed, 98 insertions(+) create mode 100644 web/components/kanban-layout/index.tsx create mode 100644 web/store/kanban.ts diff --git a/web/components/core/views/board-view/all-boards.tsx b/web/components/core/views/board-view/all-boards.tsx index ee0fc668bd6..49f53704489 100644 --- a/web/components/core/views/board-view/all-boards.tsx +++ b/web/components/core/views/board-view/all-boards.tsx @@ -36,6 +36,8 @@ export const AllBoards: React.FC = ({ }) => { const { groupByProperty: selectedGroup, groupedIssues, showEmptyGroups } = viewProps; + console.log("viewProps", viewProps); + return ( <> {groupedIssues ? ( diff --git a/web/components/kanban-layout/index.tsx b/web/components/kanban-layout/index.tsx new file mode 100644 index 00000000000..cd910124d34 --- /dev/null +++ b/web/components/kanban-layout/index.tsx @@ -0,0 +1,11 @@ +import React from "react"; + +export const KanbanInitLayout = () => { + console.log(""); + + return ( +
+
Hello
+
+ ); +}; diff --git a/web/store/kanban.ts b/web/store/kanban.ts new file mode 100644 index 00000000000..81730032ffc --- /dev/null +++ b/web/store/kanban.ts @@ -0,0 +1,82 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services + +export interface IKanbanStore { + loader: boolean; + error: any | null; + + // current issue view + issueView?: "kanban"; + + // filters + priority?: null; + state?: null; + assignees?: null; + createdBy?: null; + labels?: null; + startDate?: null; + dueDate?: null; + userSelectedParams?: { + assignees: undefined | string; + created_by: undefined | string; + group_by: undefined | string; + labels: undefined | string; + order_by: undefined | string; + priority: undefined | string; + start_date: undefined | string; + state: undefined | string; + sub_issue: boolean; + target_date: undefined | string; + type: undefined | string; + }; + + // display properties + displayProperties?: { + assignee: boolean; + attachment_count: boolean; + created_on: boolean; + due_date: boolean; + estimate: boolean; + key: boolean; + labels: boolean; + link: boolean; + priority: boolean; + start_date: boolean; + state: boolean; + sub_issue_count: boolean; + updated_on: boolean; + }; + + // extra's + showEmptyGroups?: boolean; + + issues?: null; +} + +class KanbanStore implements IKanbanStore { + loader: boolean = false; + error: any | null = null; + + // root store + rootStore; + // service + projectPublishService = null; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + // action + // computed + }); + + this.rootStore = _rootStore; + this.projectPublishService = null; + } +} + +export default KanbanStore; diff --git a/web/store/root.ts b/web/store/root.ts index 40dd62fe6d2..2e7a0f242fe 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -5,6 +5,7 @@ import UserStore from "./user"; import ThemeStore from "./theme"; import IssuesStore from "./issues"; import ProjectPublishStore, { IProjectPublishStore } from "./project-publish"; +import KanbanStore from "./kanban"; enableStaticRendering(typeof window === "undefined"); @@ -13,11 +14,13 @@ export class RootStore { theme; projectPublish: IProjectPublishStore; issues: IssuesStore; + kanban: KanbanStore; constructor() { this.user = new UserStore(this); this.theme = new ThemeStore(this); this.projectPublish = new ProjectPublishStore(this); this.issues = new IssuesStore(this); + this.kanban = new KanbanStore(this); } } From ef630ef66383a16802a55bf9a5c41e634dd59d4f Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 5 Sep 2023 23:37:52 +0530 Subject: [PATCH 002/102] chore: Implemented new kanaban board UX and implemented draggable using react beautiful dnd --- .../issue-layouts/kanban/content.tsx | 52 ++++++ .../issue-layouts/kanban/footer.tsx | 1 + .../issue-layouts/kanban/header.tsx | 1 + web/components/issue-layouts/kanban/index.tsx | 70 ++++++++ web/components/kanban-layout/index.tsx | 11 -- web/pages/kanban.tsx | 29 ++++ web/services/issues.service.ts | 2 +- web/store/issue-views/data.ts | 60 +++++++ web/store/issue-views/filters.ts | 154 ++++++++++++++++++ web/store/issue-views/kanban.ts | 92 +++++++++++ web/store/kanban.ts | 82 ---------- web/store/root.ts | 6 +- 12 files changed, 465 insertions(+), 95 deletions(-) create mode 100644 web/components/issue-layouts/kanban/content.tsx create mode 100644 web/components/issue-layouts/kanban/footer.tsx create mode 100644 web/components/issue-layouts/kanban/header.tsx create mode 100644 web/components/issue-layouts/kanban/index.tsx delete mode 100644 web/components/kanban-layout/index.tsx create mode 100644 web/pages/kanban.tsx create mode 100644 web/store/issue-views/data.ts create mode 100644 web/store/issue-views/filters.ts create mode 100644 web/store/issue-views/kanban.ts delete mode 100644 web/store/kanban.ts diff --git a/web/components/issue-layouts/kanban/content.tsx b/web/components/issue-layouts/kanban/content.tsx new file mode 100644 index 00000000000..15e34becde9 --- /dev/null +++ b/web/components/issue-layouts/kanban/content.tsx @@ -0,0 +1,52 @@ +// react beautiful dnd +import { Draggable } from "react-beautiful-dnd"; + +interface IssueContentProps { + columnId: string; + issues: any; +} + +export const IssueContent = ({ columnId, issues }: IssueContentProps) => { + console.log(); + + return ( + <> + {issues && issues.length > 0 ? ( + <> + {issues.map((issue: any, index: any) => ( + + {(provided: any, snapshot: any) => ( +
+
+
+ ONE-{issue.sequence_id}-{issue.sort_order} +
+
+ {issue.name} {issue.name} {issue.name} {issue.name} {issue.name} {issue.name}{" "} + {issue.name} {issue.name} +
+
Footer
+
+
+ )} +
+ ))} + + ) : ( +
No issues are available.
+ )} + + ); +}; diff --git a/web/components/issue-layouts/kanban/footer.tsx b/web/components/issue-layouts/kanban/footer.tsx new file mode 100644 index 00000000000..21b09c11f17 --- /dev/null +++ b/web/components/issue-layouts/kanban/footer.tsx @@ -0,0 +1 @@ +export const IssueFooter = () =>
Footer
; diff --git a/web/components/issue-layouts/kanban/header.tsx b/web/components/issue-layouts/kanban/header.tsx new file mode 100644 index 00000000000..4852fabd971 --- /dev/null +++ b/web/components/issue-layouts/kanban/header.tsx @@ -0,0 +1 @@ +export const IssueHeader = () =>
Header
; diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx new file mode 100644 index 00000000000..eaa6e4468bc --- /dev/null +++ b/web/components/issue-layouts/kanban/index.tsx @@ -0,0 +1,70 @@ +import React from "react"; +// react beautiful dnd +import { DragDropContext, Droppable } from "react-beautiful-dnd"; +// components +import { IssueHeader } from "./header"; +import { IssueContent } from "./content"; +import { IssueFooter } from "./footer"; +// mobx +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const IssueRoot = observer(() => { + const store: RootStore = useMobxStore(); + const { kanban: issueViewStore } = store; + + const onDragEnd = (result: any) => { + console.log("result", result); + }; + + return ( +
+ {issueViewStore.loader && issueViewStore?.issues === null ? ( +
Loading...
+ ) : ( +
+ {issueViewStore?.getIssues && Object.keys(issueViewStore?.getIssues).length > 0 ? ( +
+ + {Object.keys(issueViewStore?.getIssues).map((_issueStateKey: any) => ( +
+
+ +
+ +
+ + {(provided: any, snapshot: any) => ( + <> +
+ +
+ {provided.placeholder} + + )} +
+
+ +
+ +
+
+ ))} +
+
+ ) : ( +
No Issues are available
+ )} +
+ )} +
+ ); +}); diff --git a/web/components/kanban-layout/index.tsx b/web/components/kanban-layout/index.tsx deleted file mode 100644 index cd910124d34..00000000000 --- a/web/components/kanban-layout/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from "react"; - -export const KanbanInitLayout = () => { - console.log(""); - - return ( -
-
Hello
-
- ); -}; diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx new file mode 100644 index 00000000000..a25d75824b1 --- /dev/null +++ b/web/pages/kanban.tsx @@ -0,0 +1,29 @@ +import React from "react"; +// swr +import useSWR from "swr"; +// components +import { IssueRoot } from "components/issue-layouts/kanban"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanbanViewRoot = () => { + const workspaceSlug: string = "plane-demo"; + const projectSlug: string = "5b0e3f6e-c9f1-444d-be22-a8c2706bcf54"; + + const store: RootStore = useMobxStore(); + const { kanban: issueViewStore } = store; + + useSWR(`PROJECT_ISSUES_KANBAN_VIEW`, () => { + if (workspaceSlug && projectSlug) + issueViewStore.getIssuesAsync(workspaceSlug, projectSlug, "kanban"); + }); + + return ( +
+ +
+ ); +}; + +export default KanbanViewRoot; diff --git a/web/services/issues.service.ts b/web/services/issues.service.ts index b8875e6c5e0..c6e122a3be9 100644 --- a/web/services/issues.service.ts +++ b/web/services/issues.service.ts @@ -17,7 +17,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env; const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class ProjectIssuesServices extends APIService { +export class ProjectIssuesServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/store/issue-views/data.ts b/web/store/issue-views/data.ts new file mode 100644 index 00000000000..559084e089d --- /dev/null +++ b/web/store/issue-views/data.ts @@ -0,0 +1,60 @@ +export const filtersPriority: { key: string; title: string }[] = [ + { key: "", title: "Urgent" }, + { key: "", title: "High" }, + { key: "", title: "Medium" }, + { key: "", title: "Low" }, + { key: "", title: "None" }, +]; + +export const filtersStartDate = [ + { key: "", title: "Last Week" }, + { key: "", title: "2 weeks from now" }, + { key: "", title: "1 month from now" }, + { key: "", title: "2 months from now" }, + { key: "", title: "Custom" }, +]; + +export const filtersDueDate = [ + { key: "", title: "Last Week" }, + { key: "", title: "2 weeks from now" }, + { key: "", title: "1 month from now" }, + { key: "", title: "2 months from now" }, + { key: "", title: "Custom" }, +]; + +export const displayPropertyGroupBy = [ + { key: "state", title: "States" }, + { key: "state_detail.group", title: "State Groups" }, + { key: "priority", title: "Priority" }, + { key: "labels", title: "Labels" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, +]; + +export const displayPropertyOrderBy = [ + { key: "sort_order", title: "Manual" }, + { key: "created_at", title: "Last Created" }, + { key: "updated_at", title: "Last Updated" }, + { key: "start_date", title: "Start Date" }, + { key: "priority", title: "Priority" }, +]; + +export const displayPropertyIssueType = [ + { key: "all", title: "All" }, + { key: "active", title: "Active Issues" }, + { key: "backlog", title: "Backlog Issues" }, +]; + +export const displayProperties = [ + { key: "assignee", title: "Assignee" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, + { key: "key", title: "Id" }, + { key: "labels", title: "Labels" }, + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "sub_issue_count", title: "Sub Issue Count" }, + { key: "attachment_count", title: "Attachment Count" }, + { key: "link", title: "Link" }, + { key: "estimate", title: "Estimate" }, +]; diff --git a/web/store/issue-views/filters.ts b/web/store/issue-views/filters.ts new file mode 100644 index 00000000000..2f79b9d3d05 --- /dev/null +++ b/web/store/issue-views/filters.ts @@ -0,0 +1,154 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import {} from "services/issues.service"; + +export type TIssueViews = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; + +export interface IIssueFilterStore { + loader: boolean; + error: any | null; + + // current issue view + workspaceId: string | null; + projectId: string | null; + issueView: string | null; + + // filters + priority?: null; + state?: null; + assignees?: null; + createdBy?: null; + labels?: null; + startDate?: null; + dueDate?: null; + userSelectedParams?: { + assignees: undefined | string; + created_by: undefined | string; + group_by: undefined | string; + labels: undefined | string; + order_by: undefined | string; + priority: undefined | string; + start_date: undefined | string; + state: undefined | string; + sub_issue: boolean; + target_date: undefined | string; + type: undefined | string; + }; + + // display properties + displayProperties?: { + assignee: boolean; + attachment_count: boolean; + created_on: boolean; + due_date: boolean; + estimate: boolean; + key: boolean; + labels: boolean; + link: boolean; + priority: boolean; + start_date: boolean; + state: boolean; + sub_issue_count: boolean; + updated_on: boolean; + }; + + // extra's + showEmptyGroups?: boolean; + + // actions + getProjectIssueFilterProperties: () => any | Promise; + getProjectIssueDisplayProperties: () => any | Promise; + getProjectMembers: () => any | Promise; + getProjectStates: () => any | Promise; + getProjectLabels: () => any | Promise; +} + +class IssueFilterStore implements IIssueFilterStore { + loader: boolean = false; + error: any | null = null; + + workspaceId: string | null = null; + projectId: string | null = null; + issueView: string | null = null; + + // root store + rootStore; + // service + projectPublishService = null; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + workspaceId: observable, + projectId: observable, + + // action + getProjectIssueFilterProperties: action, + getProjectIssueDisplayProperties: action, + getProjectMembers: action, + getProjectStates: action, + getProjectLabels: action, + // computed + }); + + this.rootStore = _rootStore; + this.projectPublishService = null; + } + + // computed functions starts + getComputedFilters = ( + _workspaceId: string, + _projectId: string, + _view: TIssueViews | null = "kanban" + ) => { + this.workspaceId = _workspaceId; + this.projectId = _projectId; + this.issueView = _view; + + let filteredRouteParams = { + assignees: undefined, // ['user_id', 'user_id'] + state: undefined, // ['state_id', 'state_id'] + priority: undefined, // ['low', 'high', 'medium', 'urgent', 'null'] + type: undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) + labels: undefined, // ['label_id', 'label_id'] + created_by: undefined, // ['user_id', 'user_id'] + start_date: undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] + target_date: undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] + order_by: "-created_at", // TIssueOrderByOptions + group_by: "state", // TIssueGroupByOptions + sub_issue: true, // true for all other views except spreadsheet + }; + + if (_view === "list") filteredRouteParams = { ...filteredRouteParams }; + if (_view === "kanban") filteredRouteParams = { ...filteredRouteParams }; + if (_view === "calendar") filteredRouteParams = { ...filteredRouteParams }; + if (_view === "spreadsheet") filteredRouteParams = { ...filteredRouteParams }; + if (_view === "gantt") filteredRouteParams = { ...filteredRouteParams }; + + return filteredRouteParams; + }; + + // computed functions ends + + // fetching current user project issue filter and display settings + getProjectIssueFilterProperties = () => {}; + + // fetching display properties + getProjectIssueDisplayProperties = () => {}; + + // fetching project members + getProjectMembers = () => {}; + + // fetching project state <-> groups + getProjectStates = () => {}; + + // fetching project labels + getProjectLabels = () => {}; +} + +export default IssueFilterStore; diff --git a/web/store/issue-views/kanban.ts b/web/store/issue-views/kanban.ts new file mode 100644 index 00000000000..34a9e5b14b3 --- /dev/null +++ b/web/store/issue-views/kanban.ts @@ -0,0 +1,92 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import { ProjectIssuesServices } from "services/issues.service"; +// types +import { TIssueViews } from "./filters"; + +export interface IKanbanStore { + loader: boolean; + error: any | null; + issues: { [key: string]: any } | null; + + getIssuesAsync: ( + workspaceId: string, + projectId: string, + view: TIssueViews | null + ) => null | Promise; +} + +class KanbanStore implements IKanbanStore { + loader: boolean = false; + error: any | null = null; + + issues: { [key: string]: any } | null = null; + + // root store + rootStore; + // service + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + issues: observable.ref, + // action + getIssuesAsync: action, + // computed + }); + + this.rootStore = _rootStore; + this.issueService = new ProjectIssuesServices(); + } + + // computed + get getIssues() { + if (this.rootStore.issueFilters.projectId && this.issues != null) + return this.issues[this.rootStore.issueFilters.projectId]; + else return null; + } + + // fetching issues + getIssuesAsync = async (workspaceId: string, projectId: string, view: TIssueViews | null) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + view + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { ...issuesResponse } }; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // handle issue drag and drop +} + +export default KanbanStore; diff --git a/web/store/kanban.ts b/web/store/kanban.ts deleted file mode 100644 index 81730032ffc..00000000000 --- a/web/store/kanban.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "./root"; -// services - -export interface IKanbanStore { - loader: boolean; - error: any | null; - - // current issue view - issueView?: "kanban"; - - // filters - priority?: null; - state?: null; - assignees?: null; - createdBy?: null; - labels?: null; - startDate?: null; - dueDate?: null; - userSelectedParams?: { - assignees: undefined | string; - created_by: undefined | string; - group_by: undefined | string; - labels: undefined | string; - order_by: undefined | string; - priority: undefined | string; - start_date: undefined | string; - state: undefined | string; - sub_issue: boolean; - target_date: undefined | string; - type: undefined | string; - }; - - // display properties - displayProperties?: { - assignee: boolean; - attachment_count: boolean; - created_on: boolean; - due_date: boolean; - estimate: boolean; - key: boolean; - labels: boolean; - link: boolean; - priority: boolean; - start_date: boolean; - state: boolean; - sub_issue_count: boolean; - updated_on: boolean; - }; - - // extra's - showEmptyGroups?: boolean; - - issues?: null; -} - -class KanbanStore implements IKanbanStore { - loader: boolean = false; - error: any | null = null; - - // root store - rootStore; - // service - projectPublishService = null; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - // action - // computed - }); - - this.rootStore = _rootStore; - this.projectPublishService = null; - } -} - -export default KanbanStore; diff --git a/web/store/root.ts b/web/store/root.ts index 2e81922d2b8..eba9aff9514 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -5,8 +5,10 @@ import UserStore from "./user"; import ThemeStore from "./theme"; import ProjectStore, { IProjectStore } from "./project"; import ProjectPublishStore, { IProjectPublishStore } from "./project-publish"; -import KanbanStore from "./kanban"; import IssuesStore from "./issues"; +// issues views and filters +import IssueFilterStore from "./issue-views/filters"; +import KanbanStore from "./issue-views/kanban"; enableStaticRendering(typeof window === "undefined"); @@ -16,6 +18,7 @@ export class RootStore { project: IProjectStore; projectPublish: IProjectPublishStore; issues: IssuesStore; + issueFilters: IssueFilterStore; kanban: KanbanStore; constructor() { @@ -24,6 +27,7 @@ export class RootStore { this.project = new ProjectStore(this); this.projectPublish = new ProjectPublishStore(this); this.issues = new IssuesStore(this); + this.issueFilters = new IssueFilterStore(this); this.kanban = new KanbanStore(this); } } From b86c30baed91c909f55c1b1b83a6a7c647a5631d Mon Sep 17 00:00:00 2001 From: gurusainath Date: Wed, 6 Sep 2023 11:17:34 +0530 Subject: [PATCH 003/102] chore: updated yarn lock --- yarn.lock | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/yarn.lock b/yarn.lock index 1aa8e5bdea4..c0b96cdb935 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1367,7 +1367,7 @@ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.7.tgz#95bed2487bf59632125a13b8eb8f4c21e460afec" integrity sha512-sCWTUNElBPgB30iLvWe3PU7SIlTKZNf6/E/sko85iHVeHCM6WPkDw+y89CrZYjhFNmPqt2fIQM/pZu+rP2lFLA== -"@mui/icons-material@^5.14.1", "@mui/icons-material@^5.14.7": +"@mui/icons-material@^5.14.1": version "5.14.7" resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.7.tgz#d7f6bd188fe38adf35c89d9343b8a529c2306383" integrity sha512-mWp4DwMa8c1Gx9yOEtPgxM4b+e6hAbtZyzfSubdBwrnEE6G5D2rbAJ5MB+If6kfI48JaYaJ5j8+zAdmZLuZc0A== @@ -4892,11 +4892,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -husky@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" - integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== - idb@^7.0.1: version "7.1.1" resolved "https://registry.yarnpkg.com/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" @@ -6046,11 +6041,6 @@ next-pwa@^5.6.0: workbox-webpack-plugin "^6.5.4" workbox-window "^6.5.4" -next-theme@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/next-theme/-/next-theme-0.1.5.tgz#aa6655c516892925e577349d7715a8ed54bad727" - integrity sha512-WR8UCLEFjWvRl+UO2lTM4pGo7R4jzGZqQ6YL3hiL1Ns587Qb91GhJZLPu/Aa4ExtGQ/5wlcDX8zDYZoCN9oDPw== - next-themes@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45" From b9a6a004704452ecf2aad0bdaacb8269378eefbc Mon Sep 17 00:00:00 2001 From: gurusainath Date: Fri, 8 Sep 2023 12:42:09 +0530 Subject: [PATCH 004/102] chore: updated the store for issues and issue filters --- .../issue-layouts/kanban/content.tsx | 17 +- .../issue-layouts/kanban/footer.tsx | 1 - .../issue-layouts/kanban/header.tsx | 23 +- web/components/issue-layouts/kanban/index.tsx | 69 +-- web/package.json | 2 +- web/pages/kanban.tsx | 169 ++++++- web/services/cycles.service.ts | 2 +- web/services/modules.service.ts | 2 +- web/services/user.service.ts | 2 +- web/store/issue-views/Issue_details.ts | 205 ++++++++ web/store/issue-views/Issues.ts | 454 ++++++++++++++++++ web/store/issue-views/filters.ts | 154 ------ .../issue-views/{data.ts => issue_data.ts} | 30 +- web/store/issue-views/issue_filters.ts | 330 +++++++++++++ web/store/issue-views/kanban.ts | 92 ---- web/store/root.ts | 8 +- yarn.lock | 14 +- 17 files changed, 1253 insertions(+), 321 deletions(-) delete mode 100644 web/components/issue-layouts/kanban/footer.tsx create mode 100644 web/store/issue-views/Issue_details.ts create mode 100644 web/store/issue-views/Issues.ts delete mode 100644 web/store/issue-views/filters.ts rename web/store/issue-views/{data.ts => issue_data.ts} (66%) create mode 100644 web/store/issue-views/issue_filters.ts delete mode 100644 web/store/issue-views/kanban.ts diff --git a/web/components/issue-layouts/kanban/content.tsx b/web/components/issue-layouts/kanban/content.tsx index 15e34becde9..6f297fcf686 100644 --- a/web/components/issue-layouts/kanban/content.tsx +++ b/web/components/issue-layouts/kanban/content.tsx @@ -22,22 +22,23 @@ export const IssueContent = ({ columnId, issues }: IssueContentProps) => { {(provided: any, snapshot: any) => (
-
+
ONE-{issue.sequence_id}-{issue.sort_order}
-
- {issue.name} {issue.name} {issue.name} {issue.name} {issue.name} {issue.name}{" "} - {issue.name} {issue.name} -
-
Footer
+
{issue.name}
+
Footer
)} diff --git a/web/components/issue-layouts/kanban/footer.tsx b/web/components/issue-layouts/kanban/footer.tsx deleted file mode 100644 index 21b09c11f17..00000000000 --- a/web/components/issue-layouts/kanban/footer.tsx +++ /dev/null @@ -1 +0,0 @@ -export const IssueFooter = () =>
Footer
; diff --git a/web/components/issue-layouts/kanban/header.tsx b/web/components/issue-layouts/kanban/header.tsx index 4852fabd971..c399b643cb3 100644 --- a/web/components/issue-layouts/kanban/header.tsx +++ b/web/components/issue-layouts/kanban/header.tsx @@ -1 +1,22 @@ -export const IssueHeader = () =>
Header
; +// lucide icons +import { Plus } from "lucide-react"; + +export const IssueHeader = () => ( +
+ {/* default layout */} +
+ I +
+
Kanban Issue Heading
+
+ 0 +
+ +
+ M +
+
+ +
+
+); diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx index eaa6e4468bc..27d7fcbc01d 100644 --- a/web/components/issue-layouts/kanban/index.tsx +++ b/web/components/issue-layouts/kanban/index.tsx @@ -4,66 +4,75 @@ import { DragDropContext, Droppable } from "react-beautiful-dnd"; // components import { IssueHeader } from "./header"; import { IssueContent } from "./content"; -import { IssueFooter } from "./footer"; // mobx import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -export const IssueRoot = observer(() => { +export const IssueKanBanViewRoot = observer(() => { const store: RootStore = useMobxStore(); - const { kanban: issueViewStore } = store; + const { issueView: issueViewStore } = store; const onDragEnd = (result: any) => { + if (!result) return; + + if ( + result.destination && + result.source && + result.destination.droppableId === result.source.droppableId && + result.destination.index === result.source.index + ) + return; + console.log("result", result); }; return ( -
+
{issueViewStore.loader && issueViewStore?.issues === null ? (
Loading...
) : ( -
+ <> {issueViewStore?.getIssues && Object.keys(issueViewStore?.getIssues).length > 0 ? ( -
- + +
{Object.keys(issueViewStore?.getIssues).map((_issueStateKey: any) => (
-
+
-
- - {(provided: any, snapshot: any) => ( - <> -
- -
- {provided.placeholder} - - )} -
-
- -
- -
+ + {(provided: any, snapshot: any) => ( +
+ {issueViewStore?.getIssues && ( + + )} + {provided.placeholder} +
+ )} +
))} - -
+
+
) : (
No Issues are available
)} -
+ )}
); diff --git a/web/package.json b/web/package.json index 1743e4b6c8b..1c5997d413c 100644 --- a/web/package.json +++ b/web/package.json @@ -58,7 +58,7 @@ "js-cookie": "^3.0.1", "lodash.debounce": "^4.0.8", "lowlight": "^2.9.0", - "lucide-react": "^0.263.1", + "lucide-react": "^0.274.0", "mobx": "^6.10.0", "mobx-react-lite": "^4.0.3", "next": "12.3.2", diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx index a25d75824b1..8e0312dd918 100644 --- a/web/pages/kanban.tsx +++ b/web/pages/kanban.tsx @@ -2,28 +2,175 @@ import React from "react"; // swr import useSWR from "swr"; // components -import { IssueRoot } from "components/issue-layouts/kanban"; +import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -const KanbanViewRoot = () => { +const KanBanViewRoot = () => { const workspaceSlug: string = "plane-demo"; - const projectSlug: string = "5b0e3f6e-c9f1-444d-be22-a8c2706bcf54"; + const projectSlug: string = "08d59d96-9dfb-40e5-aa30-ecc66319450f"; + const moduleSlug: string = "05613afc-29ea-4fd8-a025-a3cdfed209d1"; + const cycleSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; + const viewSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; const store: RootStore = useMobxStore(); - const { kanban: issueViewStore } = store; + const { issueView: issueViewStore } = store; - useSWR(`PROJECT_ISSUES_KANBAN_VIEW`, () => { - if (workspaceSlug && projectSlug) - issueViewStore.getIssuesAsync(workspaceSlug, projectSlug, "kanban"); - }); + React.useEffect(() => { + const init = async () => { + // my issues under a workspace + console.log("started--->"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "list"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "kanban"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "calendar"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "spreadsheet"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "gantt"); + + // project issues under and workspace and project + // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); + await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); + // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "calendar"); + // await issueViewStore.getProjectIssuesAsync( + // workspaceSlug, + // projectSlug, + // "issues", + // "spreadsheet" + // ); + // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "gantt"); + + // module issues under and workspace and project + // await issueViewStore.getIssuesForModulesAsync( + // workspaceSlug, + // projectSlug, + // moduleSlug, + // "modules", + // "list" + // ); + // await issueViewStore.getIssuesForModulesAsync( + // workspaceSlug, + // projectSlug, + // moduleSlug, + // "modules", + // "kanban" + // ); + // await issueViewStore.getIssuesForModulesAsync( + // workspaceSlug, + // projectSlug, + // moduleSlug, + // "modules", + // "calendar" + // ); + // await issueViewStore.getIssuesForModulesAsync( + // workspaceSlug, + // projectSlug, + // moduleSlug, + // "modules", + // "spreadsheet" + // ); + // await issueViewStore.getIssuesForModulesAsync( + // workspaceSlug, + // projectSlug, + // moduleSlug, + // "modules", + // "gantt" + // ); + + // cycle issues under and workspace and project + // await issueViewStore.getIssuesForCyclesAsync( + // workspaceSlug, + // projectSlug, + // cycleSlug, + // "cycles", + // "list" + // ); + // await issueViewStore.getIssuesForCyclesAsync( + // workspaceSlug, + // projectSlug, + // cycleSlug, + // "cycles", + // "kanban" + // ); + // await issueViewStore.getIssuesForCyclesAsync( + // workspaceSlug, + // projectSlug, + // cycleSlug, + // "cycles", + // "calendar" + // ); + // await issueViewStore.getIssuesForCyclesAsync( + // workspaceSlug, + // projectSlug, + // cycleSlug, + // "cycles", + // "spreadsheet" + // ); + // await issueViewStore.getIssuesForCyclesAsync( + // workspaceSlug, + // projectSlug, + // cycleSlug, + // "cycles", + // "gantt" + // ); + + // cycle issues under and workspace and project + // await issueViewStore.getIssuesForViewsAsync( + // workspaceSlug, + // projectSlug, + // viewSlug, + // "views", + // "list" + // ); + // await issueViewStore.getIssuesForViewsAsync( + // workspaceSlug, + // projectSlug, + // viewSlug, + // "views", + // "kanban" + // ); + // await issueViewStore.getIssuesForViewsAsync( + // workspaceSlug, + // projectSlug, + // viewSlug, + // "views", + // "calendar" + // ); + // await issueViewStore.getIssuesForViewsAsync( + // workspaceSlug, + // projectSlug, + // viewSlug, + // "views", + // "spreadsheet" + // ); + // await issueViewStore.getIssuesForViewsAsync( + // workspaceSlug, + // projectSlug, + // viewSlug, + // "views", + // "gantt" + // ); + + console.log("ended--->"); + }; + + init(); + }, []); return ( -
- +
+
+
+ Filter Header +
+
+ +
+
); }; -export default KanbanViewRoot; +export default KanBanViewRoot; diff --git a/web/services/cycles.service.ts b/web/services/cycles.service.ts index 89cd50a2fcc..c41f4188d64 100644 --- a/web/services/cycles.service.ts +++ b/web/services/cycles.service.ts @@ -10,7 +10,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env; const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class ProjectCycleServices extends APIService { +export class ProjectCycleServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/services/modules.service.ts b/web/services/modules.service.ts index 0e3b5cfe29e..d415c1ba416 100644 --- a/web/services/modules.service.ts +++ b/web/services/modules.service.ts @@ -10,7 +10,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env; const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class ProjectIssuesServices extends APIService { +export class ProjectIssuesServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/services/user.service.ts b/web/services/user.service.ts index 0e5def647bd..17836ae3aab 100644 --- a/web/services/user.service.ts +++ b/web/services/user.service.ts @@ -17,7 +17,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env; const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class UserService extends APIService { +export class UserService extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/store/issue-views/Issue_details.ts b/web/store/issue-views/Issue_details.ts new file mode 100644 index 00000000000..9f0268bbd7d --- /dev/null +++ b/web/store/issue-views/Issue_details.ts @@ -0,0 +1,205 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import { ProjectIssuesServices } from "services/issues.service"; +// types +import { TIssueLayouts } from "./issue_filters"; + +export interface IIssueViewStore { + loader: boolean; + error: any | null; + + issues: { [key: string]: { [key: string]: any } } | null; + + getIssuesAsync: ( + workspaceId: string, + projectId: string, + view: TIssueLayouts | null + ) => null | Promise; +} + +class IssueViewStore implements IIssueViewStore { + loader: boolean = false; + error: any | null = null; + + issues: { [key: string]: { [key: string]: any } } | null = null; + + // root store + rootStore; + // service + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + issues: observable.ref, + // action + getIssuesAsync: action, + // computed + }); + + this.rootStore = _rootStore; + this.issueService = new ProjectIssuesServices(); + } + + // computed + get getIssues() { + if ( + this.rootStore.issueFilters.projectId && + this.issues != null && + this.rootStore.issueFilters.issueView != null + ) + return this.issues[this.rootStore.issueFilters.projectId][ + this.rootStore.issueFilters.issueView + ]; + else return null; + } + + // handling kanBan drag and drop events + + // fetching issues + getIssuesAsync = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + "kanBan", + "issues" + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { issues: { ...issuesResponse } } }; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching issues for modules + getIssuesForModulesAsync = async (workspaceId: string, projectId: string, moduleId: string) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + "kanBan", + "modules" + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching issues for cycles + getIssuesForModulesCycles = async (workspaceId: string, projectId: string, moduleId: string) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + "kanBan", + "cycles" + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching issues for views + getIssuesForViews = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + "kanBan", + "views" + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + runInAction(() => { + this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; +} + +export default IssueViewStore; diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts new file mode 100644 index 00000000000..817eb7c23f2 --- /dev/null +++ b/web/store/issue-views/Issues.ts @@ -0,0 +1,454 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import { UserService } from "services/user.service"; +import { ProjectIssuesServices } from "services/issues.service"; +import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; +import { ProjectCycleServices } from "services/cycles.service"; +// types +import { TIssueLayouts, TIssueViews } from "./issue_filters"; + +export interface IIssues { + [key: string]: any; +} + +export interface IIssuesLayout { + list: IIssues; + kanban: IIssues; + calendar: IIssues; + spreadsheet: IIssues; + gantt: IIssues; +} + +export interface IIssueState { + [key: string]: { + my_issues: IIssuesLayout; + project_issues: { + [key: string]: { + issues: IIssuesLayout; + cycles: { + [key: string]: IIssuesLayout; + }; + modules: { + [key: string]: IIssuesLayout; + }; + views: { + [key: string]: IIssuesLayout; + }; + }; + }; + }; +} + +export interface IIssueViewStore { + loader: boolean; + error: any | null; + issues: IIssueState; + // computed + getIssues: IIssues | null | undefined; + // actions + getMyIssuesAsync: ( + workspaceId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => null | Promise; + getProjectIssuesAsync: ( + workspaceId: string, + projectId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => null | Promise; + getIssuesForModulesAsync: ( + workspaceId: string, + projectId: string, + moduleId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => null | Promise; + getIssuesForCyclesAsync: ( + workspaceId: string, + projectId: string, + cycleId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => null | Promise; + getIssuesForViewsAsync: ( + workspaceId: string, + projectId: string, + viewId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => null | Promise; +} + +class IssueViewStore implements IIssueViewStore { + loader: boolean = false; + error: any | null = null; + issues: IIssueState = {}; + // root store + rootStore; + // service + issueService; + userService; + modulesService; + cyclesService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + issues: observable.ref, + // action + getMyIssuesAsync: action, + getProjectIssuesAsync: action, + getIssuesForModulesAsync: action, + getIssuesForCyclesAsync: action, + getIssuesForViewsAsync: action, + // computed + getIssues: computed, + }); + + this.rootStore = _rootStore; + this.issueService = new ProjectIssuesServices(); + this.userService = new UserService(); + this.modulesService = new ProjectModuleServices(); + this.cyclesService = new ProjectCycleServices(); + } + + // computed + get getIssues() { + if (this.issues != null) { + const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; + const currentLayout: TIssueLayouts | null = this.rootStore.issueFilters.issueLayout; + const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; + const currentProjectId: string | null = this.rootStore.issueFilters.projectId; + const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; + const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; + const currentViewId: string | null = this.rootStore.issueFilters.viewId; + + if (!currentView || !currentLayout || !currentWorkspaceId) return null; + + if (currentView === "my_issues") + return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; + else if (currentView === "issues" && currentProjectId) + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ + currentLayout + ]; + else if (currentView === "modules" && currentProjectId && currentModuleId) + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.modules?.[ + currentModuleId + ]?.[currentLayout]; + else if (currentView === "cycles" && currentProjectId && currentCycleId) + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.cycles?.[ + currentCycleId + ]?.[currentLayout]; + else if (currentView === "views" && currentProjectId && currentViewId) + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.views?.[ + currentViewId + ]?.[currentLayout]; + } + } + + // fetching my issues + getMyIssuesAsync = async (workspaceId: string, _view: TIssueViews, _layout: TIssueLayouts) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + null, + null, + null, + null, + _view, + _layout + ); + const issuesResponse = await this.userService.userIssues(workspaceId, filteredParams); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [workspaceId]: { + ...this?.issues[workspaceId], + my_issues: { + ...this?.issues[workspaceId]?.my_issues, + [_layout as string]: issuesResponse, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues + getProjectIssuesAsync = async ( + workspaceId: string, + projectId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + null, + null, + null, + _view, + _layout + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [workspaceId]: { + ...this?.issues?.[workspaceId], + project_issues: { + ...this?.issues?.[workspaceId]?.project_issues, + [projectId]: { + ...this?.issues?.[workspaceId]?.project_issues?.[projectId], + issues: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.issues, + [_layout as string]: issuesResponse, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for modules + getIssuesForModulesAsync = async ( + workspaceId: string, + projectId: string, + moduleId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + moduleId, + null, + null, + _view, + _layout + ); + const issuesResponse = await this.modulesService.getModuleIssuesWithParams( + workspaceId, + projectId, + moduleId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [workspaceId]: { + ...this?.issues?.[workspaceId], + project_issues: { + ...this?.issues?.[workspaceId]?.project_issues, + [projectId]: { + ...this?.issues?.[workspaceId]?.project_issues?.[projectId], + modules: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules, + [moduleId]: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules?.[moduleId], + [_layout as string]: issuesResponse, + }, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for cycles + getIssuesForCyclesAsync = async ( + workspaceId: string, + projectId: string, + cycleId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + null, + cycleId, + null, + _view, + _layout + ); + const issuesResponse = await this.cyclesService.getCycleIssuesWithParams( + workspaceId, + projectId, + cycleId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [workspaceId]: { + ...this?.issues?.[workspaceId], + project_issues: { + ...this?.issues?.[workspaceId]?.project_issues, + [projectId]: { + ...this?.issues?.[workspaceId]?.project_issues?.[projectId], + cycles: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles, + [cycleId]: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles?.[cycleId], + [_layout as string]: issuesResponse, + }, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for views + getIssuesForViewsAsync = async ( + workspaceId: string, + projectId: string, + viewId: string, + _view: TIssueViews, + _layout: TIssueLayouts + ) => { + try { + this.loader = true; + this.error = null; + + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + null, + null, + viewId, + _view, + _layout + ); + const issuesResponse = await this.issueService.getIssuesWithParams( + workspaceId, + projectId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [workspaceId]: { + ...this?.issues?.[workspaceId], + project_issues: { + ...this?.issues?.[workspaceId]?.project_issues, + [projectId]: { + ...this?.issues?.[workspaceId]?.project_issues?.[projectId], + views: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views, + [viewId]: { + ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views?.[viewId], + [_layout as string]: issuesResponse, + }, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error", error); + this.loader = false; + this.error = null; + return error; + } + }; +} + +export default IssueViewStore; diff --git a/web/store/issue-views/filters.ts b/web/store/issue-views/filters.ts deleted file mode 100644 index 2f79b9d3d05..00000000000 --- a/web/store/issue-views/filters.ts +++ /dev/null @@ -1,154 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "../root"; -// services -import {} from "services/issues.service"; - -export type TIssueViews = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; - -export interface IIssueFilterStore { - loader: boolean; - error: any | null; - - // current issue view - workspaceId: string | null; - projectId: string | null; - issueView: string | null; - - // filters - priority?: null; - state?: null; - assignees?: null; - createdBy?: null; - labels?: null; - startDate?: null; - dueDate?: null; - userSelectedParams?: { - assignees: undefined | string; - created_by: undefined | string; - group_by: undefined | string; - labels: undefined | string; - order_by: undefined | string; - priority: undefined | string; - start_date: undefined | string; - state: undefined | string; - sub_issue: boolean; - target_date: undefined | string; - type: undefined | string; - }; - - // display properties - displayProperties?: { - assignee: boolean; - attachment_count: boolean; - created_on: boolean; - due_date: boolean; - estimate: boolean; - key: boolean; - labels: boolean; - link: boolean; - priority: boolean; - start_date: boolean; - state: boolean; - sub_issue_count: boolean; - updated_on: boolean; - }; - - // extra's - showEmptyGroups?: boolean; - - // actions - getProjectIssueFilterProperties: () => any | Promise; - getProjectIssueDisplayProperties: () => any | Promise; - getProjectMembers: () => any | Promise; - getProjectStates: () => any | Promise; - getProjectLabels: () => any | Promise; -} - -class IssueFilterStore implements IIssueFilterStore { - loader: boolean = false; - error: any | null = null; - - workspaceId: string | null = null; - projectId: string | null = null; - issueView: string | null = null; - - // root store - rootStore; - // service - projectPublishService = null; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - workspaceId: observable, - projectId: observable, - - // action - getProjectIssueFilterProperties: action, - getProjectIssueDisplayProperties: action, - getProjectMembers: action, - getProjectStates: action, - getProjectLabels: action, - // computed - }); - - this.rootStore = _rootStore; - this.projectPublishService = null; - } - - // computed functions starts - getComputedFilters = ( - _workspaceId: string, - _projectId: string, - _view: TIssueViews | null = "kanban" - ) => { - this.workspaceId = _workspaceId; - this.projectId = _projectId; - this.issueView = _view; - - let filteredRouteParams = { - assignees: undefined, // ['user_id', 'user_id'] - state: undefined, // ['state_id', 'state_id'] - priority: undefined, // ['low', 'high', 'medium', 'urgent', 'null'] - type: undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) - labels: undefined, // ['label_id', 'label_id'] - created_by: undefined, // ['user_id', 'user_id'] - start_date: undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] - target_date: undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] - order_by: "-created_at", // TIssueOrderByOptions - group_by: "state", // TIssueGroupByOptions - sub_issue: true, // true for all other views except spreadsheet - }; - - if (_view === "list") filteredRouteParams = { ...filteredRouteParams }; - if (_view === "kanban") filteredRouteParams = { ...filteredRouteParams }; - if (_view === "calendar") filteredRouteParams = { ...filteredRouteParams }; - if (_view === "spreadsheet") filteredRouteParams = { ...filteredRouteParams }; - if (_view === "gantt") filteredRouteParams = { ...filteredRouteParams }; - - return filteredRouteParams; - }; - - // computed functions ends - - // fetching current user project issue filter and display settings - getProjectIssueFilterProperties = () => {}; - - // fetching display properties - getProjectIssueDisplayProperties = () => {}; - - // fetching project members - getProjectMembers = () => {}; - - // fetching project state <-> groups - getProjectStates = () => {}; - - // fetching project labels - getProjectLabels = () => {}; -} - -export default IssueFilterStore; diff --git a/web/store/issue-views/data.ts b/web/store/issue-views/issue_data.ts similarity index 66% rename from web/store/issue-views/data.ts rename to web/store/issue-views/issue_data.ts index 559084e089d..939967023ac 100644 --- a/web/store/issue-views/data.ts +++ b/web/store/issue-views/issue_data.ts @@ -1,25 +1,25 @@ export const filtersPriority: { key: string; title: string }[] = [ - { key: "", title: "Urgent" }, - { key: "", title: "High" }, - { key: "", title: "Medium" }, - { key: "", title: "Low" }, - { key: "", title: "None" }, + { key: "urgent", title: "Urgent" }, + { key: "high", title: "High" }, + { key: "medium", title: "Medium" }, + { key: "low", title: "Low" }, + { key: "null", title: "None" }, ]; export const filtersStartDate = [ - { key: "", title: "Last Week" }, - { key: "", title: "2 weeks from now" }, - { key: "", title: "1 month from now" }, - { key: "", title: "2 months from now" }, - { key: "", title: "Custom" }, + { key: "last_week", title: "Last Week" }, + { key: "2_weeks_from_now", title: "2 weeks from now" }, + { key: "1_month_from_now", title: "1 month from now" }, + { key: "2_months_from_now", title: "2 months from now" }, + { key: "custom", title: "Custom" }, ]; export const filtersDueDate = [ - { key: "", title: "Last Week" }, - { key: "", title: "2 weeks from now" }, - { key: "", title: "1 month from now" }, - { key: "", title: "2 months from now" }, - { key: "", title: "Custom" }, + { key: "last_week", title: "Last Week" }, + { key: "2_weeks_from_now", title: "2 weeks from now" }, + { key: "1_month_from_now", title: "1 month from now" }, + { key: "2_months_from_now", title: "2 months from now" }, + { key: "custom", title: "Custom" }, ]; export const displayPropertyGroupBy = [ diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts new file mode 100644 index 00000000000..9cb21817eae --- /dev/null +++ b/web/store/issue-views/issue_filters.ts @@ -0,0 +1,330 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import {} from "services/issues.service"; +// default data +import { + filtersPriority, + filtersStartDate, + filtersDueDate, + displayPropertyGroupBy, + displayPropertyOrderBy, + displayPropertyIssueType, + displayProperties, +} from "./issue_data"; + +export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; +export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; + +export interface IIssueFilterStore { + loader: boolean; + error: any | null; + + // current workspace and project id + workspaceId: string | null; + projectId: string | null; + moduleId: string | null; + cycleId: string | null; + viewId: string | null; + // current issue layout:TIssueLayouts and view:TIssueViews + issueView: TIssueViews | null; + issueLayout: TIssueLayouts | null; + + // filters + // static filters data + priority: { key: string; title: string }[]; + startDate: { key: string; title: string }[]; + dueDate: { key: string; title: string }[]; + issueType: { key: string; title: string }[]; + + // static display filters data + groupBy: { key: string; title: string }[]; + orderBy: { key: string; title: string }[]; + + // dynamic filters data + state: { [key: string]: { key: string; title: string }[] } | null; + members: { [key: string]: { key: string; title: string }[] } | null; // members are used for both assignees and crated_by + labels: { [key: string]: { key: string; title: string }[] } | null; + + userSelectedFilters: { + priority: string[] | null; + state: string[] | null; + assignees: string[] | null; + created_by: string[] | null; + labels: string[] | null; + start_date: string[] | null; + target_date: string[] | null; + type: string; + }; + + userSelectedDisplayFilters?: { + group_by: undefined | string; + order_by: undefined | string; + sub_issue: boolean; + showEmptyGroups: boolean; + }; + + // static display properties data + displayProperties?: { key: string; title: string }[] | null; + userSelectedDisplayProperties?: { + assignee: boolean; + attachment_count: boolean; + created_on: boolean; + due_date: boolean; + estimate: boolean; + key: boolean; + labels: boolean; + link: boolean; + priority: boolean; + start_date: boolean; + state: boolean; + sub_issue_count: boolean; + updated_on: boolean; + }; + + // actions + getProjectIssueFilterProperties: () => any | Promise; + getProjectIssueDisplayProperties: () => any | Promise; + getProjectMembers: () => any | Promise; + getProjectStates: () => any | Promise; + getProjectLabels: () => any | Promise; +} + +class IssueFilterStore implements IIssueFilterStore { + loader: boolean = false; + error: any | null = null; + + workspaceId: string | null = null; + projectId: string | null = null; + moduleId: string | null = null; + cycleId: string | null = null; + viewId: string | null = null; + + issueLayout: TIssueLayouts | null = null; + issueView: TIssueViews | null = null; + + priority: { key: string; title: string }[] = filtersPriority; + startDate: { key: string; title: string }[] = filtersStartDate; + dueDate: { key: string; title: string }[] = filtersDueDate; + issueType: { key: string; title: string }[] = displayPropertyIssueType; + + // static display filters data + groupBy: { key: string; title: string }[] = displayPropertyGroupBy; + orderBy: { key: string; title: string }[] = displayPropertyOrderBy; + + state: { [key: string]: { key: string; title: string }[] } | null = null; + members: { [key: string]: { key: string; title: string }[] } | null = null; + labels: { [key: string]: { key: string; title: string }[] } | null = null; + + userSelectedFilters: { + priority: string[] | null; + state: string[] | null; + assignees: string[] | null; + created_by: string[] | null; + labels: string[] | null; + start_date: string[] | null; + target_date: string[] | null; + type: string; + } = { + priority: null, + state: null, + assignees: null, + created_by: null, + labels: null, + start_date: null, + target_date: null, + type: "all", + }; + + // root store + rootStore; + // service + projectPublishService = null; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + workspaceId: observable, + projectId: observable, + moduleId: observable, + cycleId: observable, + viewId: observable, + + issueLayout: observable, + issueView: observable, + + state: observable.ref, + members: observable.ref, + labels: observable.ref, + + userSelectedFilters: observable.ref, + + // action + setWorkspaceId: action, + setProjectId: action, + setModuleId: action, + setCycleId: action, + setViewId: action, + + setIssueLayout: action, + setIssueView: action, + + getProjectIssueFilterProperties: action, + getProjectIssueDisplayProperties: action, + getProjectMembers: action, + getProjectStates: action, + getProjectLabels: action, + // computed + }); + + this.rootStore = _rootStore; + this.projectPublishService = null; + } + + setWorkspaceId = (_workspaceId: string | null) => (this.workspaceId = _workspaceId); + setProjectId = (_projectId: string | null) => (this.projectId = _projectId); + setModuleId = (_moduleId: string | null) => (this.moduleId = _moduleId); + setCycleId = (_cycleId: string | null) => (this.cycleId = _cycleId); + setViewId = (_viewId: string | null) => (this.viewId = _viewId); + setIssueLayout = (_layout: TIssueLayouts | null) => (this.issueLayout = _layout); + setIssueView = (_view: TIssueViews | null) => (this.issueView = _view); + + computedFilter = (filters: any, filteredParams: any) => { + const computedFilters: any = {}; + Object.keys(filters).map((key) => { + if (filters[key] != undefined && filteredParams.includes(key)) + computedFilters[key] = + typeof filters[key] === "string" || typeof filters[key] === "boolean" + ? filters[key] + : filters[key].join(","); + }); + + return computedFilters; + }; + + // computed functions starts + getComputedFilters = ( + _workspaceId: string | null, + _projectId: string | null, + _moduleId: string | null, + _cycleId: string | null, + _viewId: string | null, + _issueView: TIssueViews, + _issueLayout: TIssueLayouts + ) => { + this.setWorkspaceId(_workspaceId); + this.setProjectId(_projectId); + this.setModuleId(_moduleId); + this.setCycleId(_cycleId); + this.setViewId(_viewId); + this.setIssueView(_issueView); + this.setIssueLayout(_issueLayout); + + let filteredRouteParams: any = { + priority: this.userSelectedFilters?.priority || undefined, + state: this.userSelectedFilters?.state || undefined, + assignees: this.userSelectedFilters?.assignees || undefined, // ['user_id', 'user_id'] + created_by: this.userSelectedFilters?.created_by || undefined, // ['user_id', 'user_id'] + labels: this.userSelectedFilters?.labels || undefined, // ['label_id', 'label_id'] + start_date: this.userSelectedFilters?.start_date || undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] + target_date: this.userSelectedFilters?.target_date || undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] + type: this.userSelectedFilters?.type || undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) + group_by: "state", // TIssueGroupByOptions + order_by: "-created_at", // TIssueOrderByOptions + sub_issue: true, // true for all other views except spreadsheet + }; + + let filteredParams: any = {}; + + if (this.issueLayout === "list") + filteredParams = [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "group_by", + "order_by", + "sub_issue", + ]; + if (this.issueLayout === "kanban") + filteredParams = [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "group_by", + "order_by", + "sub_issue", + ]; + if (this.issueLayout === "calendar") + filteredParams = [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + ]; + if (this.issueLayout === "spreadsheet") + filteredParams = [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + ]; + if (this.issueLayout === "gantt") + filteredParams = [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "order_by", + "sub_issue_id", + ]; + + filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); + + return filteredRouteParams; + }; + + // computed functions ends + + // fetching current user project issue filter and display settings + getProjectIssueFilterProperties = () => {}; + + // fetching display properties + getProjectIssueDisplayProperties = () => {}; + + // fetching project members + getProjectMembers = () => {}; + + // fetching project state <-> groups + getProjectStates = () => {}; + + // fetching project labels + getProjectLabels = () => {}; +} + +export default IssueFilterStore; diff --git a/web/store/issue-views/kanban.ts b/web/store/issue-views/kanban.ts deleted file mode 100644 index 34a9e5b14b3..00000000000 --- a/web/store/issue-views/kanban.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "../root"; -// services -import { ProjectIssuesServices } from "services/issues.service"; -// types -import { TIssueViews } from "./filters"; - -export interface IKanbanStore { - loader: boolean; - error: any | null; - issues: { [key: string]: any } | null; - - getIssuesAsync: ( - workspaceId: string, - projectId: string, - view: TIssueViews | null - ) => null | Promise; -} - -class KanbanStore implements IKanbanStore { - loader: boolean = false; - error: any | null = null; - - issues: { [key: string]: any } | null = null; - - // root store - rootStore; - // service - issueService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - issues: observable.ref, - // action - getIssuesAsync: action, - // computed - }); - - this.rootStore = _rootStore; - this.issueService = new ProjectIssuesServices(); - } - - // computed - get getIssues() { - if (this.rootStore.issueFilters.projectId && this.issues != null) - return this.issues[this.rootStore.issueFilters.projectId]; - else return null; - } - - // fetching issues - getIssuesAsync = async (workspaceId: string, projectId: string, view: TIssueViews | null) => { - try { - this.loader = true; - this.error = null; - - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - view - ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); - - if (issuesResponse) { - runInAction(() => { - this.issues = { ...this.issues, [projectId]: { ...issuesResponse } }; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // handle issue drag and drop -} - -export default KanbanStore; diff --git a/web/store/root.ts b/web/store/root.ts index eba9aff9514..9f4fd1d835b 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -7,8 +7,8 @@ import ProjectStore, { IProjectStore } from "./project"; import ProjectPublishStore, { IProjectPublishStore } from "./project-publish"; import IssuesStore from "./issues"; // issues views and filters -import IssueFilterStore from "./issue-views/filters"; -import KanbanStore from "./issue-views/kanban"; +import IssueFilterStore from "./issue-views/issue_filters"; +import IssueViewStore from "./issue-views/Issues"; enableStaticRendering(typeof window === "undefined"); @@ -19,7 +19,7 @@ export class RootStore { projectPublish: IProjectPublishStore; issues: IssuesStore; issueFilters: IssueFilterStore; - kanban: KanbanStore; + issueView: IssueViewStore; constructor() { this.user = new UserStore(this); @@ -28,6 +28,6 @@ export class RootStore { this.projectPublish = new ProjectPublishStore(this); this.issues = new IssuesStore(this); this.issueFilters = new IssueFilterStore(this); - this.kanban = new KanbanStore(this); + this.issueView = new IssueViewStore(this); } } diff --git a/yarn.lock b/yarn.lock index c0b96cdb935..f7ca7be8f54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5600,6 +5600,11 @@ lucide-react@^0.263.1: resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.263.1.tgz#a456ee0d171aa373929bd3ee20d6f9fb4429c301" integrity sha512-keqxAx97PlaEN89PXZ6ki1N8nRjGWtDa4021GFYLNj0RgruM5odbpl8GHTExj0hhPq3sF6Up0gnxt6TSHu+ovw== +lucide-react@^0.274.0: + version "0.274.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.274.0.tgz#d3b54dcb972b12f1292061448d61d422ef2e269d" + integrity sha512-qiWcojRXEwDiSimMX1+arnxha+ROJzZjJaVvCC0rsG6a9pUPjZePXSq7em4ZKMp0NDm1hyzPNkM7UaWC3LU2AA== + magic-string@^0.25.0, magic-string@^0.25.7: version "0.25.9" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" @@ -6623,7 +6628,14 @@ prosemirror-menu@^1.2.1: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1: +prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.8.1: + version "1.18.1" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd" + integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw== + dependencies: + orderedmap "^2.0.0" + +prosemirror-model@^1.19.0: version "1.19.3" resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006" integrity sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ== From 8c04e770c080a113bb8d7c316520c79b811602f6 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Fri, 8 Sep 2023 13:06:02 +0530 Subject: [PATCH 005/102] chore: resolved build error --- web/store/issue-views/Issue_details.ts | 176 ------------------------- 1 file changed, 176 deletions(-) diff --git a/web/store/issue-views/Issue_details.ts b/web/store/issue-views/Issue_details.ts index 9f0268bbd7d..b6da85b1b5d 100644 --- a/web/store/issue-views/Issue_details.ts +++ b/web/store/issue-views/Issue_details.ts @@ -1,205 +1,29 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"; // types import { RootStore } from "../root"; -// services -import { ProjectIssuesServices } from "services/issues.service"; -// types -import { TIssueLayouts } from "./issue_filters"; export interface IIssueViewStore { loader: boolean; error: any | null; - - issues: { [key: string]: { [key: string]: any } } | null; - - getIssuesAsync: ( - workspaceId: string, - projectId: string, - view: TIssueLayouts | null - ) => null | Promise; } class IssueViewStore implements IIssueViewStore { loader: boolean = false; error: any | null = null; - issues: { [key: string]: { [key: string]: any } } | null = null; - // root store rootStore; // service - issueService; constructor(_rootStore: RootStore) { makeObservable(this, { // observable loader: observable, error: observable, - - issues: observable.ref, - // action - getIssuesAsync: action, - // computed }); this.rootStore = _rootStore; - this.issueService = new ProjectIssuesServices(); - } - - // computed - get getIssues() { - if ( - this.rootStore.issueFilters.projectId && - this.issues != null && - this.rootStore.issueFilters.issueView != null - ) - return this.issues[this.rootStore.issueFilters.projectId][ - this.rootStore.issueFilters.issueView - ]; - else return null; } - - // handling kanBan drag and drop events - - // fetching issues - getIssuesAsync = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - "kanBan", - "issues" - ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); - - if (issuesResponse) { - runInAction(() => { - this.issues = { ...this.issues, [projectId]: { issues: { ...issuesResponse } } }; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching issues for modules - getIssuesForModulesAsync = async (workspaceId: string, projectId: string, moduleId: string) => { - try { - this.loader = true; - this.error = null; - - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - "kanBan", - "modules" - ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); - - if (issuesResponse) { - runInAction(() => { - this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching issues for cycles - getIssuesForModulesCycles = async (workspaceId: string, projectId: string, moduleId: string) => { - try { - this.loader = true; - this.error = null; - - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - "kanBan", - "cycles" - ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); - - if (issuesResponse) { - runInAction(() => { - this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching issues for views - getIssuesForViews = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - "kanBan", - "views" - ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); - - if (issuesResponse) { - runInAction(() => { - this.issues = { ...this.issues, [projectId]: { views: { ...issuesResponse } } }; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error", error); - this.loader = false; - this.error = null; - return error; - } - }; } export default IssueViewStore; From 0445c610bf2d105a224b5a9014793f39fad636c3 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 12 Sep 2023 19:15:36 +0530 Subject: [PATCH 006/102] chore: created filters and updated the issue filters, display_filter and display_properties in mobx and components --- .../header/display-filters/index.tsx | 15 + .../header/filters/assignees.tsx | 90 ++ .../header/filters/created-by.tsx | 90 ++ .../issue-layouts/header/filters/index.tsx | 57 + .../issue-layouts/header/filters/labels.tsx | 90 ++ .../issue-layouts/header/filters/priority.tsx | 90 ++ .../header/filters/start-date.tsx | 90 ++ .../header/filters/state-group.tsx | 90 ++ .../issue-layouts/header/filters/state.tsx | 51 + .../header/filters/target-date.tsx | 90 ++ .../header/layout-filter/index.tsx | 115 ++ web/components/issue-layouts/kanban/index.tsx | 26 +- web/components/issue-layouts/root.tsx | 14 + web/pages/kanban.tsx | 32 +- web/services/state.service.ts | 2 +- web/services/workspace.service.ts | 2 +- web/store/issue-views/Issues.ts | 34 +- web/store/issue-views/issue_data.ts | 21 +- web/store/issue-views/issue_filters.ts | 1166 +++++++++++++++-- 19 files changed, 2003 insertions(+), 162 deletions(-) create mode 100644 web/components/issue-layouts/header/display-filters/index.tsx create mode 100644 web/components/issue-layouts/header/filters/assignees.tsx create mode 100644 web/components/issue-layouts/header/filters/created-by.tsx create mode 100644 web/components/issue-layouts/header/filters/index.tsx create mode 100644 web/components/issue-layouts/header/filters/labels.tsx create mode 100644 web/components/issue-layouts/header/filters/priority.tsx create mode 100644 web/components/issue-layouts/header/filters/start-date.tsx create mode 100644 web/components/issue-layouts/header/filters/state-group.tsx create mode 100644 web/components/issue-layouts/header/filters/state.tsx create mode 100644 web/components/issue-layouts/header/filters/target-date.tsx create mode 100644 web/components/issue-layouts/header/layout-filter/index.tsx create mode 100644 web/components/issue-layouts/root.tsx diff --git a/web/components/issue-layouts/header/display-filters/index.tsx b/web/components/issue-layouts/header/display-filters/index.tsx new file mode 100644 index 00000000000..33561c0ae39 --- /dev/null +++ b/web/components/issue-layouts/header/display-filters/index.tsx @@ -0,0 +1,15 @@ +import React from "react"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const DisplayPropertiesSelection = () => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + return ( +
+
Filter Selection
+
+ ); +}; diff --git a/web/components/issue-layouts/header/filters/assignees.tsx b/web/components/issue-layouts/header/filters/assignees.tsx new file mode 100644 index 00000000000..66aa66e7957 --- /dev/null +++ b/web/components/issue-layouts/header/filters/assignees.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterAssignees = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); + }; + + return ( +
+
+
Assignees
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( +
+ +
+ {priority.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/created-by.tsx b/web/components/issue-layouts/header/filters/created-by.tsx new file mode 100644 index 00000000000..f1d28dad5fb --- /dev/null +++ b/web/components/issue-layouts/header/filters/created-by.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterCreatedBy = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); + }; + + return ( +
+
+
Created By
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( +
+ +
+ {priority.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/index.tsx b/web/components/issue-layouts/header/filters/index.tsx new file mode 100644 index 00000000000..0913ed033cb --- /dev/null +++ b/web/components/issue-layouts/header/filters/index.tsx @@ -0,0 +1,57 @@ +import React from "react"; +// components +import { FilterPriority } from "./priority"; +import { FilterState } from "./state"; +import { FilterStateGroup } from "./state-group"; +import { FilterAssignees } from "./assignees"; +import { FilterCreatedBy } from "./created-by"; +import { FilterLabels } from "./labels"; +import { FilterStartDate } from "./start-date"; +import { FilterTargetDate } from "./target-date"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterSelection = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + return ( +
+ {/* priority */} +
+ +
+ {/* state group */} +
+ +
+ {/* state */} +
+ +
+ {/* assignees */} +
+ +
+ {/* created_by */} +
+ +
+ {/* labels */} +
+ +
+ {/* start_date */} +
+ +
+ {/* due_date */} +
+ +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/labels.tsx b/web/components/issue-layouts/header/filters/labels.tsx new file mode 100644 index 00000000000..6d8eed30a16 --- /dev/null +++ b/web/components/issue-layouts/header/filters/labels.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterLabels = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); + }; + + return ( +
+
+
Labels
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( +
+ +
+ {priority.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/priority.tsx b/web/components/issue-layouts/header/filters/priority.tsx new file mode 100644 index 00000000000..4615fbfc473 --- /dev/null +++ b/web/components/issue-layouts/header/filters/priority.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircle, + SignalHigh, + SignalMedium, + SignalLow, + Ban, + Check, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); +}; + +export const FilterPriority = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + return ( +
+
+
Priority
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((_priority) => ( +
+ +
+ {_priority.title} +
+
+ {false && } +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/start-date.tsx b/web/components/issue-layouts/header/filters/start-date.tsx new file mode 100644 index 00000000000..b35d5f30f9a --- /dev/null +++ b/web/components/issue-layouts/header/filters/start-date.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterStartDate = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); + }; + + return ( +
+
+
Start Date
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( +
+ +
+ {priority.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/state-group.tsx b/web/components/issue-layouts/header/filters/state-group.tsx new file mode 100644 index 00000000000..15049650a0c --- /dev/null +++ b/web/components/issue-layouts/header/filters/state-group.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const StateGroupIcons = ({ stateGroup }: { stateGroup: string }) => { + if (stateGroup === "cancelled") + return ( +
+ +
+ ); + if (stateGroup === "completed") + return ( +
+ +
+ ); + if (stateGroup === "started") + return ( +
+ +
+ ); + if (stateGroup === "unstarted") + return ( +
+ +
+ ); + return ( +
+ +
+ ); +}; + +export const FilterStateGroup = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + return ( +
+
+
State Group
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.state_group && + issueFilterStore?.issueRenderFilters?.state_group.length > 0 && + issueFilterStore?.issueRenderFilters?.state_group.map((_stateGroup) => ( +
+ +
+ {_stateGroup.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/state.tsx b/web/components/issue-layouts/header/filters/state.tsx new file mode 100644 index 00000000000..a2b29fbee63 --- /dev/null +++ b/web/components/issue-layouts/header/filters/state.tsx @@ -0,0 +1,51 @@ +import React from "react"; +// lucide icons +import { CheckIcon, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { StateGroupIcons } from "./state-group"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterState = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + return ( +
+
+
State
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.projectStates && + issueFilterStore?.projectStates.length > 0 && + issueFilterStore?.projectStates.map((_state) => ( +
+ +
+ {_state?.name} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/filters/target-date.tsx b/web/components/issue-layouts/header/filters/target-date.tsx new file mode 100644 index 00000000000..8d5af198db8 --- /dev/null +++ b/web/components/issue-layouts/header/filters/target-date.tsx @@ -0,0 +1,90 @@ +import React from "react"; +// lucide icons +import { + AlertCircleIcon, + SignalHighIcon, + SignalMediumIcon, + SignalLowIcon, + BanIcon, + CheckIcon, + ChevronDown, + ChevronUp, +} from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterTargetDate = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + + const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") + return ( +
+ +
+ ); + if (priority === "high") + return ( +
+ +
+ ); + if (priority === "medium") + return ( +
+ +
+ ); + if (priority === "low") + return ( +
+ +
+ ); + return ( +
+ +
+ ); + }; + + return ( +
+
+
Target Date
+
setAllFiltersToggle(!allFiltersToggle)} + > + {allFiltersToggle ? : } +
+
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( +
+ +
+ {priority.title} +
+
+ +
+
+ ))} +
+
+ ); +}); diff --git a/web/components/issue-layouts/header/layout-filter/index.tsx b/web/components/issue-layouts/header/layout-filter/index.tsx new file mode 100644 index 00000000000..ce0410f7561 --- /dev/null +++ b/web/components/issue-layouts/header/layout-filter/index.tsx @@ -0,0 +1,115 @@ +import React from "react"; +// lucide icons +import { Columns, Grid3x3, Calendar, GanttChart, List } from "lucide-react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { RootStore } from "store/root"; +import { TIssueLayouts } from "store/issue-views/issue_filters"; +import { useMobxStore } from "lib/mobx/store-provider"; + +export const LayoutSelection = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const layoutSelectionFilters: { key: TIssueLayouts; title: string; icon: any }[] = [ + { + key: "list", + title: "List", + icon: List, + }, + { + key: "kanban", + title: "Kanban", + icon: Grid3x3, + }, + { + key: "calendar", + title: "Calendar", + icon: Calendar, + }, + { + key: "spreadsheet", + title: "Spreadsheet", + icon: Columns, + }, + { + key: "gantt", + title: "Gantt", + icon: GanttChart, + }, + ]; + + const handleLayoutSelection = (layout: TIssueLayouts) => { + if (!issueFilterStore.workspaceId) return; + if (issueFilterStore.issueView === "my_issues") { + issueStore.getMyIssuesAsync(issueFilterStore.workspaceId, issueFilterStore.issueView, layout); + return; + } + + if (!issueFilterStore.projectId) return; + if (issueFilterStore.issueView === "issues") { + issueStore.getProjectIssuesAsync( + issueFilterStore.workspaceId, + issueFilterStore.projectId, + issueFilterStore.issueView, + layout + ); + return; + } + if (issueFilterStore.issueView === "modules" && issueFilterStore.moduleId) { + issueStore.getIssuesForModulesAsync( + issueFilterStore.workspaceId, + issueFilterStore.projectId, + issueFilterStore.moduleId, + issueFilterStore.issueView, + layout + ); + return; + } + if (issueFilterStore.issueView === "cycles" && issueFilterStore.cycleId) { + issueStore.getIssuesForCyclesAsync( + issueFilterStore.workspaceId, + issueFilterStore.projectId, + issueFilterStore.cycleId, + issueFilterStore.issueView, + layout + ); + return; + } + if (issueFilterStore.issueView === "views" && issueFilterStore.viewId) { + issueStore.getIssuesForViewsAsync( + issueFilterStore.workspaceId, + issueFilterStore.projectId, + issueFilterStore.viewId, + issueFilterStore.issueView, + layout + ); + return; + } + }; + + return ( +
+ {layoutSelectionFilters.map((_layout) => ( +
handleLayoutSelection(_layout?.key)} + > + <_layout.icon + size={15} + strokeWidth={2} + className={`${ + issueFilterStore?.issueLayout == _layout?.key + ? `text-gray-900` + : `text-gray-700 group-hover:text-gray-900` + }`} + /> +
+ ))} +
+ ); +}); diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx index 27d7fcbc01d..51828ae992c 100644 --- a/web/components/issue-layouts/kanban/index.tsx +++ b/web/components/issue-layouts/kanban/index.tsx @@ -12,7 +12,7 @@ import { RootStore } from "store/root"; export const IssueKanBanViewRoot = observer(() => { const store: RootStore = useMobxStore(); - const { issueView: issueViewStore } = store; + const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; const onDragEnd = (result: any) => { if (!result) return; @@ -28,9 +28,31 @@ export const IssueKanBanViewRoot = observer(() => { console.log("result", result); }; + console.log("------"); + console.log("workspace id -->", issueFilterStore?.workspaceId); + console.log("project id -->", issueFilterStore?.projectId); + console.log("module id -->", issueFilterStore?.moduleId); + console.log("cycle id -->", issueFilterStore?.cycleId); + console.log("view id -->", issueFilterStore?.viewId); + + console.log("<-- workspace level -->"); + console.log("workspace projects -->", issueFilterStore?.workspaceProjects); + console.log("workspace labels -->", issueFilterStore?.workspaceLabels); + + console.log("<-- project level -->"); + console.log("project states -->", issueFilterStore?.projectStates); + console.log("project labels -->", issueFilterStore?.projectLabels); + console.log("project members -->", issueFilterStore?.projectMembers); + + console.log("project display properties -->", issueFilterStore?.projectDisplayProperties); + + console.log("issue layout -->", issueFilterStore?.issueLayout); + console.log("issues -->", issueViewStore?.getIssues); + console.log("------"); + return (
- {issueViewStore.loader && issueViewStore?.issues === null ? ( + {issueViewStore.loader || issueViewStore?.getIssues === null ? (
Loading...
) : ( <> diff --git a/web/components/issue-layouts/root.tsx b/web/components/issue-layouts/root.tsx new file mode 100644 index 00000000000..23752fe49c4 --- /dev/null +++ b/web/components/issue-layouts/root.tsx @@ -0,0 +1,14 @@ +import React from "react"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { RootStore } from "store/root"; +import { TIssueLayouts } from "store/issue-views/issue_filters"; +import { useMobxStore } from "lib/mobx/store-provider"; + +export const IssuesRoot = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + return
issue root
; +}); diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx index 8e0312dd918..a31d39bfcc7 100644 --- a/web/pages/kanban.tsx +++ b/web/pages/kanban.tsx @@ -3,6 +3,8 @@ import React from "react"; import useSWR from "swr"; // components import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; +import { LayoutSelection } from "components/issue-layouts/header/layout-filter"; +import { FilterSelection } from "components/issue-layouts/header/filters"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; @@ -15,21 +17,20 @@ const KanBanViewRoot = () => { const viewSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; const store: RootStore = useMobxStore(); - const { issueView: issueViewStore } = store; + const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; React.useEffect(() => { const init = async () => { // my issues under a workspace - console.log("started--->"); + // console.log("started--->"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "list"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "kanban"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "calendar"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "spreadsheet"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "gantt"); - // project issues under and workspace and project - // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); - await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); + await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); + // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "calendar"); // await issueViewStore.getProjectIssuesAsync( // workspaceSlug, @@ -38,7 +39,6 @@ const KanBanViewRoot = () => { // "spreadsheet" // ); // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "gantt"); - // module issues under and workspace and project // await issueViewStore.getIssuesForModulesAsync( // workspaceSlug, @@ -75,7 +75,6 @@ const KanBanViewRoot = () => { // "modules", // "gantt" // ); - // cycle issues under and workspace and project // await issueViewStore.getIssuesForCyclesAsync( // workspaceSlug, @@ -112,7 +111,6 @@ const KanBanViewRoot = () => { // "cycles", // "gantt" // ); - // cycle issues under and workspace and project // await issueViewStore.getIssuesForViewsAsync( // workspaceSlug, @@ -149,8 +147,7 @@ const KanBanViewRoot = () => { // "views", // "gantt" // ); - - console.log("ended--->"); + // console.log("ended--->"); }; init(); @@ -163,10 +160,21 @@ const KanBanViewRoot = () => { className="flex-shrink-0 h-[60px] border-b border-gray-200" // style={{ writingMode: "vertical-lr" }} > - Filter Header +
+
+
Filter Header
+
+
+
{/* */}
+
+ +
+
+
- + + {/* */}
diff --git a/web/services/state.service.ts b/web/services/state.service.ts index 52481f8bb31..a0d2c34fd13 100644 --- a/web/services/state.service.ts +++ b/web/services/state.service.ts @@ -10,7 +10,7 @@ const trackEvent = // types import type { ICurrentUserResponse, IState, IStateResponse } from "types"; -class ProjectStateServices extends APIService { +export class ProjectStateServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/services/workspace.service.ts b/web/services/workspace.service.ts index 8097253e634..47d6b329e94 100644 --- a/web/services/workspace.service.ts +++ b/web/services/workspace.service.ts @@ -20,7 +20,7 @@ import { const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class WorkspaceService extends APIService { +export class WorkspaceService extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index 817eb7c23f2..b839cfeec2d 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -121,14 +121,19 @@ class IssueViewStore implements IIssueViewStore { get getIssues() { if (this.issues != null) { const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; - const currentLayout: TIssueLayouts | null = this.rootStore.issueFilters.issueLayout; const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; const currentProjectId: string | null = this.rootStore.issueFilters.projectId; const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; const currentViewId: string | null = this.rootStore.issueFilters.viewId; - if (!currentView || !currentLayout || !currentWorkspaceId) return null; + if (!currentView || !currentWorkspaceId) return null; + + const currentLayout: TIssueLayouts = currentProjectId + ? this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId] + ?.project_issue_properties?.[currentProjectId]?.renderLayout + : this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.my_issue_properties + ?.renderLayout; if (currentView === "my_issues") return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; @@ -149,6 +154,8 @@ class IssueViewStore implements IIssueViewStore { currentViewId ]?.[currentLayout]; } + + return null; } // fetching my issues @@ -157,6 +164,7 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; + await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, null, @@ -189,7 +197,7 @@ class IssueViewStore implements IIssueViewStore { return issuesResponse; } catch (error) { - console.warn("error", error); + console.warn("error in fetching the my issues", error); this.loader = false; this.error = null; return error; @@ -207,6 +215,7 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; + await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -249,7 +258,7 @@ class IssueViewStore implements IIssueViewStore { return issuesResponse; } catch (error) { - console.warn("error", error); + console.warn("error in fetching the project issues", error); this.loader = false; this.error = null; return error; @@ -268,6 +277,11 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; + await this.rootStore.issueFilters.getProjectIssueModuleFilters( + workspaceId, + projectId, + moduleId + ); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -314,7 +328,7 @@ class IssueViewStore implements IIssueViewStore { return issuesResponse; } catch (error) { - console.warn("error", error); + console.warn("error in fetching the project module issues", error); this.loader = false; this.error = null; return error; @@ -333,6 +347,11 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; + await this.rootStore.issueFilters.getProjectIssueCyclesFilters( + workspaceId, + projectId, + cycleId + ); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -379,7 +398,7 @@ class IssueViewStore implements IIssueViewStore { return issuesResponse; } catch (error) { - console.warn("error", error); + console.warn("error in fetching the project cycles issues", error); this.loader = false; this.error = null; return error; @@ -398,6 +417,7 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; + await this.rootStore.issueFilters.getProjectIssueViewsFilters(workspaceId, projectId, viewId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -443,7 +463,7 @@ class IssueViewStore implements IIssueViewStore { return issuesResponse; } catch (error) { - console.warn("error", error); + console.warn("error in fetching the project view issues", error); this.loader = false; this.error = null; return error; diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index 939967023ac..d5efa6e7ece 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -6,7 +6,15 @@ export const filtersPriority: { key: string; title: string }[] = [ { key: "null", title: "None" }, ]; -export const filtersStartDate = [ +export const filterStateGroup: { key: string; title: string }[] = [ + { key: "backlog", title: "Backlog" }, + { key: "unstarted", title: "Unstarted" }, + { key: "started", title: "Started" }, + { key: "completed", title: "Completed" }, + { key: "cancelled", title: "Cancelled" }, +]; + +export const filtersStartDate: { key: string; title: string }[] = [ { key: "last_week", title: "Last Week" }, { key: "2_weeks_from_now", title: "2 weeks from now" }, { key: "1_month_from_now", title: "1 month from now" }, @@ -14,7 +22,7 @@ export const filtersStartDate = [ { key: "custom", title: "Custom" }, ]; -export const filtersDueDate = [ +export const filtersDueDate: { key: string; title: string }[] = [ { key: "last_week", title: "Last Week" }, { key: "2_weeks_from_now", title: "2 weeks from now" }, { key: "1_month_from_now", title: "1 month from now" }, @@ -22,16 +30,17 @@ export const filtersDueDate = [ { key: "custom", title: "Custom" }, ]; -export const displayPropertyGroupBy = [ +export const displayPropertyGroupBy: { key: string; title: string }[] = [ { key: "state", title: "States" }, { key: "state_detail.group", title: "State Groups" }, { key: "priority", title: "Priority" }, + { key: "Project", title: "project" }, // required this on my issues { key: "labels", title: "Labels" }, { key: "assignees", title: "Assignees" }, { key: "created_by", title: "Created By" }, ]; -export const displayPropertyOrderBy = [ +export const displayPropertyOrderBy: { key: string; title: string }[] = [ { key: "sort_order", title: "Manual" }, { key: "created_at", title: "Last Created" }, { key: "updated_at", title: "Last Updated" }, @@ -39,13 +48,13 @@ export const displayPropertyOrderBy = [ { key: "priority", title: "Priority" }, ]; -export const displayPropertyIssueType = [ +export const displayPropertyIssueType: { key: string; title: string }[] = [ { key: "all", title: "All" }, { key: "active", title: "Active Issues" }, { key: "backlog", title: "Backlog Issues" }, ]; -export const displayProperties = [ +export const displayProperties: { key: string; title: string }[] = [ { key: "assignee", title: "Assignee" }, { key: "start_date", title: "Start Date" }, { key: "due_date", title: "Due Date" }, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 9cb21817eae..102f1519343 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -2,10 +2,14 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx" // types import { RootStore } from "../root"; // services -import {} from "services/issues.service"; +import { WorkspaceService } from "services/workspace.service"; +import { ProjectIssuesServices } from "services/issues.service"; +import { ProjectStateServices } from "services/state.service"; +import { ProjectServices } from "services/project.service"; // default data import { filtersPriority, + filterStateGroup, filtersStartDate, filtersDueDate, displayPropertyGroupBy, @@ -15,8 +19,98 @@ import { } from "./issue_data"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; + export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; +export interface IIssueFilter { + priority: string[] | undefined; + state: string[] | undefined; + state_group: string[] | undefined; + assignees: string[] | undefined; + created_by: string[] | undefined; + labels: string[] | undefined; + start_date: string[] | undefined; + target_date: string[] | undefined; + [key: string]: any; +} + +export interface IIssueDisplayFilters { + group_by: undefined | string; + order_by: undefined | string; + type: string | undefined; + sub_issue: boolean; + show_empty_groups: boolean; + layout: TIssueLayouts; + calendar_date_range: string | undefined; // only for calendar + start_target_date: boolean; + [key: string]: any; +} + +export interface IIssueDisplayProperties { + assignee: boolean; + attachment_count: boolean; + created_on: boolean; + due_date: boolean; + estimate: boolean; + key: boolean; + labels: boolean; + link: boolean; + priority: boolean; + start_date: boolean; + state: boolean; + sub_issue_count: boolean; + updated_on: boolean; + [key: string]: any; +} + +export interface IIssueRenderFilters { + priority: { key: string; title: string }[]; + state_group: { key: string; title: string }[]; + start_date: { key: string; title: string }[]; + due_date: { key: string; title: string }[]; + group_by: { key: string; title: string }[]; + order_by: { key: string; title: string }[]; + issue_type: { key: string; title: string }[]; + display_properties: { key: string; title: string }[]; + workspace_properties: { + [key: string]: { + projects: any[]; + labels: any[]; + project_properties: { + [key: string]: { + states: any[] | null; + labels: any[] | null; + members: any[] | null; + }; + }; + }; + }; +} + +export interface IIssueFilters { + [key: string]: { + my_issue_properties: { + filters: IIssueFilter; + display_filters: IIssueDisplayFilters; + display_properties: IIssueDisplayProperties; + renderLayout: TIssueLayouts; + }; + project_issue_properties: { + [key: string]: { + issues: { + filters: IIssueFilter; + display_filters: IIssueDisplayFilters; + }; + cycles: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; + modules: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; + views: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; + display_properties: IIssueDisplayProperties; + renderLayout: TIssueLayouts; + }; + }; + }; +} + export interface IIssueFilterStore { loader: boolean; error: any | null; @@ -27,68 +121,37 @@ export interface IIssueFilterStore { moduleId: string | null; cycleId: string | null; viewId: string | null; - // current issue layout:TIssueLayouts and view:TIssueViews issueView: TIssueViews | null; - issueLayout: TIssueLayouts | null; - // filters - // static filters data - priority: { key: string; title: string }[]; - startDate: { key: string; title: string }[]; - dueDate: { key: string; title: string }[]; - issueType: { key: string; title: string }[]; - - // static display filters data - groupBy: { key: string; title: string }[]; - orderBy: { key: string; title: string }[]; - - // dynamic filters data - state: { [key: string]: { key: string; title: string }[] } | null; - members: { [key: string]: { key: string; title: string }[] } | null; // members are used for both assignees and crated_by - labels: { [key: string]: { key: string; title: string }[] } | null; - - userSelectedFilters: { - priority: string[] | null; - state: string[] | null; - assignees: string[] | null; - created_by: string[] | null; - labels: string[] | null; - start_date: string[] | null; - target_date: string[] | null; - type: string; - }; + issueRenderFilters: IIssueRenderFilters; + issueFilters: IIssueFilters; - userSelectedDisplayFilters?: { - group_by: undefined | string; - order_by: undefined | string; - sub_issue: boolean; - showEmptyGroups: boolean; - }; + // actions + getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; + updateWorkspaceMyIssuesFilters: () => any | Promise; - // static display properties data - displayProperties?: { key: string; title: string }[] | null; - userSelectedDisplayProperties?: { - assignee: boolean; - attachment_count: boolean; - created_on: boolean; - due_date: boolean; - estimate: boolean; - key: boolean; - labels: boolean; - link: boolean; - priority: boolean; - start_date: boolean; - state: boolean; - sub_issue_count: boolean; - updated_on: boolean; - }; + getProjectLevelMembers: (workspaceId: string, projectId: string) => any | Promise; + getProjectLevelStates: (workspaceId: string, projectId: string) => any | Promise; + getProjectLevelLabels: (workspaceId: string, projectId: string) => any | Promise; + getProjectDisplayFilters: (workspaceId: string, projectId: string) => any | Promise; + getProjectDisplayProperties: (workspaceId: string, projectId: string) => any | Promise; - // actions - getProjectIssueFilterProperties: () => any | Promise; - getProjectIssueDisplayProperties: () => any | Promise; - getProjectMembers: () => any | Promise; - getProjectStates: () => any | Promise; - getProjectLabels: () => any | Promise; + getProjectIssueFilters: (workspaceId: string, projectId: string) => any | Promise; + getProjectIssueModuleFilters: ( + workspaceId: string, + projectId: string, + moduleId: string + ) => any | Promise; + getProjectIssueCyclesFilters: ( + workspaceId: string, + projectId: string, + cycleId: string + ) => any | Promise; + getProjectIssueViewsFilters: ( + workspaceId: string, + projectId: string, + viewId: string + ) => any | Promise; } class IssueFilterStore implements IIssueFilterStore { @@ -101,46 +164,28 @@ class IssueFilterStore implements IIssueFilterStore { cycleId: string | null = null; viewId: string | null = null; - issueLayout: TIssueLayouts | null = null; issueView: TIssueViews | null = null; - priority: { key: string; title: string }[] = filtersPriority; - startDate: { key: string; title: string }[] = filtersStartDate; - dueDate: { key: string; title: string }[] = filtersDueDate; - issueType: { key: string; title: string }[] = displayPropertyIssueType; - - // static display filters data - groupBy: { key: string; title: string }[] = displayPropertyGroupBy; - orderBy: { key: string; title: string }[] = displayPropertyOrderBy; - - state: { [key: string]: { key: string; title: string }[] } | null = null; - members: { [key: string]: { key: string; title: string }[] } | null = null; - labels: { [key: string]: { key: string; title: string }[] } | null = null; - - userSelectedFilters: { - priority: string[] | null; - state: string[] | null; - assignees: string[] | null; - created_by: string[] | null; - labels: string[] | null; - start_date: string[] | null; - target_date: string[] | null; - type: string; - } = { - priority: null, - state: null, - assignees: null, - created_by: null, - labels: null, - start_date: null, - target_date: null, - type: "all", + issueRenderFilters: IIssueRenderFilters = { + priority: filtersPriority, + state_group: filterStateGroup, + start_date: filtersStartDate, + due_date: filtersDueDate, + group_by: displayPropertyGroupBy, + order_by: displayPropertyOrderBy, + issue_type: displayPropertyIssueType, + display_properties: displayProperties, + workspace_properties: {}, }; + issueFilters: IIssueFilters = {}; // root store rootStore; // service - projectPublishService = null; + workspaceService; + issueService; + stateService; + projectService; constructor(_rootStore: RootStore) { makeObservable(this, { @@ -154,14 +199,19 @@ class IssueFilterStore implements IIssueFilterStore { cycleId: observable, viewId: observable, - issueLayout: observable, issueView: observable, - state: observable.ref, - members: observable.ref, - labels: observable.ref, + issueRenderFilters: observable.ref, + issueFilters: observable.ref, - userSelectedFilters: observable.ref, + // computed + issueLayout: computed, + workspaceProjects: computed, + workspaceLabels: computed, + projectStates: computed, + projectLabels: computed, + projectMembers: computed, + projectDisplayProperties: computed, // action setWorkspaceId: action, @@ -169,20 +219,30 @@ class IssueFilterStore implements IIssueFilterStore { setModuleId: action, setCycleId: action, setViewId: action, - - setIssueLayout: action, setIssueView: action, - getProjectIssueFilterProperties: action, - getProjectIssueDisplayProperties: action, - getProjectMembers: action, - getProjectStates: action, - getProjectLabels: action, - // computed + getComputedFilters: action, + + getWorkspaceMyIssuesFilters: action, + updateWorkspaceMyIssuesFilters: action, + + getProjectLevelMembers: action, + getProjectLevelStates: action, + getProjectLevelLabels: action, + getProjectDisplayFilters: action, + getProjectDisplayProperties: action, + + getProjectIssueFilters: action, + getProjectIssueModuleFilters: action, + getProjectIssueCyclesFilters: action, + getProjectIssueViewsFilters: action, }); this.rootStore = _rootStore; - this.projectPublishService = null; + this.workspaceService = new WorkspaceService(); + this.issueService = new ProjectIssuesServices(); + this.stateService = new ProjectStateServices(); + this.projectService = new ProjectServices(); } setWorkspaceId = (_workspaceId: string | null) => (this.workspaceId = _workspaceId); @@ -190,9 +250,52 @@ class IssueFilterStore implements IIssueFilterStore { setModuleId = (_moduleId: string | null) => (this.moduleId = _moduleId); setCycleId = (_cycleId: string | null) => (this.cycleId = _cycleId); setViewId = (_viewId: string | null) => (this.viewId = _viewId); - setIssueLayout = (_layout: TIssueLayouts | null) => (this.issueLayout = _layout); setIssueView = (_view: TIssueViews | null) => (this.issueView = _view); + // computed + get issueLayout() { + if (!this.workspaceId) return null; + + if (!this.projectId) + return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.renderLayout; + if (this.projectId) + return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.renderLayout; + } + + get workspaceProjects() { + if (!this.workspaceId) return null; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.projects; + } + get workspaceLabels() { + if (!this.workspaceId) return null; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.labels; + } + + get projectStates() { + if (!this.workspaceId || !this.projectId) return null; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ + this.projectId + ]?.states; + } + get projectLabels() { + if (!this.workspaceId || !this.projectId) return null; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ + this.projectId + ]?.labels; + } + get projectMembers() { + if (!this.workspaceId || !this.projectId) return null; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ + this.projectId + ]?.members; + } + get projectDisplayProperties() { + if (!this.workspaceId || !this.projectId) return null; + return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.display_properties; + } + computedFilter = (filters: any, filteredParams: any) => { const computedFilters: any = {}; Object.keys(filters).map((key) => { @@ -205,8 +308,6 @@ class IssueFilterStore implements IIssueFilterStore { return computedFilters; }; - - // computed functions starts getComputedFilters = ( _workspaceId: string | null, _projectId: string | null, @@ -222,17 +323,44 @@ class IssueFilterStore implements IIssueFilterStore { this.setCycleId(_cycleId); this.setViewId(_viewId); this.setIssueView(_issueView); - this.setIssueLayout(_issueLayout); + + if (_workspaceId) { + if (!_projectId) + this.issueFilters = { + ...this.issueFilters, + [_workspaceId]: { + ...this.issueFilters[_workspaceId], + my_issue_properties: { + ...this.issueFilters[_workspaceId]?.my_issue_properties, + renderLayout: _issueLayout, + }, + }, + }; + else + this.issueFilters = { + ...this.issueFilters, + [_workspaceId]: { + ...this.issueFilters[_workspaceId], + project_issue_properties: { + ...this.issueFilters[_workspaceId]?.project_issue_properties, + [_projectId]: { + ...this.issueFilters[_workspaceId]?.project_issue_properties?.[_projectId], + renderLayout: _issueLayout, + }, + }, + }, + }; + } let filteredRouteParams: any = { - priority: this.userSelectedFilters?.priority || undefined, - state: this.userSelectedFilters?.state || undefined, - assignees: this.userSelectedFilters?.assignees || undefined, // ['user_id', 'user_id'] - created_by: this.userSelectedFilters?.created_by || undefined, // ['user_id', 'user_id'] - labels: this.userSelectedFilters?.labels || undefined, // ['label_id', 'label_id'] - start_date: this.userSelectedFilters?.start_date || undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] - target_date: this.userSelectedFilters?.target_date || undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] - type: this.userSelectedFilters?.type || undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) + priority: [] || undefined, + state: [] || undefined, + assignees: [] || undefined, // ['user_id', 'user_id'] + created_by: [] || undefined, // ['user_id', 'user_id'] + labels: [] || undefined, // ['label_id', 'label_id'] + start_date: [] || undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] + target_date: [] || undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] + type: "" || undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) group_by: "state", // TIssueGroupByOptions order_by: "-created_at", // TIssueOrderByOptions sub_issue: true, // true for all other views except spreadsheet @@ -240,7 +368,7 @@ class IssueFilterStore implements IIssueFilterStore { let filteredParams: any = {}; - if (this.issueLayout === "list") + if (_issueLayout === "list") filteredParams = [ "priority", "state", @@ -254,7 +382,7 @@ class IssueFilterStore implements IIssueFilterStore { "order_by", "sub_issue", ]; - if (this.issueLayout === "kanban") + if (_issueLayout === "kanban") filteredParams = [ "priority", "state", @@ -268,7 +396,7 @@ class IssueFilterStore implements IIssueFilterStore { "order_by", "sub_issue", ]; - if (this.issueLayout === "calendar") + if (_issueLayout === "calendar") filteredParams = [ "priority", "state", @@ -279,7 +407,7 @@ class IssueFilterStore implements IIssueFilterStore { "target_date", "type", ]; - if (this.issueLayout === "spreadsheet") + if (_issueLayout === "spreadsheet") filteredParams = [ "priority", "state", @@ -290,7 +418,7 @@ class IssueFilterStore implements IIssueFilterStore { "target_date", "type", ]; - if (this.issueLayout === "gantt") + if (_issueLayout === "gantt") filteredParams = [ "priority", "state", @@ -309,22 +437,794 @@ class IssueFilterStore implements IIssueFilterStore { return filteredRouteParams; }; - // computed functions ends + // services + getWorkspaceMyIssuesProjects = async (workspaceId: string) => { + try { + this.loader = true; + this.error = null; + + const params = { is_favorite: false }; + const issuesProjectsResponse = await this.projectService.getProjects(workspaceId, params); + + if (issuesProjectsResponse) { + const _issuesProjectsResponse = { + ...this.issueRenderFilters, + workspace_properties: { + ...this.issueRenderFilters?.workspace_properties, + [workspaceId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId], + projects: issuesProjectsResponse, + }, + }, + }; + + runInAction(() => { + this.issueRenderFilters = _issuesProjectsResponse; + this.loader = false; + this.error = null; + }); + } + return issuesProjectsResponse; + } catch (error) { + console.warn("error in fetching workspace level projects", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getWorkspaceMyIssuesLabels = async (workspaceId: string) => { + try { + this.loader = true; + this.error = null; + + const issuesLabelsResponse = await this.issueService.getWorkspaceLabels(workspaceId); + + if (issuesLabelsResponse) { + const _issuesLabelsResponse = { + ...this.issueRenderFilters, + workspace_properties: { + ...this.issueRenderFilters?.workspace_properties, + [workspaceId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId], + labels: issuesLabelsResponse, + }, + }, + }; + + runInAction(() => { + this.issueRenderFilters = _issuesLabelsResponse; + this.loader = false; + this.error = null; + }); + } + return issuesLabelsResponse; + } catch (error) { + console.warn("error in fetching workspace level labels", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getWorkspaceMyIssuesFilters = async (workspaceId: string) => { + try { + this.loader = true; + this.error = null; + + // fetching workspace level issue filters + await this.getWorkspaceMyIssuesProjects(workspaceId); + await this.getWorkspaceMyIssuesLabels(workspaceId); + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + if (issuesFiltersResponse) { + const _issuesFiltersResponse: any = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters?.[workspaceId], + my_issue_properties: { + ...this?.issueFilters?.[workspaceId]?.my_issue_properties, + filters: { + priority: undefined, + state: undefined, + state_group: undefined, + assignees: undefined, + created_by: undefined, + labels: undefined, + start_date: undefined, + target_date: undefined, + subscriber: undefined, + }, + display_filters: { + group_by: undefined, + order_by: undefined, + type: undefined, + sub_issue: undefined, + show_empty_groups: undefined, + layout: undefined, + calendar_date_range: undefined, + start_target_date: undefined, + }, + display_properties: { + assignee: false, + attachment_count: false, + created_on: false, + due_date: false, + estimate: false, + key: false, + labels: false, + link: false, + priority: false, + start_date: false, + state: false, + sub_issue_count: false, + updated_on: false, + }, + }, + }, + }; + runInAction(() => { + this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + return issuesFiltersResponse; + } catch (error) { + console.warn("error in fetching workspace level filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateWorkspaceMyIssuesFilters = async () => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectLevelStates = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const issuesStateResponse = await this.stateService.getStates(workspaceId, projectId); + if (issuesStateResponse) { + const _states: any[] = []; + Object.keys(issuesStateResponse).map((state) => { + _states.push(...issuesStateResponse[state]); + }); + + const _issuesStateResponse = { + ...this.issueRenderFilters, + workspace_properties: { + ...this.issueRenderFilters?.workspace_properties, + [workspaceId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId], + project_properties: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, + [projectId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId] + ?.project_properties?.[projectId], + states: _states, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueRenderFilters = _issuesStateResponse; + this.loader = false; + this.error = null; + }); + } + return issuesStateResponse; + } catch (error) { + console.warn("error in fetching project level states", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectLevelLabels = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const issuesLabelsResponse = await this.issueService.getIssueLabels(workspaceId, projectId); + if (issuesLabelsResponse) { + const _issuesLabelsResponse = { + ...this.issueRenderFilters, + workspace_properties: { + ...this.issueRenderFilters?.workspace_properties, + [workspaceId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId], + project_properties: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, + [projectId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId] + ?.project_properties?.[projectId], + labels: issuesLabelsResponse, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueRenderFilters = _issuesLabelsResponse; + this.loader = false; + this.error = null; + }); + } + return issuesLabelsResponse; + } catch (error) { + console.warn("error in fetching project level labels", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectLevelMembers = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const issuesMembersResponse = await this.projectService.projectMembers( + workspaceId, + projectId + ); + if (issuesMembersResponse) { + const _issuesMembersResponse = { + ...this.issueRenderFilters, + workspace_properties: { + ...this.issueRenderFilters?.workspace_properties, + [workspaceId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId], + project_properties: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, + [projectId]: { + ...this.issueRenderFilters?.workspace_properties?.[workspaceId] + ?.project_properties?.[projectId], + members: issuesMembersResponse, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueRenderFilters = _issuesMembersResponse; + this.loader = false; + this.error = null; + }); + } + return issuesMembersResponse; + } catch (error) { + console.warn("error in fetching project level members", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectDisplayProperties = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; - // fetching current user project issue filter and display settings - getProjectIssueFilterProperties = () => {}; + const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties( + workspaceId, + projectId + ); - // fetching display properties - getProjectIssueDisplayProperties = () => {}; + if (issuesDisplayPropertiesResponse) { + const _issuesDisplayPropertiesResponse: any = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + display_properties: issuesDisplayPropertiesResponse, + }, + }, + }, + }; - // fetching project members - getProjectMembers = () => {}; + runInAction(() => { + this.issueFilters = _issuesDisplayPropertiesResponse; + this.loader = false; + this.error = null; + }); + } - // fetching project state <-> groups - getProjectStates = () => {}; + return issuesDisplayPropertiesResponse; + } catch (error) { + console.warn("error in fetching project level display properties", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectDisplayProperties = async (workspaceId: string, projectId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties( + workspaceId, + projectId + ); + + if (issuesDisplayPropertiesResponse) { + const _issuesDisplayPropertiesResponse: any = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + display_properties: issuesDisplayPropertiesResponse, + }, + }, + }, + }; + + runInAction(() => { + this.issueFilters = _issuesDisplayPropertiesResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesDisplayPropertiesResponse; + } catch (error) { + console.warn("error in fetching project level display properties", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectDisplayFilters = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectDisplayFilters = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectIssueFilters = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + await this.getProjectLevelStates(workspaceId, projectId); + await this.getProjectLevelLabels(workspaceId, projectId); + await this.getProjectLevelMembers(workspaceId, projectId); + await this.getProjectDisplayProperties(workspaceId, projectId); + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectIssueFilters = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + await this.getProjectLevelStates(workspaceId, projectId); + await this.getProjectLevelLabels(workspaceId, projectId); + await this.getProjectLevelMembers(workspaceId, projectId); + // await this.getProjectDisplayProperties(workspaceId, projectId); + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectIssueModuleFilters = async ( + workspaceId: string, + projectId: string, + moduleId: string + ) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } - // fetching project labels - getProjectLabels = () => {}; + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectIssueModuleFilters = async ( + workspaceId: string, + projectId: string, + moduleId: string + ) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectIssueCyclesFilters = async ( + workspaceId: string, + projectId: string, + cycleId: string + ) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectIssueCyclesFilters = async ( + workspaceId: string, + projectId: string, + cycleId: string + ) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + + getProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + updateProjectIssueViewsFilters = async ( + workspaceId: string, + projectId: string, + viewId: string + ) => { + try { + this.loader = true; + this.error = null; + + const workspaceId = "1"; + + const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + + if (issuesFiltersResponse) { + // const _issuesFiltersResponse = this.issueFilters; + // const _issuesFiltersResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [_layout as string]: issuesResponse, + // }, + // }, + // }; + + runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + return error; + } + }; + // project level filters ends } export default IssueFilterStore; From 3b85444e1f00efc4ed16d6cf66c75f19200ccf00 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 12 Sep 2023 23:05:59 +0530 Subject: [PATCH 007/102] chore: implemented filters for issues --- web/components/icons/module/cancelled.tsx | 2 +- web/components/icons/module/paused.tsx | 2 +- web/components/icons/state/backlog.tsx | 2 +- web/components/icons/state/cancelled.tsx | 2 +- web/components/icons/state/started.tsx | 4 +- web/components/icons/state/unstarted.tsx | 2 +- .../header/filters/assignees.tsx | 117 +++++++--------- .../header/filters/created-by.tsx | 100 ++++---------- .../header/filters/filter-card.tsx | 23 ++++ .../header/filters/filter-header.tsx | 25 ++++ .../issue-layouts/header/filters/labels.tsx | 100 ++++---------- .../issue-layouts/header/filters/priority.tsx | 82 +++++------ .../header/filters/start-date.tsx | 89 +++--------- .../header/filters/state-group.tsx | 129 +++++++++++------- .../issue-layouts/header/filters/state.tsx | 58 ++++---- .../header/filters/target-date.tsx | 89 +++--------- web/public/empty-state/state_graph.svg | 12 +- web/public/services/json.svg | 2 +- web/store/issue-views/issue_data.ts | 11 +- web/store/issue-views/issue_filters.ts | 11 +- 20 files changed, 356 insertions(+), 506 deletions(-) create mode 100644 web/components/issue-layouts/header/filters/filter-card.tsx create mode 100644 web/components/issue-layouts/header/filters/filter-header.tsx diff --git a/web/components/icons/module/cancelled.tsx b/web/components/icons/module/cancelled.tsx index 9bfc0294381..6ea5fd6944d 100644 --- a/web/components/icons/module/cancelled.tsx +++ b/web/components/icons/module/cancelled.tsx @@ -20,7 +20,7 @@ export const ModuleCancelledIcon: React.FC = ({ fill="none" xmlns="http://www.w3.org/2000/svg" > - + = ({ width = "20", height = "20", fill="none" xmlns="http://www.w3.org/2000/svg" > - + = ({ fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); diff --git a/web/components/icons/state/cancelled.tsx b/web/components/icons/state/cancelled.tsx index 1c3c4e3d244..4b06d80ba88 100644 --- a/web/components/icons/state/cancelled.tsx +++ b/web/components/icons/state/cancelled.tsx @@ -19,7 +19,7 @@ export const StateGroupCancelledIcon: React.FC = ({ fill="none" xmlns="http://www.w3.org/2000/svg" > - + = ({ viewBox="0 0 12 12" fill="none" > - - + + ); diff --git a/web/components/icons/state/unstarted.tsx b/web/components/icons/state/unstarted.tsx index 61a782b1f75..aa0d44935e5 100644 --- a/web/components/icons/state/unstarted.tsx +++ b/web/components/icons/state/unstarted.tsx @@ -19,6 +19,6 @@ export const StateGroupUnstartedIcon: React.FC = ({ fill="none" xmlns="http://www.w3.org/2000/svg" > - + ); diff --git a/web/components/issue-layouts/header/filters/assignees.tsx b/web/components/issue-layouts/header/filters/assignees.tsx index 66aa66e7957..f8627c937bd 100644 --- a/web/components/issue-layouts/header/filters/assignees.tsx +++ b/web/components/issue-layouts/header/filters/assignees.tsx @@ -1,90 +1,65 @@ import React from "react"; // lucide icons -import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +export const MemberIcons = ({ + display_name, + avatar, +}: { + display_name: string; + avatar: string | null; +}) => ( +
+ {avatar ? ( + {display_name + ) : ( +
+ {(display_name ?? "U")[0]} +
+ )} +
+); + export const FilterAssignees = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); - - const PriorityIcons = ({ priority }: { priority: string }) => { - if (priority === "urgent") - return ( -
- -
- ); - if (priority === "high") - return ( -
- -
- ); - if (priority === "medium") - return ( -
- -
- ); - if (priority === "low") - return ( -
- -
- ); - return ( -
- -
- ); - }; + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Assignees
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.projectMembers && + issueFilterStore?.projectMembers.length > 0 && + issueFilterStore?.projectMembers.map((_member) => ( + + } + title={`${_member?.member?.display_name} (${_member?.member?.first_name} ${_member?.member?.last_name})`} + /> + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( -
- -
- {priority.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/created-by.tsx b/web/components/issue-layouts/header/filters/created-by.tsx index f1d28dad5fb..af6ea0151c4 100644 --- a/web/components/issue-layouts/header/filters/created-by.tsx +++ b/web/components/issue-layouts/header/filters/created-by.tsx @@ -1,15 +1,10 @@ import React from "react"; // lucide icons -import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { MemberIcons } from "./assignees"; +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -20,71 +15,34 @@ export const FilterCreatedBy = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); - - const PriorityIcons = ({ priority }: { priority: string }) => { - if (priority === "urgent") - return ( -
- -
- ); - if (priority === "high") - return ( -
- -
- ); - if (priority === "medium") - return ( -
- -
- ); - if (priority === "low") - return ( -
- -
- ); - return ( -
- -
- ); - }; + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Created By
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.projectMembers && + issueFilterStore?.projectMembers.length > 0 && + issueFilterStore?.projectMembers.map((_member) => ( + + } + title={`${_member?.member?.display_name} (${_member?.member?.first_name} ${_member?.member?.last_name})`} + /> + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( -
- -
- {priority.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/filter-card.tsx b/web/components/issue-layouts/header/filters/filter-card.tsx new file mode 100644 index 00000000000..3133e65aa0b --- /dev/null +++ b/web/components/issue-layouts/header/filters/filter-card.tsx @@ -0,0 +1,23 @@ +import React from "react"; +// lucide icons +import { Check } from "lucide-react"; + +interface IFilterCard { + isChecked: boolean; + icon?: React.ReactNode; + title: string; +} + +export const FilterCard = ({ isChecked, icon, title }: IFilterCard) => ( +
+
+ {isChecked && } +
+ {icon} +
{title}
+
+); diff --git a/web/components/issue-layouts/header/filters/filter-header.tsx b/web/components/issue-layouts/header/filters/filter-header.tsx new file mode 100644 index 00000000000..b619d57aea5 --- /dev/null +++ b/web/components/issue-layouts/header/filters/filter-header.tsx @@ -0,0 +1,25 @@ +import React from "react"; +// lucide icons +import { ChevronDown, ChevronUp } from "lucide-react"; + +interface IFilterHeader { + title: string; + isPreviewEnabled: boolean; + handleIsPreviewEnabled: (isPreviewEnabled: boolean) => void; +} + +export const FilterHeader = ({ + title, + isPreviewEnabled, + handleIsPreviewEnabled, +}: IFilterHeader) => ( +
+
{title}
+
handleIsPreviewEnabled(!isPreviewEnabled)} + > + {isPreviewEnabled ? : } +
+
+); diff --git a/web/components/issue-layouts/header/filters/labels.tsx b/web/components/issue-layouts/header/filters/labels.tsx index 6d8eed30a16..fd23664d83e 100644 --- a/web/components/issue-layouts/header/filters/labels.tsx +++ b/web/components/issue-layouts/header/filters/labels.tsx @@ -1,90 +1,48 @@ import React from "react"; // lucide icons -import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +const LabelIcons = ({ color }: { color: string }) => ( +
+
+
+); + export const FilterLabels = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); - - const PriorityIcons = ({ priority }: { priority: string }) => { - if (priority === "urgent") - return ( -
- -
- ); - if (priority === "high") - return ( -
- -
- ); - if (priority === "medium") - return ( -
- -
- ); - if (priority === "low") - return ( -
- -
- ); - return ( -
- -
- ); - }; + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Labels
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.projectLabels && + issueFilterStore?.projectLabels.length > 0 && + issueFilterStore?.projectLabels.map((_label) => ( + } + title={_label.name} + /> + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( -
- -
- {priority.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/priority.tsx b/web/components/issue-layouts/header/filters/priority.tsx index 4615fbfc473..1230038095f 100644 --- a/web/components/issue-layouts/header/filters/priority.tsx +++ b/web/components/issue-layouts/header/filters/priority.tsx @@ -1,49 +1,51 @@ import React from "react"; // lucide icons -import { - AlertCircle, - SignalHigh, - SignalMedium, - SignalLow, - Ban, - Check, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban, Check } from "lucide-react"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -const PriorityIcons = ({ priority }: { priority: string }) => { +const PriorityIcons = ({ + priority, + size = 14, + strokeWidth = 2, +}: { + priority: string; + size?: number; + strokeWidth?: number; +}) => { if (priority === "urgent") return (
- +
); if (priority === "high") return (
- +
); if (priority === "medium") return (
- +
); if (priority === "low") return (
- +
); return (
- +
); }; @@ -52,39 +54,29 @@ export const FilterPriority = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Priority
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map((_priority) => ( + } + title={_priority.title} + /> + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((_priority) => ( -
- -
- {_priority.title} -
-
- {false && } -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/start-date.tsx b/web/components/issue-layouts/header/filters/start-date.tsx index b35d5f30f9a..efcae3be5b0 100644 --- a/web/components/issue-layouts/header/filters/start-date.tsx +++ b/web/components/issue-layouts/header/filters/start-date.tsx @@ -1,15 +1,9 @@ import React from "react"; // lucide icons -import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -20,71 +14,24 @@ export const FilterStartDate = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); - - const PriorityIcons = ({ priority }: { priority: string }) => { - if (priority === "urgent") - return ( -
- -
- ); - if (priority === "high") - return ( -
- -
- ); - if (priority === "medium") - return ( -
- -
- ); - if (priority === "low") - return ( -
- -
- ); - return ( -
- -
- ); - }; + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Start Date
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.start_date && + issueFilterStore?.issueRenderFilters?.start_date.length > 0 && + issueFilterStore?.issueRenderFilters?.start_date.map((_startDate) => ( + + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( -
- -
- {priority.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/state-group.tsx b/web/components/issue-layouts/header/filters/state-group.tsx index 15049650a0c..c7211b042a2 100644 --- a/web/components/issue-layouts/header/filters/state-group.tsx +++ b/web/components/issue-layouts/header/filters/state-group.tsx @@ -1,90 +1,115 @@ import React from "react"; // lucide icons +import { Check, ChevronDown, ChevronUp } from "lucide-react"; import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; + StateGroupBacklogIcon, + StateGroupCancelledIcon, + StateGroupCompletedIcon, + StateGroupStartedIcon, + StateGroupUnstartedIcon, +} from "components/icons"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +// constants +import { STATE_GROUP_COLORS } from "constants/state"; -export const StateGroupIcons = ({ stateGroup }: { stateGroup: string }) => { +export const StateGroupIcons = ({ + stateGroup, + width = "14px", + height = "14px", + color = null, +}: { + stateGroup: string; + width?: string | undefined; + height?: string | undefined; + color?: string | null; +}) => { if (stateGroup === "cancelled") return ( -
- +
+
); if (stateGroup === "completed") return ( -
- +
+
); if (stateGroup === "started") return ( -
- +
+
); if (stateGroup === "unstarted") return ( -
- +
+
); - return ( -
- -
- ); + if (stateGroup === "backlog") + return ( +
+ +
+ ); + return <>; }; export const FilterStateGroup = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
State Group
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.state_group && + issueFilterStore?.issueRenderFilters?.state_group.length > 0 && + issueFilterStore?.issueRenderFilters?.state_group.map((_stateGroup) => ( + } + title={_stateGroup.title} + /> + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.state_group && - issueFilterStore?.issueRenderFilters?.state_group.length > 0 && - issueFilterStore?.issueRenderFilters?.state_group.map((_stateGroup) => ( -
- -
- {_stateGroup.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/state.tsx b/web/components/issue-layouts/header/filters/state.tsx index a2b29fbee63..3b8bfcf1245 100644 --- a/web/components/issue-layouts/header/filters/state.tsx +++ b/web/components/issue-layouts/header/filters/state.tsx @@ -1,51 +1,49 @@ import React from "react"; // lucide icons -import { CheckIcon, ChevronDown, ChevronUp } from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { StateGroupIcons } from "./state-group"; +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +// store default data +import { issueStateGroupKeys } from "store/issue-views/issue_data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
State
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueStateGroupKeys.map( + (_stateGroup) => + issueFilterStore?.projectStates && + issueFilterStore?.projectStates[_stateGroup] && + issueFilterStore?.projectStates[_stateGroup].length > 0 && + issueFilterStore?.projectStates[_stateGroup].map((_state: any) => ( + } + title={_state?.name} + /> + )) + )}
-
-
- {issueFilterStore?.projectStates && - issueFilterStore?.projectStates.length > 0 && - issueFilterStore?.projectStates.map((_state) => ( -
- -
- {_state?.name} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/components/issue-layouts/header/filters/target-date.tsx b/web/components/issue-layouts/header/filters/target-date.tsx index 8d5af198db8..28320b44308 100644 --- a/web/components/issue-layouts/header/filters/target-date.tsx +++ b/web/components/issue-layouts/header/filters/target-date.tsx @@ -1,15 +1,9 @@ import React from "react"; // lucide icons -import { - AlertCircleIcon, - SignalHighIcon, - SignalMediumIcon, - SignalLowIcon, - BanIcon, - CheckIcon, - ChevronDown, - ChevronUp, -} from "lucide-react"; +import { Check, ChevronDown, ChevronUp } from "lucide-react"; +// components +import { FilterHeader } from "./filter-header"; +import { FilterCard } from "./filter-card"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -20,71 +14,24 @@ export const FilterTargetDate = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [allFiltersToggle, setAllFiltersToggle] = React.useState(false); - - const PriorityIcons = ({ priority }: { priority: string }) => { - if (priority === "urgent") - return ( -
- -
- ); - if (priority === "high") - return ( -
- -
- ); - if (priority === "medium") - return ( -
- -
- ); - if (priority === "low") - return ( -
- -
- ); - return ( -
- -
- ); - }; + const [previewEnabled, setPreviewEnabled] = React.useState(false); return (
-
-
Target Date
-
setAllFiltersToggle(!allFiltersToggle)} - > - {allFiltersToggle ? : } + + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.due_date && + issueFilterStore?.issueRenderFilters?.due_date.length > 0 && + issueFilterStore?.issueRenderFilters?.due_date.map((_targetDate) => ( + + ))}
-
-
- {issueFilterStore?.issueRenderFilters?.priority && - issueFilterStore?.issueRenderFilters?.priority.length > 0 && - issueFilterStore?.issueRenderFilters?.priority.map((priority) => ( -
- -
- {priority.title} -
-
- -
-
- ))} -
+ )}
); }); diff --git a/web/public/empty-state/state_graph.svg b/web/public/empty-state/state_graph.svg index 07337991ee1..651ea347498 100644 --- a/web/public/empty-state/state_graph.svg +++ b/web/public/empty-state/state_graph.svg @@ -2,25 +2,25 @@ - + - + - + - + - + - + diff --git a/web/public/services/json.svg b/web/public/services/json.svg index 4c2df222236..0fe32e276d4 100644 --- a/web/public/services/json.svg +++ b/web/public/services/json.svg @@ -2,7 +2,7 @@ - + diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index d5efa6e7ece..bfa17146e6f 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -1,3 +1,12 @@ +export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; +export const issueStateGroupKeys: TStateGroup[] = [ + "backlog", + "unstarted", + "started", + "completed", + "cancelled", +]; + export const filtersPriority: { key: string; title: string }[] = [ { key: "urgent", title: "Urgent" }, { key: "high", title: "High" }, @@ -6,7 +15,7 @@ export const filtersPriority: { key: string; title: string }[] = [ { key: "null", title: "None" }, ]; -export const filterStateGroup: { key: string; title: string }[] = [ +export const filterStateGroup: { key: TStateGroup; title: string }[] = [ { key: "backlog", title: "Backlog" }, { key: "unstarted", title: "Unstarted" }, { key: "started", title: "Started" }, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 102f1519343..5138c413a1e 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -19,9 +19,7 @@ import { } from "./issue_data"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; - export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; - export interface IIssueFilter { priority: string[] | undefined; state: string[] | undefined; @@ -78,7 +76,7 @@ export interface IIssueRenderFilters { labels: any[]; project_properties: { [key: string]: { - states: any[] | null; + states: any | null; labels: any[] | null; members: any[] | null; }; @@ -622,11 +620,6 @@ class IssueFilterStore implements IIssueFilterStore { const issuesStateResponse = await this.stateService.getStates(workspaceId, projectId); if (issuesStateResponse) { - const _states: any[] = []; - Object.keys(issuesStateResponse).map((state) => { - _states.push(...issuesStateResponse[state]); - }); - const _issuesStateResponse = { ...this.issueRenderFilters, workspace_properties: { @@ -638,7 +631,7 @@ class IssueFilterStore implements IIssueFilterStore { [projectId]: { ...this.issueRenderFilters?.workspace_properties?.[workspaceId] ?.project_properties?.[projectId], - states: _states, + states: issuesStateResponse, }, }, }, From 834e672245dd66cb0d0f3f8534b1715ec9a7e5aa Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 12 Sep 2023 23:17:47 +0530 Subject: [PATCH 008/102] chore: UI theming updates --- .../issue-layouts/header/filters/filter-header.tsx | 2 +- .../issue-layouts/header/layout-filter/index.tsx | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/web/components/issue-layouts/header/filters/filter-header.tsx b/web/components/issue-layouts/header/filters/filter-header.tsx index b619d57aea5..79e76501e61 100644 --- a/web/components/issue-layouts/header/filters/filter-header.tsx +++ b/web/components/issue-layouts/header/filters/filter-header.tsx @@ -16,7 +16,7 @@ export const FilterHeader = ({
{title}
handleIsPreviewEnabled(!isPreviewEnabled)} > {isPreviewEnabled ? : } diff --git a/web/components/issue-layouts/header/layout-filter/index.tsx b/web/components/issue-layouts/header/layout-filter/index.tsx index ce0410f7561..b2bf6184c45 100644 --- a/web/components/issue-layouts/header/layout-filter/index.tsx +++ b/web/components/issue-layouts/header/layout-filter/index.tsx @@ -90,12 +90,14 @@ export const LayoutSelection = observer(() => { }; return ( -
+
{layoutSelectionFilters.map((_layout) => (
handleLayoutSelection(_layout?.key)} > @@ -104,8 +106,8 @@ export const LayoutSelection = observer(() => { strokeWidth={2} className={`${ issueFilterStore?.issueLayout == _layout?.key - ? `text-gray-900` - : `text-gray-700 group-hover:text-gray-900` + ? `text-custom-text-100` + : `text-custom-text-100 group-hover:text-custom-text-200` }`} />
From 698021ab8b81025aa6d72469e5edc27471e8cdb3 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Wed, 13 Sep 2023 02:02:45 +0530 Subject: [PATCH 009/102] chore: handled single and multi select in filter cards --- .../{header => }/display-filters/index.tsx | 0 .../issue-layouts/{header => }/filters/assignees.tsx | 6 +++--- .../issue-layouts/{header => }/filters/created-by.tsx | 6 +++--- .../issue-layouts/{header => }/filters/index.tsx | 0 .../issue-layouts/{header => }/filters/labels.tsx | 6 +++--- .../issue-layouts/{header => }/filters/priority.tsx | 6 +++--- .../issue-layouts/{header => }/filters/start-date.tsx | 11 ++++++++--- .../{header => }/filters/state-group.tsx | 6 +++--- .../issue-layouts/{header => }/filters/state.tsx | 6 +++--- .../{header => }/filters/target-date.tsx | 11 ++++++++--- .../{header/filters => helpers}/filter-header.tsx | 0 .../filter-card.tsx => helpers/filter-option.tsx} | 9 +++++---- .../layout-filter/index.tsx => layout-selection.tsx} | 0 web/pages/kanban.tsx | 4 ++-- 14 files changed, 41 insertions(+), 30 deletions(-) rename web/components/issue-layouts/{header => }/display-filters/index.tsx (100%) rename web/components/issue-layouts/{header => }/filters/assignees.tsx (93%) rename web/components/issue-layouts/{header => }/filters/created-by.tsx (91%) rename web/components/issue-layouts/{header => }/filters/index.tsx (100%) rename web/components/issue-layouts/{header => }/filters/labels.tsx (91%) rename web/components/issue-layouts/{header => }/filters/priority.tsx (95%) rename web/components/issue-layouts/{header => }/filters/start-date.tsx (77%) rename web/components/issue-layouts/{header => }/filters/state-group.tsx (96%) rename web/components/issue-layouts/{header => }/filters/state.tsx (91%) rename web/components/issue-layouts/{header => }/filters/target-date.tsx (77%) rename web/components/issue-layouts/{header/filters => helpers}/filter-header.tsx (100%) rename web/components/issue-layouts/{header/filters/filter-card.tsx => helpers/filter-option.tsx} (68%) rename web/components/issue-layouts/{header/layout-filter/index.tsx => layout-selection.tsx} (100%) diff --git a/web/components/issue-layouts/header/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx similarity index 100% rename from web/components/issue-layouts/header/display-filters/index.tsx rename to web/components/issue-layouts/display-filters/index.tsx diff --git a/web/components/issue-layouts/header/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx similarity index 93% rename from web/components/issue-layouts/header/filters/assignees.tsx rename to web/components/issue-layouts/filters/assignees.tsx index f8627c937bd..2e5c96a47ce 100644 --- a/web/components/issue-layouts/header/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -2,8 +2,8 @@ import React from "react"; // lucide icons import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -46,7 +46,7 @@ export const FilterAssignees = observer(() => { {issueFilterStore?.projectMembers && issueFilterStore?.projectMembers.length > 0 && issueFilterStore?.projectMembers.map((_member) => ( - { {issueFilterStore?.projectMembers && issueFilterStore?.projectMembers.length > 0 && issueFilterStore?.projectMembers.map((_member) => ( - { {issueFilterStore?.projectLabels && issueFilterStore?.projectLabels.length > 0 && issueFilterStore?.projectLabels.map((_label) => ( - } diff --git a/web/components/issue-layouts/header/filters/priority.tsx b/web/components/issue-layouts/filters/priority.tsx similarity index 95% rename from web/components/issue-layouts/header/filters/priority.tsx rename to web/components/issue-layouts/filters/priority.tsx index 1230038095f..8baeb20fd59 100644 --- a/web/components/issue-layouts/header/filters/priority.tsx +++ b/web/components/issue-layouts/filters/priority.tsx @@ -2,8 +2,8 @@ import React from "react"; // lucide icons import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban, Check } from "lucide-react"; // components -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -68,7 +68,7 @@ export const FilterPriority = observer(() => { {issueFilterStore?.issueRenderFilters?.priority && issueFilterStore?.issueRenderFilters?.priority.length > 0 && issueFilterStore?.issueRenderFilters?.priority.map((_priority) => ( - } diff --git a/web/components/issue-layouts/header/filters/start-date.tsx b/web/components/issue-layouts/filters/start-date.tsx similarity index 77% rename from web/components/issue-layouts/header/filters/start-date.tsx rename to web/components/issue-layouts/filters/start-date.tsx index efcae3be5b0..4f731ffd96a 100644 --- a/web/components/issue-layouts/header/filters/start-date.tsx +++ b/web/components/issue-layouts/filters/start-date.tsx @@ -2,8 +2,8 @@ import React from "react"; // lucide icons import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -28,7 +28,12 @@ export const FilterStartDate = observer(() => { {issueFilterStore?.issueRenderFilters?.start_date && issueFilterStore?.issueRenderFilters?.start_date.length > 0 && issueFilterStore?.issueRenderFilters?.start_date.map((_startDate) => ( - + ))}
)} diff --git a/web/components/issue-layouts/header/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx similarity index 96% rename from web/components/issue-layouts/header/filters/state-group.tsx rename to web/components/issue-layouts/filters/state-group.tsx index c7211b042a2..9f206672596 100644 --- a/web/components/issue-layouts/header/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -9,8 +9,8 @@ import { StateGroupUnstartedIcon, } from "components/icons"; // components -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -101,7 +101,7 @@ export const FilterStateGroup = observer(() => { {issueFilterStore?.issueRenderFilters?.state_group && issueFilterStore?.issueRenderFilters?.state_group.length > 0 && issueFilterStore?.issueRenderFilters?.state_group.map((_stateGroup) => ( - } diff --git a/web/components/issue-layouts/header/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx similarity index 91% rename from web/components/issue-layouts/header/filters/state.tsx rename to web/components/issue-layouts/filters/state.tsx index 3b8bfcf1245..21f2fde0b6f 100644 --- a/web/components/issue-layouts/header/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -3,8 +3,8 @@ import React from "react"; import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { StateGroupIcons } from "./state-group"; -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -34,7 +34,7 @@ export const FilterState = observer(() => { issueFilterStore?.projectStates[_stateGroup] && issueFilterStore?.projectStates[_stateGroup].length > 0 && issueFilterStore?.projectStates[_stateGroup].map((_state: any) => ( - } diff --git a/web/components/issue-layouts/header/filters/target-date.tsx b/web/components/issue-layouts/filters/target-date.tsx similarity index 77% rename from web/components/issue-layouts/header/filters/target-date.tsx rename to web/components/issue-layouts/filters/target-date.tsx index 28320b44308..04f5cb2dbd4 100644 --- a/web/components/issue-layouts/header/filters/target-date.tsx +++ b/web/components/issue-layouts/filters/target-date.tsx @@ -2,8 +2,8 @@ import React from "react"; // lucide icons import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components -import { FilterHeader } from "./filter-header"; -import { FilterCard } from "./filter-card"; +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store @@ -28,7 +28,12 @@ export const FilterTargetDate = observer(() => { {issueFilterStore?.issueRenderFilters?.due_date && issueFilterStore?.issueRenderFilters?.due_date.length > 0 && issueFilterStore?.issueRenderFilters?.due_date.map((_targetDate) => ( - + ))}
)} diff --git a/web/components/issue-layouts/header/filters/filter-header.tsx b/web/components/issue-layouts/helpers/filter-header.tsx similarity index 100% rename from web/components/issue-layouts/header/filters/filter-header.tsx rename to web/components/issue-layouts/helpers/filter-header.tsx diff --git a/web/components/issue-layouts/header/filters/filter-card.tsx b/web/components/issue-layouts/helpers/filter-option.tsx similarity index 68% rename from web/components/issue-layouts/header/filters/filter-card.tsx rename to web/components/issue-layouts/helpers/filter-option.tsx index 3133e65aa0b..6989156f5df 100644 --- a/web/components/issue-layouts/header/filters/filter-card.tsx +++ b/web/components/issue-layouts/helpers/filter-option.tsx @@ -2,18 +2,19 @@ import React from "react"; // lucide icons import { Check } from "lucide-react"; -interface IFilterCard { +interface IFilterOption { isChecked: boolean; icon?: React.ReactNode; title: string; + multiple?: boolean; } -export const FilterCard = ({ isChecked, icon, title }: IFilterCard) => ( +export const FilterOption = ({ isChecked, icon, title, multiple = true }: IFilterOption) => (
{isChecked && }
diff --git a/web/components/issue-layouts/header/layout-filter/index.tsx b/web/components/issue-layouts/layout-selection.tsx similarity index 100% rename from web/components/issue-layouts/header/layout-filter/index.tsx rename to web/components/issue-layouts/layout-selection.tsx diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx index a31d39bfcc7..db533b2c43c 100644 --- a/web/pages/kanban.tsx +++ b/web/pages/kanban.tsx @@ -3,8 +3,8 @@ import React from "react"; import useSWR from "swr"; // components import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; -import { LayoutSelection } from "components/issue-layouts/header/layout-filter"; -import { FilterSelection } from "components/issue-layouts/header/filters"; +import { LayoutSelection } from "components/issue-layouts/layout-selection"; +import { FilterSelection } from "components/issue-layouts/filters"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; From 0ec0ad6abafa1d109eb381099d691625a1347453 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Wed, 13 Sep 2023 19:40:35 +0530 Subject: [PATCH 010/102] chore: implemented filters and views in kanaban --- .../display-filters/display-properties.tsx | 43 +++ .../display-filters/extra-options.tsx | 43 +++ .../display-filters/group-by.tsx | 44 +++ .../issue-layouts/display-filters/index.tsx | 52 ++- .../display-filters/issue-type.tsx | 44 +++ .../display-filters/order-by.tsx | 44 +++ .../issue-layouts/filters/assignees.tsx | 13 +- .../issue-layouts/filters/created-by.tsx | 11 +- .../issue-layouts/filters/index.tsx | 43 +-- .../issue-layouts/filters/labels.tsx | 13 +- .../issue-layouts/filters/priority.tsx | 18 +- .../issue-layouts/filters/start-date.tsx | 4 +- .../issue-layouts/filters/state-group.tsx | 11 +- .../issue-layouts/filters/state.tsx | 11 +- .../issue-layouts/filters/target-date.tsx | 4 +- .../issue-layouts/helpers/dropdown.tsx | 50 +++ .../issue-layouts/helpers/filter-header.tsx | 10 +- .../issue-layouts/helpers/filter-option.tsx | 4 +- web/components/issue-layouts/kanban/index.tsx | 22 -- .../issue-layouts/layout-selection.tsx | 4 +- web/pages/kanban.tsx | 22 +- web/store/issue-views/Issues.ts | 4 +- web/store/issue-views/issue_data.ts | 13 +- web/store/issue-views/issue_filters.ts | 339 +++++++++++------- 24 files changed, 636 insertions(+), 230 deletions(-) create mode 100644 web/components/issue-layouts/display-filters/display-properties.tsx create mode 100644 web/components/issue-layouts/display-filters/extra-options.tsx create mode 100644 web/components/issue-layouts/display-filters/group-by.tsx create mode 100644 web/components/issue-layouts/display-filters/issue-type.tsx create mode 100644 web/components/issue-layouts/display-filters/order-by.tsx create mode 100644 web/components/issue-layouts/helpers/dropdown.tsx diff --git a/web/components/issue-layouts/display-filters/display-properties.tsx b/web/components/issue-layouts/display-filters/display-properties.tsx new file mode 100644 index 00000000000..40be9345b56 --- /dev/null +++ b/web/components/issue-layouts/display-filters/display-properties.tsx @@ -0,0 +1,43 @@ +import React from "react"; +// components +import { FilterHeader } from "../helpers/filter-header"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterDisplayProperties = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [previewEnabled, setPreviewEnabled] = React.useState(true); + + return ( +
+ setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.display_properties && + issueFilterStore?.issueRenderFilters?.display_properties.length > 0 && + issueFilterStore?.issueRenderFilters?.display_properties.map((_displayProperties) => ( +
+ {_displayProperties?.title} +
+ ))} +
+ )} +
+ ); +}); diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx new file mode 100644 index 00000000000..3e74e91d321 --- /dev/null +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -0,0 +1,43 @@ +import React from "react"; +// components +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterExtraOptions = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [previewEnabled, setPreviewEnabled] = React.useState(true); + + return ( +
+ setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.extra_properties && + issueFilterStore?.issueRenderFilters?.extra_properties.length > 0 && + issueFilterStore?.issueRenderFilters?.extra_properties.map((_extraProperties) => ( + + ))} +
+ )} +
+ ); +}); diff --git a/web/components/issue-layouts/display-filters/group-by.tsx b/web/components/issue-layouts/display-filters/group-by.tsx new file mode 100644 index 00000000000..43ee083e07f --- /dev/null +++ b/web/components/issue-layouts/display-filters/group-by.tsx @@ -0,0 +1,44 @@ +import React from "react"; +// components +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterGroupBy = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [previewEnabled, setPreviewEnabled] = React.useState(true); + + return ( +
+ setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.group_by && + issueFilterStore?.issueRenderFilters?.group_by.length > 0 && + issueFilterStore?.issueRenderFilters?.group_by.map((_groupBy) => ( + + ))} +
+ )} +
+ ); +}); diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index 33561c0ae39..5a3fb3a0824 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -1,15 +1,45 @@ import React from "react"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; +// components +import { FilterDisplayProperties } from "./display-properties"; +import { FilterGroupBy } from "./group-by"; +import { FilterOrderBy } from "./order-by"; +import { FilterIssueType } from "./issue-type"; +import { FilterExtraOptions } from "./extra-options"; +// // mobx react lite +// import { observer } from "mobx-react-lite"; +// // mobx store +// import { useMobxStore } from "lib/mobx/store-provider"; +// import { RootStore } from "store/root"; -export const DisplayPropertiesSelection = () => { - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; +// const store: RootStore = useMobxStore(); +// const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; - return ( -
-
Filter Selection
+export const DisplayFiltersSelection = () => ( +
+
+ Search container
- ); -}; +
+ {/* display properties */} +
+ +
+ {/* group by */} +
+ +
+ {/* order by */} +
+ +
+ {/* issue type */} +
+ +
+ {/* Options */} +
+ +
+
+
+); diff --git a/web/components/issue-layouts/display-filters/issue-type.tsx b/web/components/issue-layouts/display-filters/issue-type.tsx new file mode 100644 index 00000000000..7171162c79e --- /dev/null +++ b/web/components/issue-layouts/display-filters/issue-type.tsx @@ -0,0 +1,44 @@ +import React from "react"; +// components +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterIssueType = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [previewEnabled, setPreviewEnabled] = React.useState(true); + + return ( +
+ setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.issue_type && + issueFilterStore?.issueRenderFilters?.issue_type.length > 0 && + issueFilterStore?.issueRenderFilters?.issue_type.map((_issueType) => ( + + ))} +
+ )} +
+ ); +}); diff --git a/web/components/issue-layouts/display-filters/order-by.tsx b/web/components/issue-layouts/display-filters/order-by.tsx new file mode 100644 index 00000000000..7ada18cab94 --- /dev/null +++ b/web/components/issue-layouts/display-filters/order-by.tsx @@ -0,0 +1,44 @@ +import React from "react"; +// components +import { FilterHeader } from "../helpers/filter-header"; +import { FilterOption } from "../helpers/filter-option"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterOrderBy = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore, issueView: issueStore } = store; + + const [previewEnabled, setPreviewEnabled] = React.useState(true); + + return ( +
+ setPreviewEnabled(!previewEnabled)} + /> + {previewEnabled && ( +
+ {issueFilterStore?.issueRenderFilters?.order_by && + issueFilterStore?.issueRenderFilters?.order_by.length > 0 && + issueFilterStore?.issueRenderFilters?.order_by.map((_orderBy) => ( + + ))} +
+ )} +
+ ); +}); diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index 2e5c96a47ce..e8e222aa81b 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -17,7 +17,7 @@ export const MemberIcons = ({ display_name: string; avatar: string | null; }) => ( -
+
{avatar ? ( {display_name ) : ( @@ -32,14 +32,14 @@ export const FilterAssignees = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -48,7 +48,12 @@ export const FilterAssignees = observer(() => { issueFilterStore?.projectMembers.map((_member) => ( { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -31,7 +31,12 @@ export const FilterCreatedBy = observer(() => { issueFilterStore?.projectMembers.map((_member) => ( { - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; +// const store: RootStore = useMobxStore(); +// const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; - return ( -
+export const FilterSelection = () => ( +
+
+ Search container +
+
{/* priority */} -
+
{/* state group */} -
+
{/* state */} -
+
{/* assignees */} -
+
{/* created_by */} -
+
{/* labels */} -
+
{/* start_date */} -
+
{/* due_date */} -
+
- ); -}); +
+); diff --git a/web/components/issue-layouts/filters/labels.tsx b/web/components/issue-layouts/filters/labels.tsx index 6ebebdd516a..f7497f5d809 100644 --- a/web/components/issue-layouts/filters/labels.tsx +++ b/web/components/issue-layouts/filters/labels.tsx @@ -20,14 +20,14 @@ export const FilterLabels = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -35,8 +35,13 @@ export const FilterLabels = observer(() => { issueFilterStore?.projectLabels.length > 0 && issueFilterStore?.projectLabels.map((_label) => ( } title={_label.name} /> diff --git a/web/components/issue-layouts/filters/priority.tsx b/web/components/issue-layouts/filters/priority.tsx index 8baeb20fd59..d2f48ab9b4d 100644 --- a/web/components/issue-layouts/filters/priority.tsx +++ b/web/components/issue-layouts/filters/priority.tsx @@ -1,6 +1,6 @@ import React from "react"; // lucide icons -import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban, Check } from "lucide-react"; +import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban } from "lucide-react"; // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; @@ -54,14 +54,14 @@ export const FilterPriority = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -70,11 +70,21 @@ export const FilterPriority = observer(() => { issueFilterStore?.issueRenderFilters?.priority.map((_priority) => ( } title={_priority.title} /> ))} +
+
View more
+
View less
+
View all
+
)}
diff --git a/web/components/issue-layouts/filters/start-date.tsx b/web/components/issue-layouts/filters/start-date.tsx index 4f731ffd96a..2f62785abff 100644 --- a/web/components/issue-layouts/filters/start-date.tsx +++ b/web/components/issue-layouts/filters/start-date.tsx @@ -14,14 +14,14 @@ export const FilterStartDate = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
diff --git a/web/components/issue-layouts/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx index 9f206672596..be739d45931 100644 --- a/web/components/issue-layouts/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -87,14 +87,14 @@ export const FilterStateGroup = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -103,7 +103,12 @@ export const FilterStateGroup = observer(() => { issueFilterStore?.issueRenderFilters?.state_group.map((_stateGroup) => ( } title={_stateGroup.title} /> diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index 21f2fde0b6f..340080a4c0a 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -17,14 +17,14 @@ export const FilterState = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
@@ -36,7 +36,12 @@ export const FilterState = observer(() => { issueFilterStore?.projectStates[_stateGroup].map((_state: any) => ( } title={_state?.name} /> diff --git a/web/components/issue-layouts/filters/target-date.tsx b/web/components/issue-layouts/filters/target-date.tsx index 04f5cb2dbd4..f886b70c488 100644 --- a/web/components/issue-layouts/filters/target-date.tsx +++ b/web/components/issue-layouts/filters/target-date.tsx @@ -14,14 +14,14 @@ export const FilterTargetDate = observer(() => { const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueStore } = store; - const [previewEnabled, setPreviewEnabled] = React.useState(false); + const [previewEnabled, setPreviewEnabled] = React.useState(true); return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
diff --git a/web/components/issue-layouts/helpers/dropdown.tsx b/web/components/issue-layouts/helpers/dropdown.tsx new file mode 100644 index 00000000000..66b7537e9b9 --- /dev/null +++ b/web/components/issue-layouts/helpers/dropdown.tsx @@ -0,0 +1,50 @@ +import { Fragment } from "react"; +// headless ui +import { Popover, Transition } from "@headlessui/react"; +// lucide icons +import { ChevronDown, ChevronUp } from "lucide-react"; + +interface IIssueDropdown { + children: React.ReactNode; + title?: string; +} + +export const IssueDropdown = ({ children, title = "Dropdown" }: IIssueDropdown) => ( + + {({ open }) => { + if (open) { + } + return ( + <> + +
{title}
+
+ {open ? ( + + ) : ( + + )} +
+
+ + +
+ {children} +
+
+
+ + ); + }} +
+); diff --git a/web/components/issue-layouts/helpers/filter-header.tsx b/web/components/issue-layouts/helpers/filter-header.tsx index 79e76501e61..3cae7400172 100644 --- a/web/components/issue-layouts/helpers/filter-header.tsx +++ b/web/components/issue-layouts/helpers/filter-header.tsx @@ -5,7 +5,7 @@ import { ChevronDown, ChevronUp } from "lucide-react"; interface IFilterHeader { title: string; isPreviewEnabled: boolean; - handleIsPreviewEnabled: (isPreviewEnabled: boolean) => void; + handleIsPreviewEnabled: () => void; } export const FilterHeader = ({ @@ -13,11 +13,11 @@ export const FilterHeader = ({ isPreviewEnabled, handleIsPreviewEnabled, }: IFilterHeader) => ( -
-
{title}
+
+
{title}
handleIsPreviewEnabled(!isPreviewEnabled)} + className="flex-shrink-0 w-[20px] h-[20px] flex justify-center items-center rounded transition-all hover:bg-custom-background-80 cursor-pointer" + onClick={handleIsPreviewEnabled} > {isPreviewEnabled ? : }
diff --git a/web/components/issue-layouts/helpers/filter-option.tsx b/web/components/issue-layouts/helpers/filter-option.tsx index 6989156f5df..34ed036a0c1 100644 --- a/web/components/issue-layouts/helpers/filter-option.tsx +++ b/web/components/issue-layouts/helpers/filter-option.tsx @@ -10,7 +10,7 @@ interface IFilterOption { } export const FilterOption = ({ isChecked, icon, title, multiple = true }: IFilterOption) => ( -
+
}
{icon} -
{title}
+
{title}
); diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx index 51828ae992c..22a79c08a77 100644 --- a/web/components/issue-layouts/kanban/index.tsx +++ b/web/components/issue-layouts/kanban/index.tsx @@ -28,28 +28,6 @@ export const IssueKanBanViewRoot = observer(() => { console.log("result", result); }; - console.log("------"); - console.log("workspace id -->", issueFilterStore?.workspaceId); - console.log("project id -->", issueFilterStore?.projectId); - console.log("module id -->", issueFilterStore?.moduleId); - console.log("cycle id -->", issueFilterStore?.cycleId); - console.log("view id -->", issueFilterStore?.viewId); - - console.log("<-- workspace level -->"); - console.log("workspace projects -->", issueFilterStore?.workspaceProjects); - console.log("workspace labels -->", issueFilterStore?.workspaceLabels); - - console.log("<-- project level -->"); - console.log("project states -->", issueFilterStore?.projectStates); - console.log("project labels -->", issueFilterStore?.projectLabels); - console.log("project members -->", issueFilterStore?.projectMembers); - - console.log("project display properties -->", issueFilterStore?.projectDisplayProperties); - - console.log("issue layout -->", issueFilterStore?.issueLayout); - console.log("issues -->", issueViewStore?.getIssues); - console.log("------"); - return (
{issueViewStore.loader || issueViewStore?.getIssues === null ? ( diff --git a/web/components/issue-layouts/layout-selection.tsx b/web/components/issue-layouts/layout-selection.tsx index b2bf6184c45..a32595def71 100644 --- a/web/components/issue-layouts/layout-selection.tsx +++ b/web/components/issue-layouts/layout-selection.tsx @@ -94,7 +94,7 @@ export const LayoutSelection = observer(() => { {layoutSelectionFilters.map((_layout) => (
{ onClick={() => handleLayoutSelection(_layout?.key)} > <_layout.icon - size={15} + size={14} strokeWidth={2} className={`${ issueFilterStore?.issueLayout == _layout?.key diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx index db533b2c43c..08c4fe667cc 100644 --- a/web/pages/kanban.tsx +++ b/web/pages/kanban.tsx @@ -4,7 +4,11 @@ import useSWR from "swr"; // components import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; import { LayoutSelection } from "components/issue-layouts/layout-selection"; +// issue dropdowns +import { IssueDropdown } from "components/issue-layouts/helpers/dropdown"; +// filter components import { FilterSelection } from "components/issue-layouts/filters"; +import { DisplayFiltersSelection } from "components/issue-layouts/display-filters"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; @@ -29,8 +33,8 @@ const KanBanViewRoot = () => { // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "spreadsheet"); // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "gantt"); // project issues under and workspace and project - await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); - // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); + // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); + await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "calendar"); // await issueViewStore.getProjectIssuesAsync( // workspaceSlug, @@ -165,16 +169,18 @@ const KanBanViewRoot = () => {
Filter Header
-
{/* */}
-
- -
+ + + + + + +
- - {/* */} +
diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index b839cfeec2d..e5cb82422d1 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -131,9 +131,9 @@ class IssueViewStore implements IIssueViewStore { const currentLayout: TIssueLayouts = currentProjectId ? this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId] - ?.project_issue_properties?.[currentProjectId]?.renderLayout + ?.project_issue_properties?.[currentProjectId]?.issues?.display_filters?.layout : this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.my_issue_properties - ?.renderLayout; + ?.display_filters?.layout; if (currentView === "my_issues") return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index bfa17146e6f..ab369f73278 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -12,7 +12,7 @@ export const filtersPriority: { key: string; title: string }[] = [ { key: "high", title: "High" }, { key: "medium", title: "Medium" }, { key: "low", title: "Low" }, - { key: "null", title: "None" }, + { key: "none", title: "None" }, ]; export const filterStateGroup: { key: TStateGroup; title: string }[] = [ @@ -43,7 +43,7 @@ export const displayPropertyGroupBy: { key: string; title: string }[] = [ { key: "state", title: "States" }, { key: "state_detail.group", title: "State Groups" }, { key: "priority", title: "Priority" }, - { key: "Project", title: "project" }, // required this on my issues + { key: "Project", title: "Project" }, // required this on my issues { key: "labels", title: "Labels" }, { key: "assignees", title: "Assignees" }, { key: "created_by", title: "Created By" }, @@ -67,7 +67,7 @@ export const displayProperties: { key: string; title: string }[] = [ { key: "assignee", title: "Assignee" }, { key: "start_date", title: "Start Date" }, { key: "due_date", title: "Due Date" }, - { key: "key", title: "Id" }, + { key: "key", title: "ID" }, { key: "labels", title: "Labels" }, { key: "priority", title: "Priority" }, { key: "state", title: "State" }, @@ -76,3 +76,10 @@ export const displayProperties: { key: string; title: string }[] = [ { key: "link", title: "Link" }, { key: "estimate", title: "Estimate" }, ]; + +export const extraProperties: { key: string; title: string }[] = [ + { key: "sub_issues", title: "Show sub-issues" }, // in spreadsheet its always false + { key: "show_empty_groups", title: "Show empty states" }, // filter on front-end + { key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after + { key: "start_target_date", title: "Start target Date" }, // gantt always be true +]; diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 5138c413a1e..ee37f1f48a3 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -16,6 +16,7 @@ import { displayPropertyOrderBy, displayPropertyIssueType, displayProperties, + extraProperties, } from "./issue_data"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; @@ -70,6 +71,7 @@ export interface IIssueRenderFilters { order_by: { key: string; title: string }[]; issue_type: { key: string; title: string }[]; display_properties: { key: string; title: string }[]; + extra_properties: { key: string; title: string }[]; workspace_properties: { [key: string]: { projects: any[]; @@ -91,7 +93,6 @@ export interface IIssueFilters { filters: IIssueFilter; display_filters: IIssueDisplayFilters; display_properties: IIssueDisplayProperties; - renderLayout: TIssueLayouts; }; project_issue_properties: { [key: string]: { @@ -99,11 +100,22 @@ export interface IIssueFilters { filters: IIssueFilter; display_filters: IIssueDisplayFilters; }; - cycles: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; - modules: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; - views: { filters: IIssueFilter; display_filters: IIssueDisplayFilters }; + cycles: { + [key: string]: { + filters: IIssueFilter; + }; + }; + modules: { + [key: string]: { + filters: IIssueFilter; + }; + }; + views: { + [key: string]: { + filters: IIssueFilter; + }; + }; display_properties: IIssueDisplayProperties; - renderLayout: TIssueLayouts; }; }; }; @@ -124,6 +136,16 @@ export interface IIssueFilterStore { issueRenderFilters: IIssueRenderFilters; issueFilters: IIssueFilters; + filterRenderProperties: + | { + [key: string]: { + isPreviewEnabled: boolean; + totalElements: number; + elementsVisible: number; + }; + }[] + | null; + // actions getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; updateWorkspaceMyIssuesFilters: () => any | Promise; @@ -173,10 +195,21 @@ class IssueFilterStore implements IIssueFilterStore { order_by: displayPropertyOrderBy, issue_type: displayPropertyIssueType, display_properties: displayProperties, + extra_properties: extraProperties, workspace_properties: {}, }; issueFilters: IIssueFilters = {}; + filterRenderProperties: + | { + [key: string]: { + isPreviewEnabled: boolean; + totalElements: number; + elementsVisible: number; + }; + }[] + | null = null; + // root store rootStore; // service @@ -211,6 +244,8 @@ class IssueFilterStore implements IIssueFilterStore { projectMembers: computed, projectDisplayProperties: computed, + userFilters: computed, + // action setWorkspaceId: action, setProjectId: action, @@ -253,12 +288,11 @@ class IssueFilterStore implements IIssueFilterStore { // computed get issueLayout() { if (!this.workspaceId) return null; - if (!this.projectId) - return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.renderLayout; + return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout; if (this.projectId) return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.renderLayout; + ?.issues?.display_filters?.layout; } get workspaceProjects() { @@ -291,9 +325,68 @@ class IssueFilterStore implements IIssueFilterStore { get projectDisplayProperties() { if (!this.workspaceId || !this.projectId) return null; return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.display_properties; + ?.display_properties as any; } + get userFilters() { + if (!this.workspaceId) return null; + if (this.issueView === "my_issues") + return this.issueFilters?.[this.workspaceId]?.my_issue_properties; + + if (!this.projectId) return null; + let _issueFilters: { + filters: IIssueFilter | null; + display_filters: IIssueDisplayFilters; + display_properties: IIssueDisplayProperties; + } = { + filters: null, + display_filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues + ?.display_filters, + display_properties: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.display_properties, + }; + if (this.issueView === "issues") { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues + ?.filters, + }; + return _issueFilters; + } + if (this.issueView === "modules" && this.moduleId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.modules?.[this.moduleId]?.filters, + }; + return _issueFilters; + } + if (this.issueView === "cycles" && this.cycleId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.cycles?.[this.cycleId]?.filters, + }; + return _issueFilters; + } + if (this.issueView === "views" && this.viewId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.views?.[this.viewId]?.filters, + }; + return _issueFilters; + } + return null; + } + handleUserFilter = () => {}; + computedFilter = (filters: any, filteredParams: any) => { const computedFilters: any = {}; Object.keys(filters).map((key) => { @@ -322,67 +415,51 @@ class IssueFilterStore implements IIssueFilterStore { this.setViewId(_viewId); this.setIssueView(_issueView); - if (_workspaceId) { - if (!_projectId) - this.issueFilters = { - ...this.issueFilters, - [_workspaceId]: { - ...this.issueFilters[_workspaceId], - my_issue_properties: { - ...this.issueFilters[_workspaceId]?.my_issue_properties, - renderLayout: _issueLayout, - }, - }, - }; - else - this.issueFilters = { - ...this.issueFilters, - [_workspaceId]: { - ...this.issueFilters[_workspaceId], - project_issue_properties: { - ...this.issueFilters[_workspaceId]?.project_issue_properties, - [_projectId]: { - ...this.issueFilters[_workspaceId]?.project_issue_properties?.[_projectId], - renderLayout: _issueLayout, - }, - }, - }, - }; - } + const _layout = this.userFilters?.display_filters?.layout; let filteredRouteParams: any = { - priority: [] || undefined, - state: [] || undefined, - assignees: [] || undefined, // ['user_id', 'user_id'] - created_by: [] || undefined, // ['user_id', 'user_id'] - labels: [] || undefined, // ['label_id', 'label_id'] - start_date: [] || undefined, // ['yyyy-mm-dd:after/before', 'yyyy-mm-dd:after/before'] - target_date: [] || undefined, // [yyyy-mm-dd:after, yyyy-mm-dd:before] - type: "" || undefined, // 'active' (started, un_started) || 'backlog' || 'null' (all_the_issues) - group_by: "state", // TIssueGroupByOptions - order_by: "-created_at", // TIssueOrderByOptions - sub_issue: true, // true for all other views except spreadsheet + priority: this.userFilters?.filters?.priority || undefined, + state_group: this.userFilters?.filters?.state_group || undefined, + state: this.userFilters?.filters?.state || undefined, + assignees: this.userFilters?.filters?.assignees || undefined, + created_by: this.userFilters?.filters?.created_by || undefined, + labels: this.userFilters?.filters?.labels || undefined, + start_date: this.userFilters?.filters?.start_date || undefined, + target_date: this.userFilters?.filters?.target_date || undefined, + type: this.userFilters?.display_filters?.type || undefined, + group_by: this.userFilters?.display_filters?.group_by || "state", + order_by: this.userFilters?.display_filters?.order_by || "-created_at", + sub_issue: this.userFilters?.display_filters?.sub_issue || true, + show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, + calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, + start_target_date: this.userFilters?.display_filters?.start_target_date || true, }; - let filteredParams: any = {}; + console.log("filteredRouteParams", filteredRouteParams); + + // start date and target date we have to construct the format here - if (_issueLayout === "list") + let filteredParams: any = {}; + if (_layout === "list") filteredParams = [ "priority", + "state_group", "state", "assignees", "created_by", "labels", "start_date", "target_date", - "type", "group_by", "order_by", + "type", "sub_issue", + "show_empty_groups", ]; - if (_issueLayout === "kanban") + if (_layout === "kanban") filteredParams = [ "priority", + "state_group", "state", "assignees", "created_by", @@ -394,9 +471,10 @@ class IssueFilterStore implements IIssueFilterStore { "order_by", "sub_issue", ]; - if (_issueLayout === "calendar") + if (_layout === "calendar") filteredParams = [ "priority", + "state_group", "state", "assignees", "created_by", @@ -404,10 +482,12 @@ class IssueFilterStore implements IIssueFilterStore { "start_date", "target_date", "type", + "calendar_date_range", ]; - if (_issueLayout === "spreadsheet") + if (_layout === "spreadsheet") filteredParams = [ "priority", + "state_group", "state", "assignees", "created_by", @@ -415,8 +495,9 @@ class IssueFilterStore implements IIssueFilterStore { "start_date", "target_date", "type", + "sub_issues", ]; - if (_issueLayout === "gantt") + if (_layout === "gantt") filteredParams = [ "priority", "state", @@ -425,13 +506,17 @@ class IssueFilterStore implements IIssueFilterStore { "labels", "start_date", "target_date", - "type", "order_by", + "type", "sub_issue_id", + "start_target_date", ]; filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); + // remove few attributes from the object when we are in workspace issues + console.log("filteredRouteParams", filteredRouteParams); + return filteredRouteParams; }; @@ -470,7 +555,6 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - getWorkspaceMyIssuesLabels = async (workspaceId: string) => { try { this.loader = true; @@ -523,40 +607,48 @@ class IssueFilterStore implements IIssueFilterStore { my_issue_properties: { ...this?.issueFilters?.[workspaceId]?.my_issue_properties, filters: { - priority: undefined, - state: undefined, - state_group: undefined, - assignees: undefined, - created_by: undefined, - labels: undefined, - start_date: undefined, - target_date: undefined, - subscriber: undefined, + priority: issuesFiltersResponse?.view_props?.filters?.priority ?? null, + state: issuesFiltersResponse?.view_props?.filters?.state ?? null, + state_group: issuesFiltersResponse?.view_props?.filters?.state_group ?? null, + assignees: issuesFiltersResponse?.view_props?.filters?.assignees ?? null, + created_by: issuesFiltersResponse?.view_props?.filters?.created_by ?? null, + labels: issuesFiltersResponse?.view_props?.filters?.labels ?? null, + start_date: issuesFiltersResponse?.view_props?.filters?.start_date ?? null, + target_date: issuesFiltersResponse?.view_props?.filters?.target_date ?? null, + subscriber: issuesFiltersResponse?.view_props?.filters?.subscriber ?? null, }, display_filters: { - group_by: undefined, - order_by: undefined, - type: undefined, - sub_issue: undefined, - show_empty_groups: undefined, - layout: undefined, - calendar_date_range: undefined, - start_target_date: undefined, + group_by: issuesFiltersResponse?.view_props?.display_filters?.group_by ?? null, + order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null, + type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null, + sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false, + show_empty_groups: + issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, + layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list", + calendar_date_range: + issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, + start_target_date: + issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, }, display_properties: { - assignee: false, - attachment_count: false, - created_on: false, - due_date: false, - estimate: false, - key: false, - labels: false, - link: false, - priority: false, - start_date: false, - state: false, - sub_issue_count: false, - updated_on: false, + assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false, + attachment_count: + issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, + created_on: + issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, + due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false, + estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false, + key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false, + labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false, + link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false, + priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false, + start_date: + issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, + state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false, + sub_issue_count: + issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, + updated_on: + issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, }, }, }, @@ -652,7 +744,6 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - getProjectLevelLabels = async (workspaceId: string, projectId: string) => { try { this.loader = true; @@ -692,7 +783,6 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - getProjectLevelMembers = async (workspaceId: string, projectId: string) => { try { this.loader = true; @@ -755,7 +845,7 @@ class IssueFilterStore implements IIssueFilterStore { ...this?.issueFilters[workspaceId]?.project_issue_properties, [projectId]: { ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - display_properties: issuesDisplayPropertiesResponse, + display_properties: issuesDisplayPropertiesResponse?.properties, }, }, }, @@ -822,25 +912,35 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const workspaceId = "1"; + const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe( + workspaceId, + projectId + ); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + if (issuesDisplayFiltersResponse) { + const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters }; + const _displayFilters = { ...issuesDisplayFiltersResponse?.view_props?.display_filters }; - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + const _issuesDisplayFiltersResponse: any = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + issues: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.issues, + filters: _filters, + display_filters: _displayFilters, + }, + }, + }, + }, + }; runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; + this.issueFilters = _issuesDisplayFiltersResponse; this.loader = false; this.error = null; }); @@ -901,28 +1001,12 @@ class IssueFilterStore implements IIssueFilterStore { await this.getProjectLevelLabels(workspaceId, projectId); await this.getProjectLevelMembers(workspaceId, projectId); await this.getProjectDisplayProperties(workspaceId, projectId); + await this.getProjectDisplayFilters(workspaceId, projectId); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; - - runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; - this.loader = false; - this.error = null; - }); - } + runInAction(() => { + this.loader = false; + this.error = null; + }); // return issuesResponse; } catch (error) { @@ -937,11 +1021,6 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - await this.getProjectLevelStates(workspaceId, projectId); - await this.getProjectLevelLabels(workspaceId, projectId); - await this.getProjectLevelMembers(workspaceId, projectId); - // await this.getProjectDisplayProperties(workspaceId, projectId); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); if (issuesFiltersResponse) { From 3ffbb6ac1743ec3079e7f57f09c21aeaf8fcb1cf Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 14:41:41 +0530 Subject: [PATCH 011/102] chore: updating filters, display_filter and display properties --- .../display-filters/display-properties.tsx | 10 + .../display-filters/extra-options.tsx | 10 + .../display-filters/group-by.tsx | 5 + .../display-filters/issue-type.tsx | 5 + .../display-filters/order-by.tsx | 5 + .../issue-layouts/filters/assignees.tsx | 13 +- .../issue-layouts/filters/created-by.tsx | 13 +- .../issue-layouts/filters/labels.tsx | 13 +- .../issue-layouts/filters/priority.tsx | 17 +- .../issue-layouts/filters/start-date.tsx | 15 +- .../issue-layouts/filters/state-group.tsx | 13 +- .../issue-layouts/filters/state.tsx | 19 +- .../issue-layouts/filters/target-date.tsx | 15 +- .../issue-layouts/helpers/filter-option.tsx | 14 +- .../issue-layouts/layout-selection.tsx | 61 +- web/pages/kanban.tsx | 143 +--- web/services/views.service.ts | 2 +- web/store/issue-views/Issues.ts | 88 +- web/store/issue-views/issue_filters.ts | 781 ++++++++++++------ 19 files changed, 724 insertions(+), 518 deletions(-) diff --git a/web/components/issue-layouts/display-filters/display-properties.tsx b/web/components/issue-layouts/display-filters/display-properties.tsx index 40be9345b56..dd234340a3e 100644 --- a/web/components/issue-layouts/display-filters/display-properties.tsx +++ b/web/components/issue-layouts/display-filters/display-properties.tsx @@ -13,6 +13,10 @@ export const FilterDisplayProperties = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleDisplayProperties = (key: string, value: boolean) => { + issueFilterStore.handleUserFilter("display_properties", key, !value); + }; + return (
{ ? `bg-custom-primary-200 border-custom-primary-200 text-white` : `hover:bg-custom-border-100 border-custom-border-100` }`} + onClick={() => + handleDisplayProperties( + _displayProperties?.key, + issueFilterStore?.userFilters?.display_properties?.[_displayProperties?.key] + ) + } > {_displayProperties?.title}
diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index 3e74e91d321..15450a24f21 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -14,6 +14,10 @@ export const FilterExtraOptions = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleExtraOptions = (key: string, value: boolean) => { + issueFilterStore.handleUserFilter("display_filters", key, !value); + }; + return (
{ ? true : false } + onClick={() => + handleExtraOptions( + _extraProperties?.key, + issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key] + ) + } title={_extraProperties.title} /> ))} diff --git a/web/components/issue-layouts/display-filters/group-by.tsx b/web/components/issue-layouts/display-filters/group-by.tsx index 43ee083e07f..fa46415ab64 100644 --- a/web/components/issue-layouts/display-filters/group-by.tsx +++ b/web/components/issue-layouts/display-filters/group-by.tsx @@ -14,6 +14,10 @@ export const FilterGroupBy = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleGroupBy = (key: string, value: string) => { + issueFilterStore.handleUserFilter("display_filters", key, value); + }; + return (
{ ? true : false } + onClick={() => handleGroupBy("group_by", _groupBy?.key)} title={_groupBy.title} multiple={false} /> diff --git a/web/components/issue-layouts/display-filters/issue-type.tsx b/web/components/issue-layouts/display-filters/issue-type.tsx index 7171162c79e..eaf9ae7bda0 100644 --- a/web/components/issue-layouts/display-filters/issue-type.tsx +++ b/web/components/issue-layouts/display-filters/issue-type.tsx @@ -14,6 +14,10 @@ export const FilterIssueType = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleIssueType = (key: string, value: string) => { + issueFilterStore.handleUserFilter("display_filters", key, value); + }; + return (
{ ? true : false } + onClick={() => handleIssueType("type", _issueType?.key)} title={_issueType.title} multiple={false} /> diff --git a/web/components/issue-layouts/display-filters/order-by.tsx b/web/components/issue-layouts/display-filters/order-by.tsx index 7ada18cab94..9e3b9e35db8 100644 --- a/web/components/issue-layouts/display-filters/order-by.tsx +++ b/web/components/issue-layouts/display-filters/order-by.tsx @@ -14,6 +14,10 @@ export const FilterOrderBy = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleOrderBy = (key: string, value: string) => { + issueFilterStore.handleUserFilter("display_filters", key, value); + }; + return (
{ ? true : false } + onClick={() => handleOrderBy("order_by", _orderBy?.key)} title={_orderBy.title} multiple={false} /> diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index e8e222aa81b..2e51a3a4903 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -34,10 +34,20 @@ export const FilterAssignees = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -54,6 +64,7 @@ export const FilterAssignees = observer(() => { ? true : false } + onClick={() => handleFilter("assignees", _member?.member?.id)} icon={ { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -37,6 +47,7 @@ export const FilterCreatedBy = observer(() => { ? true : false } + onClick={() => handleFilter("created_by", _member?.member?.id)} icon={ { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -42,6 +52,7 @@ export const FilterLabels = observer(() => { ? true : false } + onClick={() => handleFilter("labels", _label?.id)} icon={} title={_label.name} /> diff --git a/web/components/issue-layouts/filters/priority.tsx b/web/components/issue-layouts/filters/priority.tsx index d2f48ab9b4d..f8b104c812f 100644 --- a/web/components/issue-layouts/filters/priority.tsx +++ b/web/components/issue-layouts/filters/priority.tsx @@ -56,10 +56,20 @@ export const FilterPriority = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -76,14 +86,15 @@ export const FilterPriority = observer(() => { ? true : false } + onClick={() => handleFilter("priority", _priority?.key)} icon={} title={_priority.title} /> ))}
-
View more
View less
-
View all
+
View more
+ {/* TODO:
View all
*/}
)} diff --git a/web/components/issue-layouts/filters/start-date.tsx b/web/components/issue-layouts/filters/start-date.tsx index 2f62785abff..bfa342922b6 100644 --- a/web/components/issue-layouts/filters/start-date.tsx +++ b/web/components/issue-layouts/filters/start-date.tsx @@ -16,10 +16,15 @@ export const FilterStartDate = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -30,7 +35,13 @@ export const FilterStartDate = observer(() => { issueFilterStore?.issueRenderFilters?.start_date.map((_startDate) => ( handleFilter("start_date", _startDate?.key)} title={_startDate.title} multiple={false} /> diff --git a/web/components/issue-layouts/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx index be739d45931..0c3da34ec03 100644 --- a/web/components/issue-layouts/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -89,10 +89,20 @@ export const FilterStateGroup = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -109,6 +119,7 @@ export const FilterStateGroup = observer(() => { ? true : false } + onClick={() => handleFilter("state_group", _stateGroup?.key)} icon={} title={_stateGroup.title} /> diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index 340080a4c0a..6cabd68a197 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -19,10 +19,26 @@ export const FilterState = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = + issueFilterStore?.userFilters?.filters?.[key] != null + ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + : [...issueFilterStore?.userFilters?.filters?.[key], value] + : [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const countAllState = issueStateGroupKeys + .map((_stateGroup) => issueFilterStore?.projectStates?.[_stateGroup].length || 0) + .reduce((sum: number, currentValue: number) => sum + currentValue, 0); + + console.log("countAllState", countAllState); + return (
setPreviewEnabled(!previewEnabled)} /> @@ -42,6 +58,7 @@ export const FilterState = observer(() => { ? true : false } + onClick={() => handleFilter("state", _state?.id)} icon={} title={_state?.name} /> diff --git a/web/components/issue-layouts/filters/target-date.tsx b/web/components/issue-layouts/filters/target-date.tsx index f886b70c488..0f777f7528d 100644 --- a/web/components/issue-layouts/filters/target-date.tsx +++ b/web/components/issue-layouts/filters/target-date.tsx @@ -16,10 +16,15 @@ export const FilterTargetDate = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); + const handleFilter = (key: string, value: string) => { + const _value = [value]; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + return (
setPreviewEnabled(!previewEnabled)} /> @@ -30,7 +35,13 @@ export const FilterTargetDate = observer(() => { issueFilterStore?.issueRenderFilters?.due_date.map((_targetDate) => ( handleFilter("target_date", _targetDate?.key)} title={_targetDate.title} multiple={false} /> diff --git a/web/components/issue-layouts/helpers/filter-option.tsx b/web/components/issue-layouts/helpers/filter-option.tsx index 34ed036a0c1..e96b3c5c9be 100644 --- a/web/components/issue-layouts/helpers/filter-option.tsx +++ b/web/components/issue-layouts/helpers/filter-option.tsx @@ -7,10 +7,20 @@ interface IFilterOption { icon?: React.ReactNode; title: string; multiple?: boolean; + onClick?: () => void; } -export const FilterOption = ({ isChecked, icon, title, multiple = true }: IFilterOption) => ( -
+export const FilterOption = ({ + isChecked, + icon, + title, + multiple = true, + onClick, +}: IFilterOption) => ( +
{ }, ]; - const handleLayoutSelection = (layout: TIssueLayouts) => { - if (!issueFilterStore.workspaceId) return; - if (issueFilterStore.issueView === "my_issues") { - issueStore.getMyIssuesAsync(issueFilterStore.workspaceId, issueFilterStore.issueView, layout); - return; - } - - if (!issueFilterStore.projectId) return; - if (issueFilterStore.issueView === "issues") { - issueStore.getProjectIssuesAsync( - issueFilterStore.workspaceId, - issueFilterStore.projectId, - issueFilterStore.issueView, - layout - ); - return; - } - if (issueFilterStore.issueView === "modules" && issueFilterStore.moduleId) { - issueStore.getIssuesForModulesAsync( - issueFilterStore.workspaceId, - issueFilterStore.projectId, - issueFilterStore.moduleId, - issueFilterStore.issueView, - layout - ); - return; - } - if (issueFilterStore.issueView === "cycles" && issueFilterStore.cycleId) { - issueStore.getIssuesForCyclesAsync( - issueFilterStore.workspaceId, - issueFilterStore.projectId, - issueFilterStore.cycleId, - issueFilterStore.issueView, - layout - ); - return; - } - if (issueFilterStore.issueView === "views" && issueFilterStore.viewId) { - issueStore.getIssuesForViewsAsync( - issueFilterStore.workspaceId, - issueFilterStore.projectId, - issueFilterStore.viewId, - issueFilterStore.issueView, - layout - ); - return; - } + const handleLayoutSelection = (_layoutKey: string) => { + issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey); }; + console.log("----"); + console.log("workspace_id", issueFilterStore.workspaceId); + console.log("project_id", issueFilterStore.projectId); + console.log("module_id", issueFilterStore.moduleId); + console.log("cycle_id", issueFilterStore.cycleId); + console.log("view_id", issueFilterStore.viewId); + + console.log("issue_view", issueFilterStore.issueView); + console.log("issue_layout", issueFilterStore.issueLayout); + + console.log("----"); + return (
{layoutSelectionFilters.map((_layout) => ( diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx index 08c4fe667cc..1a7d5b07390 100644 --- a/web/pages/kanban.tsx +++ b/web/pages/kanban.tsx @@ -1,6 +1,4 @@ import React from "react"; -// swr -import useSWR from "swr"; // components import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; import { LayoutSelection } from "components/issue-layouts/layout-selection"; @@ -18,140 +16,29 @@ const KanBanViewRoot = () => { const projectSlug: string = "08d59d96-9dfb-40e5-aa30-ecc66319450f"; const moduleSlug: string = "05613afc-29ea-4fd8-a025-a3cdfed209d1"; const cycleSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; - const viewSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; + const viewSlug: string = "64e6ecca-80ca-4f7c-8476-d650fca9d5b9"; const store: RootStore = useMobxStore(); const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; React.useEffect(() => { const init = async () => { + console.log("started--->"); // my issues under a workspace - // console.log("started--->"); - // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "list"); - // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "kanban"); - // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "calendar"); - // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "spreadsheet"); - // await issueViewStore.getMyIssuesAsync(workspaceSlug, "my_issues", "gantt"); + // await issueViewStore.getMyIssuesAsync(workspaceSlug); + // project issues under and workspace and project - // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "list"); - await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "kanban"); - // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "calendar"); - // await issueViewStore.getProjectIssuesAsync( - // workspaceSlug, - // projectSlug, - // "issues", - // "spreadsheet" - // ); - // await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug, "issues", "gantt"); + await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug); + // module issues under and workspace and project - // await issueViewStore.getIssuesForModulesAsync( - // workspaceSlug, - // projectSlug, - // moduleSlug, - // "modules", - // "list" - // ); - // await issueViewStore.getIssuesForModulesAsync( - // workspaceSlug, - // projectSlug, - // moduleSlug, - // "modules", - // "kanban" - // ); - // await issueViewStore.getIssuesForModulesAsync( - // workspaceSlug, - // projectSlug, - // moduleSlug, - // "modules", - // "calendar" - // ); - // await issueViewStore.getIssuesForModulesAsync( - // workspaceSlug, - // projectSlug, - // moduleSlug, - // "modules", - // "spreadsheet" - // ); - // await issueViewStore.getIssuesForModulesAsync( - // workspaceSlug, - // projectSlug, - // moduleSlug, - // "modules", - // "gantt" - // ); + // await issueViewStore.getIssuesForModulesAsync(workspaceSlug, projectSlug, moduleSlug); + // cycle issues under and workspace and project - // await issueViewStore.getIssuesForCyclesAsync( - // workspaceSlug, - // projectSlug, - // cycleSlug, - // "cycles", - // "list" - // ); - // await issueViewStore.getIssuesForCyclesAsync( - // workspaceSlug, - // projectSlug, - // cycleSlug, - // "cycles", - // "kanban" - // ); - // await issueViewStore.getIssuesForCyclesAsync( - // workspaceSlug, - // projectSlug, - // cycleSlug, - // "cycles", - // "calendar" - // ); - // await issueViewStore.getIssuesForCyclesAsync( - // workspaceSlug, - // projectSlug, - // cycleSlug, - // "cycles", - // "spreadsheet" - // ); - // await issueViewStore.getIssuesForCyclesAsync( - // workspaceSlug, - // projectSlug, - // cycleSlug, - // "cycles", - // "gantt" - // ); + // await issueViewStore.getIssuesForCyclesAsync(workspaceSlug, projectSlug, cycleSlug); + // cycle issues under and workspace and project - // await issueViewStore.getIssuesForViewsAsync( - // workspaceSlug, - // projectSlug, - // viewSlug, - // "views", - // "list" - // ); - // await issueViewStore.getIssuesForViewsAsync( - // workspaceSlug, - // projectSlug, - // viewSlug, - // "views", - // "kanban" - // ); - // await issueViewStore.getIssuesForViewsAsync( - // workspaceSlug, - // projectSlug, - // viewSlug, - // "views", - // "calendar" - // ); - // await issueViewStore.getIssuesForViewsAsync( - // workspaceSlug, - // projectSlug, - // viewSlug, - // "views", - // "spreadsheet" - // ); - // await issueViewStore.getIssuesForViewsAsync( - // workspaceSlug, - // projectSlug, - // viewSlug, - // "views", - // "gantt" - // ); - // console.log("ended--->"); + // await issueViewStore.getIssuesForViewsAsync(workspaceSlug, projectSlug, viewSlug); + console.log("ended--->"); }; init(); @@ -160,10 +47,7 @@ const KanBanViewRoot = () => { return (
-
+
Filter Header
@@ -179,6 +63,7 @@ const KanBanViewRoot = () => {
+
Hello
diff --git a/web/services/views.service.ts b/web/services/views.service.ts index e1d25925ed7..861f035e2a2 100644 --- a/web/services/views.service.ts +++ b/web/services/views.service.ts @@ -11,7 +11,7 @@ const { NEXT_PUBLIC_API_BASE_URL } = process.env; const trackEvent = process.env.NEXT_PUBLIC_TRACK_EVENTS === "true" || process.env.NEXT_PUBLIC_TRACK_EVENTS === "1"; -class ViewServices extends APIService { +export class ViewServices extends APIService { constructor() { super(NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000"); } diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index e5cb82422d1..74803dc8a8d 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -48,37 +48,22 @@ export interface IIssueViewStore { // computed getIssues: IIssues | null | undefined; // actions - getMyIssuesAsync: ( - workspaceId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => null | Promise; - getProjectIssuesAsync: ( - workspaceId: string, - projectId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => null | Promise; + getMyIssuesAsync: (workspaceId: string) => null | Promise; + getProjectIssuesAsync: (workspaceId: string, projectId: string) => null | Promise; getIssuesForModulesAsync: ( workspaceId: string, projectId: string, - moduleId: string, - _view: TIssueViews, - _layout: TIssueLayouts + moduleId: string ) => null | Promise; getIssuesForCyclesAsync: ( workspaceId: string, projectId: string, - cycleId: string, - _view: TIssueViews, - _layout: TIssueLayouts + cycleId: string ) => null | Promise; getIssuesForViewsAsync: ( workspaceId: string, projectId: string, - viewId: string, - _view: TIssueViews, - _layout: TIssueLayouts + viewId: string ) => null | Promise; } @@ -159,7 +144,7 @@ class IssueViewStore implements IIssueViewStore { } // fetching my issues - getMyIssuesAsync = async (workspaceId: string, _view: TIssueViews, _layout: TIssueLayouts) => { + getMyIssuesAsync = async (workspaceId: string) => { try { this.loader = true; this.error = null; @@ -171,8 +156,7 @@ class IssueViewStore implements IIssueViewStore { null, null, null, - _view, - _layout + "my_issues" ); const issuesResponse = await this.userService.userIssues(workspaceId, filteredParams); @@ -183,7 +167,8 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId], my_issues: { ...this?.issues[workspaceId]?.my_issues, - [_layout as string]: issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: + issuesResponse, }, }, }; @@ -205,12 +190,7 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues - getProjectIssuesAsync = async ( - workspaceId: string, - projectId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => { + getProjectIssuesAsync = async (workspaceId: string, projectId: string) => { try { this.loader = true; this.error = null; @@ -222,8 +202,7 @@ class IssueViewStore implements IIssueViewStore { null, null, null, - _view, - _layout + "issues" ); const issuesResponse = await this.issueService.getIssuesWithParams( workspaceId, @@ -242,7 +221,8 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues?.[workspaceId]?.project_issues?.[projectId], issues: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.issues, - [_layout as string]: issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: + issuesResponse, }, }, }, @@ -266,13 +246,7 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for modules - getIssuesForModulesAsync = async ( - workspaceId: string, - projectId: string, - moduleId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => { + getIssuesForModulesAsync = async (workspaceId: string, projectId: string, moduleId: string) => { try { this.loader = true; this.error = null; @@ -288,8 +262,7 @@ class IssueViewStore implements IIssueViewStore { moduleId, null, null, - _view, - _layout + "modules" ); const issuesResponse = await this.modulesService.getModuleIssuesWithParams( workspaceId, @@ -311,7 +284,8 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules, [moduleId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules?.[moduleId], - [_layout as string]: issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: + issuesResponse, }, }, }, @@ -336,13 +310,7 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for cycles - getIssuesForCyclesAsync = async ( - workspaceId: string, - projectId: string, - cycleId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => { + getIssuesForCyclesAsync = async (workspaceId: string, projectId: string, cycleId: string) => { try { this.loader = true; this.error = null; @@ -358,8 +326,7 @@ class IssueViewStore implements IIssueViewStore { null, cycleId, null, - _view, - _layout + "cycles" ); const issuesResponse = await this.cyclesService.getCycleIssuesWithParams( workspaceId, @@ -381,7 +348,8 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles, [cycleId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles?.[cycleId], - [_layout as string]: issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: + issuesResponse, }, }, }, @@ -406,13 +374,7 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for views - getIssuesForViewsAsync = async ( - workspaceId: string, - projectId: string, - viewId: string, - _view: TIssueViews, - _layout: TIssueLayouts - ) => { + getIssuesForViewsAsync = async (workspaceId: string, projectId: string, viewId: string) => { try { this.loader = true; this.error = null; @@ -424,8 +386,7 @@ class IssueViewStore implements IIssueViewStore { null, null, viewId, - _view, - _layout + "views" ); const issuesResponse = await this.issueService.getIssuesWithParams( workspaceId, @@ -446,7 +407,8 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views, [viewId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views?.[viewId], - [_layout as string]: issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: + issuesResponse, }, }, }, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index ee37f1f48a3..f5c16fc7a67 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -6,6 +6,9 @@ import { WorkspaceService } from "services/workspace.service"; import { ProjectIssuesServices } from "services/issues.service"; import { ProjectStateServices } from "services/state.service"; import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; +import { ProjectCycleServices } from "services/cycles.service"; +import { ViewServices as ProjectViewServices } from "services/views.service"; // default data import { filtersPriority, @@ -21,6 +24,7 @@ import { export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; + export interface IIssueFilter { priority: string[] | undefined; state: string[] | undefined; @@ -92,6 +96,7 @@ export interface IIssueFilters { my_issue_properties: { filters: IIssueFilter; display_filters: IIssueDisplayFilters; + display_properties_id: null; display_properties: IIssueDisplayProperties; }; project_issue_properties: { @@ -115,6 +120,7 @@ export interface IIssueFilters { filters: IIssueFilter; }; }; + display_properties_id: string; display_properties: IIssueDisplayProperties; }; }; @@ -126,6 +132,7 @@ export interface IIssueFilterStore { error: any | null; // current workspace and project id + myUserId: string | null; workspaceId: string | null; projectId: string | null; moduleId: string | null; @@ -136,48 +143,65 @@ export interface IIssueFilterStore { issueRenderFilters: IIssueRenderFilters; issueFilters: IIssueFilters; - filterRenderProperties: - | { - [key: string]: { - isPreviewEnabled: boolean; - totalElements: number; - elementsVisible: number; - }; - }[] - | null; - // actions getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; - updateWorkspaceMyIssuesFilters: () => any | Promise; + updateWorkspaceMyIssuesFilters: (workspaceId: string, data: any) => Promise; - getProjectLevelMembers: (workspaceId: string, projectId: string) => any | Promise; - getProjectLevelStates: (workspaceId: string, projectId: string) => any | Promise; - getProjectLevelLabels: (workspaceId: string, projectId: string) => any | Promise; - getProjectDisplayFilters: (workspaceId: string, projectId: string) => any | Promise; - getProjectDisplayProperties: (workspaceId: string, projectId: string) => any | Promise; + getProjectLevelMembers: (workspaceId: string, projectId: string) => Promise; + getProjectLevelStates: (workspaceId: string, projectId: string) => Promise; + getProjectLevelLabels: (workspaceId: string, projectId: string) => Promise; + getProjectDisplayProperties: (workspaceId: string, projectId: string) => Promise; + updateProjectDisplayProperties: ( + workspaceId: string, + projectId: string, + display_properties_id: string, + data: any + ) => Promise; + getProjectDisplayFilters: (workspaceId: string, projectId: string) => Promise; + updateProjectDisplayFilters: (workspaceId: string, projectId: string, data: any) => Promise; + + getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise; - getProjectIssueFilters: (workspaceId: string, projectId: string) => any | Promise; getProjectIssueModuleFilters: ( workspaceId: string, projectId: string, moduleId: string - ) => any | Promise; + ) => Promise; + updateProjectIssueModuleFilters: ( + workspaceId: string, + projectId: string, + moduleId: string, + data: any + ) => Promise; getProjectIssueCyclesFilters: ( workspaceId: string, projectId: string, cycleId: string - ) => any | Promise; + ) => Promise; + updateProjectIssueCyclesFilters: ( + workspaceId: string, + projectId: string, + cycleId: string, + data: any + ) => Promise; getProjectIssueViewsFilters: ( workspaceId: string, projectId: string, viewId: string - ) => any | Promise; + ) => Promise; + updateProjectIssueViewsFilters: ( + workspaceId: string, + projectId: string, + viewId: string, + data: any + ) => Promise; } class IssueFilterStore implements IIssueFilterStore { loader: boolean = false; error: any | null = null; + myUserId: string | null = null; workspaceId: string | null = null; projectId: string | null = null; moduleId: string | null = null; @@ -200,16 +224,6 @@ class IssueFilterStore implements IIssueFilterStore { }; issueFilters: IIssueFilters = {}; - filterRenderProperties: - | { - [key: string]: { - isPreviewEnabled: boolean; - totalElements: number; - elementsVisible: number; - }; - }[] - | null = null; - // root store rootStore; // service @@ -217,6 +231,9 @@ class IssueFilterStore implements IIssueFilterStore { issueService; stateService; projectService; + moduleService; + cycleService; + viewService; constructor(_rootStore: RootStore) { makeObservable(this, { @@ -224,6 +241,7 @@ class IssueFilterStore implements IIssueFilterStore { loader: observable, error: observable, + myUserId: observable, workspaceId: observable, projectId: observable, moduleId: observable, @@ -246,29 +264,34 @@ class IssueFilterStore implements IIssueFilterStore { userFilters: computed, - // action - setWorkspaceId: action, - setProjectId: action, - setModuleId: action, - setCycleId: action, - setViewId: action, - setIssueView: action, - + // actions getComputedFilters: action, + handleUserFilter: action, + getWorkspaceMyIssuesFilters: action, updateWorkspaceMyIssuesFilters: action, getProjectLevelMembers: action, getProjectLevelStates: action, getProjectLevelLabels: action, + getProjectDisplayFilters: action, + updateProjectDisplayFilters: action, + getProjectDisplayProperties: action, + updateProjectDisplayProperties: action, getProjectIssueFilters: action, + getProjectIssueModuleFilters: action, + updateProjectIssueModuleFilters: action, + getProjectIssueCyclesFilters: action, + updateProjectIssueCyclesFilters: action, + getProjectIssueViewsFilters: action, + updateProjectIssueViewsFilters: action, }); this.rootStore = _rootStore; @@ -276,15 +299,11 @@ class IssueFilterStore implements IIssueFilterStore { this.issueService = new ProjectIssuesServices(); this.stateService = new ProjectStateServices(); this.projectService = new ProjectServices(); + this.moduleService = new ProjectModuleServices(); + this.cycleService = new ProjectCycleServices(); + this.viewService = new ProjectViewServices(); } - setWorkspaceId = (_workspaceId: string | null) => (this.workspaceId = _workspaceId); - setProjectId = (_projectId: string | null) => (this.projectId = _projectId); - setModuleId = (_moduleId: string | null) => (this.moduleId = _moduleId); - setCycleId = (_cycleId: string | null) => (this.cycleId = _cycleId); - setViewId = (_viewId: string | null) => (this.viewId = _viewId); - setIssueView = (_view: TIssueViews | null) => (this.issueView = _view); - // computed get issueLayout() { if (!this.workspaceId) return null; @@ -331,22 +350,30 @@ class IssueFilterStore implements IIssueFilterStore { get userFilters() { if (!this.workspaceId) return null; if (this.issueView === "my_issues") - return this.issueFilters?.[this.workspaceId]?.my_issue_properties; + return { + ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, + display_properties_id: null, + }; if (!this.projectId) return null; let _issueFilters: { filters: IIssueFilter | null; display_filters: IIssueDisplayFilters; + display_properties_id: string; display_properties: IIssueDisplayProperties; } = { filters: null, display_filters: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues ?.display_filters, + display_properties_id: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.display_properties_id, display_properties: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] ?.display_properties, }; + if (this.issueView === "issues") { _issueFilters = { ..._issueFilters, @@ -356,6 +383,7 @@ class IssueFilterStore implements IIssueFilterStore { }; return _issueFilters; } + if (this.issueView === "modules" && this.moduleId) { _issueFilters = { ..._issueFilters, @@ -365,6 +393,7 @@ class IssueFilterStore implements IIssueFilterStore { }; return _issueFilters; } + if (this.issueView === "cycles" && this.cycleId) { _issueFilters = { ..._issueFilters, @@ -374,6 +403,7 @@ class IssueFilterStore implements IIssueFilterStore { }; return _issueFilters; } + if (this.issueView === "views" && this.viewId) { _issueFilters = { ..._issueFilters, @@ -383,9 +413,243 @@ class IssueFilterStore implements IIssueFilterStore { }; return _issueFilters; } + return null; } - handleUserFilter = () => {}; + handleUserFilter = ( + filter_type: "filters" | "display_filters" | "display_properties", + filter_key: string, + value: any + ) => { + if (!this.workspaceId) return null; + + if (this.issueView === "my_issues") { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + my_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.my_issue_properties?.[filter_type], + [filter_key]: value, + }, + }, + }, + }; + this.updateWorkspaceMyIssuesFilters(this.workspaceId, this.userFilters); + } + + if (!this.projectId) return null; + if (filter_type === "display_properties") { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + display_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.display_properties, + [filter_key]: value, + }, + }, + }, + }, + }; + + if (this.userFilters?.display_properties_id) { + this.updateProjectDisplayProperties( + this.workspaceId, + this.projectId, + this.userFilters?.display_properties_id, + this.userFilters?.display_properties + ); + } + } + + if (filter_type === "display_filters") { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + issues: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + ?.issues, + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.issues?.[filter_type], + [filter_key]: value, + }, + }, + }, + }, + }, + }; + this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { + filters: this.userFilters?.filters, + display_filters: this.userFilters?.display_filters, + }); + } + + if (filter_type === "filters") { + if (this.issueView === "issues") { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ], + issues: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.issues, + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.issues?.[filter_type], + [filter_key]: value, + }, + }, + }, + }, + }, + }; + this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { + filters: this.userFilters?.filters, + display_filters: this.userFilters?.display_filters, + }); + } + + if (this.issueView === "modules" && this.moduleId) { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ], + modules: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.modules, + [this.moduleId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.modules?.[this.moduleId], + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.modules?.[this.moduleId]?.[filter_type], + [filter_key]: value, + }, + }, + }, + }, + }, + }, + }; + this.updateProjectIssueModuleFilters( + this.workspaceId, + this.projectId, + this.moduleId, + this.userFilters?.filters + ); + } + + if (this.issueView === "cycles" && this.cycleId) { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ], + cycles: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.cycles, + [this.cycleId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.cycles?.[this.cycleId], + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.cycles?.[this.cycleId]?.[filter_type], + [filter_key]: value, + }, + }, + }, + }, + }, + }, + }; + this.updateProjectIssueCyclesFilters( + this.workspaceId, + this.projectId, + this.cycleId, + this.userFilters?.filters + ); + } + + if (this.issueView === "views" && this.viewId) { + this.issueFilters = { + ...this.issueFilters, + [this.workspaceId]: { + ...this.issueFilters?.[this.workspaceId], + project_issue_properties: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + [this.projectId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ], + views: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.views, + [this.viewId]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.views?.[this.viewId], + [filter_type]: { + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ + this.projectId + ]?.views?.[this.viewId]?.[filter_type], + [filter_key]: value, + }, + }, + }, + }, + }, + }, + }; + this.updateProjectIssueViewsFilters( + this.workspaceId, + this.projectId, + this.viewId, + this.userFilters?.filters + ); + } + } + }; computedFilter = (filters: any, filteredParams: any) => { const computedFilters: any = {}; @@ -405,15 +669,14 @@ class IssueFilterStore implements IIssueFilterStore { _moduleId: string | null, _cycleId: string | null, _viewId: string | null, - _issueView: TIssueViews, - _issueLayout: TIssueLayouts + _issueView: TIssueViews ) => { - this.setWorkspaceId(_workspaceId); - this.setProjectId(_projectId); - this.setModuleId(_moduleId); - this.setCycleId(_cycleId); - this.setViewId(_viewId); - this.setIssueView(_issueView); + this.workspaceId = _workspaceId; + this.projectId = _projectId; + this.moduleId = _moduleId; + this.cycleId = _cycleId; + this.viewId = _viewId; + this.issueView = _issueView; const _layout = this.userFilters?.display_filters?.layout; @@ -426,17 +689,15 @@ class IssueFilterStore implements IIssueFilterStore { labels: this.userFilters?.filters?.labels || undefined, start_date: this.userFilters?.filters?.start_date || undefined, target_date: this.userFilters?.filters?.target_date || undefined, - type: this.userFilters?.display_filters?.type || undefined, group_by: this.userFilters?.display_filters?.group_by || "state", order_by: this.userFilters?.display_filters?.order_by || "-created_at", + type: this.userFilters?.display_filters?.type || undefined, sub_issue: this.userFilters?.display_filters?.sub_issue || true, show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, start_target_date: this.userFilters?.display_filters?.start_target_date || true, }; - console.log("filteredRouteParams", filteredRouteParams); - // start date and target date we have to construct the format here let filteredParams: any = {}; @@ -515,7 +776,6 @@ class IssueFilterStore implements IIssueFilterStore { filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); // remove few attributes from the object when we are in workspace issues - console.log("filteredRouteParams", filteredRouteParams); return filteredRouteParams; }; @@ -667,36 +927,25 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateWorkspaceMyIssuesFilters = async () => { + updateWorkspaceMyIssuesFilters = async (workspaceId: string, data: any) => { try { this.loader = true; this.error = null; - const workspaceId = "1"; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + const payload = { + view_props: data, + }; + const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView( + workspaceId, + payload + ); if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; - runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -837,6 +1086,7 @@ class IssueFilterStore implements IIssueFilterStore { ); if (issuesDisplayPropertiesResponse) { + const _myUserId: string = issuesDisplayPropertiesResponse?.user; const _issuesDisplayPropertiesResponse: any = { ...this.issueFilters, [workspaceId]: { @@ -845,13 +1095,17 @@ class IssueFilterStore implements IIssueFilterStore { ...this?.issueFilters[workspaceId]?.project_issue_properties, [projectId]: { ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - display_properties: issuesDisplayPropertiesResponse?.properties, + display_properties_id: issuesDisplayPropertiesResponse?.id, + display_properties: { + ...issuesDisplayPropertiesResponse?.properties, + }, }, }, }, }; runInAction(() => { + this.myUserId = _myUserId; this.issueFilters = _issuesDisplayPropertiesResponse; this.loader = false; this.error = null; @@ -866,33 +1120,29 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateProjectDisplayProperties = async (workspaceId: string, projectId: string, data: any) => { + updateProjectDisplayProperties = async ( + workspaceId: string, + projectId: string, + display_properties_id: string, + data: any + ) => { try { this.loader = true; this.error = null; - const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties( + const payload = { + properties: data, + user: this.myUserId, + }; + const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties( workspaceId, - projectId + projectId, + display_properties_id, + payload ); if (issuesDisplayPropertiesResponse) { - const _issuesDisplayPropertiesResponse: any = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - display_properties: issuesDisplayPropertiesResponse, - }, - }, - }, - }; - runInAction(() => { - this.issueFilters = _issuesDisplayPropertiesResponse; this.loader = false; this.error = null; }); @@ -946,7 +1196,7 @@ class IssueFilterStore implements IIssueFilterStore { }); } - // return issuesResponse; + return issuesDisplayFiltersResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -954,37 +1204,30 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateProjectDisplayFilters = async (workspaceId: string, projectId: string) => { + updateProjectDisplayFilters = async (workspaceId: string, projectId: string, data: any) => { try { this.loader = true; this.error = null; - const workspaceId = "1"; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + const payload: any = { + view_props: data, + }; + const issuesFiltersResponse = await this.projectService.setProjectView( + workspaceId, + projectId, + payload + ); if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; - runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; this.loader = false; this.error = null; }); } - // return issuesResponse; + return issuesFiltersResponse; } catch (error) { + this.getProjectDisplayFilters(workspaceId, projectId); console.warn("error in fetching workspace level issue filters", error); this.loader = false; this.error = null; @@ -1007,43 +1250,6 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = false; this.error = null; }); - - // return issuesResponse; - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectIssueFilters = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; - - runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; - this.loader = false; - this.error = null; - }); - } - - // return issuesResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -1061,31 +1267,53 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const workspaceId = "1"; + await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails( + workspaceId, + projectId, + moduleId + ); - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + if (issuesFiltersModuleResponse) { + const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters }; + const _issuesFiltersModuleResponse = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + modules: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] + ?.modules, + [moduleId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] + ?.modules?.[moduleId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }, + }, + }; runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; + this.issueFilters = _issuesFiltersModuleResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -1096,38 +1324,32 @@ class IssueFilterStore implements IIssueFilterStore { updateProjectIssueModuleFilters = async ( workspaceId: string, projectId: string, - moduleId: string + moduleId: string, + data: any ) => { try { this.loader = true; this.error = null; - const workspaceId = "1"; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + const payload = { + view_props: { filters: data }, + }; + const issuesFiltersModuleResponse = await this.moduleService.patchModule( + workspaceId, + projectId, + moduleId, + payload, + undefined // TODO: replace this with user + ); + if (issuesFiltersModuleResponse) { runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { + this.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); console.warn("error in fetching workspace level issue filters", error); this.loader = false; this.error = null; @@ -1144,31 +1366,52 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const workspaceId = "1"; + await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails( + workspaceId, + projectId, + cycleId + ); - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + if (issuesFiltersCycleResponse) { + const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters }; + const _issuesFiltersCycleResponse = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + cycles: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, + [cycleId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] + ?.modules?.[cycleId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }, + }, + }; runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; + this.issueFilters = _issuesFiltersCycleResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -1179,38 +1422,32 @@ class IssueFilterStore implements IIssueFilterStore { updateProjectIssueCyclesFilters = async ( workspaceId: string, projectId: string, - cycleId: string + cycleId: string, + data: any ) => { try { this.loader = true; this.error = null; - const workspaceId = "1"; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + const payload = { + view_props: { filters: data }, + }; + const issuesFiltersCycleResponse = await this.cycleService.patchCycle( + workspaceId, + projectId, + cycleId, + payload, + undefined // TODO: replace this with user + ); + if (issuesFiltersCycleResponse) { runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { + this.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); console.warn("error in fetching workspace level issue filters", error); this.loader = false; this.error = null; @@ -1223,31 +1460,52 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const workspaceId = "1"; + await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + const issuesFiltersViewResponse = await this.viewService.getViewDetails( + workspaceId, + projectId, + viewId + ); - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + if (issuesFiltersViewResponse) { + const _filters = { ...issuesFiltersViewResponse?.query_data } as any; + const _issuesFiltersViewResponse = { + ...this.issueFilters, + [workspaceId]: { + ...this?.issueFilters[workspaceId], + project_issue_properties: { + ...this?.issueFilters[workspaceId]?.project_issue_properties, + [projectId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], + views: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, + [viewId]: { + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] + ?.modules?.[viewId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }, + }, + }; runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; + this.issueFilters = _issuesFiltersViewResponse; this.loader = false; this.error = null; }); } - - // return issuesResponse; } catch (error) { console.warn("error in fetching workspace level issue filters", error); this.loader = false; @@ -1258,45 +1516,40 @@ class IssueFilterStore implements IIssueFilterStore { updateProjectIssueViewsFilters = async ( workspaceId: string, projectId: string, - viewId: string + viewId: string, + data: any ) => { try { this.loader = true; this.error = null; - const workspaceId = "1"; - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - - if (issuesFiltersResponse) { - // const _issuesFiltersResponse = this.issueFilters; - // const _issuesFiltersResponse: any = { - // ...this.issues, - // [workspaceId]: { - // ...this?.issues[workspaceId], - // my_issues: { - // ...this?.issues[workspaceId]?.my_issues, - // [_layout as string]: issuesResponse, - // }, - // }, - // }; + const payload = { + query_data: data, + }; + const issuesFiltersViewResponse = await this.viewService.patchView( + workspaceId, + projectId, + viewId, + payload, + undefined // TODO: replace this with user + ); + if (issuesFiltersViewResponse) { runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; this.loader = false; this.error = null; }); } - // return issuesResponse; + return issuesFiltersViewResponse; } catch (error) { + this.getProjectIssueViewsFilters(projectId, workspaceId, viewId); console.warn("error in fetching workspace level issue filters", error); this.loader = false; this.error = null; return error; } }; - // project level filters ends } export default IssueFilterStore; From c67f08fca4387f1b72d2a2169b9bbd9c92ec6a28 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 16:03:35 +0530 Subject: [PATCH 012/102] chore: filter, layout, display filters, extra filters and display properties render validation --- .../display-filters/extra-options.tsx | 46 ++++--- .../issue-layouts/display-filters/index.tsx | 107 ++++++++++----- .../issue-layouts/filters/index.tsx | 127 +++++++++++------- .../issue-layouts/filters/labels.tsx | 13 +- .../issue-layouts/layout-selection.tsx | 60 ++++++--- web/store/issue-views/issue_data.ts | 67 ++++++++- 6 files changed, 294 insertions(+), 126 deletions(-) diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index 15450a24f21..11ef74a9400 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -7,6 +7,8 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +// default data +import { issueFilterVisibilityData } from "store/issue-views/issue_data"; export const FilterExtraOptions = observer(() => { const store: RootStore = useMobxStore(); @@ -18,6 +20,13 @@ export const FilterExtraOptions = observer(() => { issueFilterStore.handleUserFilter("display_filters", key, !value); }; + const handleExtraOptionsSectionVisibility = (key: string) => + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ]?.extra_options?.[issueFilterStore?.issueLayout].values?.includes(key); + return (
{
{issueFilterStore?.issueRenderFilters?.extra_properties && issueFilterStore?.issueRenderFilters?.extra_properties.length > 0 && - issueFilterStore?.issueRenderFilters?.extra_properties.map((_extraProperties) => ( - - handleExtraOptions( - _extraProperties?.key, - issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key] - ) - } - title={_extraProperties.title} - /> - ))} + issueFilterStore?.issueRenderFilters?.extra_properties.map( + (_extraProperties) => + handleExtraOptionsSectionVisibility(_extraProperties?.key) && ( + + handleExtraOptions( + _extraProperties?.key, + issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key] + ) + } + title={_extraProperties.title} + /> + ) + )}
)}
diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index 5a3fb3a0824..d629327afb6 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -5,41 +5,78 @@ import { FilterGroupBy } from "./group-by"; import { FilterOrderBy } from "./order-by"; import { FilterIssueType } from "./issue-type"; import { FilterExtraOptions } from "./extra-options"; -// // mobx react lite -// import { observer } from "mobx-react-lite"; -// // mobx store -// import { useMobxStore } from "lib/mobx/store-provider"; -// import { RootStore } from "store/root"; - -// const store: RootStore = useMobxStore(); -// const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; - -export const DisplayFiltersSelection = () => ( -
-
- Search container -
-
- {/* display properties */} -
- -
- {/* group by */} -
- -
- {/* order by */} -
- -
- {/* issue type */} -
- +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// default data +import { issueFilterVisibilityData } from "store/issue-views/issue_data"; + +export const DisplayFiltersSelection = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleDisplayPropertiesSectionVisibility = + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"] + ?.display_properties?.[issueFilterStore?.issueLayout]; + + const handleDisplayFilterSectionVisibility = (section_key: string) => + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ]?.display_filters?.[issueFilterStore?.issueLayout].includes(section_key); + + const handleExtraOptionsSectionVisibility = + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"] + ?.extra_options?.[issueFilterStore?.issueLayout].access; + + return ( +
+
+ Search container
- {/* Options */} -
- +
+ {/* display properties */} + {handleDisplayPropertiesSectionVisibility && ( +
+ +
+ )} + + {/* group by */} + {handleDisplayFilterSectionVisibility("group_by") && ( +
+ +
+ )} + + {/* order by */} + {handleDisplayFilterSectionVisibility("order_by") && ( +
+ +
+ )} + + {/* issue type */} + {handleDisplayFilterSectionVisibility("issue_type") && ( +
+ +
+ )} + + {/* Options */} + {handleExtraOptionsSectionVisibility && ( +
+ +
+ )}
-
-); + ); +}); diff --git a/web/components/issue-layouts/filters/index.tsx b/web/components/issue-layouts/filters/index.tsx index 4376f2d33a0..2ad446eb316 100644 --- a/web/components/issue-layouts/filters/index.tsx +++ b/web/components/issue-layouts/filters/index.tsx @@ -8,53 +8,86 @@ import { FilterCreatedBy } from "./created-by"; import { FilterLabels } from "./labels"; import { FilterStartDate } from "./start-date"; import { FilterTargetDate } from "./target-date"; -// // mobx react lite -// import { observer } from "mobx-react-lite"; -// // mobx store -// import { useMobxStore } from "lib/mobx/store-provider"; -// import { RootStore } from "store/root"; - -// const store: RootStore = useMobxStore(); -// const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; - -export const FilterSelection = () => ( -
-
- Search container -
-
- {/* priority */} -
- -
- {/* state group */} -
- -
- {/* state */} -
- -
- {/* assignees */} -
- -
- {/* created_by */} -
- -
- {/* labels */} -
- -
- {/* start_date */} -
- +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// default data +import { issueFilterVisibilityData } from "store/issue-views/issue_data"; + +export const FilterSelection = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilterSectionVisibility = (section_key: string) => + issueFilterStore?.issueView && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ].filters.includes(section_key); + + return ( +
+
+ Search container
- {/* due_date */} -
- +
+ {/* priority */} + {handleFilterSectionVisibility("priority") && ( +
+ +
+ )} + + {/* state group */} + {handleFilterSectionVisibility("state_group") && ( +
+ +
+ )} + + {/* state */} + {handleFilterSectionVisibility("state") && ( +
+ +
+ )} + + {/* assignees */} + {handleFilterSectionVisibility("assignees") && ( +
+ +
+ )} + + {/* created_by */} + {handleFilterSectionVisibility("created_by") && ( +
+ +
+ )} + + {/* labels */} + {handleFilterSectionVisibility("labels") && ( +
+ +
+ )} + + {/* start_date */} + {handleFilterSectionVisibility("start_date") && ( +
+ +
+ )} + + {/* due_date */} + {handleFilterSectionVisibility("due_date") && ( +
+ +
+ )}
-
-); + ); +}); diff --git a/web/components/issue-layouts/filters/labels.tsx b/web/components/issue-layouts/filters/labels.tsx index 61ba8d182c1..6b38ff123a9 100644 --- a/web/components/issue-layouts/filters/labels.tsx +++ b/web/components/issue-layouts/filters/labels.tsx @@ -32,18 +32,23 @@ export const FilterLabels = observer(() => { issueFilterStore.handleUserFilter("filters", key, _value); }; + const handleLabels = + issueFilterStore.issueView && issueFilterStore.issueView === "my_issues" + ? issueFilterStore?.workspaceLabels + : issueFilterStore?.projectLabels; + return (
setPreviewEnabled(!previewEnabled)} /> {previewEnabled && (
- {issueFilterStore?.projectLabels && - issueFilterStore?.projectLabels.length > 0 && - issueFilterStore?.projectLabels.map((_label) => ( + {handleLabels && + handleLabels.length > 0 && + handleLabels.map((_label) => ( { const store: RootStore = useMobxStore(); @@ -40,11 +42,18 @@ export const LayoutSelection = observer(() => { }, ]; + const handleLayoutSectionVisibility = (layout_key: string) => + issueFilterStore?.issueView && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ].layout.includes(layout_key); + const handleLayoutSelection = (_layoutKey: string) => { issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey); }; console.log("----"); + console.log("my_user_id", issueFilterStore.myUserId); console.log("workspace_id", issueFilterStore.workspaceId); console.log("project_id", issueFilterStore.projectId); console.log("module_id", issueFilterStore.moduleId); @@ -54,31 +63,38 @@ export const LayoutSelection = observer(() => { console.log("issue_view", issueFilterStore.issueView); console.log("issue_layout", issueFilterStore.issueLayout); + console.log("user_filters", issueFilterStore.userFilters); + console.log("issues", issueStore.issues); + console.log("issues", issueStore.getIssues); + console.log("----"); return (
- {layoutSelectionFilters.map((_layout) => ( -
handleLayoutSelection(_layout?.key)} - > - <_layout.icon - size={14} - strokeWidth={2} - className={`${ - issueFilterStore?.issueLayout == _layout?.key - ? `text-custom-text-100` - : `text-custom-text-100 group-hover:text-custom-text-200` - }`} - /> -
- ))} + {layoutSelectionFilters.map( + (_layout) => + handleLayoutSectionVisibility(_layout?.key) && ( +
handleLayoutSelection(_layout?.key)} + > + <_layout.icon + size={14} + strokeWidth={2} + className={`${ + issueFilterStore?.issueLayout == _layout?.key + ? `text-custom-text-100` + : `text-custom-text-100 group-hover:text-custom-text-200` + }`} + /> +
+ ) + )}
); }); diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index ab369f73278..eff9a13dbb6 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -78,8 +78,73 @@ export const displayProperties: { key: string; title: string }[] = [ ]; export const extraProperties: { key: string; title: string }[] = [ - { key: "sub_issues", title: "Show sub-issues" }, // in spreadsheet its always false + { key: "sub_issue", title: "Show sub-issues" }, // in spreadsheet its always false { key: "show_empty_groups", title: "Show empty states" }, // filter on front-end { key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after { key: "start_target_date", title: "Start target Date" }, // gantt always be true ]; + +export const issueFilterVisibilityData: any = { + my_issues: { + layout: ["list", "kanban"], + filters: ["priority", "state_group", "labels", "start_date", "due_date"], + display_properties: { + list: true, + kanban: true, + }, + display_filters: { + list: ["group_by", "order_by", "issue_type"], + kanban: ["group_by", "order_by", "issue_type"], + }, + extra_options: { + list: { + access: true, + values: ["show_empty_groups"], + }, + kanban: { + access: true, + values: ["show_empty_groups"], + }, + }, + }, + others: { + layout: ["list", "kanban", "calendar", "spreadsheet", "gantt"], + filters: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], + display_properties: { + list: true, + kanban: true, + calendar: true, + spreadsheet: true, + gantt: false, + }, + display_filters: { + list: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], + kanban: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], + calendar: ["issue_type"], + spreadsheet: ["issue_type"], + gantt: ["order_by", "issue_type", "sub_issue"], + }, + extra_options: { + list: { + access: true, + values: ["show_empty_groups", "sub_issue"], + }, + kanban: { + access: true, + values: ["show_empty_groups", "sub_issue"], + }, + calendar: { + access: false, + values: [], + }, + spreadsheet: { + access: false, + values: [], + }, + gantt: { + access: true, + values: ["sub_issue"], + }, + }, + }, +}; From 60883baea70c26a50071c76bf05fb02a86f7a368 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 16:09:43 +0530 Subject: [PATCH 013/102] chore: clean up and resolved import warnings --- .../issue-layouts/display-filters/display-properties.tsx | 2 +- .../issue-layouts/display-filters/extra-options.tsx | 2 +- web/components/issue-layouts/display-filters/group-by.tsx | 2 +- web/components/issue-layouts/display-filters/issue-type.tsx | 2 +- web/components/issue-layouts/display-filters/order-by.tsx | 2 +- web/components/issue-layouts/filters/assignees.tsx | 4 +--- web/components/issue-layouts/filters/created-by.tsx | 4 +--- web/components/issue-layouts/filters/labels.tsx | 4 +--- web/components/issue-layouts/filters/priority.tsx | 2 +- web/components/issue-layouts/filters/start-date.tsx | 4 +--- web/components/issue-layouts/filters/state-group.tsx | 4 +--- web/components/issue-layouts/filters/state.tsx | 4 +--- web/components/issue-layouts/filters/target-date.tsx | 5 ++--- web/components/issue-layouts/kanban/header.tsx | 2 +- web/components/issue-layouts/kanban/index.tsx | 2 +- 15 files changed, 16 insertions(+), 29 deletions(-) diff --git a/web/components/issue-layouts/display-filters/display-properties.tsx b/web/components/issue-layouts/display-filters/display-properties.tsx index dd234340a3e..309763c3f18 100644 --- a/web/components/issue-layouts/display-filters/display-properties.tsx +++ b/web/components/issue-layouts/display-filters/display-properties.tsx @@ -9,7 +9,7 @@ import { RootStore } from "store/root"; export const FilterDisplayProperties = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index 11ef74a9400..100a6cfd718 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -12,7 +12,7 @@ import { issueFilterVisibilityData } from "store/issue-views/issue_data"; export const FilterExtraOptions = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/display-filters/group-by.tsx b/web/components/issue-layouts/display-filters/group-by.tsx index fa46415ab64..93e297803a1 100644 --- a/web/components/issue-layouts/display-filters/group-by.tsx +++ b/web/components/issue-layouts/display-filters/group-by.tsx @@ -10,7 +10,7 @@ import { RootStore } from "store/root"; export const FilterGroupBy = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/display-filters/issue-type.tsx b/web/components/issue-layouts/display-filters/issue-type.tsx index eaf9ae7bda0..10f50800be0 100644 --- a/web/components/issue-layouts/display-filters/issue-type.tsx +++ b/web/components/issue-layouts/display-filters/issue-type.tsx @@ -10,7 +10,7 @@ import { RootStore } from "store/root"; export const FilterIssueType = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/display-filters/order-by.tsx b/web/components/issue-layouts/display-filters/order-by.tsx index 9e3b9e35db8..c7c3f2ebb56 100644 --- a/web/components/issue-layouts/display-filters/order-by.tsx +++ b/web/components/issue-layouts/display-filters/order-by.tsx @@ -10,7 +10,7 @@ import { RootStore } from "store/root"; export const FilterOrderBy = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index 2e51a3a4903..e591ea44fd6 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; @@ -30,7 +28,7 @@ export const MemberIcons = ({ export const FilterAssignees = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/created-by.tsx b/web/components/issue-layouts/filters/created-by.tsx index 5ba7beb0127..e9b34342fa4 100644 --- a/web/components/issue-layouts/filters/created-by.tsx +++ b/web/components/issue-layouts/filters/created-by.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { MemberIcons } from "./assignees"; import { FilterHeader } from "../helpers/filter-header"; @@ -13,7 +11,7 @@ import { RootStore } from "store/root"; export const FilterCreatedBy = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/labels.tsx b/web/components/issue-layouts/filters/labels.tsx index 6b38ff123a9..79a82ddd218 100644 --- a/web/components/issue-layouts/filters/labels.tsx +++ b/web/components/issue-layouts/filters/labels.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; @@ -18,7 +16,7 @@ const LabelIcons = ({ color }: { color: string }) => ( export const FilterLabels = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/priority.tsx b/web/components/issue-layouts/filters/priority.tsx index f8b104c812f..048e2246900 100644 --- a/web/components/issue-layouts/filters/priority.tsx +++ b/web/components/issue-layouts/filters/priority.tsx @@ -52,7 +52,7 @@ const PriorityIcons = ({ export const FilterPriority = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/start-date.tsx b/web/components/issue-layouts/filters/start-date.tsx index bfa342922b6..8c92518af66 100644 --- a/web/components/issue-layouts/filters/start-date.tsx +++ b/web/components/issue-layouts/filters/start-date.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; @@ -12,7 +10,7 @@ import { RootStore } from "store/root"; export const FilterStartDate = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx index 0c3da34ec03..1598734a7ba 100644 --- a/web/components/issue-layouts/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; import { StateGroupBacklogIcon, StateGroupCancelledIcon, @@ -85,7 +83,7 @@ export const StateGroupIcons = ({ export const FilterStateGroup = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index 6cabd68a197..917fe2af7e9 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -1,6 +1,4 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; // components import { StateGroupIcons } from "./state-group"; import { FilterHeader } from "../helpers/filter-header"; @@ -15,7 +13,7 @@ import { issueStateGroupKeys } from "store/issue-views/issue_data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/filters/target-date.tsx b/web/components/issue-layouts/filters/target-date.tsx index 0f777f7528d..cec765b057c 100644 --- a/web/components/issue-layouts/filters/target-date.tsx +++ b/web/components/issue-layouts/filters/target-date.tsx @@ -1,6 +1,5 @@ import React from "react"; -// lucide icons -import { Check, ChevronDown, ChevronUp } from "lucide-react"; + // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; @@ -12,7 +11,7 @@ import { RootStore } from "store/root"; export const FilterTargetDate = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; + const { issueFilters: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); diff --git a/web/components/issue-layouts/kanban/header.tsx b/web/components/issue-layouts/kanban/header.tsx index c399b643cb3..8c04dc20d31 100644 --- a/web/components/issue-layouts/kanban/header.tsx +++ b/web/components/issue-layouts/kanban/header.tsx @@ -2,7 +2,7 @@ import { Plus } from "lucide-react"; export const IssueHeader = () => ( -
+
{/* default layout */}
I diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx index 22a79c08a77..b517484dc8e 100644 --- a/web/components/issue-layouts/kanban/index.tsx +++ b/web/components/issue-layouts/kanban/index.tsx @@ -12,7 +12,7 @@ import { RootStore } from "store/root"; export const IssueKanBanViewRoot = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; + const { issueView: issueViewStore } = store; const onDragEnd = (result: any) => { if (!result) return; From 66022ea478277f54e13b3b8bd7dfed067bf86c3c Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 16:54:18 +0530 Subject: [PATCH 014/102] chore: type check --- web/store/issue-views/issue_filters.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index f5c16fc7a67..2b26a52f418 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -1309,7 +1309,7 @@ class IssueFilterStore implements IIssueFilterStore { }; runInAction(() => { - this.issueFilters = _issuesFiltersModuleResponse; + this.issueFilters = _issuesFiltersModuleResponse as any; this.loader = false; this.error = null; }); @@ -1407,7 +1407,7 @@ class IssueFilterStore implements IIssueFilterStore { }; runInAction(() => { - this.issueFilters = _issuesFiltersCycleResponse; + this.issueFilters = _issuesFiltersCycleResponse as any; this.loader = false; this.error = null; }); @@ -1501,7 +1501,7 @@ class IssueFilterStore implements IIssueFilterStore { }; runInAction(() => { - this.issueFilters = _issuesFiltersViewResponse; + this.issueFilters = _issuesFiltersViewResponse as any; this.loader = false; this.error = null; }); From 28ce96aaca73acbc14f6c2cf751d7f7f280f84c4 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 17:26:00 +0530 Subject: [PATCH 015/102] chore: renamed gantt key to gantt_chart --- .../issue-layouts/layout-selection.tsx | 2 +- web/components/issue-layouts/root.tsx | 44 ++++++++--- web/pages/kanban.tsx | 75 ------------------- .../[project_slug]/cycles/[cycle_slug].tsx | 36 +++++++++ .../[project_slug]/issues.tsx | 35 +++++++++ .../[project_slug]/modules/[module_slug].tsx | 36 +++++++++ .../[project_slug]/views/[view_slug].tsx | 36 +++++++++ .../m-store/[workspace_slug]/my-issues.tsx | 31 ++++++++ web/store/issue-views/Issues.ts | 2 +- web/store/issue-views/issue_data.ts | 8 +- web/store/issue-views/issue_filters.ts | 4 +- 11 files changed, 215 insertions(+), 94 deletions(-) delete mode 100644 web/pages/kanban.tsx create mode 100644 web/pages/m-store/[workspace_slug]/[project_slug]/cycles/[cycle_slug].tsx create mode 100644 web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx create mode 100644 web/pages/m-store/[workspace_slug]/[project_slug]/modules/[module_slug].tsx create mode 100644 web/pages/m-store/[workspace_slug]/[project_slug]/views/[view_slug].tsx create mode 100644 web/pages/m-store/[workspace_slug]/my-issues.tsx diff --git a/web/components/issue-layouts/layout-selection.tsx b/web/components/issue-layouts/layout-selection.tsx index d1499ed7eae..f5f3d77fd27 100644 --- a/web/components/issue-layouts/layout-selection.tsx +++ b/web/components/issue-layouts/layout-selection.tsx @@ -36,7 +36,7 @@ export const LayoutSelection = observer(() => { icon: Columns, }, { - key: "gantt", + key: "gantt_chart", title: "Gantt", icon: GanttChart, }, diff --git a/web/components/issue-layouts/root.tsx b/web/components/issue-layouts/root.tsx index 23752fe49c4..660f398f295 100644 --- a/web/components/issue-layouts/root.tsx +++ b/web/components/issue-layouts/root.tsx @@ -1,14 +1,36 @@ import React from "react"; -// mobx react lite -import { observer } from "mobx-react-lite"; -// mobx store -import { RootStore } from "store/root"; -import { TIssueLayouts } from "store/issue-views/issue_filters"; -import { useMobxStore } from "lib/mobx/store-provider"; +// components +import { IssueKanBanViewRoot } from "./kanban"; +import { LayoutSelection } from "./layout-selection"; +import { IssueDropdown } from "./helpers/dropdown"; +import { FilterSelection } from "./filters"; +import { DisplayFiltersSelection } from "./display-filters"; -export const IssuesRoot = observer(() => { - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueStore } = store; +export const IssuesRoot = () => { + console.log("issue root"); - return
issue root
; -}); + return ( +
+
+
+
+
Filter Header
+
+
+ + + + + + + +
+
+
+
Hello
+
+ +
+
+ ); +}; diff --git a/web/pages/kanban.tsx b/web/pages/kanban.tsx deleted file mode 100644 index 1a7d5b07390..00000000000 --- a/web/pages/kanban.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from "react"; -// components -import { IssueKanBanViewRoot } from "components/issue-layouts/kanban"; -import { LayoutSelection } from "components/issue-layouts/layout-selection"; -// issue dropdowns -import { IssueDropdown } from "components/issue-layouts/helpers/dropdown"; -// filter components -import { FilterSelection } from "components/issue-layouts/filters"; -import { DisplayFiltersSelection } from "components/issue-layouts/display-filters"; -// mobx store -import { useMobxStore } from "lib/mobx/store-provider"; -import { RootStore } from "store/root"; - -const KanBanViewRoot = () => { - const workspaceSlug: string = "plane-demo"; - const projectSlug: string = "08d59d96-9dfb-40e5-aa30-ecc66319450f"; - const moduleSlug: string = "05613afc-29ea-4fd8-a025-a3cdfed209d1"; - const cycleSlug: string = "1f66a767-00d1-422c-8f8f-6925282b7249"; - const viewSlug: string = "64e6ecca-80ca-4f7c-8476-d650fca9d5b9"; - - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore, issueView: issueViewStore } = store; - - React.useEffect(() => { - const init = async () => { - console.log("started--->"); - // my issues under a workspace - // await issueViewStore.getMyIssuesAsync(workspaceSlug); - - // project issues under and workspace and project - await issueViewStore.getProjectIssuesAsync(workspaceSlug, projectSlug); - - // module issues under and workspace and project - // await issueViewStore.getIssuesForModulesAsync(workspaceSlug, projectSlug, moduleSlug); - - // cycle issues under and workspace and project - // await issueViewStore.getIssuesForCyclesAsync(workspaceSlug, projectSlug, cycleSlug); - - // cycle issues under and workspace and project - // await issueViewStore.getIssuesForViewsAsync(workspaceSlug, projectSlug, viewSlug); - console.log("ended--->"); - }; - - init(); - }, []); - - return ( -
-
-
-
-
-
Filter Header
-
-
- - - - - - - -
-
-
-
Hello
-
- -
-
-
- ); -}; - -export default KanBanViewRoot; diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/cycles/[cycle_slug].tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/cycles/[cycle_slug].tsx new file mode 100644 index 00000000000..52676e37635 --- /dev/null +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/cycles/[cycle_slug].tsx @@ -0,0 +1,36 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// components +import { IssuesRoot } from "components/issue-layouts/root"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanBanViewRoot = () => { + const router = useRouter(); + const { workspace_slug, project_slug, cycle_slug } = router.query as { + workspace_slug: string; + project_slug: string; + cycle_slug: string; + }; + + const store: RootStore = useMobxStore(); + const { issueView: issueViewStore } = store; + + React.useEffect(() => { + console.log("request init--->"); + const init = async () => + await issueViewStore.getIssuesForCyclesAsync(workspace_slug, project_slug, cycle_slug); + if (workspace_slug && project_slug && cycle_slug) init(); + console.log("request completed--->"); + }, [workspace_slug, project_slug, cycle_slug, issueViewStore]); + + return ( +
+ +
+ ); +}; + +export default KanBanViewRoot; diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx new file mode 100644 index 00000000000..c6319bcaae5 --- /dev/null +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx @@ -0,0 +1,35 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// components +import { IssuesRoot } from "components/issue-layouts/root"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanBanViewRoot = () => { + const router = useRouter(); + const { workspace_slug, project_slug } = router.query as { + workspace_slug: string; + project_slug: string; + }; + + const store: RootStore = useMobxStore(); + const { issueView: issueViewStore } = store; + + React.useEffect(() => { + console.log("request init--->"); + const init = async () => + await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); + if (workspace_slug && project_slug) init(); + console.log("request completed--->"); + }, [workspace_slug, project_slug, issueViewStore]); + + return ( +
+ +
+ ); +}; + +export default KanBanViewRoot; diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/modules/[module_slug].tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/modules/[module_slug].tsx new file mode 100644 index 00000000000..c5aad04fafc --- /dev/null +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/modules/[module_slug].tsx @@ -0,0 +1,36 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// components +import { IssuesRoot } from "components/issue-layouts/root"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanBanViewRoot = () => { + const router = useRouter(); + const { workspace_slug, project_slug, module_slug } = router.query as { + workspace_slug: string; + project_slug: string; + module_slug: string; + }; + + const store: RootStore = useMobxStore(); + const { issueView: issueViewStore } = store; + + React.useEffect(() => { + console.log("request init--->"); + const init = async () => + await issueViewStore.getIssuesForModulesAsync(workspace_slug, project_slug, module_slug); + if (workspace_slug && project_slug && module_slug) init(); + console.log("request completed--->"); + }, [workspace_slug, project_slug, module_slug, issueViewStore]); + + return ( +
+ +
+ ); +}; + +export default KanBanViewRoot; diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/views/[view_slug].tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/views/[view_slug].tsx new file mode 100644 index 00000000000..8da9d22c4b1 --- /dev/null +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/views/[view_slug].tsx @@ -0,0 +1,36 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// components +import { IssuesRoot } from "components/issue-layouts/root"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanBanViewRoot = () => { + const router = useRouter(); + const { workspace_slug, project_slug, view_slug } = router.query as { + workspace_slug: string; + project_slug: string; + view_slug: string; + }; + + const store: RootStore = useMobxStore(); + const { issueView: issueViewStore } = store; + + React.useEffect(() => { + console.log("request init--->"); + const init = async () => + await issueViewStore.getIssuesForViewsAsync(workspace_slug, project_slug, view_slug); + if (workspace_slug && project_slug && view_slug) init(); + console.log("request completed--->"); + }, [workspace_slug, project_slug, view_slug, issueViewStore]); + + return ( +
+ +
+ ); +}; + +export default KanBanViewRoot; diff --git a/web/pages/m-store/[workspace_slug]/my-issues.tsx b/web/pages/m-store/[workspace_slug]/my-issues.tsx new file mode 100644 index 00000000000..766381fd268 --- /dev/null +++ b/web/pages/m-store/[workspace_slug]/my-issues.tsx @@ -0,0 +1,31 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// components +import { IssuesRoot } from "components/issue-layouts/root"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const KanBanViewRoot = () => { + const router = useRouter(); + const { workspace_slug } = router.query as { workspace_slug: string }; + + const store: RootStore = useMobxStore(); + const { issueView: issueViewStore } = store; + + React.useEffect(() => { + console.log("request init--->"); + const init = async () => await issueViewStore.getMyIssuesAsync(workspace_slug); + if (workspace_slug) init(); + console.log("request completed--->"); + }, [workspace_slug, issueViewStore]); + + return ( +
+ +
+ ); +}; + +export default KanBanViewRoot; diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index 74803dc8a8d..f3b021f00f0 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -18,7 +18,7 @@ export interface IIssuesLayout { kanban: IIssues; calendar: IIssues; spreadsheet: IIssues; - gantt: IIssues; + gantt_chart: IIssues; } export interface IIssueState { diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index eff9a13dbb6..f4de061e7d9 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -108,21 +108,21 @@ export const issueFilterVisibilityData: any = { }, }, others: { - layout: ["list", "kanban", "calendar", "spreadsheet", "gantt"], + layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"], filters: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], display_properties: { list: true, kanban: true, calendar: true, spreadsheet: true, - gantt: false, + gantt_chart: false, }, display_filters: { list: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], kanban: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], calendar: ["issue_type"], spreadsheet: ["issue_type"], - gantt: ["order_by", "issue_type", "sub_issue"], + gantt_chart: ["order_by", "issue_type", "sub_issue"], }, extra_options: { list: { @@ -141,7 +141,7 @@ export const issueFilterVisibilityData: any = { access: false, values: [], }, - gantt: { + gantt_chart: { access: true, values: ["sub_issue"], }, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 2b26a52f418..5dc063711aa 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -23,7 +23,7 @@ import { } from "./issue_data"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; -export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt"; +export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; export interface IIssueFilter { priority: string[] | undefined; @@ -758,7 +758,7 @@ class IssueFilterStore implements IIssueFilterStore { "type", "sub_issues", ]; - if (_layout === "gantt") + if (_layout === "gantt_chart") filteredParams = [ "priority", "state", From 3c9e62d308204864eed03af93955a85ebde34c93 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 22:28:42 +0530 Subject: [PATCH 016/102] chore: filter render UI and Functionality implementation --- .../issue-layouts/calendar/index.tsx | 6 + .../issue-layouts/display-filters/index.tsx | 16 +- .../filters-preview/assignees.tsx | 88 ++++++++++ .../filters-preview/created-by.tsx | 72 ++++++++ .../filters-preview/helpers/clear.tsx | 17 ++ .../filters-preview/helpers/content.tsx | 32 ++++ .../filters-preview/helpers/header.tsx | 12 ++ .../filters-preview/index copy.tsx | 92 ++++++++++ .../issue-layouts/filters-preview/index.tsx | 68 ++++++++ .../issue-layouts/filters-preview/labels.tsx | 75 +++++++++ .../filters-preview/priority.tsx | 79 +++++++++ .../filters-preview/start-date.tsx | 56 ++++++ .../filters-preview/state-group.tsx | 159 ++++++++++++++++++ .../issue-layouts/filters-preview/state.tsx | 68 ++++++++ .../filters-preview/target-date.tsx | 56 ++++++ .../issue-layouts/filters/index.tsx | 25 ++- web/components/issue-layouts/gantt/index.tsx | 6 + .../issue-layouts/helpers/dropdown.tsx | 2 +- .../issue-layouts/layout-selection.tsx | 27 ++- web/components/issue-layouts/list/index.tsx | 6 + web/components/issue-layouts/root.tsx | 33 +++- .../issue-layouts/spreadsheet/index.tsx | 6 + .../m-store/[workspace_slug]/my-issues.tsx | 6 + web/store/issue-views/Issues.ts | 81 ++++++--- web/store/issue-views/issue_data.ts | 59 ++++++- web/store/issue-views/issue_filters.ts | 58 ++++++- 26 files changed, 1129 insertions(+), 76 deletions(-) create mode 100644 web/components/issue-layouts/calendar/index.tsx create mode 100644 web/components/issue-layouts/filters-preview/assignees.tsx create mode 100644 web/components/issue-layouts/filters-preview/created-by.tsx create mode 100644 web/components/issue-layouts/filters-preview/helpers/clear.tsx create mode 100644 web/components/issue-layouts/filters-preview/helpers/content.tsx create mode 100644 web/components/issue-layouts/filters-preview/helpers/header.tsx create mode 100644 web/components/issue-layouts/filters-preview/index copy.tsx create mode 100644 web/components/issue-layouts/filters-preview/index.tsx create mode 100644 web/components/issue-layouts/filters-preview/labels.tsx create mode 100644 web/components/issue-layouts/filters-preview/priority.tsx create mode 100644 web/components/issue-layouts/filters-preview/start-date.tsx create mode 100644 web/components/issue-layouts/filters-preview/state-group.tsx create mode 100644 web/components/issue-layouts/filters-preview/state.tsx create mode 100644 web/components/issue-layouts/filters-preview/target-date.tsx create mode 100644 web/components/issue-layouts/gantt/index.tsx create mode 100644 web/components/issue-layouts/list/index.tsx create mode 100644 web/components/issue-layouts/spreadsheet/index.tsx diff --git a/web/components/issue-layouts/calendar/index.tsx b/web/components/issue-layouts/calendar/index.tsx new file mode 100644 index 00000000000..c3c4147f9b0 --- /dev/null +++ b/web/components/issue-layouts/calendar/index.tsx @@ -0,0 +1,6 @@ +import React from "react"; + +export const IssueCalendarViewRoot = () => { + console.log(); + return
IssueCalendarViewRoot
; +}; diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index d629327afb6..0c7ff05fd55 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -37,35 +37,33 @@ export const DisplayFiltersSelection = observer(() => { ?.extra_options?.[issueFilterStore?.issueLayout].access; return ( -
-
- Search container -
-
+
+
Search container
+
{/* display properties */} {handleDisplayPropertiesSectionVisibility && ( -
+
)} {/* group by */} {handleDisplayFilterSectionVisibility("group_by") && ( -
+
)} {/* order by */} {handleDisplayFilterSectionVisibility("order_by") && ( -
+
)} {/* issue type */} {handleDisplayFilterSectionVisibility("issue_type") && ( -
+
)} diff --git a/web/components/issue-layouts/filters-preview/assignees.tsx b/web/components/issue-layouts/filters-preview/assignees.tsx new file mode 100644 index 00000000000..80bfbc084b1 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/assignees.tsx @@ -0,0 +1,88 @@ +import React from "react"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const MemberIcons = ({ + display_name, + avatar, +}: { + display_name: string; + avatar: string | null; +}) => ( +
+ {avatar ? ( + {display_name + ) : ( +
+ {(display_name ?? "U")[0]} +
+ )} +
+); + +export const FilterAssignees = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "assignees", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.assignees != null && ( +
+
+ +
+
+ {issueFilterStore?.projectMembers && + issueFilterStore?.projectMembers.length > 0 && + issueFilterStore?.projectMembers.map( + (_member) => + issueFilterStore?.userFilters?.filters?.assignees != null && + issueFilterStore?.userFilters?.filters?.assignees.includes( + _member?.member?.id + ) && ( + + } + title={`${_member?.member?.display_name}`} + onClick={() => handleFilter("assignees", _member?.member?.id)} + className="border border-custom-border-100 bg-custom-background-100" + /> + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/created-by.tsx b/web/components/issue-layouts/filters-preview/created-by.tsx new file mode 100644 index 00000000000..c69234b7c9d --- /dev/null +++ b/web/components/issue-layouts/filters-preview/created-by.tsx @@ -0,0 +1,72 @@ +import React from "react"; +// components +import { MemberIcons } from "./assignees"; +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterCreatedBy = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "created_by", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.created_by != null && ( +
+
+ +
+ +
+ {issueFilterStore?.projectMembers && + issueFilterStore?.projectMembers.length > 0 && + issueFilterStore?.projectMembers.map( + (_member) => + issueFilterStore?.userFilters?.filters?.created_by != null && + issueFilterStore?.userFilters?.filters?.created_by.includes( + _member?.member?.id + ) && ( + + } + onClick={() => handleFilter("created_by", _member?.member?.id)} + className="border border-custom-border-100 bg-custom-background-100" + /> + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/helpers/clear.tsx b/web/components/issue-layouts/filters-preview/helpers/clear.tsx new file mode 100644 index 00000000000..d2cc57a3781 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/helpers/clear.tsx @@ -0,0 +1,17 @@ +// lucide icons +import { X } from "lucide-react"; + +interface IFilterPreviewClear { + onClick?: () => void; +} + +export const FilterPreviewClear = ({ onClick }: IFilterPreviewClear) => ( +
{ + if (onClick) onClick(); + }} + > + +
+); diff --git a/web/components/issue-layouts/filters-preview/helpers/content.tsx b/web/components/issue-layouts/filters-preview/helpers/content.tsx new file mode 100644 index 00000000000..dc56bc391b8 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/helpers/content.tsx @@ -0,0 +1,32 @@ +import { FilterPreviewClear } from "./clear"; + +interface IFilterPreviewContent { + icon?: React.ReactNode; + title?: string; + onClick?: () => void; + className?: string; + style?: any; +} + +export const FilterPreviewContent = ({ + icon, + title, + onClick, + className, + style, +}: IFilterPreviewContent) => ( +
+
{icon}
+
{title}
+
+ { + if (onClick) onClick(); + }} + /> +
+
+); diff --git a/web/components/issue-layouts/filters-preview/helpers/header.tsx b/web/components/issue-layouts/filters-preview/helpers/header.tsx new file mode 100644 index 00000000000..5fc9c9caae7 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/helpers/header.tsx @@ -0,0 +1,12 @@ +interface IFilterPreviewHeader { + title: string; +} + +export const FilterPreviewHeader = ({ title }: IFilterPreviewHeader) => { + console.log(); + return ( +
+
{title}
+
+ ); +}; diff --git a/web/components/issue-layouts/filters-preview/index copy.tsx b/web/components/issue-layouts/filters-preview/index copy.tsx new file mode 100644 index 00000000000..d83f3f725b9 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/index copy.tsx @@ -0,0 +1,92 @@ +import React from "react"; +// components +import { FilterPriority } from "./priority"; +import { FilterState } from "./state"; +import { FilterStateGroup } from "./state-group"; +import { FilterAssignees } from "./assignees"; +import { FilterCreatedBy } from "./created-by"; +import { FilterLabels } from "./labels"; +import { FilterStartDate } from "./start-date"; +import { FilterTargetDate } from "./target-date"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// default data +import { issueFilterVisibilityData } from "store/issue-views/issue_data"; + +export const FilterSelection = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilterSectionVisibility = (section_key: string) => + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); + + return ( +
+
Search container
+
+ {/* priority */} + {handleFilterSectionVisibility("priority") && ( +
+ +
+ )} + + {/* state group */} + {handleFilterSectionVisibility("state_group") && ( +
+ +
+ )} + + {/* state */} + {handleFilterSectionVisibility("state") && ( +
+ +
+ )} + + {/* assignees */} + {handleFilterSectionVisibility("assignees") && ( +
+ +
+ )} + + {/* created_by */} + {handleFilterSectionVisibility("created_by") && ( +
+ +
+ )} + + {/* labels */} + {handleFilterSectionVisibility("labels") && ( +
+ +
+ )} + + {/* start_date */} + {handleFilterSectionVisibility("start_date") && ( +
+ +
+ )} + + {/* due_date */} + {handleFilterSectionVisibility("due_date") && ( +
+ +
+ )} +
+
+ ); +}); diff --git a/web/components/issue-layouts/filters-preview/index.tsx b/web/components/issue-layouts/filters-preview/index.tsx new file mode 100644 index 00000000000..fd202e11b9f --- /dev/null +++ b/web/components/issue-layouts/filters-preview/index.tsx @@ -0,0 +1,68 @@ +import React from "react"; +// components +import { FilterPriority } from "./priority"; +import { FilterState } from "./state"; +import { FilterStateGroup } from "./state-group"; +import { FilterAssignees } from "./assignees"; +import { FilterCreatedBy } from "./created-by"; +import { FilterLabels } from "./labels"; +import { FilterStartDate } from "./start-date"; +import { FilterTargetDate } from "./target-date"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// default data +import { issueFilterVisibilityData } from "store/issue-views/issue_data"; + +export const FilterPreview = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilterSectionVisibility = (section_key: string) => + issueFilterStore?.issueView && + issueFilterStore?.issueLayout && + issueFilterVisibilityData[ + issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" + ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); + + const validateFiltersAvailability = + issueFilterStore?.userFilters?.filters != null && + Object.keys(issueFilterStore?.userFilters?.filters).length > 0 && + Object.keys(issueFilterStore?.userFilters?.filters) + .map((key) => issueFilterStore?.userFilters?.filters?.[key]?.length) + .filter((v) => v != undefined || v != null).length > 0; + + return ( + <> + {validateFiltersAvailability && ( +
+ {/* priority */} + {handleFilterSectionVisibility("priority") && } + + {/* state group */} + {handleFilterSectionVisibility("state_group") && } + + {/* state */} + {handleFilterSectionVisibility("state") && } + + {/* assignees */} + {handleFilterSectionVisibility("assignees") && } + + {/* created_by */} + {handleFilterSectionVisibility("created_by") && } + + {/* labels */} + {handleFilterSectionVisibility("labels") && } + + {/* start_date */} + {handleFilterSectionVisibility("start_date") && } + + {/* due_date */} + {handleFilterSectionVisibility("due_date") && } +
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/labels.tsx b/web/components/issue-layouts/filters-preview/labels.tsx new file mode 100644 index 00000000000..dbe825a7c3f --- /dev/null +++ b/web/components/issue-layouts/filters-preview/labels.tsx @@ -0,0 +1,75 @@ +import React from "react"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const LabelIcons = ({ color }: { color: string }) => ( +
+
+
+); + +export const FilterLabels = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const stateStyles = (color: any) => ({ color: color, backgroundColor: `${color}20` }); + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "labels", null); + }; + + const handleLabels = + issueFilterStore.issueView && issueFilterStore.issueView === "my_issues" + ? issueFilterStore?.workspaceLabels + : issueFilterStore?.projectLabels; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.labels != null && ( +
+
+ +
+ +
+ {handleLabels && + handleLabels.length > 0 && + handleLabels.map( + (_label) => + issueFilterStore?.userFilters?.filters?.labels != null && + issueFilterStore?.userFilters?.filters?.labels.includes(_label?.id) && ( + handleFilter("labels", _label?.id)} + icon={} + title={_label.name} + style={stateStyles(_label.color)} + /> + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/priority.tsx b/web/components/issue-layouts/filters-preview/priority.tsx new file mode 100644 index 00000000000..44780d81f03 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/priority.tsx @@ -0,0 +1,79 @@ +import React from "react"; +// lucide icons +import { AlertCircle, SignalHigh, SignalMedium, SignalLow, Ban } from "lucide-react"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +const PriorityIcons = ({ priority }: { priority: string }) => { + if (priority === "urgent") return ; + if (priority === "high") return ; + if (priority === "medium") return ; + if (priority === "low") return ; + return ; +}; + +const classNamesStyling = (priority: string) => { + if (priority == "urgent") return "bg-red-500/20 text-red-500"; + if (priority == "high") return "bg-orange-500/20 text-orange-500 !-pt-[30px]"; + if (priority == "medium") return "bg-orange-500/20 text-orange-500 -pt-2"; + if (priority == "low") return "bg-green-500/20 text-green-500 -pt-2"; + return "bg-gray-500/10 text-gray-500"; +}; + +export const FilterPriority = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "priority", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.priority != null && ( +
+
+ +
+
+ {issueFilterStore?.issueRenderFilters?.priority && + issueFilterStore?.issueRenderFilters?.priority.length > 0 && + issueFilterStore?.issueRenderFilters?.priority.map( + (_priority) => + issueFilterStore?.userFilters?.filters?.priority != null && + issueFilterStore?.userFilters?.filters?.priority.includes(_priority?.key) && ( + } + title={_priority.title} + className={classNamesStyling(_priority?.key)} + onClick={() => handleFilter("priority", _priority?.key)} + /> + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/start-date.tsx b/web/components/issue-layouts/filters-preview/start-date.tsx new file mode 100644 index 00000000000..7967917621d --- /dev/null +++ b/web/components/issue-layouts/filters-preview/start-date.tsx @@ -0,0 +1,56 @@ +import React from "react"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterStartDate = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "start_date", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.start_date != null && ( +
+
+ +
+ +
+ {issueFilterStore?.issueRenderFilters?.start_date && + issueFilterStore?.issueRenderFilters?.start_date.length > 0 && + issueFilterStore?.issueRenderFilters?.start_date.map((_startDate) => ( + handleFilter("start_date", _startDate?.key)} + /> + ))} +
+
+ +
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/state-group.tsx b/web/components/issue-layouts/filters-preview/state-group.tsx new file mode 100644 index 00000000000..e461f2eb033 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/state-group.tsx @@ -0,0 +1,159 @@ +import React from "react"; +import { + StateGroupBacklogIcon, + StateGroupCancelledIcon, + StateGroupCompletedIcon, + StateGroupStartedIcon, + StateGroupUnstartedIcon, +} from "components/icons"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// constants +import { STATE_GROUP_COLORS } from "constants/state"; + +export const StateGroupIcons = ({ + stateGroup, + color = null, +}: { + stateGroup: string; + color?: string | null; +}) => { + if (stateGroup === "cancelled") + return ( + + ); + if (stateGroup === "completed") + return ( + + ); + if (stateGroup === "started") + return ( + + ); + if (stateGroup === "unstarted") + return ( + + ); + if (stateGroup === "backlog") + return ( +
+ +
+ ); + return <>; +}; + +export const stateStyles = (stateGroup: string, color: any) => { + if (stateGroup === "cancelled") { + return { + color: color ? color : STATE_GROUP_COLORS[stateGroup], + backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`, + }; + } + if (stateGroup === "completed") { + return { + color: color ? color : STATE_GROUP_COLORS[stateGroup], + backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`, + }; + } + if (stateGroup === "started") { + return { + color: color ? color : STATE_GROUP_COLORS[stateGroup], + backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`, + }; + } + if (stateGroup === "unstarted") { + return { + color: color ? color : STATE_GROUP_COLORS[stateGroup], + backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`, + }; + } + if (stateGroup === "backlog") { + return { + color: color ? color : STATE_GROUP_COLORS[stateGroup], + backgroundColor: `${color ? color : STATE_GROUP_COLORS[stateGroup]}20`, + }; + } +}; + +export const FilterStateGroup = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "state_group", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.state_group != null && ( +
+
+ +
+
+ {issueFilterStore?.issueRenderFilters?.state_group && + issueFilterStore?.issueRenderFilters?.state_group.length > 0 && + issueFilterStore?.issueRenderFilters?.state_group.map( + (_stateGroup) => + issueFilterStore?.userFilters?.filters?.state_group != null && + issueFilterStore?.userFilters?.filters?.state_group.includes( + _stateGroup?.key + ) && ( + } + title={_stateGroup.title} + style={stateStyles(_stateGroup?.key, null)} + onClick={() => handleFilter("state_group", _stateGroup?.key)} + /> + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/state.tsx b/web/components/issue-layouts/filters-preview/state.tsx new file mode 100644 index 00000000000..3e408897471 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/state.tsx @@ -0,0 +1,68 @@ +import React from "react"; +// components +import { StateGroupIcons, stateStyles } from "./state-group"; +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// store default data +import { issueStateGroupKeys } from "store/issue-views/issue_data"; + +export const FilterState = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "state", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.state != null && ( +
+
+ +
+
+ {issueStateGroupKeys.map( + (_stateGroup) => + issueFilterStore?.projectStates && + issueFilterStore?.projectStates[_stateGroup] && + issueFilterStore?.projectStates[_stateGroup].length > 0 && + issueFilterStore?.projectStates[_stateGroup].map( + (_state: any) => + issueFilterStore?.userFilters?.filters?.state != null && + issueFilterStore?.userFilters?.filters?.state.includes(_state?.id) && ( + } + title={_state?.name} + style={stateStyles(_state?.group, _state?.color)} + onClick={() => handleFilter("state", _state?.id)} + /> + ) + ) + )} +
+ +
+
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters-preview/target-date.tsx b/web/components/issue-layouts/filters-preview/target-date.tsx new file mode 100644 index 00000000000..866f550b5e4 --- /dev/null +++ b/web/components/issue-layouts/filters-preview/target-date.tsx @@ -0,0 +1,56 @@ +import React from "react"; +// components +import { FilterPreviewHeader } from "./helpers/header"; +import { FilterPreviewContent } from "./helpers/content"; +import { FilterPreviewClear } from "./helpers/clear"; +// mobx react lite +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const FilterTargetDate = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; + + const handleFilter = (key: string, value: string) => { + let _value = + issueFilterStore?.userFilters?.filters?.[key] != null && + issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value); + _value = _value && _value.length > 0 ? _value : null; + + issueFilterStore.handleUserFilter("filters", key, _value); + }; + + const clearFilter = () => { + issueFilterStore.handleUserFilter("filters", "target_date", null); + }; + + return ( + <> + {issueFilterStore?.userFilters?.filters?.target_date != null && ( +
+
+ +
+ +
+ {issueFilterStore?.issueRenderFilters?.due_date && + issueFilterStore?.issueRenderFilters?.due_date.length > 0 && + issueFilterStore?.issueRenderFilters?.due_date.map((_targetDate) => ( + handleFilter("target_date", _targetDate?.key)} + /> + ))} +
+
+ +
+
+ )} + + ); +}); diff --git a/web/components/issue-layouts/filters/index.tsx b/web/components/issue-layouts/filters/index.tsx index 2ad446eb316..d83f3f725b9 100644 --- a/web/components/issue-layouts/filters/index.tsx +++ b/web/components/issue-layouts/filters/index.tsx @@ -22,61 +22,60 @@ export const FilterSelection = observer(() => { const handleFilterSectionVisibility = (section_key: string) => issueFilterStore?.issueView && + issueFilterStore?.issueLayout && issueFilterVisibilityData[ issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ].filters.includes(section_key); + ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); return ( -
-
- Search container -
-
+
+
Search container
+
{/* priority */} {handleFilterSectionVisibility("priority") && ( -
+
)} {/* state group */} {handleFilterSectionVisibility("state_group") && ( -
+
)} {/* state */} {handleFilterSectionVisibility("state") && ( -
+
)} {/* assignees */} {handleFilterSectionVisibility("assignees") && ( -
+
)} {/* created_by */} {handleFilterSectionVisibility("created_by") && ( -
+
)} {/* labels */} {handleFilterSectionVisibility("labels") && ( -
+
)} {/* start_date */} {handleFilterSectionVisibility("start_date") && ( -
+
)} diff --git a/web/components/issue-layouts/gantt/index.tsx b/web/components/issue-layouts/gantt/index.tsx new file mode 100644 index 00000000000..b00e20632f6 --- /dev/null +++ b/web/components/issue-layouts/gantt/index.tsx @@ -0,0 +1,6 @@ +import React from "react"; + +export const IssueGanttViewRoot = () => { + console.log(); + return
IssueGanttViewRoot
; +}; diff --git a/web/components/issue-layouts/helpers/dropdown.tsx b/web/components/issue-layouts/helpers/dropdown.tsx index 66b7537e9b9..988f1050e0c 100644 --- a/web/components/issue-layouts/helpers/dropdown.tsx +++ b/web/components/issue-layouts/helpers/dropdown.tsx @@ -37,7 +37,7 @@ export const IssueDropdown = ({ children, title = "Dropdown" }: IIssueDropdown) leaveFrom="opacity-100 translate-y-0" leaveTo="opacity-0 translate-y-1" > - +
{children}
diff --git a/web/components/issue-layouts/layout-selection.tsx b/web/components/issue-layouts/layout-selection.tsx index f5f3d77fd27..87960824c5d 100644 --- a/web/components/issue-layouts/layout-selection.tsx +++ b/web/components/issue-layouts/layout-selection.tsx @@ -52,22 +52,21 @@ export const LayoutSelection = observer(() => { issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey); }; - console.log("----"); - console.log("my_user_id", issueFilterStore.myUserId); - console.log("workspace_id", issueFilterStore.workspaceId); - console.log("project_id", issueFilterStore.projectId); - console.log("module_id", issueFilterStore.moduleId); - console.log("cycle_id", issueFilterStore.cycleId); - console.log("view_id", issueFilterStore.viewId); + // console.log("----"); + // console.log("my_user_id", issueFilterStore.myUserId); + // console.log("workspace_id", issueFilterStore.workspaceId); + // console.log("project_id", issueFilterStore.projectId); + // console.log("module_id", issueFilterStore.moduleId); + // console.log("cycle_id", issueFilterStore.cycleId); + // console.log("view_id", issueFilterStore.viewId); - console.log("issue_view", issueFilterStore.issueView); - console.log("issue_layout", issueFilterStore.issueLayout); + // console.log("issue_view", issueFilterStore.issueView); + // console.log("issue_layout", issueFilterStore.issueLayout); - console.log("user_filters", issueFilterStore.userFilters); - console.log("issues", issueStore.issues); - console.log("issues", issueStore.getIssues); - - console.log("----"); + // console.log("user_filters", issueFilterStore.userFilters); + // console.log("issues", issueStore.issues); + // console.log("issues", issueStore.getIssues); + // console.log("----"); return (
diff --git a/web/components/issue-layouts/list/index.tsx b/web/components/issue-layouts/list/index.tsx new file mode 100644 index 00000000000..826f1b8843e --- /dev/null +++ b/web/components/issue-layouts/list/index.tsx @@ -0,0 +1,6 @@ +import React from "react"; + +export const IssueListViewRoot = () => { + console.log(); + return
IssueListViewRoot
; +}; diff --git a/web/components/issue-layouts/root.tsx b/web/components/issue-layouts/root.tsx index 660f398f295..897c4712130 100644 --- a/web/components/issue-layouts/root.tsx +++ b/web/components/issue-layouts/root.tsx @@ -1,17 +1,30 @@ import React from "react"; // components -import { IssueKanBanViewRoot } from "./kanban"; import { LayoutSelection } from "./layout-selection"; import { IssueDropdown } from "./helpers/dropdown"; import { FilterSelection } from "./filters"; import { DisplayFiltersSelection } from "./display-filters"; -export const IssuesRoot = () => { - console.log("issue root"); +import { FilterPreview } from "./filters-preview"; + +import { IssueListViewRoot } from "./list"; +import { IssueKanBanViewRoot } from "./kanban"; +import { IssueCalendarViewRoot } from "./calendar"; +import { IssueSpreadsheetViewRoot } from "./spreadsheet"; +import { IssueGanttViewRoot } from "./gantt"; +// mobx +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; + +export const IssuesRoot = observer(() => { + const store: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore } = store; return (
-
+
Filter Header
@@ -27,10 +40,16 @@ export const IssuesRoot = () => {
-
Hello
+
+ +
- + {issueFilterStore?.issueLayout === "list" && } + {issueFilterStore?.issueLayout === "kanban" && } + {issueFilterStore?.issueLayout === "calendar" && } + {issueFilterStore?.issueLayout === "spreadsheet" && } + {issueFilterStore?.issueLayout === "gantt_chart" && }
); -}; +}); diff --git a/web/components/issue-layouts/spreadsheet/index.tsx b/web/components/issue-layouts/spreadsheet/index.tsx new file mode 100644 index 00000000000..02313458dab --- /dev/null +++ b/web/components/issue-layouts/spreadsheet/index.tsx @@ -0,0 +1,6 @@ +import React from "react"; + +export const IssueSpreadsheetViewRoot = () => { + console.log(); + return
IssueSpreadsheetViewRoot
; +}; diff --git a/web/pages/m-store/[workspace_slug]/my-issues.tsx b/web/pages/m-store/[workspace_slug]/my-issues.tsx index 766381fd268..a5b24444681 100644 --- a/web/pages/m-store/[workspace_slug]/my-issues.tsx +++ b/web/pages/m-store/[workspace_slug]/my-issues.tsx @@ -1,6 +1,8 @@ import React from "react"; // next imports import { useRouter } from "next/router"; +// swr +// import useSWR from "swr"; // components import { IssuesRoot } from "components/issue-layouts/root"; // mobx store @@ -14,6 +16,10 @@ const KanBanViewRoot = () => { const store: RootStore = useMobxStore(); const { issueView: issueViewStore } = store; + // useSWR(`REVALIDATE_MY_ISSUES`, async () => { + // if (workspace_slug) await issueViewStore.getMyIssuesAsync(workspace_slug); + // }); + React.useEffect(() => { console.log("request init--->"); const init = async () => await issueViewStore.getMyIssuesAsync(workspace_slug); diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index f3b021f00f0..1eb29188db1 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -48,22 +48,29 @@ export interface IIssueViewStore { // computed getIssues: IIssues | null | undefined; // actions - getMyIssuesAsync: (workspaceId: string) => null | Promise; - getProjectIssuesAsync: (workspaceId: string, projectId: string) => null | Promise; + getMyIssuesAsync: (workspaceId: string, fetchFilterToggle: boolean) => null | Promise; + getProjectIssuesAsync: ( + workspaceId: string, + projectId: string, + fetchFilterToggle: boolean + ) => null | Promise; getIssuesForModulesAsync: ( workspaceId: string, projectId: string, - moduleId: string + moduleId: string, + fetchFilterToggle: boolean ) => null | Promise; getIssuesForCyclesAsync: ( workspaceId: string, projectId: string, - cycleId: string + cycleId: string, + fetchFilterToggle: boolean ) => null | Promise; getIssuesForViewsAsync: ( workspaceId: string, projectId: string, - viewId: string + viewId: string, + fetchFilterToggle: boolean ) => null | Promise; } @@ -144,12 +151,13 @@ class IssueViewStore implements IIssueViewStore { } // fetching my issues - getMyIssuesAsync = async (workspaceId: string) => { + getMyIssuesAsync = async (workspaceId: string, fetchFilterToggle: boolean = true) => { try { this.loader = true; this.error = null; - await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); + if (fetchFilterToggle) + await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, null, @@ -190,12 +198,17 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues - getProjectIssuesAsync = async (workspaceId: string, projectId: string) => { + getProjectIssuesAsync = async ( + workspaceId: string, + projectId: string, + fetchFilterToggle: boolean = true + ) => { try { this.loader = true; this.error = null; - await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); + if (fetchFilterToggle) + await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -246,16 +259,22 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for modules - getIssuesForModulesAsync = async (workspaceId: string, projectId: string, moduleId: string) => { + getIssuesForModulesAsync = async ( + workspaceId: string, + projectId: string, + moduleId: string, + fetchFilterToggle: boolean = true + ) => { try { this.loader = true; this.error = null; - await this.rootStore.issueFilters.getProjectIssueModuleFilters( - workspaceId, - projectId, - moduleId - ); + if (fetchFilterToggle) + await this.rootStore.issueFilters.getProjectIssueModuleFilters( + workspaceId, + projectId, + moduleId + ); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -310,16 +329,22 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for cycles - getIssuesForCyclesAsync = async (workspaceId: string, projectId: string, cycleId: string) => { + getIssuesForCyclesAsync = async ( + workspaceId: string, + projectId: string, + cycleId: string, + fetchFilterToggle: boolean = true + ) => { try { this.loader = true; this.error = null; - await this.rootStore.issueFilters.getProjectIssueCyclesFilters( - workspaceId, - projectId, - cycleId - ); + if (fetchFilterToggle) + await this.rootStore.issueFilters.getProjectIssueCyclesFilters( + workspaceId, + projectId, + cycleId + ); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -374,12 +399,22 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues for views - getIssuesForViewsAsync = async (workspaceId: string, projectId: string, viewId: string) => { + getIssuesForViewsAsync = async ( + workspaceId: string, + projectId: string, + viewId: string, + fetchFilterToggle: boolean = true + ) => { try { this.loader = true; this.error = null; - await this.rootStore.issueFilters.getProjectIssueViewsFilters(workspaceId, projectId, viewId); + if (fetchFilterToggle) + await this.rootStore.issueFilters.getProjectIssueViewsFilters( + workspaceId, + projectId, + viewId + ); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index f4de061e7d9..7c870e5b5d9 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -1,3 +1,5 @@ +import { renderDateFormat } from "helpers/date-time.helper"; + export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; export const issueStateGroupKeys: TStateGroup[] = [ "backlog", @@ -87,7 +89,10 @@ export const extraProperties: { key: string; title: string }[] = [ export const issueFilterVisibilityData: any = { my_issues: { layout: ["list", "kanban"], - filters: ["priority", "state_group", "labels", "start_date", "due_date"], + filters: { + list: ["priority", "state_group", "labels", "start_date", "due_date"], + kanban: ["priority", "state_group", "labels", "start_date", "due_date"], + }, display_properties: { list: true, kanban: true, @@ -109,7 +114,29 @@ export const issueFilterVisibilityData: any = { }, others: { layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"], - filters: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], + filters: { + list: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], + kanban: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], + calendar: ["priority", "state", "assignees", "created_by", "labels"], + spreadsheet: [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "due_date", + ], + gantt_chart: [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "due_date", + ], + }, display_properties: { list: true, kanban: true, @@ -148,3 +175,31 @@ export const issueFilterVisibilityData: any = { }, }, }; + +export const handleIssueParamsDateFormat = ( + key: string, + start_date: any | null, + target_date: any | null +) => { + if (key === "last_week") + return `${renderDateFormat( + new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000) + )};after,${renderDateFormat(new Date())};before`; + + if (key === "2_weeks_from_now") + return `${renderDateFormat(new Date())};after, + ${renderDateFormat(new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000))};before`; + + if (key === "1_month_from_now") + return `${renderDateFormat(new Date())};after,${renderDateFormat( + new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()) + )};before`; + + if (key === "2_months_from_now") + return `${renderDateFormat(new Date())};after,${renderDateFormat( + new Date(new Date().getFullYear(), new Date().getMonth() + 2, new Date().getDate()) + )};before`; + + if (key === "custom" && start_date && target_date) + return `${renderDateFormat(start_date)};after,${renderDateFormat(target_date)};before`; +}; diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 5dc063711aa..dda2f0dac59 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -1,4 +1,4 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; +import { observable, action, computed, makeObservable, runInAction, autorun } from "mobx"; // types import { RootStore } from "../root"; // services @@ -24,6 +24,22 @@ import { export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; +export type TIssueParams = + | "priority" + | "state_group" + | "state" + | "assignees" + | "created_by" + | "labels" + | "start_date" + | "target_date" + | "group_by" + | "order_by" + | "type" + | "sub_issue" + | "show_empty_groups" + | "calendar_date_range" + | "start_target_date"; export interface IIssueFilter { priority: string[] | undefined; @@ -649,6 +665,32 @@ class IssueFilterStore implements IIssueFilterStore { ); } } + + if (this.issueView === "my_issues") + this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + if (this.issueView === "issues") + this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + if (this.issueView === "modules" && this.moduleId) + this.rootStore?.issueView?.getIssuesForModulesAsync( + this.workspaceId, + this.projectId, + this.moduleId, + false + ); + if (this.issueView === "cycles" && this.cycleId) + this.rootStore?.issueView?.getIssuesForCyclesAsync( + this.workspaceId, + this.projectId, + this.cycleId, + false + ); + if (this.issueView === "views" && this.viewId) + this.rootStore?.issueView?.getIssuesForViewsAsync( + this.workspaceId, + this.projectId, + this.viewId, + false + ); }; computedFilter = (filters: any, filteredParams: any) => { @@ -699,8 +741,11 @@ class IssueFilterStore implements IIssueFilterStore { }; // start date and target date we have to construct the format here + // in calendar view calendar_date_range send as target_date + // in spreadsheet sub issue is false for sure + // in gantt start_target_date is true for sure - let filteredParams: any = {}; + let filteredParams: TIssueParams[] = []; if (_layout === "list") filteredParams = [ "priority", @@ -727,10 +772,11 @@ class IssueFilterStore implements IIssueFilterStore { "labels", "start_date", "target_date", - "type", "group_by", "order_by", + "type", "sub_issue", + "show_empty_groups", ]; if (_layout === "calendar") filteredParams = [ @@ -756,7 +802,7 @@ class IssueFilterStore implements IIssueFilterStore { "start_date", "target_date", "type", - "sub_issues", + "sub_issue", ]; if (_layout === "gantt_chart") filteredParams = [ @@ -769,14 +815,12 @@ class IssueFilterStore implements IIssueFilterStore { "target_date", "order_by", "type", - "sub_issue_id", + "sub_issue", "start_target_date", ]; filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); - // remove few attributes from the object when we are in workspace issues - return filteredRouteParams; }; From fce6907465d196bdac3a3ecdc79dbb52f2c7a044 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Thu, 14 Sep 2023 22:34:44 +0530 Subject: [PATCH 017/102] chore: filter empty state handling in issue filter selection --- web/components/issue-layouts/filters/assignees.tsx | 3 ++- web/components/issue-layouts/filters/created-by.tsx | 3 ++- web/components/issue-layouts/filters/labels.tsx | 3 ++- web/components/issue-layouts/filters/priority.tsx | 3 ++- web/components/issue-layouts/filters/state-group.tsx | 3 ++- web/components/issue-layouts/filters/state.tsx | 3 ++- 6 files changed, 12 insertions(+), 6 deletions(-) diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index e591ea44fd6..422318ec140 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -33,12 +33,13 @@ export const FilterAssignees = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; diff --git a/web/components/issue-layouts/filters/created-by.tsx b/web/components/issue-layouts/filters/created-by.tsx index e9b34342fa4..e2353d32c63 100644 --- a/web/components/issue-layouts/filters/created-by.tsx +++ b/web/components/issue-layouts/filters/created-by.tsx @@ -16,12 +16,13 @@ export const FilterCreatedBy = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; diff --git a/web/components/issue-layouts/filters/labels.tsx b/web/components/issue-layouts/filters/labels.tsx index 79a82ddd218..4c42e8af9f9 100644 --- a/web/components/issue-layouts/filters/labels.tsx +++ b/web/components/issue-layouts/filters/labels.tsx @@ -21,12 +21,13 @@ export const FilterLabels = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; diff --git a/web/components/issue-layouts/filters/priority.tsx b/web/components/issue-layouts/filters/priority.tsx index 048e2246900..2bbcce8f704 100644 --- a/web/components/issue-layouts/filters/priority.tsx +++ b/web/components/issue-layouts/filters/priority.tsx @@ -57,12 +57,13 @@ export const FilterPriority = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; diff --git a/web/components/issue-layouts/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx index 1598734a7ba..e9ea5c6fa13 100644 --- a/web/components/issue-layouts/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -88,12 +88,13 @@ export const FilterStateGroup = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index 917fe2af7e9..bb56c2f7278 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -18,12 +18,13 @@ export const FilterState = observer(() => { const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - const _value = + let _value = issueFilterStore?.userFilters?.filters?.[key] != null ? issueFilterStore?.userFilters?.filters?.[key].includes(value) ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) : [...issueFilterStore?.userFilters?.filters?.[key], value] : [value]; + _value = _value && _value.length > 0 ? _value : null; issueFilterStore.handleUserFilter("filters", key, _value); }; From 9136258926ab5aa7deaee37ba779af09cf8ca8e0 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Fri, 15 Sep 2023 15:37:47 +0530 Subject: [PATCH 018/102] Implementing list view --- .../core/views/list-view/single-issue.tsx | 2 + .../issue-layouts/list/group-header.tsx | 41 +++ web/components/issue-layouts/list/index.ts | 4 + web/components/issue-layouts/list/index.tsx | 6 - web/components/issue-layouts/list/item.tsx | 234 ++++++++++++++++++ web/components/issue-layouts/list/list.tsx | 18 ++ web/components/issue-layouts/list/root.tsx | 44 ++++ web/components/issue-layouts/root.tsx | 5 +- web/store/issue-views/issue_data.ts | 2 +- web/store/issue-views/issue_filters.ts | 23 ++ web/store/theme.ts | 2 +- 11 files changed, 370 insertions(+), 11 deletions(-) create mode 100644 web/components/issue-layouts/list/group-header.tsx create mode 100644 web/components/issue-layouts/list/index.ts delete mode 100644 web/components/issue-layouts/list/index.tsx create mode 100644 web/components/issue-layouts/list/item.tsx create mode 100644 web/components/issue-layouts/list/list.tsx create mode 100644 web/components/issue-layouts/list/root.tsx diff --git a/web/components/core/views/list-view/single-issue.tsx b/web/components/core/views/list-view/single-issue.tsx index aad6af6c83d..62d35e73ffc 100644 --- a/web/components/core/views/list-view/single-issue.tsx +++ b/web/components/core/views/list-view/single-issue.tsx @@ -198,6 +198,8 @@ export const SingleListIssue: React.FC = ({ const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues; + console.log("properties", properties); + return ( <> = (props) => { + const { groupId, groupBy } = props; + + const { issueView: issueViewStore, issueFilters: issueFilterStore }: RootStore = useMobxStore(); + + return ( +
+ {groupBy === "state" && <>{issueFilterStore.getProjectStateById(groupId)?.name}} + {groupBy === "state_detail.group" && <>{groupId}} + {groupBy === "priority" && <>{groupId}} + {groupBy === "project" && ( + <>{issueFilterStore.workspaceProjects?.find((p) => (p.id = groupId))} + )} + {groupBy === "labels" && ( + <>{issueFilterStore.projectLabels?.find((p) => p.id === groupId)?.name || " None"} + )} + {groupBy === "assignees" && ( + <> + {issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member + ?.display_name || " None"} + + )} + {groupBy === "created_by" && ( + <> + {issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member + ?.display_name || " None"} + + )} +
+ ); +}; diff --git a/web/components/issue-layouts/list/index.ts b/web/components/issue-layouts/list/index.ts new file mode 100644 index 00000000000..a4e3561c619 --- /dev/null +++ b/web/components/issue-layouts/list/index.ts @@ -0,0 +1,4 @@ +export * from "./root"; +export * from "./list"; +export * from "./item"; +export * from "./group-header"; diff --git a/web/components/issue-layouts/list/index.tsx b/web/components/issue-layouts/list/index.tsx deleted file mode 100644 index 826f1b8843e..00000000000 --- a/web/components/issue-layouts/list/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import React from "react"; - -export const IssueListViewRoot = () => { - console.log(); - return
IssueListViewRoot
; -}; diff --git a/web/components/issue-layouts/list/item.tsx b/web/components/issue-layouts/list/item.tsx new file mode 100644 index 00000000000..accd79fd82d --- /dev/null +++ b/web/components/issue-layouts/list/item.tsx @@ -0,0 +1,234 @@ +import React, { FC, useState } from "react"; +import { Tooltip, CustomMenu, ContextMenu } from "components/ui"; +// lib +import { useMobxStore } from "lib/mobx/store-provider"; +import { IIssue } from "types"; +import useUserAuth from "hooks/use-user-auth"; +// icons +import { + ClipboardDocumentCheckIcon, + LinkIcon, + PencilIcon, + TrashIcon, + XMarkIcon, + ArrowTopRightOnSquareIcon, + PaperClipIcon, +} from "@heroicons/react/24/outline"; +// components +import { LayerDiagonalIcon } from "components/icons"; +import { + ViewAssigneeSelect, + ViewDueDateSelect, + ViewEstimateSelect, + ViewIssueLabel, + ViewPrioritySelect, + ViewStartDateSelect, + ViewStateSelect, +} from "components/issues"; + +export interface IIssueListItem { + issue: IIssue; +} + +export const IssueListItem: FC = (props) => { + const { issue } = props; + // store + const { user: userStore, issueFilters: issueFilterStore } = useMobxStore(); + const displayProperties = issueFilterStore.userFilters?.display_properties; + console.log("userStore", userStore); + // context menu + const [contextMenu, setContextMenu] = useState(false); + const [contextMenuPosition, setContextMenuPosition] = useState(null); + const { user: userAuth } = useUserAuth(); + + // const isNotAllowed = + // userAuth?.isGuest || userAuth?.isViewer || disableUserActions || isArchivedIssues; + + return ( +
+ <> + + {/* {!isNotAllowed && ( + <> + + Edit issue + + + Make a copy... + + handleDeleteIssue(issue)}> + Delete issue + + + )} + + Copy issue link + + + + Open issue in new tab + + */} + +
{ + e.preventDefault(); + setContextMenu(true); + setContextMenuPosition(e); + }} + > +
+
+ {/* {properties.key && ( + + + {issue.project_detail?.identifier}-{issue.sequence_id} + + + )} */} + + + +
+
+ +
+ {displayProperties?.priority && ( + + )} + {displayProperties?.state && ( + + )} + {displayProperties?.start_date && issue.start_date && ( + + )} + {displayProperties?.due_date && issue.target_date && ( + + )} + {displayProperties?.labels && ( + + )} + {displayProperties?.assignee && ( + + )} + {displayProperties?.estimate && issue.estimate_point !== null && ( + + )} + {displayProperties?.sub_issue_count && issue.sub_issues_count > 0 && ( +
+ +
+ + {issue.sub_issues_count} +
+
+
+ )} + {displayProperties?.link && issue.link_count > 0 && ( +
+ +
+ + {issue.link_count} +
+
+
+ )} + {displayProperties?.attachment_count && issue.attachment_count > 0 && ( +
+ +
+ + {issue.attachment_count} +
+
+
+ )} + {/* {type && !isNotAllowed && ( + + +
+ + Edit issue +
+
+ {type !== "issue" && removeIssue && ( + +
+ + Remove from {type} +
+
+ )} + handleDeleteIssue(issue)}> +
+ + Delete issue +
+
+ +
+ + Copy issue link +
+
+
+ )} */} +
+
+ +
+ ); +}; diff --git a/web/components/issue-layouts/list/list.tsx b/web/components/issue-layouts/list/list.tsx new file mode 100644 index 00000000000..8ece7b1c8d9 --- /dev/null +++ b/web/components/issue-layouts/list/list.tsx @@ -0,0 +1,18 @@ +import React, { FC } from "react"; +import { IIssue } from "types"; +import { IssueListItem } from "./item"; + +export interface IIssueListView { + issues: IIssue[]; +} + +export const IssueListView: FC = (props) => { + const { issues = [] } = props; + return ( +
+ {issues.map((issue) => ( + + ))} +
+ ); +}; diff --git a/web/components/issue-layouts/list/root.tsx b/web/components/issue-layouts/list/root.tsx new file mode 100644 index 00000000000..6b136cf40c4 --- /dev/null +++ b/web/components/issue-layouts/list/root.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { Disclosure } from "@headlessui/react"; +import { observer } from "mobx-react-lite"; +// mobx store +import { useMobxStore } from "lib/mobx/store-provider"; +import { RootStore } from "store/root"; +// components +import { IssueListView } from "./list"; +import { IssueListGroupHeader } from "./group-header"; + +export const IssueListViewRoot = observer(() => { + const { issueView: issueViewStore, issueFilters: issueFilterStore }: RootStore = useMobxStore(); + console.log("issueViewStore", issueViewStore); + console.log("userFilters", issueFilterStore.userFilters); + console.log("issueFilterStore", issueFilterStore); + + return ( +
+ {issueViewStore.loader || issueViewStore?.getIssues === null ? ( +
Loading...
+ ) : ( + <> + {Object.keys(issueViewStore?.getIssues).map((groupId) => ( + + {({ open }) => ( + <> + + + + + + + + )} + + ))} + + )} +
+ ); +}); diff --git a/web/components/issue-layouts/root.tsx b/web/components/issue-layouts/root.tsx index 897c4712130..92cbf54937a 100644 --- a/web/components/issue-layouts/root.tsx +++ b/web/components/issue-layouts/root.tsx @@ -7,7 +7,7 @@ import { DisplayFiltersSelection } from "./display-filters"; import { FilterPreview } from "./filters-preview"; -import { IssueListViewRoot } from "./list"; +import { IssueListViewRoot } from "./list/root"; import { IssueKanBanViewRoot } from "./kanban"; import { IssueCalendarViewRoot } from "./calendar"; import { IssueSpreadsheetViewRoot } from "./spreadsheet"; @@ -19,8 +19,7 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; export const IssuesRoot = observer(() => { - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilters: issueFilterStore }: RootStore = useMobxStore(); return (
diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index 7c870e5b5d9..d6d12743a34 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -45,7 +45,7 @@ export const displayPropertyGroupBy: { key: string; title: string }[] = [ { key: "state", title: "States" }, { key: "state_detail.group", title: "State Groups" }, { key: "priority", title: "Priority" }, - { key: "Project", title: "Project" }, // required this on my issues + { key: "project", title: "Project" }, // required this on my issues { key: "labels", title: "Labels" }, { key: "assignees", title: "Assignees" }, { key: "created_by", title: "Created By" }, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index dda2f0dac59..c0f5a255201 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -21,6 +21,7 @@ import { displayProperties, extraProperties, } from "./issue_data"; +import { IIssueState } from "./Issues"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; @@ -211,6 +212,8 @@ export interface IIssueFilterStore { viewId: string, data: any ) => Promise; + + getProjectStateById: (state_id: string) => any; } class IssueFilterStore implements IIssueFilterStore { @@ -281,6 +284,9 @@ class IssueFilterStore implements IIssueFilterStore { userFilters: computed, // actions + + getProjectStateById: action, + getComputedFilters: action, handleUserFilter: action, @@ -345,6 +351,23 @@ class IssueFilterStore implements IIssueFilterStore { this.projectId ]?.states; } + + getProjectStateById = (stateId: string) => { + if (!this.workspaceId || !this.projectId) return null; + const states = + this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ + this.projectId + ]?.states; + + let stateInfo: any = null; + Object.keys(states).forEach((stateGroupName) => { + if (states[stateGroupName].find((state: any) => state.id === stateId)) { + stateInfo = states[stateGroupName].find((state: any) => state.id === stateId); + } + }); + return stateInfo; + }; + get projectLabels() { if (!this.workspaceId || !this.projectId) return null; return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ diff --git a/web/store/theme.ts b/web/store/theme.ts index ecd02ec97be..c4b52c6e534 100644 --- a/web/store/theme.ts +++ b/web/store/theme.ts @@ -40,7 +40,7 @@ class ThemeStore { setTheme = async (_theme: { theme: ICurrentUserSettings }) => { try { - const currentTheme: string = _theme.theme.theme.toString(); + const currentTheme: string = _theme?.theme?.theme?.toString(); // updating the local storage theme value localStorage.setItem("theme", currentTheme); From 7b04adf03a81143f7f93db5452bb4afda004f088 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Fri, 15 Sep 2023 15:37:54 +0530 Subject: [PATCH 019/102] chore: kanban drag drop logic --- web/.prettierrc | 2 +- .../issue-layouts/filters/index.tsx | 6 +- .../issue-layouts/kanban/content.tsx | 14 +- .../issue-layouts/kanban/header.tsx | 14 +- web/components/issue-layouts/kanban/index.tsx | 10 +- .../[project_slug]/issues.tsx | 3 +- web/services/issues.service.ts | 140 ++------ web/store/issue-views/Issue_details.ts | 29 -- web/store/issue-views/Issues.ts | 93 ++--- web/store/issue-views/issue_data.ts | 2 +- web/store/issue-views/issue_detail.ts | 175 ++++++++++ web/store/issue-views/issue_filters.ts | 326 +++++------------- web/store/issue-views/kanban-view.ts | 185 ++++++++++ web/store/root.ts | 6 + 14 files changed, 530 insertions(+), 475 deletions(-) delete mode 100644 web/store/issue-views/Issue_details.ts create mode 100644 web/store/issue-views/issue_detail.ts create mode 100644 web/store/issue-views/kanban-view.ts diff --git a/web/.prettierrc b/web/.prettierrc index d5cb26e5447..87d988f1b26 100644 --- a/web/.prettierrc +++ b/web/.prettierrc @@ -1,5 +1,5 @@ { - "printWidth": 100, + "printWidth": 120, "tabWidth": 2, "trailingComma": "es5" } diff --git a/web/components/issue-layouts/filters/index.tsx b/web/components/issue-layouts/filters/index.tsx index d83f3f725b9..89fbcdd91eb 100644 --- a/web/components/issue-layouts/filters/index.tsx +++ b/web/components/issue-layouts/filters/index.tsx @@ -23,9 +23,9 @@ export const FilterSelection = observer(() => { const handleFilterSectionVisibility = (section_key: string) => issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"]?.filters?.[ + issueFilterStore?.issueLayout + ]?.includes(section_key); return (
diff --git a/web/components/issue-layouts/kanban/content.tsx b/web/components/issue-layouts/kanban/content.tsx index 6f297fcf686..ad83c29602e 100644 --- a/web/components/issue-layouts/kanban/content.tsx +++ b/web/components/issue-layouts/kanban/content.tsx @@ -14,11 +14,7 @@ export const IssueContent = ({ columnId, issues }: IssueContentProps) => { {issues && issues.length > 0 ? ( <> {issues.map((issue: any, index: any) => ( - + {(provided: any, snapshot: any) => (
{ >
-
- ONE-{issue.sequence_id}-{issue.sort_order} -
+
ONE-{issue.sequence_id}
{issue.name}
Footer
diff --git a/web/components/issue-layouts/kanban/header.tsx b/web/components/issue-layouts/kanban/header.tsx index 8c04dc20d31..c9a308a276b 100644 --- a/web/components/issue-layouts/kanban/header.tsx +++ b/web/components/issue-layouts/kanban/header.tsx @@ -4,18 +4,14 @@ import { Plus } from "lucide-react"; export const IssueHeader = () => (
{/* default layout */} -
- I -
-
Kanban Issue Heading
-
- 0 -
+
I
+
Kanban Issue Heading
+
0
-
+
M
-
+
diff --git a/web/components/issue-layouts/kanban/index.tsx b/web/components/issue-layouts/kanban/index.tsx index b517484dc8e..33b72c4b43a 100644 --- a/web/components/issue-layouts/kanban/index.tsx +++ b/web/components/issue-layouts/kanban/index.tsx @@ -11,8 +11,7 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; export const IssueKanBanViewRoot = observer(() => { - const store: RootStore = useMobxStore(); - const { issueView: issueViewStore } = store; + const { issueView: issueViewStore, issueKanBanView: issueKanBanViewStore }: RootStore = useMobxStore(); const onDragEnd = (result: any) => { if (!result) return; @@ -25,7 +24,7 @@ export const IssueKanBanViewRoot = observer(() => { ) return; - console.log("result", result); + issueKanBanViewStore?.handleDragDrop(result.source, result.destination); }; return ( @@ -38,10 +37,7 @@ export const IssueKanBanViewRoot = observer(() => {
{Object.keys(issueViewStore?.getIssues).map((_issueStateKey: any) => ( -
+
diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx index c6319bcaae5..c068f14f66a 100644 --- a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx @@ -19,8 +19,7 @@ const KanBanViewRoot = () => { React.useEffect(() => { console.log("request init--->"); - const init = async () => - await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); + const init = async () => await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); if (workspace_slug && project_slug) init(); console.log("request completed--->"); }, [workspace_slug, project_slug, issueViewStore]); diff --git a/web/services/issues.service.ts b/web/services/issues.service.ts index a62d26d3c05..e5ec55784e0 100644 --- a/web/services/issues.service.ts +++ b/web/services/issues.service.ts @@ -63,14 +63,8 @@ export class ProjectIssuesServices extends APIService { }); } - async getIssueActivities( - workspaceSlug: string, - projectId: string, - issueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/history/` - ) + async getIssueActivities(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/history/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -78,9 +72,7 @@ export class ProjectIssuesServices extends APIService { } async getIssueComments(workspaceSlug: string, projectId: string, issueId: string): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/` - ) + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -104,10 +96,7 @@ export class ProjectIssuesServices extends APIService { }, user: ICurrentUserResponse | undefined ) { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/`, data) .then((response) => { trackEventServices.trackIssueMovedToCycleOrModuleEvent( { @@ -129,12 +118,7 @@ export class ProjectIssuesServices extends APIService { }); } - async removeIssueFromCycle( - workspaceSlug: string, - projectId: string, - cycleId: string, - bridgeId: string - ) { + async removeIssueFromCycle(workspaceSlug: string, projectId: string, cycleId: string, bridgeId: string) { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/cycles/${cycleId}/cycle-issues/${bridgeId}/` ) @@ -156,10 +140,7 @@ export class ProjectIssuesServices extends APIService { }>; } ) { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-relation/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-relation/`, data) .then((response) => { trackEventServices.trackIssueRelationEvent(response.data, "ISSUE_RELATION_CREATE", user); return response?.data; @@ -189,10 +170,7 @@ export class ProjectIssuesServices extends APIService { } async createIssueProperties(workspaceSlug: string, projectId: string, data: any): Promise { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -206,8 +184,7 @@ export class ProjectIssuesServices extends APIService { data: any ): Promise { return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` + - `${issuePropertyId}/`, + `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` + `${issuePropertyId}/`, data ) .then((response) => response?.data) @@ -223,10 +200,7 @@ export class ProjectIssuesServices extends APIService { data: Partial, user: ICurrentUserResponse | undefined ): Promise { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/comments/`, data) .then((response) => { trackEventServices.trackIssueCommentEvent(response.data, "ISSUE_COMMENT_CREATE", user); return response?.data; @@ -335,10 +309,7 @@ export class ProjectIssuesServices extends APIService { data: any, user: ICurrentUserResponse | undefined ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`, - data - ) + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`, data) .then((response) => { trackEventServices.trackIssueLabelEvent( { @@ -367,9 +338,7 @@ export class ProjectIssuesServices extends APIService { labelId: string, user: ICurrentUserResponse | undefined ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/` - ) + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-labels/${labelId}/`) .then((response) => { trackEventServices.trackIssueLabelEvent( { @@ -393,10 +362,7 @@ export class ProjectIssuesServices extends APIService { data: Partial, user: ICurrentUserResponse | undefined ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, - data - ) + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/`, data) .then((response) => { trackEventServices.trackIssueEvent(response.data, "ISSUE_UPDATE", user); return response?.data; @@ -428,10 +394,7 @@ export class ProjectIssuesServices extends APIService { data: any, user: ICurrentUserResponse | undefined ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, - data - ) + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/bulk-delete-issues/`, data) .then((response) => { trackEventServices.trackIssueBulkDeleteEvent(data, user); return response?.data; @@ -441,14 +404,8 @@ export class ProjectIssuesServices extends APIService { }); } - async subIssues( - workspaceSlug: string, - projectId: string, - issueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/` - ) + async subIssues(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -461,10 +418,7 @@ export class ProjectIssuesServices extends APIService { issueId: string, data: { sub_issue_ids: string[] } ): Promise { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/sub-issues/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -481,10 +435,7 @@ export class ProjectIssuesServices extends APIService { url: string; } ): Promise { - return this.post( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, - data - ) + return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response; @@ -512,12 +463,7 @@ export class ProjectIssuesServices extends APIService { }); } - async deleteIssueLink( - workspaceSlug: string, - projectId: string, - issueId: string, - linkId: string - ): Promise { + async deleteIssueLink(workspaceSlug: string, projectId: string, issueId: string, linkId: string): Promise { return this.delete( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/` ) @@ -527,12 +473,7 @@ export class ProjectIssuesServices extends APIService { }); } - async uploadIssueAttachment( - workspaceSlug: string, - projectId: string, - issueId: string, - file: FormData - ): Promise { + async uploadIssueAttachment(workspaceSlug: string, projectId: string, issueId: string, file: FormData): Promise { return this.mediaUpload( `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/`, file @@ -543,14 +484,8 @@ export class ProjectIssuesServices extends APIService { }); } - async getIssueAttachment( - workspaceSlug: string, - projectId: string, - issueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/` - ) + async getIssueAttachment(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-attachments/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -590,28 +525,16 @@ export class ProjectIssuesServices extends APIService { }); } - async retrieveArchivedIssue( - workspaceSlug: string, - projectId: string, - issueId: string - ): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issueId}/` - ) + async retrieveArchivedIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issueId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async deleteArchivedIssue( - workspaceSlug: string, - projectId: string, - issuesId: string - ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issuesId}/` - ) + async deleteArchivedIssue(workspaceSlug: string, projectId: string, issuesId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/archived-issues/${issuesId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -648,10 +571,7 @@ export class ProjectIssuesServices extends APIService { data: any, user: ICurrentUserResponse ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, - data - ) + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response; @@ -659,9 +579,7 @@ export class ProjectIssuesServices extends APIService { } async deleteDraftIssue(workspaceSlug: string, projectId: string, issueId: string): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/` - ) + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response; @@ -669,9 +587,7 @@ export class ProjectIssuesServices extends APIService { } async getDraftIssueById(workspaceSlug: string, projectId: string, issueId: string): Promise { - return this.get( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/` - ) + return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response; diff --git a/web/store/issue-views/Issue_details.ts b/web/store/issue-views/Issue_details.ts deleted file mode 100644 index b6da85b1b5d..00000000000 --- a/web/store/issue-views/Issue_details.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "../root"; - -export interface IIssueViewStore { - loader: boolean; - error: any | null; -} - -class IssueViewStore implements IIssueViewStore { - loader: boolean = false; - error: any | null = null; - - // root store - rootStore; - // service - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - }); - - this.rootStore = _rootStore; - } -} - -export default IssueViewStore; diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index 1eb29188db1..d8dacc1f558 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -49,11 +49,7 @@ export interface IIssueViewStore { getIssues: IIssues | null | undefined; // actions getMyIssuesAsync: (workspaceId: string, fetchFilterToggle: boolean) => null | Promise; - getProjectIssuesAsync: ( - workspaceId: string, - projectId: string, - fetchFilterToggle: boolean - ) => null | Promise; + getProjectIssuesAsync: (workspaceId: string, projectId: string, fetchFilterToggle: boolean) => null | Promise; getIssuesForModulesAsync: ( workspaceId: string, projectId: string, @@ -122,29 +118,25 @@ class IssueViewStore implements IIssueViewStore { if (!currentView || !currentWorkspaceId) return null; const currentLayout: TIssueLayouts = currentProjectId - ? this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId] - ?.project_issue_properties?.[currentProjectId]?.issues?.display_filters?.layout - : this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.my_issue_properties - ?.display_filters?.layout; + ? this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.project_issue_properties?.[currentProjectId] + ?.issues?.display_filters?.layout + : this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.my_issue_properties?.display_filters?.layout; - if (currentView === "my_issues") - return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; + if (currentView === "my_issues") return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; else if (currentView === "issues" && currentProjectId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[currentLayout]; + else if (currentView === "modules" && currentProjectId && currentModuleId) + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.modules?.[currentModuleId]?.[ currentLayout ]; - else if (currentView === "modules" && currentProjectId && currentModuleId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.modules?.[ - currentModuleId - ]?.[currentLayout]; else if (currentView === "cycles" && currentProjectId && currentCycleId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.cycles?.[ - currentCycleId - ]?.[currentLayout]; + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.cycles?.[currentCycleId]?.[ + currentLayout + ]; else if (currentView === "views" && currentProjectId && currentViewId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.views?.[ - currentViewId - ]?.[currentLayout]; + return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.views?.[currentViewId]?.[ + currentLayout + ]; } return null; @@ -156,8 +148,7 @@ class IssueViewStore implements IIssueViewStore { this.loader = true; this.error = null; - if (fetchFilterToggle) - await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); + if (fetchFilterToggle) await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, null, @@ -175,8 +166,7 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId], my_issues: { ...this?.issues[workspaceId]?.my_issues, - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: - issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, }, }, }; @@ -198,17 +188,12 @@ class IssueViewStore implements IIssueViewStore { }; // fetching project issues - getProjectIssuesAsync = async ( - workspaceId: string, - projectId: string, - fetchFilterToggle: boolean = true - ) => { + getProjectIssuesAsync = async (workspaceId: string, projectId: string, fetchFilterToggle: boolean = true) => { try { this.loader = true; this.error = null; - if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); + if (fetchFilterToggle) await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -217,11 +202,7 @@ class IssueViewStore implements IIssueViewStore { null, "issues" ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); + const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); if (issuesResponse) { const _issueResponse: any = { @@ -234,8 +215,7 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues?.[workspaceId]?.project_issues?.[projectId], issues: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.issues, - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: - issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, }, }, }, @@ -270,11 +250,7 @@ class IssueViewStore implements IIssueViewStore { this.error = null; if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueModuleFilters( - workspaceId, - projectId, - moduleId - ); + await this.rootStore.issueFilters.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -303,8 +279,7 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules, [moduleId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules?.[moduleId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: - issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, }, }, }, @@ -340,11 +315,7 @@ class IssueViewStore implements IIssueViewStore { this.error = null; if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueCyclesFilters( - workspaceId, - projectId, - cycleId - ); + await this.rootStore.issueFilters.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -373,8 +344,7 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles, [cycleId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles?.[cycleId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: - issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, }, }, }, @@ -410,11 +380,7 @@ class IssueViewStore implements IIssueViewStore { this.error = null; if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueViewsFilters( - workspaceId, - projectId, - viewId - ); + await this.rootStore.issueFilters.getProjectIssueViewsFilters(workspaceId, projectId, viewId); const filteredParams = this.rootStore.issueFilters.getComputedFilters( workspaceId, projectId, @@ -423,11 +389,7 @@ class IssueViewStore implements IIssueViewStore { viewId, "views" ); - const issuesResponse = await this.issueService.getIssuesWithParams( - workspaceId, - projectId, - filteredParams - ); + const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); if (issuesResponse) { const _issueResponse: any = { @@ -442,8 +404,7 @@ class IssueViewStore implements IIssueViewStore { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views, [viewId]: { ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views?.[viewId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: - issuesResponse, + [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, }, }, }, diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index 7c870e5b5d9..d6d12743a34 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -45,7 +45,7 @@ export const displayPropertyGroupBy: { key: string; title: string }[] = [ { key: "state", title: "States" }, { key: "state_detail.group", title: "State Groups" }, { key: "priority", title: "Priority" }, - { key: "Project", title: "Project" }, // required this on my issues + { key: "project", title: "Project" }, // required this on my issues { key: "labels", title: "Labels" }, { key: "assignees", title: "Assignees" }, { key: "created_by", title: "Created By" }, diff --git a/web/store/issue-views/issue_detail.ts b/web/store/issue-views/issue_detail.ts new file mode 100644 index 00000000000..224b16ac861 --- /dev/null +++ b/web/store/issue-views/issue_detail.ts @@ -0,0 +1,175 @@ +import { observable, action, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "../root"; +// services +import { ProjectIssuesServices } from "services/issues.service"; + +export type IPeekMode = "side" | "modal" | "full"; + +export interface IIssueViewDetailStore { + loader: boolean; + error: any | null; + + peekId: string | null; + peekMode: IPeekMode | null; + + issue_detail: { + workspace: { + [key: string]: { + issues: { + [key: string]: any; + }; + }; + }; + }; + + setPeekId: (issueId: string | null) => void; + setPeekMode: (issueId: IPeekMode | null) => void; + + // fetch issue details + fetchIssueDetailsAsync: (workspaceId: string, projectId: string, issueId: string) => void; + // creating issue + createIssueAsync: (workspaceId: string, projectId: string, issueId: string, data: any) => void; + // updating issue + updateIssueAsync: (workspaceId: string, projectId: string, issueId: string, data: any) => void; + // deleting issue + deleteIssueAsync: (workspaceId: string, projectId: string, issueId: string) => void; +} + +class IssueViewDetailStore implements IIssueViewDetailStore { + loader: boolean = false; + error: any | null = null; + + peekId: string | null = null; + peekMode: IPeekMode | null = null; + + issue_detail: { + workspace: { + [key: string]: { + issues: { + [key: string]: any; + }; + }; + }; + } = { + workspace: {}, + }; + + // root store + rootStore; + // service + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + peekId: observable, + peekMode: observable, + issue_detail: observable, + + setPeekId: action, + setPeekMode: action, + + fetchIssueDetailsAsync: action, + createIssueAsync: action, + updateIssueAsync: action, + deleteIssueAsync: action, + }); + + this.rootStore = _rootStore; + this.issueService = new ProjectIssuesServices(); + } + + setPeekId = (issueId: string | null) => (this.peekId = issueId); + setPeekMode = (mode: IPeekMode | null) => (this.peekMode = mode); + + fetchIssueDetailsAsync = async (workspaceId: string, projectId: string, issueId: string) => { + try { + this.loader = true; + this.error = null; + + console.log("workspaceId", workspaceId); + console.log("projectId", projectId); + console.log("issueId", issueId); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + } catch (error) { + console.log("error in fetching issue details", error); + this.loader = false; + this.error = error; + return error; + } + }; + + createIssueAsync = async (workspaceId: string, projectId: string, issueId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + console.log("workspaceId", workspaceId); + console.log("projectId", projectId); + console.log("issueId", issueId); + console.log("data", data); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + } catch (error) { + console.log("error in fetching issue details", error); + this.loader = false; + this.error = error; + return error; + } + }; + + updateIssueAsync = async (workspaceId: string, projectId: string, issueId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const issueResponse = await this.issueService.patchIssue(workspaceId, projectId, issueId, data, undefined); + + if (issueResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + } catch (error) { + console.log("error in fetching issue details", error); + this.loader = false; + this.error = error; + return error; + } + }; + + deleteIssueAsync = async (workspaceId: string, projectId: string, issueId: string) => { + try { + this.loader = true; + this.error = null; + + console.log("workspaceId", workspaceId); + console.log("projectId", projectId); + console.log("issueId", issueId); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + } catch (error) { + console.log("error in fetching issue details", error); + this.loader = false; + this.error = error; + return error; + } + }; +} + +export default IssueViewDetailStore; diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index dda2f0dac59..e24dae0e10d 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -178,39 +178,17 @@ export interface IIssueFilterStore { getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise; - getProjectIssueModuleFilters: ( - workspaceId: string, - projectId: string, - moduleId: string - ) => Promise; + getProjectIssueModuleFilters: (workspaceId: string, projectId: string, moduleId: string) => Promise; updateProjectIssueModuleFilters: ( workspaceId: string, projectId: string, moduleId: string, data: any ) => Promise; - getProjectIssueCyclesFilters: ( - workspaceId: string, - projectId: string, - cycleId: string - ) => Promise; - updateProjectIssueCyclesFilters: ( - workspaceId: string, - projectId: string, - cycleId: string, - data: any - ) => Promise; - getProjectIssueViewsFilters: ( - workspaceId: string, - projectId: string, - viewId: string - ) => Promise; - updateProjectIssueViewsFilters: ( - workspaceId: string, - projectId: string, - viewId: string, - data: any - ) => Promise; + getProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string) => Promise; + updateProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string, data: any) => Promise; + getProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string) => Promise; + updateProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string, data: any) => Promise; } class IssueFilterStore implements IIssueFilterStore { @@ -323,11 +301,10 @@ class IssueFilterStore implements IIssueFilterStore { // computed get issueLayout() { if (!this.workspaceId) return null; - if (!this.projectId) - return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout; + if (!this.projectId) return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout; if (this.projectId) - return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.issues?.display_filters?.layout; + return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters + ?.layout; } get workspaceProjects() { @@ -341,26 +318,22 @@ class IssueFilterStore implements IIssueFilterStore { get projectStates() { if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ - this.projectId - ]?.states; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] + ?.states; } get projectLabels() { if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ - this.projectId - ]?.labels; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] + ?.labels; } get projectMembers() { if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[ - this.projectId - ]?.members; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] + ?.members; } get projectDisplayProperties() { if (!this.workspaceId || !this.projectId) return null; - return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.display_properties as any; + return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties as any; } get userFilters() { @@ -380,22 +353,17 @@ class IssueFilterStore implements IIssueFilterStore { } = { filters: null, display_filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues - ?.display_filters, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters, display_properties_id: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.display_properties_id, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties_id, display_properties: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.display_properties, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties, }; if (this.issueView === "issues") { _issueFilters = { ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues - ?.filters, + filters: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.filters, }; return _issueFilters; } @@ -404,8 +372,8 @@ class IssueFilterStore implements IIssueFilterStore { _issueFilters = { ..._issueFilters, filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.modules?.[this.moduleId]?.filters, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[this.moduleId] + ?.filters, }; return _issueFilters; } @@ -414,8 +382,8 @@ class IssueFilterStore implements IIssueFilterStore { _issueFilters = { ..._issueFilters, filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.cycles?.[this.cycleId]?.filters, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[this.cycleId] + ?.filters, }; return _issueFilters; } @@ -424,8 +392,8 @@ class IssueFilterStore implements IIssueFilterStore { _issueFilters = { ..._issueFilters, filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.views?.[this.viewId]?.filters, + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[this.viewId] + ?.filters, }; return _issueFilters; } @@ -496,12 +464,11 @@ class IssueFilterStore implements IIssueFilterStore { [this.projectId]: { ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], issues: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.issues, + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.issues?.[filter_type], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ + filter_type + ], [filter_key]: value, }, }, @@ -524,17 +491,13 @@ class IssueFilterStore implements IIssueFilterStore { project_issue_properties: { ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], issues: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.issues, + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.issues?.[filter_type], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ + filter_type + ], [filter_key]: value, }, }, @@ -556,21 +519,17 @@ class IssueFilterStore implements IIssueFilterStore { project_issue_properties: { ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], modules: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.modules, + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules, [this.moduleId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.modules?.[this.moduleId], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ + this.moduleId + ], [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.modules?.[this.moduleId]?.[filter_type], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ + this.moduleId + ]?.[filter_type], [filter_key]: value, }, }, @@ -595,21 +554,17 @@ class IssueFilterStore implements IIssueFilterStore { project_issue_properties: { ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], cycles: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.cycles, + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles, [this.cycleId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.cycles?.[this.cycleId], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ + this.cycleId + ], [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.cycles?.[this.cycleId]?.[filter_type], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ + this.cycleId + ]?.[filter_type], [filter_key]: value, }, }, @@ -618,12 +573,7 @@ class IssueFilterStore implements IIssueFilterStore { }, }, }; - this.updateProjectIssueCyclesFilters( - this.workspaceId, - this.projectId, - this.cycleId, - this.userFilters?.filters - ); + this.updateProjectIssueCyclesFilters(this.workspaceId, this.projectId, this.cycleId, this.userFilters?.filters); } if (this.issueView === "views" && this.viewId) { @@ -634,21 +584,17 @@ class IssueFilterStore implements IIssueFilterStore { project_issue_properties: { ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], views: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.views, + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views, [this.viewId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.views?.[this.viewId], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ + this.viewId + ], [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[ - this.projectId - ]?.views?.[this.viewId]?.[filter_type], + ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ + this.viewId + ]?.[filter_type], [filter_key]: value, }, }, @@ -657,12 +603,7 @@ class IssueFilterStore implements IIssueFilterStore { }, }, }; - this.updateProjectIssueViewsFilters( - this.workspaceId, - this.projectId, - this.viewId, - this.userFilters?.filters - ); + this.updateProjectIssueViewsFilters(this.workspaceId, this.projectId, this.viewId, this.userFilters?.filters); } } @@ -671,26 +612,11 @@ class IssueFilterStore implements IIssueFilterStore { if (this.issueView === "issues") this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); if (this.issueView === "modules" && this.moduleId) - this.rootStore?.issueView?.getIssuesForModulesAsync( - this.workspaceId, - this.projectId, - this.moduleId, - false - ); + this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); if (this.issueView === "cycles" && this.cycleId) - this.rootStore?.issueView?.getIssuesForCyclesAsync( - this.workspaceId, - this.projectId, - this.cycleId, - false - ); + this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); if (this.issueView === "views" && this.viewId) - this.rootStore?.issueView?.getIssuesForViewsAsync( - this.workspaceId, - this.projectId, - this.viewId, - false - ); + this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); }; computedFilter = (filters: any, filteredParams: any) => { @@ -698,9 +624,7 @@ class IssueFilterStore implements IIssueFilterStore { Object.keys(filters).map((key) => { if (filters[key] != undefined && filteredParams.includes(key)) computedFilters[key] = - typeof filters[key] === "string" || typeof filters[key] === "boolean" - ? filters[key] - : filters[key].join(","); + typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(","); }); return computedFilters; @@ -926,33 +850,25 @@ class IssueFilterStore implements IIssueFilterStore { order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null, type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null, sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false, - show_empty_groups: - issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, + show_empty_groups: issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list", - calendar_date_range: - issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, - start_target_date: - issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, + calendar_date_range: issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, + start_target_date: issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, }, display_properties: { assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false, - attachment_count: - issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, - created_on: - issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, + attachment_count: issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, + created_on: issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false, estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false, key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false, labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false, link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false, priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false, - start_date: - issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, + start_date: issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false, - sub_issue_count: - issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, - updated_on: - issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, + sub_issue_count: issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, + updated_on: issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, }, }, }, @@ -979,10 +895,7 @@ class IssueFilterStore implements IIssueFilterStore { const payload = { view_props: data, }; - const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView( - workspaceId, - payload - ); + const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView(workspaceId, payload); if (issuesFiltersResponse) { runInAction(() => { @@ -1014,8 +927,7 @@ class IssueFilterStore implements IIssueFilterStore { project_properties: { ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId] - ?.project_properties?.[projectId], + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], states: issuesStateResponse, }, }, @@ -1053,8 +965,7 @@ class IssueFilterStore implements IIssueFilterStore { project_properties: { ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId] - ?.project_properties?.[projectId], + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], labels: issuesLabelsResponse, }, }, @@ -1081,10 +992,7 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const issuesMembersResponse = await this.projectService.projectMembers( - workspaceId, - projectId - ); + const issuesMembersResponse = await this.projectService.projectMembers(workspaceId, projectId); if (issuesMembersResponse) { const _issuesMembersResponse = { ...this.issueRenderFilters, @@ -1095,8 +1003,7 @@ class IssueFilterStore implements IIssueFilterStore { project_properties: { ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId] - ?.project_properties?.[projectId], + ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], members: issuesMembersResponse, }, }, @@ -1124,10 +1031,7 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties( - workspaceId, - projectId - ); + const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId); if (issuesDisplayPropertiesResponse) { const _myUserId: string = issuesDisplayPropertiesResponse?.user; @@ -1206,10 +1110,7 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; - const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe( - workspaceId, - projectId - ); + const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe(workspaceId, projectId); if (issuesDisplayFiltersResponse) { const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters }; @@ -1256,11 +1157,7 @@ class IssueFilterStore implements IIssueFilterStore { const payload: any = { view_props: data, }; - const issuesFiltersResponse = await this.projectService.setProjectView( - workspaceId, - projectId, - payload - ); + const issuesFiltersResponse = await this.projectService.setProjectView(workspaceId, projectId, payload); if (issuesFiltersResponse) { runInAction(() => { @@ -1302,22 +1199,14 @@ class IssueFilterStore implements IIssueFilterStore { } }; - getProjectIssueModuleFilters = async ( - workspaceId: string, - projectId: string, - moduleId: string - ) => { + getProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string) => { try { this.loader = true; this.error = null; await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails( - workspaceId, - projectId, - moduleId - ); + const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails(workspaceId, projectId, moduleId); if (issuesFiltersModuleResponse) { const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters }; @@ -1330,11 +1219,9 @@ class IssueFilterStore implements IIssueFilterStore { [projectId]: { ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], modules: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] - ?.modules, + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules, [moduleId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] - ?.modules?.[moduleId], + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[moduleId], filters: { priority: _filters?.priority ?? undefined, state: _filters?.state ?? undefined, @@ -1365,12 +1252,7 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateProjectIssueModuleFilters = async ( - workspaceId: string, - projectId: string, - moduleId: string, - data: any - ) => { + updateProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string, data: any) => { try { this.loader = true; this.error = null; @@ -1401,22 +1283,14 @@ class IssueFilterStore implements IIssueFilterStore { } }; - getProjectIssueCyclesFilters = async ( - workspaceId: string, - projectId: string, - cycleId: string - ) => { + getProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string) => { try { this.loader = true; this.error = null; await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails( - workspaceId, - projectId, - cycleId - ); + const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails(workspaceId, projectId, cycleId); if (issuesFiltersCycleResponse) { const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters }; @@ -1431,8 +1305,7 @@ class IssueFilterStore implements IIssueFilterStore { cycles: { ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, [cycleId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] - ?.modules?.[cycleId], + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[cycleId], filters: { priority: _filters?.priority ?? undefined, state: _filters?.state ?? undefined, @@ -1463,12 +1336,7 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateProjectIssueCyclesFilters = async ( - workspaceId: string, - projectId: string, - cycleId: string, - data: any - ) => { + updateProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string, data: any) => { try { this.loader = true; this.error = null; @@ -1506,11 +1374,7 @@ class IssueFilterStore implements IIssueFilterStore { await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersViewResponse = await this.viewService.getViewDetails( - workspaceId, - projectId, - viewId - ); + const issuesFiltersViewResponse = await this.viewService.getViewDetails(workspaceId, projectId, viewId); if (issuesFiltersViewResponse) { const _filters = { ...issuesFiltersViewResponse?.query_data } as any; @@ -1525,8 +1389,7 @@ class IssueFilterStore implements IIssueFilterStore { views: { ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, [viewId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId] - ?.modules?.[viewId], + ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[viewId], filters: { priority: _filters?.priority ?? undefined, state: _filters?.state ?? undefined, @@ -1557,12 +1420,7 @@ class IssueFilterStore implements IIssueFilterStore { return error; } }; - updateProjectIssueViewsFilters = async ( - workspaceId: string, - projectId: string, - viewId: string, - data: any - ) => { + updateProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string, data: any) => { try { this.loader = true; this.error = null; diff --git a/web/store/issue-views/kanban-view.ts b/web/store/issue-views/kanban-view.ts new file mode 100644 index 00000000000..2f8f14e2615 --- /dev/null +++ b/web/store/issue-views/kanban-view.ts @@ -0,0 +1,185 @@ +import { action, computed, makeObservable } from "mobx"; +// types +import { RootStore } from "../root"; + +export interface IIssueKanBanViewStore { + handleDragDrop: (source: any, destination: any) => void; +} + +class IssueKanBanViewStore implements IIssueKanBanViewStore { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // computed + canUserDragDrop: computed, + canUserDragDropVertically: computed, + canUserDragDropHorizontally: computed, + + // actions + handleDragDrop: action, + }); + + this.rootStore = _rootStore; + } + + get canUserDragDrop() { + if ( + this.rootStore?.issueFilters?.issueView && + this.rootStore?.issueFilters?.userFilters?.display_filters?.group_by && + this.rootStore?.issueFilters?.userFilters?.display_filters?.order_by && + !["my_issues"].includes(this.rootStore?.issueFilters?.issueView) && + ["state", "priority"].includes(this.rootStore?.issueFilters?.userFilters?.display_filters?.group_by) && + this.rootStore?.issueFilters?.userFilters?.display_filters?.order_by === "sort_order" + ) { + return true; + } + return false; + } + get canUserDragDropVertically() { + return true; + } + get canUserDragDropHorizontally() { + return true; + } + + handleDragDrop = async (source: any, destination: any) => { + const workspaceId = this.rootStore?.issueFilters?.workspaceId; + const projectId = this.rootStore?.issueFilters?.projectId; + const issueView = this.rootStore?.issueFilters?.issueView; + const issueLayout = this.rootStore?.issueFilters?.userFilters?.display_filters?.layout; + + const sortOrderDefaultValue = 10000; + + if ( + this.rootStore?.issueView?.getIssues && + workspaceId && + projectId && + issueView && + issueLayout && + issueView != "my_issues" + ) { + const projectSortedIssues: any = + this.rootStore?.issueView.issues?.[workspaceId]?.project_issues?.[projectId]?.[issueView]?.[issueLayout]; + + let updateIssue: any = { + workspaceId: workspaceId, + projectId: projectId, + }; + + // user can drag the issues from any direction + if (this.canUserDragDrop) { + // vertical + if (source.droppableId === destination.droppableId) { + const _columnId = source.droppableId; + const _issues = projectSortedIssues[_columnId]; + + // update the sort order + if (destination.index === 0) { + updateIssue = { ...updateIssue, sort_order: _issues[destination.index].sort_order - sortOrderDefaultValue }; + } else if (destination.index === _issues.length - 1) { + updateIssue = { ...updateIssue, sort_order: _issues[destination.index].sort_order + sortOrderDefaultValue }; + } else { + updateIssue = { + ...updateIssue, + sort_order: (_issues[destination.index - 1].sort_order + _issues[destination.index].sort_order) / 2, + }; + } + + // update the mobx state array + const [removed] = _issues.splice(source.index, 1); + _issues.splice(destination.index, 0, { ...removed, sort_order: updateIssue.sort_order }); + updateIssue = { ...updateIssue, issueId: removed?.id }; + + projectSortedIssues[_columnId] = _issues; + } + + // horizontal + if (source.droppableId != destination.droppableId) { + const _sourceColumnId = source.droppableId; + const _destinationColumnId = destination.droppableId; + + const _sourceIssues = projectSortedIssues[_sourceColumnId]; + const _destinationIssues = projectSortedIssues[_destinationColumnId]; + + if (_destinationIssues.length > 0) { + if (destination.index === 0) { + updateIssue = { + ...updateIssue, + sort_order: _destinationIssues[destination.index].sort_order - sortOrderDefaultValue, + state: destination?.droppableId, + }; + } else if (destination.index === _destinationIssues.length - 1) { + updateIssue = { + ...updateIssue, + sort_order: _destinationIssues[destination.index].sort_order + sortOrderDefaultValue, + state: destination?.droppableId, + }; + } else { + updateIssue = { + ...updateIssue, + sort_order: + (_destinationIssues[destination.index - 1].sort_order + + _destinationIssues[destination.index].sort_order) / + 2, + state: destination?.droppableId, + }; + } + } else { + updateIssue = { + ...updateIssue, + sort_order: sortOrderDefaultValue, + state: destination?.droppableId, + }; + } + + const [removed] = _sourceIssues.splice(source.index, 1); + _destinationIssues.splice(destination.index, 0, { + ...removed, + state: destination?.droppableId, + sort_order: updateIssue.sort_order, + }); + updateIssue = { ...updateIssue, issueId: removed?.id }; + + projectSortedIssues[_sourceColumnId] = _sourceIssues; + projectSortedIssues[_destinationColumnId] = _destinationIssues; + } + } + + // user can drag the issues only vertically + if (this.canUserDragDropVertically && source.droppableId === destination.droppableId) { + } + + // user can drag the issues only horizontally + if (this.canUserDragDropHorizontally && source.droppableId != destination.droppableId) { + } + + this.rootStore.issueView.issues = { + ...this.rootStore?.issueView.issues, + [workspaceId]: { + ...this.rootStore?.issueView.issues?.[workspaceId], + project_issues: { + ...this.rootStore?.issueView.issues?.[workspaceId]?.project_issues, + [projectId]: { + ...this.rootStore?.issueView.issues?.[workspaceId]?.project_issues?.[projectId], + [issueView]: { + ...this.rootStore?.issueView.issues?.[workspaceId]?.project_issues?.[projectId]?.[issueView], + [issueLayout]: projectSortedIssues, + }, + }, + }, + }, + }; + + this.rootStore.issueDetail?.updateIssueAsync( + updateIssue.workspaceId, + updateIssue.projectId, + updateIssue.issueId, + updateIssue + ); + } + }; +} + +export default IssueKanBanViewStore; diff --git a/web/store/root.ts b/web/store/root.ts index 9f4fd1d835b..90a9ef8702c 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -9,6 +9,8 @@ import IssuesStore from "./issues"; // issues views and filters import IssueFilterStore from "./issue-views/issue_filters"; import IssueViewStore from "./issue-views/Issues"; +import IssueViewDetailStore from "./issue-views/issue_detail"; +import IssueKanBanViewStore from "./issue-views/kanban-view"; enableStaticRendering(typeof window === "undefined"); @@ -20,6 +22,8 @@ export class RootStore { issues: IssuesStore; issueFilters: IssueFilterStore; issueView: IssueViewStore; + issueDetail: IssueViewDetailStore; + issueKanBanView: IssueKanBanViewStore; constructor() { this.user = new UserStore(this); @@ -29,5 +33,7 @@ export class RootStore { this.issues = new IssuesStore(this); this.issueFilters = new IssueFilterStore(this); this.issueView = new IssueViewStore(this); + this.issueDetail = new IssueViewDetailStore(this); + this.issueKanBanView = new IssueKanBanViewStore(this); } } From 70fe8301510c3c345b8a54b44277a2017001d93b Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Fri, 15 Sep 2023 16:55:38 +0530 Subject: [PATCH 020/102] filtering --- web/components/issue-layouts/list/item.tsx | 53 +++++++++------- web/components/issue-layouts/list/list.tsx | 5 +- web/components/issue-layouts/list/root.tsx | 2 +- .../issue-layouts/properties/index.ts | 1 + .../properties/priority-select.tsx | 61 +++++++++++++++++++ web/store/issue-views/issue_detail.ts | 11 ++++ 6 files changed, 109 insertions(+), 24 deletions(-) create mode 100644 web/components/issue-layouts/properties/index.ts create mode 100644 web/components/issue-layouts/properties/priority-select.tsx diff --git a/web/components/issue-layouts/list/item.tsx b/web/components/issue-layouts/list/item.tsx index accd79fd82d..c12eb95d7ec 100644 --- a/web/components/issue-layouts/list/item.tsx +++ b/web/components/issue-layouts/list/item.tsx @@ -1,5 +1,5 @@ import React, { FC, useState } from "react"; -import { Tooltip, CustomMenu, ContextMenu } from "components/ui"; +import { observer } from "mobx-react-lite"; // lib import { useMobxStore } from "lib/mobx/store-provider"; import { IIssue } from "types"; @@ -15,6 +15,7 @@ import { PaperClipIcon, } from "@heroicons/react/24/outline"; // components +import { Tooltip, CustomMenu, ContextMenu } from "components/ui"; import { LayerDiagonalIcon } from "components/icons"; import { ViewAssigneeSelect, @@ -25,25 +26,36 @@ import { ViewStartDateSelect, ViewStateSelect, } from "components/issues"; +import { IssuePrioritySelect } from "../properties"; export interface IIssueListItem { issue: IIssue; + groupId: string; } -export const IssueListItem: FC = (props) => { - const { issue } = props; +export const IssueListItem: FC = observer((props) => { + const { issue, groupId } = props; // store - const { user: userStore, issueFilters: issueFilterStore } = useMobxStore(); + const { user: userStore, issueFilters: issueFilterStore, issueDetail: issueDetailStore } = useMobxStore(); const displayProperties = issueFilterStore.userFilters?.display_properties; + const workspaceId = issueFilterStore.workspaceId; + const projectId = issueFilterStore.projectId; + const issueId = issue.id; + const user = userStore.currentUser; console.log("userStore", userStore); // context menu const [contextMenu, setContextMenu] = useState(false); const [contextMenuPosition, setContextMenuPosition] = useState(null); - const { user: userAuth } = useUserAuth(); + const isNotAllowed = false; // const isNotAllowed = // userAuth?.isGuest || userAuth?.isViewer || disableUserActions || isArchivedIssues; + const partialUpdateIssue = (data: any) => { + // console.log("data", data); + if (workspaceId && projectId && issueId) issueDetailStore.updateIssueAsync(workspaceId, projectId, issueId, data); + }; + return (
<> @@ -112,20 +124,21 @@ export const IssueListItem: FC = (props) => {
{displayProperties?.priority && ( - + // + )} {displayProperties?.state && ( )} @@ -133,7 +146,7 @@ export const IssueListItem: FC = (props) => { )} @@ -141,19 +154,17 @@ export const IssueListItem: FC = (props) => { )} - {displayProperties?.labels && ( - - )} + {displayProperties?.labels && } {displayProperties?.assignee && ( )} @@ -162,7 +173,7 @@ export const IssueListItem: FC = (props) => { issue={issue} partialUpdateIssue={partialUpdateIssue} position="right" - user={user} + user={user as any} isNotAllowed={isNotAllowed} /> )} @@ -231,4 +242,4 @@ export const IssueListItem: FC = (props) => {
); -}; +}); diff --git a/web/components/issue-layouts/list/list.tsx b/web/components/issue-layouts/list/list.tsx index 8ece7b1c8d9..2d2e31ef9f7 100644 --- a/web/components/issue-layouts/list/list.tsx +++ b/web/components/issue-layouts/list/list.tsx @@ -4,14 +4,15 @@ import { IssueListItem } from "./item"; export interface IIssueListView { issues: IIssue[]; + groupId: string; } export const IssueListView: FC = (props) => { - const { issues = [] } = props; + const { issues = [], groupId } = props; return (
{issues.map((issue) => ( - + ))}
); diff --git a/web/components/issue-layouts/list/root.tsx b/web/components/issue-layouts/list/root.tsx index 6b136cf40c4..19ebf641aee 100644 --- a/web/components/issue-layouts/list/root.tsx +++ b/web/components/issue-layouts/list/root.tsx @@ -31,7 +31,7 @@ export const IssueListViewRoot = observer(() => { /> - + )} diff --git a/web/components/issue-layouts/properties/index.ts b/web/components/issue-layouts/properties/index.ts new file mode 100644 index 00000000000..3289b323781 --- /dev/null +++ b/web/components/issue-layouts/properties/index.ts @@ -0,0 +1 @@ +export * from "./priority-select"; diff --git a/web/components/issue-layouts/properties/priority-select.tsx b/web/components/issue-layouts/properties/priority-select.tsx new file mode 100644 index 00000000000..835adb8a92e --- /dev/null +++ b/web/components/issue-layouts/properties/priority-select.tsx @@ -0,0 +1,61 @@ +import { FC, Fragment, useState } from "react"; +import { Listbox, Transition } from "@headlessui/react"; +import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid"; +import { useMobxStore } from "lib/mobx/store-provider"; +import { IIssue } from "types"; + +export interface IIssuePrioritySelect { + issue: IIssue; + groupId: string; +} + +export const IssuePrioritySelect: FC = (props) => { + const { issue, groupId } = props; + + const { issueFilters: issueFilterStore } = useMobxStore(); + const priorityList = issueFilterStore.issueRenderFilters.priority; + + const selected = priorityList.find((p) => p.key === issue.priority); + + const changePriority = (selectedPriority: any) => { + console.log("selectedPriority", selectedPriority); + }; + + return ( + +
+ + {selected?.title || "None"} + + + + {priorityList.map((priority) => ( + + `relative cursor-default select-none py-2 pl-10 pr-4 ${ + active ? "bg-amber-100 text-amber-900" : "text-gray-900" + }` + } + value={priority} + > + {({ selected }) => ( + <> + + {priority.title} + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+
+ ); +}; diff --git a/web/store/issue-views/issue_detail.ts b/web/store/issue-views/issue_detail.ts index 224b16ac861..cda0b7bc977 100644 --- a/web/store/issue-views/issue_detail.ts +++ b/web/store/issue-views/issue_detail.ts @@ -134,12 +134,23 @@ class IssueViewDetailStore implements IIssueViewDetailStore { this.loader = true; this.error = null; + const filteredParams = this.rootStore.issueFilters.getComputedFilters( + workspaceId, + projectId, + null, + null, + null, + this.rootStore.issueFilters.issueView || "issues" + ); const issueResponse = await this.issueService.patchIssue(workspaceId, projectId, issueId, data, undefined); + const issueList = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); + console.log("issueList", issueList); if (issueResponse) { runInAction(() => { this.loader = false; this.error = null; + this.rootStore.issueView.issues[workspaceId].project_issues[projectId].issues.list = issueList; }); } } catch (error) { From a25e5accd1dfbe96773c4eb5be9c52236ba1ae6c Mon Sep 17 00:00:00 2001 From: gurusainath Date: Fri, 15 Sep 2023 20:07:38 +0530 Subject: [PATCH 021/102] chore: store setup --- web/components/issue-layouts/list/list.tsx | 5 +- web/components/issue-layouts/list/root.tsx | 2 +- .../properties/priority-select.tsx | 9 +- web/store/issue-views/Issues.ts | 92 +++++++++++++++++++ web/store/issue-views/issue_data.ts | 55 +++-------- web/store/issue-views/issue_filters.ts | 20 ++-- 6 files changed, 127 insertions(+), 56 deletions(-) diff --git a/web/components/issue-layouts/list/list.tsx b/web/components/issue-layouts/list/list.tsx index 2d2e31ef9f7..8a858ee6ab8 100644 --- a/web/components/issue-layouts/list/list.tsx +++ b/web/components/issue-layouts/list/list.tsx @@ -1,13 +1,14 @@ import React, { FC } from "react"; import { IIssue } from "types"; import { IssueListItem } from "./item"; +import { observer } from "mobx-react-lite"; export interface IIssueListView { issues: IIssue[]; groupId: string; } -export const IssueListView: FC = (props) => { +export const IssueListView: FC = observer((props) => { const { issues = [], groupId } = props; return (
@@ -16,4 +17,4 @@ export const IssueListView: FC = (props) => { ))}
); -}; +}); diff --git a/web/components/issue-layouts/list/root.tsx b/web/components/issue-layouts/list/root.tsx index 19ebf641aee..5649a522b20 100644 --- a/web/components/issue-layouts/list/root.tsx +++ b/web/components/issue-layouts/list/root.tsx @@ -31,7 +31,7 @@ export const IssueListViewRoot = observer(() => { /> - + )} diff --git a/web/components/issue-layouts/properties/priority-select.tsx b/web/components/issue-layouts/properties/priority-select.tsx index 835adb8a92e..a914ed38ac4 100644 --- a/web/components/issue-layouts/properties/priority-select.tsx +++ b/web/components/issue-layouts/properties/priority-select.tsx @@ -3,22 +3,23 @@ import { Listbox, Transition } from "@headlessui/react"; import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/20/solid"; import { useMobxStore } from "lib/mobx/store-provider"; import { IIssue } from "types"; +import { observer } from "mobx-react-lite"; export interface IIssuePrioritySelect { issue: IIssue; groupId: string; } -export const IssuePrioritySelect: FC = (props) => { +export const IssuePrioritySelect: FC = observer((props) => { const { issue, groupId } = props; - const { issueFilters: issueFilterStore } = useMobxStore(); + const { issueView: issueViewStore, issueFilters: issueFilterStore } = useMobxStore(); const priorityList = issueFilterStore.issueRenderFilters.priority; const selected = priorityList.find((p) => p.key === issue.priority); const changePriority = (selectedPriority: any) => { - console.log("selectedPriority", selectedPriority); + issueViewStore.updateIssues(groupId, issue.id, { priority: selectedPriority.key }); }; return ( @@ -58,4 +59,4 @@ export const IssuePrioritySelect: FC = (props) => {
); -}; +}); diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index d8dacc1f558..b7aede2a9d4 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -94,6 +94,7 @@ class IssueViewStore implements IIssueViewStore { getIssuesForModulesAsync: action, getIssuesForCyclesAsync: action, getIssuesForViewsAsync: action, + updateIssues: action, // computed getIssues: computed, }); @@ -142,6 +143,97 @@ class IssueViewStore implements IIssueViewStore { return null; } + updateIssues = (group_id: string | null, issue_id: string | null, data: any) => { + const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; + const currentProjectId: string | null = this.rootStore.issueFilters.projectId; + const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; + const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; + const currentViewId: string | null = this.rootStore.issueFilters.viewId; + const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; + const currentLayout: TIssueLayouts | null | undefined = this.rootStore.issueFilters.issueLayout; + + if (!currentView || !currentWorkspaceId || !currentLayout || !issue_id) return null; + + if (currentView === "my_issues") { + if (group_id) { + this.issues = { + ...this.issues, + [currentWorkspaceId]: { + ...this?.issues?.[currentWorkspaceId], + my_issues: { + ...this?.issues?.[currentWorkspaceId]?.my_issues, + [currentLayout]: { + ...this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout], + [group_id]: this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]?.[group_id].map( + (item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item }) + ), + }, + }, + }, + }; + } else { + this.issues = { + ...this.issues, + [currentWorkspaceId]: { + ...this?.issues?.[currentWorkspaceId], + my_issues: { + ...this?.issues?.[currentWorkspaceId]?.my_issues, + [currentLayout]: this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout].map((item: any) => + item.id === issue_id ? { ...item, ...data } : { ...item } + ), + }, + }, + }; + } + } + + if (!currentProjectId) return null; + if (currentView) { + if (group_id) { + this.issues = { + ...this.issues, + [currentWorkspaceId]: { + ...this?.issues?.[currentWorkspaceId], + project_issues: { + ...this?.issues?.[currentWorkspaceId]?.project_issues, + [currentProjectId]: { + ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId], + [currentView]: { + ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues, + [currentLayout]: { + ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[currentLayout], + [group_id]: this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ + currentLayout + ]?.[group_id].map((item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item })), + }, + }, + }, + }, + }, + }; + } else { + this.issues = { + ...this.issues, + [currentWorkspaceId]: { + ...this?.issues?.[currentWorkspaceId], + project_issues: { + ...this?.issues?.[currentWorkspaceId]?.project_issues, + [currentProjectId]: { + ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId], + [currentView]: { + ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues, + [currentLayout]: this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ + currentLayout + ].map((item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item })), + }, + }, + }, + }, + }; + } + } + }; + // fetching my issues getMyIssuesAsync = async (workspaceId: string, fetchFilterToggle: boolean = true) => { try { diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index d6d12743a34..11edc4e0bd6 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -1,15 +1,8 @@ import { renderDateFormat } from "helpers/date-time.helper"; export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; -export const issueStateGroupKeys: TStateGroup[] = [ - "backlog", - "unstarted", - "started", - "completed", - "cancelled", -]; -export const filtersPriority: { key: string; title: string }[] = [ +export const priorities: { key: string; title: string }[] = [ { key: "urgent", title: "Urgent" }, { key: "high", title: "High" }, { key: "medium", title: "Medium" }, @@ -17,7 +10,7 @@ export const filtersPriority: { key: string; title: string }[] = [ { key: "none", title: "None" }, ]; -export const filterStateGroup: { key: TStateGroup; title: string }[] = [ +export const stateGroups: { key: TStateGroup; title: string }[] = [ { key: "backlog", title: "Backlog" }, { key: "unstarted", title: "Unstarted" }, { key: "started", title: "Started" }, @@ -25,7 +18,7 @@ export const filterStateGroup: { key: TStateGroup; title: string }[] = [ { key: "cancelled", title: "Cancelled" }, ]; -export const filtersStartDate: { key: string; title: string }[] = [ +export const startDateOptions: { key: string; title: string }[] = [ { key: "last_week", title: "Last Week" }, { key: "2_weeks_from_now", title: "2 weeks from now" }, { key: "1_month_from_now", title: "1 month from now" }, @@ -33,7 +26,7 @@ export const filtersStartDate: { key: string; title: string }[] = [ { key: "custom", title: "Custom" }, ]; -export const filtersDueDate: { key: string; title: string }[] = [ +export const dueDateOptions: { key: string; title: string }[] = [ { key: "last_week", title: "Last Week" }, { key: "2_weeks_from_now", title: "2 weeks from now" }, { key: "1_month_from_now", title: "1 month from now" }, @@ -41,7 +34,7 @@ export const filtersDueDate: { key: string; title: string }[] = [ { key: "custom", title: "Custom" }, ]; -export const displayPropertyGroupBy: { key: string; title: string }[] = [ +export const groupByOptions: { key: string; title: string }[] = [ { key: "state", title: "States" }, { key: "state_detail.group", title: "State Groups" }, { key: "priority", title: "Priority" }, @@ -51,7 +44,7 @@ export const displayPropertyGroupBy: { key: string; title: string }[] = [ { key: "created_by", title: "Created By" }, ]; -export const displayPropertyOrderBy: { key: string; title: string }[] = [ +export const orderByOptions: { key: string; title: string }[] = [ { key: "sort_order", title: "Manual" }, { key: "created_at", title: "Last Created" }, { key: "updated_at", title: "Last Updated" }, @@ -59,7 +52,7 @@ export const displayPropertyOrderBy: { key: string; title: string }[] = [ { key: "priority", title: "Priority" }, ]; -export const displayPropertyIssueType: { key: string; title: string }[] = [ +export const issueTypes: { key: string; title: string }[] = [ { key: "all", title: "All" }, { key: "active", title: "Active Issues" }, { key: "backlog", title: "Backlog Issues" }, @@ -112,30 +105,14 @@ export const issueFilterVisibilityData: any = { }, }, }, - others: { + issues: { layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"], filters: { list: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], kanban: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], calendar: ["priority", "state", "assignees", "created_by", "labels"], - spreadsheet: [ - "priority", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "due_date", - ], - gantt_chart: [ - "priority", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "due_date", - ], + spreadsheet: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], + gantt_chart: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], }, display_properties: { list: true, @@ -176,15 +153,11 @@ export const issueFilterVisibilityData: any = { }, }; -export const handleIssueParamsDateFormat = ( - key: string, - start_date: any | null, - target_date: any | null -) => { +export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => { if (key === "last_week") - return `${renderDateFormat( - new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000) - )};after,${renderDateFormat(new Date())};before`; + return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat( + new Date() + )};before`; if (key === "2_weeks_from_now") return `${renderDateFormat(new Date())};after, diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 2239ef0f8db..17beb010881 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -196,7 +196,6 @@ class IssueFilterStore implements IIssueFilterStore { loader: boolean = false; error: any | null = null; - myUserId: string | null = null; workspaceId: string | null = null; projectId: string | null = null; moduleId: string | null = null; @@ -305,25 +304,30 @@ class IssueFilterStore implements IIssueFilterStore { // computed get issueLayout() { if (!this.workspaceId) return null; - if (!this.projectId) return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout; + if (!this.projectId) + return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout || null; if (this.projectId) - return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters - ?.layout; + return ( + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters + ?.layout || null + ); } get workspaceProjects() { if (!this.workspaceId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.projects; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.projects || null; } get workspaceLabels() { if (!this.workspaceId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.labels; + return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.labels || null; } get projectStates() { if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] - ?.states; + return ( + this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId]?.states || + null + ); } getProjectStateById = (stateId: string) => { From 906caa636b6314d7589fa344651567b5cb675d31 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Tue, 19 Sep 2023 12:50:27 +0530 Subject: [PATCH 022/102] chore: handled build issues --- .../display-filters/extra-options.tsx | 12 +- .../display-filters/group-by.tsx | 6 +- .../issue-layouts/display-filters/index.tsx | 13 +- .../display-filters/issue-type.tsx | 6 +- .../display-filters/order-by.tsx | 6 +- .../filters-preview/assignees.tsx | 23 +--- .../filters-preview/created-by.tsx | 15 +-- .../filters-preview/helpers/content.tsx | 8 +- .../filters-preview/index copy.tsx | 92 -------------- .../issue-layouts/filters-preview/index.tsx | 6 +- .../issue-layouts/filters-preview/labels.tsx | 4 +- .../filters-preview/state-group.tsx | 46 ++----- .../issue-layouts/filters-preview/state.tsx | 16 +-- .../issue-layouts/filters/assignees.tsx | 15 +-- .../issue-layouts/filters/created-by.tsx | 7 +- .../issue-layouts/filters/index.tsx | 2 +- .../issue-layouts/filters/state-group.tsx | 30 +---- .../issue-layouts/filters/state.tsx | 16 +-- .../issue-layouts/helpers/dropdown.tsx | 6 +- .../issue-layouts/helpers/filter-header.tsx | 6 +- .../issue-layouts/helpers/filter-option.tsx | 8 +- .../issue-layouts/layout-selection.tsx | 10 +- .../issue-layouts/list/group-header.tsx | 20 +-- web/components/issue-layouts/list/list.tsx | 10 +- web/components/issue-layouts/list/root.tsx | 7 +- web/store/issue-views/Issues.ts | 28 ++-- web/store/issue-views/issue_data.ts | 79 ++++++++++++ web/store/issue-views/issue_detail.ts | 2 +- web/store/issue-views/issue_filters.ts | 120 ++++-------------- web/store/issue-views/project.ts | 21 +++ web/store/issue-views/workspace.ts | 21 +++ web/store/root.ts | 8 ++ 32 files changed, 245 insertions(+), 424 deletions(-) delete mode 100644 web/components/issue-layouts/filters-preview/index copy.tsx create mode 100644 web/store/issue-views/project.ts create mode 100644 web/store/issue-views/workspace.ts diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index 100a6cfd718..58cbf193ff4 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -23,9 +23,9 @@ export const FilterExtraOptions = observer(() => { const handleExtraOptionsSectionVisibility = (key: string) => issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ]?.extra_options?.[issueFilterStore?.issueLayout].values?.includes(key); + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ + issueFilterStore?.issueLayout + ].values?.includes(key); return (
@@ -43,11 +43,7 @@ export const FilterExtraOptions = observer(() => { handleExtraOptionsSectionVisibility(_extraProperties?.key) && ( handleExtraOptions( _extraProperties?.key, diff --git a/web/components/issue-layouts/display-filters/group-by.tsx b/web/components/issue-layouts/display-filters/group-by.tsx index 93e297803a1..026ad68daf0 100644 --- a/web/components/issue-layouts/display-filters/group-by.tsx +++ b/web/components/issue-layouts/display-filters/group-by.tsx @@ -32,11 +32,7 @@ export const FilterGroupBy = observer(() => { issueFilterStore?.issueRenderFilters?.group_by.map((_groupBy) => ( handleGroupBy("group_by", _groupBy?.key)} title={_groupBy.title} multiple={false} diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index 0c7ff05fd55..c4a81bc3ca8 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -20,21 +20,22 @@ export const DisplayFiltersSelection = observer(() => { const handleDisplayPropertiesSectionVisibility = issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"] + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"] ?.display_properties?.[issueFilterStore?.issueLayout]; const handleDisplayFilterSectionVisibility = (section_key: string) => issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ]?.display_filters?.[issueFilterStore?.issueLayout].includes(section_key); + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.display_filters?.[ + issueFilterStore?.issueLayout + ].includes(section_key); const handleExtraOptionsSectionVisibility = issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"] - ?.extra_options?.[issueFilterStore?.issueLayout].access; + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ + issueFilterStore?.issueLayout + ].access; return (
diff --git a/web/components/issue-layouts/display-filters/issue-type.tsx b/web/components/issue-layouts/display-filters/issue-type.tsx index 10f50800be0..cdf5dd34263 100644 --- a/web/components/issue-layouts/display-filters/issue-type.tsx +++ b/web/components/issue-layouts/display-filters/issue-type.tsx @@ -32,11 +32,7 @@ export const FilterIssueType = observer(() => { issueFilterStore?.issueRenderFilters?.issue_type.map((_issueType) => ( handleIssueType("type", _issueType?.key)} title={_issueType.title} multiple={false} diff --git a/web/components/issue-layouts/display-filters/order-by.tsx b/web/components/issue-layouts/display-filters/order-by.tsx index c7c3f2ebb56..b575ed45eda 100644 --- a/web/components/issue-layouts/display-filters/order-by.tsx +++ b/web/components/issue-layouts/display-filters/order-by.tsx @@ -32,11 +32,7 @@ export const FilterOrderBy = observer(() => { issueFilterStore?.issueRenderFilters?.order_by.map((_orderBy) => ( handleOrderBy("order_by", _orderBy?.key)} title={_orderBy.title} multiple={false} diff --git a/web/components/issue-layouts/filters-preview/assignees.tsx b/web/components/issue-layouts/filters-preview/assignees.tsx index 80bfbc084b1..be91064a965 100644 --- a/web/components/issue-layouts/filters-preview/assignees.tsx +++ b/web/components/issue-layouts/filters-preview/assignees.tsx @@ -9,13 +9,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -export const MemberIcons = ({ - display_name, - avatar, -}: { - display_name: string; - avatar: string | null; -}) => ( +export const MemberIcons = ({ display_name, avatar }: { display_name: string; avatar: string | null }) => (
{avatar ? ( {display_name @@ -49,9 +43,7 @@ export const FilterAssignees = observer(() => {
@@ -60,17 +52,10 @@ export const FilterAssignees = observer(() => { issueFilterStore?.projectMembers.map( (_member) => issueFilterStore?.userFilters?.filters?.assignees != null && - issueFilterStore?.userFilters?.filters?.assignees.includes( - _member?.member?.id - ) && ( + issueFilterStore?.userFilters?.filters?.assignees.includes(_member?.member?.id) && ( - } + icon={} title={`${_member?.member?.display_name}`} onClick={() => handleFilter("assignees", _member?.member?.id)} className="border border-custom-border-100 bg-custom-background-100" diff --git a/web/components/issue-layouts/filters-preview/created-by.tsx b/web/components/issue-layouts/filters-preview/created-by.tsx index c69234b7c9d..c32b7fcb61b 100644 --- a/web/components/issue-layouts/filters-preview/created-by.tsx +++ b/web/components/issue-layouts/filters-preview/created-by.tsx @@ -32,9 +32,7 @@ export const FilterCreatedBy = observer(() => {
@@ -44,18 +42,11 @@ export const FilterCreatedBy = observer(() => { issueFilterStore?.projectMembers.map( (_member) => issueFilterStore?.userFilters?.filters?.created_by != null && - issueFilterStore?.userFilters?.filters?.created_by.includes( - _member?.member?.id - ) && ( + issueFilterStore?.userFilters?.filters?.created_by.includes(_member?.member?.id) && ( - } + icon={} onClick={() => handleFilter("created_by", _member?.member?.id)} className="border border-custom-border-100 bg-custom-background-100" /> diff --git a/web/components/issue-layouts/filters-preview/helpers/content.tsx b/web/components/issue-layouts/filters-preview/helpers/content.tsx index dc56bc391b8..4838c931995 100644 --- a/web/components/issue-layouts/filters-preview/helpers/content.tsx +++ b/web/components/issue-layouts/filters-preview/helpers/content.tsx @@ -8,13 +8,7 @@ interface IFilterPreviewContent { style?: any; } -export const FilterPreviewContent = ({ - icon, - title, - onClick, - className, - style, -}: IFilterPreviewContent) => ( +export const FilterPreviewContent = ({ icon, title, onClick, className, style }: IFilterPreviewContent) => (
{ - const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; - - const handleFilterSectionVisibility = (section_key: string) => - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); - - return ( -
-
Search container
-
- {/* priority */} - {handleFilterSectionVisibility("priority") && ( -
- -
- )} - - {/* state group */} - {handleFilterSectionVisibility("state_group") && ( -
- -
- )} - - {/* state */} - {handleFilterSectionVisibility("state") && ( -
- -
- )} - - {/* assignees */} - {handleFilterSectionVisibility("assignees") && ( -
- -
- )} - - {/* created_by */} - {handleFilterSectionVisibility("created_by") && ( -
- -
- )} - - {/* labels */} - {handleFilterSectionVisibility("labels") && ( -
- -
- )} - - {/* start_date */} - {handleFilterSectionVisibility("start_date") && ( -
- -
- )} - - {/* due_date */} - {handleFilterSectionVisibility("due_date") && ( -
- -
- )} -
-
- ); -}); diff --git a/web/components/issue-layouts/filters-preview/index.tsx b/web/components/issue-layouts/filters-preview/index.tsx index fd202e11b9f..03aac5b6634 100644 --- a/web/components/issue-layouts/filters-preview/index.tsx +++ b/web/components/issue-layouts/filters-preview/index.tsx @@ -23,9 +23,9 @@ export const FilterPreview = observer(() => { const handleFilterSectionVisibility = (section_key: string) => issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ]?.filters?.[issueFilterStore?.issueLayout]?.includes(section_key); + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.filters?.[ + issueFilterStore?.issueLayout + ]?.includes(section_key); const validateFiltersAvailability = issueFilterStore?.userFilters?.filters != null && diff --git a/web/components/issue-layouts/filters-preview/labels.tsx b/web/components/issue-layouts/filters-preview/labels.tsx index dbe825a7c3f..2542b2ac82d 100644 --- a/web/components/issue-layouts/filters-preview/labels.tsx +++ b/web/components/issue-layouts/filters-preview/labels.tsx @@ -43,9 +43,7 @@ export const FilterLabels = observer(() => { {issueFilterStore?.userFilters?.filters?.labels != null && (
- +
diff --git a/web/components/issue-layouts/filters-preview/state-group.tsx b/web/components/issue-layouts/filters-preview/state-group.tsx index e461f2eb033..cffaf6de8c7 100644 --- a/web/components/issue-layouts/filters-preview/state-group.tsx +++ b/web/components/issue-layouts/filters-preview/state-group.tsx @@ -18,53 +18,27 @@ import { RootStore } from "store/root"; // constants import { STATE_GROUP_COLORS } from "constants/state"; -export const StateGroupIcons = ({ - stateGroup, - color = null, -}: { - stateGroup: string; - color?: string | null; -}) => { +export const StateGroupIcons = ({ stateGroup, color = null }: { stateGroup: string; color?: string | null }) => { if (stateGroup === "cancelled") return ( - + ); if (stateGroup === "completed") return ( - + ); if (stateGroup === "started") return ( - + ); if (stateGroup === "unstarted") return ( - + ); if (stateGroup === "backlog") return (
- +
); return <>; @@ -125,9 +99,7 @@ export const FilterStateGroup = observer(() => {
@@ -136,9 +108,7 @@ export const FilterStateGroup = observer(() => { issueFilterStore?.issueRenderFilters?.state_group.map( (_stateGroup) => issueFilterStore?.userFilters?.filters?.state_group != null && - issueFilterStore?.userFilters?.filters?.state_group.includes( - _stateGroup?.key - ) && ( + issueFilterStore?.userFilters?.filters?.state_group.includes(_stateGroup?.key) && ( } diff --git a/web/components/issue-layouts/filters-preview/state.tsx b/web/components/issue-layouts/filters-preview/state.tsx index 3e408897471..f81e6e29ff7 100644 --- a/web/components/issue-layouts/filters-preview/state.tsx +++ b/web/components/issue-layouts/filters-preview/state.tsx @@ -10,7 +10,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // store default data -import { issueStateGroupKeys } from "store/issue-views/issue_data"; +import { stateGroups } from "store/issue-views/issue_data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); @@ -33,23 +33,21 @@ export const FilterState = observer(() => { {issueFilterStore?.userFilters?.filters?.state != null && (
- +
- {issueStateGroupKeys.map( + {stateGroups.map( (_stateGroup) => issueFilterStore?.projectStates && - issueFilterStore?.projectStates[_stateGroup] && - issueFilterStore?.projectStates[_stateGroup].length > 0 && - issueFilterStore?.projectStates[_stateGroup].map( + issueFilterStore?.projectStates[_stateGroup?.key] && + issueFilterStore?.projectStates[_stateGroup?.key].length > 0 && + issueFilterStore?.projectStates[_stateGroup?.key].map( (_state: any) => issueFilterStore?.userFilters?.filters?.state != null && issueFilterStore?.userFilters?.filters?.state.includes(_state?.id) && ( } + icon={} title={_state?.name} style={stateStyles(_state?.group, _state?.color)} onClick={() => handleFilter("state", _state?.id)} diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index 422318ec140..f5f49eee70e 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -8,13 +8,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -export const MemberIcons = ({ - display_name, - avatar, -}: { - display_name: string; - avatar: string | null; -}) => ( +export const MemberIcons = ({ display_name, avatar }: { display_name: string; avatar: string | null }) => (
{avatar ? ( {display_name @@ -64,12 +58,7 @@ export const FilterAssignees = observer(() => { : false } onClick={() => handleFilter("assignees", _member?.member?.id)} - icon={ - - } + icon={} title={`${_member?.member?.display_name} (${_member?.member?.first_name} ${_member?.member?.last_name})`} /> ))} diff --git a/web/components/issue-layouts/filters/created-by.tsx b/web/components/issue-layouts/filters/created-by.tsx index e2353d32c63..35693de2f0e 100644 --- a/web/components/issue-layouts/filters/created-by.tsx +++ b/web/components/issue-layouts/filters/created-by.tsx @@ -47,12 +47,7 @@ export const FilterCreatedBy = observer(() => { : false } onClick={() => handleFilter("created_by", _member?.member?.id)} - icon={ - - } + icon={} title={`${_member?.member?.display_name} (${_member?.member?.first_name} ${_member?.member?.last_name})`} /> ))} diff --git a/web/components/issue-layouts/filters/index.tsx b/web/components/issue-layouts/filters/index.tsx index 89fbcdd91eb..2512ae042fd 100644 --- a/web/components/issue-layouts/filters/index.tsx +++ b/web/components/issue-layouts/filters/index.tsx @@ -23,7 +23,7 @@ export const FilterSelection = observer(() => { const handleFilterSectionVisibility = (section_key: string) => issueFilterStore?.issueView && issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others"]?.filters?.[ + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.filters?.[ issueFilterStore?.issueLayout ]?.includes(section_key); diff --git a/web/components/issue-layouts/filters/state-group.tsx b/web/components/issue-layouts/filters/state-group.tsx index e9ea5c6fa13..dcfd71cbfbb 100644 --- a/web/components/issue-layouts/filters/state-group.tsx +++ b/web/components/issue-layouts/filters/state-group.tsx @@ -31,51 +31,31 @@ export const StateGroupIcons = ({ if (stateGroup === "cancelled") return (
- +
); if (stateGroup === "completed") return (
- +
); if (stateGroup === "started") return (
- +
); if (stateGroup === "unstarted") return (
- +
); if (stateGroup === "backlog") return (
- +
); return <>; diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index bb56c2f7278..02c1d745e4d 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -9,7 +9,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // store default data -import { issueStateGroupKeys } from "store/issue-views/issue_data"; +import { stateGroups } from "store/issue-views/issue_data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); @@ -28,8 +28,8 @@ export const FilterState = observer(() => { issueFilterStore.handleUserFilter("filters", key, _value); }; - const countAllState = issueStateGroupKeys - .map((_stateGroup) => issueFilterStore?.projectStates?.[_stateGroup].length || 0) + const countAllState = stateGroups + .map((_stateGroup) => issueFilterStore?.projectStates?.[_stateGroup?.key].length || 0) .reduce((sum: number, currentValue: number) => sum + currentValue, 0); console.log("countAllState", countAllState); @@ -43,12 +43,12 @@ export const FilterState = observer(() => { /> {previewEnabled && (
- {issueStateGroupKeys.map( + {stateGroups.map( (_stateGroup) => issueFilterStore?.projectStates && - issueFilterStore?.projectStates[_stateGroup] && - issueFilterStore?.projectStates[_stateGroup].length > 0 && - issueFilterStore?.projectStates[_stateGroup].map((_state: any) => ( + issueFilterStore?.projectStates[_stateGroup?.key] && + issueFilterStore?.projectStates[_stateGroup?.key].length > 0 && + issueFilterStore?.projectStates[_stateGroup?.key].map((_state: any) => ( { : false } onClick={() => handleFilter("state", _state?.id)} - icon={} + icon={} title={_state?.name} /> )) diff --git a/web/components/issue-layouts/helpers/dropdown.tsx b/web/components/issue-layouts/helpers/dropdown.tsx index 988f1050e0c..4e12c2bc0d3 100644 --- a/web/components/issue-layouts/helpers/dropdown.tsx +++ b/web/components/issue-layouts/helpers/dropdown.tsx @@ -21,11 +21,7 @@ export const IssueDropdown = ({ children, title = "Dropdown" }: IIssueDropdown) >
{title}
- {open ? ( - - ) : ( - - )} + {open ? : }
void; } -export const FilterHeader = ({ - title, - isPreviewEnabled, - handleIsPreviewEnabled, -}: IFilterHeader) => ( +export const FilterHeader = ({ title, isPreviewEnabled, handleIsPreviewEnabled }: IFilterHeader) => (
{title}
void; } -export const FilterOption = ({ - isChecked, - icon, - title, - multiple = true, - onClick, -}: IFilterOption) => ( +export const FilterOption = ({ isChecked, icon, title, multiple = true, onClick }: IFilterOption) => (
{ const handleLayoutSectionVisibility = (layout_key: string) => issueFilterStore?.issueView && - issueFilterVisibilityData[ - issueFilterStore?.issueView === "my_issues" ? "my_issues" : "others" - ].layout.includes(layout_key); + issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"].layout.includes( + layout_key + ); const handleLayoutSelection = (_layoutKey: string) => { issueFilterStore.handleUserFilter("display_filters", "layout", _layoutKey); @@ -76,9 +76,7 @@ export const LayoutSelection = observer(() => {
handleLayoutSelection(_layout?.key)} > diff --git a/web/components/issue-layouts/list/group-header.tsx b/web/components/issue-layouts/list/group-header.tsx index 9091ef851fa..ca9ecb1f2a0 100644 --- a/web/components/issue-layouts/list/group-header.tsx +++ b/web/components/issue-layouts/list/group-header.tsx @@ -11,30 +11,20 @@ export interface IIssueListGroupHeader { export const IssueListGroupHeader: FC = (props) => { const { groupId, groupBy } = props; - const { issueView: issueViewStore, issueFilters: issueFilterStore }: RootStore = useMobxStore(); + const { issueFilters: issueFilterStore }: RootStore = useMobxStore(); return (
{groupBy === "state" && <>{issueFilterStore.getProjectStateById(groupId)?.name}} {groupBy === "state_detail.group" && <>{groupId}} {groupBy === "priority" && <>{groupId}} - {groupBy === "project" && ( - <>{issueFilterStore.workspaceProjects?.find((p) => (p.id = groupId))} - )} - {groupBy === "labels" && ( - <>{issueFilterStore.projectLabels?.find((p) => p.id === groupId)?.name || " None"} - )} + {groupBy === "project" && <>{issueFilterStore.workspaceProjects?.find((p) => (p.id = groupId))}} + {groupBy === "labels" && <>{issueFilterStore.projectLabels?.find((p) => p.id === groupId)?.name || " None"}} {groupBy === "assignees" && ( - <> - {issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member - ?.display_name || " None"} - + <>{issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member?.display_name || " None"} )} {groupBy === "created_by" && ( - <> - {issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member - ?.display_name || " None"} - + <>{issueFilterStore.projectMembers?.find((p) => p?.member?.id === groupId)?.member?.display_name || " None"} )}
); diff --git a/web/components/issue-layouts/list/list.tsx b/web/components/issue-layouts/list/list.tsx index 8a858ee6ab8..f06c6234da4 100644 --- a/web/components/issue-layouts/list/list.tsx +++ b/web/components/issue-layouts/list/list.tsx @@ -4,17 +4,11 @@ import { IssueListItem } from "./item"; import { observer } from "mobx-react-lite"; export interface IIssueListView { - issues: IIssue[]; + issues: IIssue[] | null; groupId: string; } export const IssueListView: FC = observer((props) => { const { issues = [], groupId } = props; - return ( -
- {issues.map((issue) => ( - - ))} -
- ); + return
{issues && issues.map((issue) => )}
; }); diff --git a/web/components/issue-layouts/list/root.tsx b/web/components/issue-layouts/list/root.tsx index 5649a522b20..389c13fa16f 100644 --- a/web/components/issue-layouts/list/root.tsx +++ b/web/components/issue-layouts/list/root.tsx @@ -20,7 +20,7 @@ export const IssueListViewRoot = observer(() => {
Loading...
) : ( <> - {Object.keys(issueViewStore?.getIssues).map((groupId) => ( + {Object.keys(issueViewStore?.getIssues).map((groupId: any) => ( {({ open }) => ( <> @@ -31,7 +31,10 @@ export const IssueListViewRoot = observer(() => { /> - + )} diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts index b7aede2a9d4..7303245fc51 100644 --- a/web/store/issue-views/Issues.ts +++ b/web/store/issue-views/Issues.ts @@ -14,11 +14,11 @@ export interface IIssues { } export interface IIssuesLayout { - list: IIssues; - kanban: IIssues; - calendar: IIssues; - spreadsheet: IIssues; - gantt_chart: IIssues; + list: IIssues[]; + kanban: IIssues[]; + calendar: IIssues[]; + spreadsheet: IIssues[]; + gantt_chart: IIssues[]; } export interface IIssueState { @@ -143,14 +143,14 @@ class IssueViewStore implements IIssueViewStore { return null; } - updateIssues = (group_id: string | null, issue_id: string | null, data: any) => { + updateIssues = (group_id: any = null, issue_id: string | null, data: any) => { const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; const currentProjectId: string | null = this.rootStore.issueFilters.projectId; - const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; - const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; - const currentViewId: string | null = this.rootStore.issueFilters.viewId; + // const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; + // const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; + // const currentViewId: string | null = this.rootStore.issueFilters.viewId; const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; - const currentLayout: TIssueLayouts | null | undefined = this.rootStore.issueFilters.issueLayout; + const currentLayout: TIssueLayouts | null = this.rootStore.issueFilters.issueLayout; if (!currentView || !currentWorkspaceId || !currentLayout || !issue_id) return null; @@ -170,7 +170,7 @@ class IssueViewStore implements IIssueViewStore { }, }, }, - }; + } as any; } else { this.issues = { ...this.issues, @@ -183,7 +183,7 @@ class IssueViewStore implements IIssueViewStore { ), }, }, - }; + } as any; } } @@ -210,7 +210,7 @@ class IssueViewStore implements IIssueViewStore { }, }, }, - }; + } as any; } else { this.issues = { ...this.issues, @@ -229,7 +229,7 @@ class IssueViewStore implements IIssueViewStore { }, }, }, - }; + } as any; } } }; diff --git a/web/store/issue-views/issue_data.ts b/web/store/issue-views/issue_data.ts index 11edc4e0bd6..3b127a27248 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/issue-views/issue_data.ts @@ -1,4 +1,6 @@ import { renderDateFormat } from "helpers/date-time.helper"; +// types +import { TIssueLayouts, TIssueParams } from "./issue_filters"; export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; @@ -153,6 +155,83 @@ export const issueFilterVisibilityData: any = { }, }; +export const handleIssueQueryParamsByLayout = (_layout: TIssueLayouts | undefined): TIssueParams[] | null => { + if (_layout === "list") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "group_by", + "order_by", + "type", + "sub_issue", + "show_empty_groups", + ]; + if (_layout === "kanban") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "group_by", + "order_by", + "type", + "sub_issue", + "show_empty_groups", + ]; + if (_layout === "calendar") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "calendar_date_range", + ]; + if (_layout === "spreadsheet") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "sub_issue", + ]; + if (_layout === "gantt_chart") + return [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "order_by", + "type", + "sub_issue", + "start_target_date", + ]; + + return null; +}; + export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => { if (key === "last_week") return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat( diff --git a/web/store/issue-views/issue_detail.ts b/web/store/issue-views/issue_detail.ts index cda0b7bc977..c1dae8222a7 100644 --- a/web/store/issue-views/issue_detail.ts +++ b/web/store/issue-views/issue_detail.ts @@ -143,7 +143,7 @@ class IssueViewDetailStore implements IIssueViewDetailStore { this.rootStore.issueFilters.issueView || "issues" ); const issueResponse = await this.issueService.patchIssue(workspaceId, projectId, issueId, data, undefined); - const issueList = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); + const issueList = (await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams)) as any; console.log("issueList", issueList); if (issueResponse) { diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts index 17beb010881..bfe971b2738 100644 --- a/web/store/issue-views/issue_filters.ts +++ b/web/store/issue-views/issue_filters.ts @@ -1,4 +1,4 @@ -import { observable, action, computed, makeObservable, runInAction, autorun } from "mobx"; +import { observable, action, computed, makeObservable, runInAction } from "mobx"; // types import { RootStore } from "../root"; // services @@ -11,20 +11,22 @@ import { ProjectCycleServices } from "services/cycles.service"; import { ViewServices as ProjectViewServices } from "services/views.service"; // default data import { - filtersPriority, - filterStateGroup, - filtersStartDate, - filtersDueDate, - displayPropertyGroupBy, - displayPropertyOrderBy, - displayPropertyIssueType, + priorities, + stateGroups, + startDateOptions, + dueDateOptions, + groupByOptions, + orderByOptions, + issueTypes, displayProperties, extraProperties, + handleIssueQueryParamsByLayout, } from "./issue_data"; -import { IIssueState } from "./Issues"; export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; + export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; + export type TIssueParams = | "priority" | "state_group" @@ -149,7 +151,6 @@ export interface IIssueFilterStore { error: any | null; // current workspace and project id - myUserId: string | null; workspaceId: string | null; projectId: string | null; moduleId: string | null; @@ -205,13 +206,13 @@ class IssueFilterStore implements IIssueFilterStore { issueView: TIssueViews | null = null; issueRenderFilters: IIssueRenderFilters = { - priority: filtersPriority, - state_group: filterStateGroup, - start_date: filtersStartDate, - due_date: filtersDueDate, - group_by: displayPropertyGroupBy, - order_by: displayPropertyOrderBy, - issue_type: displayPropertyIssueType, + priority: priorities, + state_group: stateGroups, + start_date: startDateOptions, + due_date: dueDateOptions, + group_by: groupByOptions, + order_by: orderByOptions, + issue_type: issueTypes, display_properties: displayProperties, extra_properties: extraProperties, workspace_properties: {}, @@ -235,7 +236,6 @@ class IssueFilterStore implements IIssueFilterStore { loader: observable, error: observable, - myUserId: observable, workspaceId: observable, projectId: observable, moduleId: observable, @@ -311,6 +311,8 @@ class IssueFilterStore implements IIssueFilterStore { this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters ?.layout || null ); + + return null; } get workspaceProjects() { @@ -692,81 +694,8 @@ class IssueFilterStore implements IIssueFilterStore { // in spreadsheet sub issue is false for sure // in gantt start_target_date is true for sure - let filteredParams: TIssueParams[] = []; - if (_layout === "list") - filteredParams = [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "group_by", - "order_by", - "type", - "sub_issue", - "show_empty_groups", - ]; - if (_layout === "kanban") - filteredParams = [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "group_by", - "order_by", - "type", - "sub_issue", - "show_empty_groups", - ]; - if (_layout === "calendar") - filteredParams = [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "type", - "calendar_date_range", - ]; - if (_layout === "spreadsheet") - filteredParams = [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "type", - "sub_issue", - ]; - if (_layout === "gantt_chart") - filteredParams = [ - "priority", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "order_by", - "type", - "sub_issue", - "start_target_date", - ]; - - filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); + const filteredParams: TIssueParams[] | null = handleIssueQueryParamsByLayout(_layout); + if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); return filteredRouteParams; }; @@ -1054,10 +983,10 @@ class IssueFilterStore implements IIssueFilterStore { this.loader = true; this.error = null; + await this.rootStore.user.setCurrentUser(); const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId); if (issuesDisplayPropertiesResponse) { - const _myUserId: string = issuesDisplayPropertiesResponse?.user; const _issuesDisplayPropertiesResponse: any = { ...this.issueFilters, [workspaceId]: { @@ -1076,7 +1005,6 @@ class IssueFilterStore implements IIssueFilterStore { }; runInAction(() => { - this.myUserId = _myUserId; this.issueFilters = _issuesDisplayPropertiesResponse; this.loader = false; this.error = null; @@ -1103,7 +1031,7 @@ class IssueFilterStore implements IIssueFilterStore { const payload = { properties: data, - user: this.myUserId, + user: this.rootStore?.user?.currentUser?.id, }; const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties( workspaceId, diff --git a/web/store/issue-views/project.ts b/web/store/issue-views/project.ts new file mode 100644 index 00000000000..ad7c72b848d --- /dev/null +++ b/web/store/issue-views/project.ts @@ -0,0 +1,21 @@ +import { action, computed, makeObservable } from "mobx"; +// types +import { RootStore } from "../root"; + +export interface IIssueProject {} + +class IssueProject implements IIssueProject { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // computed + // actions + }); + + this.rootStore = _rootStore; + } +} + +export default IssueProject; diff --git a/web/store/issue-views/workspace.ts b/web/store/issue-views/workspace.ts new file mode 100644 index 00000000000..0203e6cfd5b --- /dev/null +++ b/web/store/issue-views/workspace.ts @@ -0,0 +1,21 @@ +import { action, computed, makeObservable } from "mobx"; +// types +import { RootStore } from "../root"; + +export interface IIssueWorkspace {} + +class IssueWorkspace implements IIssueWorkspace { + // root store + rootStore; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // computed + // actions + }); + + this.rootStore = _rootStore; + } +} + +export default IssueWorkspace; diff --git a/web/store/root.ts b/web/store/root.ts index 90a9ef8702c..763ac5e31ca 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -7,6 +7,8 @@ import ProjectStore, { IProjectStore } from "./project"; import ProjectPublishStore, { IProjectPublishStore } from "./project-publish"; import IssuesStore from "./issues"; // issues views and filters +import IssueWorkspace from "./issue-views/workspace"; +import IssueProject from "./issue-views/project"; import IssueFilterStore from "./issue-views/issue_filters"; import IssueViewStore from "./issue-views/Issues"; import IssueViewDetailStore from "./issue-views/issue_detail"; @@ -20,6 +22,9 @@ export class RootStore { project: IProjectStore; projectPublish: IProjectPublishStore; issues: IssuesStore; + // issues views and filters + issueWorkspace: IssueWorkspace; + issueProject: IssueProject; issueFilters: IssueFilterStore; issueView: IssueViewStore; issueDetail: IssueViewDetailStore; @@ -31,6 +36,9 @@ export class RootStore { this.project = new ProjectStore(this); this.projectPublish = new ProjectPublishStore(this); this.issues = new IssuesStore(this); + // issues views and filters + this.issueWorkspace = new IssueWorkspace(this); + this.issueProject = new IssueProject(this); this.issueFilters = new IssueFilterStore(this); this.issueView = new IssueViewStore(this); this.issueDetail = new IssueViewDetailStore(this); From 491592614d1395f57c4b1e7720b7a8537f9cff02 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Wed, 20 Sep 2023 12:22:48 +0530 Subject: [PATCH 023/102] chore: store setup --- .../display-filters/extra-options.tsx | 2 +- .../issue-layouts/display-filters/index.tsx | 2 +- .../issue-layouts/filters-preview/index.tsx | 2 +- .../issue-layouts/filters-preview/state.tsx | 2 +- .../issue-layouts/filters/index.tsx | 2 +- .../issue-layouts/filters/state.tsx | 2 +- .../issue-layouts/layout-selection.tsx | 4 +- web/components/issue-layouts/root.tsx | 37 +- .../workspace-authorization-wrapper.tsx | 4 +- .../[project_slug]/issues.tsx | 19 +- web/services/project.service.ts | 74 +- web/services/workspace.service.ts | 29 +- web/store/cycles.ts | 55 + .../issue_data.ts => helpers/issue-data.ts} | 2 +- web/store/issue-filters.ts | 1085 +++++++++++++ web/store/issue-store.ts | 417 +++++ web/store/issue-views/Issues.ts | 524 ------ web/store/issue-views/issue_filters.ts | 1408 ----------------- web/store/issue-views/project.ts | 21 - web/store/issue-views/workspace.ts | 21 - web/store/{issue-views => }/issue_detail.ts | 2 +- web/store/issues.ts | 33 +- web/store/modules.ts | 55 + web/store/project.ts | 86 - web/store/projects.ts | 309 ++++ web/store/root.ts | 46 +- web/store/views.ts | 55 + web/store/workspaces.ts | 198 +++ 28 files changed, 2289 insertions(+), 2207 deletions(-) create mode 100644 web/store/cycles.ts rename web/store/{issue-views/issue_data.ts => helpers/issue-data.ts} (99%) create mode 100644 web/store/issue-filters.ts create mode 100644 web/store/issue-store.ts delete mode 100644 web/store/issue-views/Issues.ts delete mode 100644 web/store/issue-views/issue_filters.ts delete mode 100644 web/store/issue-views/project.ts delete mode 100644 web/store/issue-views/workspace.ts rename web/store/{issue-views => }/issue_detail.ts (99%) create mode 100644 web/store/modules.ts delete mode 100644 web/store/project.ts create mode 100644 web/store/projects.ts create mode 100644 web/store/views.ts create mode 100644 web/store/workspaces.ts diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index 58cbf193ff4..e4f127627f3 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -8,7 +8,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/issue-views/issue_data"; +import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const FilterExtraOptions = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index c4a81bc3ca8..b8de6e51300 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -11,7 +11,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/issue-views/issue_data"; +import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const DisplayFiltersSelection = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/filters-preview/index.tsx b/web/components/issue-layouts/filters-preview/index.tsx index 03aac5b6634..2ecdc590923 100644 --- a/web/components/issue-layouts/filters-preview/index.tsx +++ b/web/components/issue-layouts/filters-preview/index.tsx @@ -14,7 +14,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/issue-views/issue_data"; +import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const FilterPreview = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/filters-preview/state.tsx b/web/components/issue-layouts/filters-preview/state.tsx index f81e6e29ff7..dd0652e78cb 100644 --- a/web/components/issue-layouts/filters-preview/state.tsx +++ b/web/components/issue-layouts/filters-preview/state.tsx @@ -10,7 +10,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // store default data -import { stateGroups } from "store/issue-views/issue_data"; +import { stateGroups } from "store/helpers/issue-data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/filters/index.tsx b/web/components/issue-layouts/filters/index.tsx index 2512ae042fd..c52cf5be167 100644 --- a/web/components/issue-layouts/filters/index.tsx +++ b/web/components/issue-layouts/filters/index.tsx @@ -14,7 +14,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/issue-views/issue_data"; +import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const FilterSelection = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/filters/state.tsx b/web/components/issue-layouts/filters/state.tsx index 02c1d745e4d..ef59fa0ca72 100644 --- a/web/components/issue-layouts/filters/state.tsx +++ b/web/components/issue-layouts/filters/state.tsx @@ -9,7 +9,7 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // store default data -import { stateGroups } from "store/issue-views/issue_data"; +import { stateGroups } from "store/helpers/issue-data"; export const FilterState = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/layout-selection.tsx b/web/components/issue-layouts/layout-selection.tsx index 5e189085118..32ae742d85d 100644 --- a/web/components/issue-layouts/layout-selection.tsx +++ b/web/components/issue-layouts/layout-selection.tsx @@ -7,8 +7,8 @@ import { observer } from "mobx-react-lite"; import { RootStore } from "store/root"; import { useMobxStore } from "lib/mobx/store-provider"; // types and default data -import { TIssueLayouts } from "store/issue-views/issue_filters"; -import { issueFilterVisibilityData } from "store/issue-views/issue_data"; +import { TIssueLayouts } from "store/issue-filters"; +import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const LayoutSelection = observer(() => { const store: RootStore = useMobxStore(); diff --git a/web/components/issue-layouts/root.tsx b/web/components/issue-layouts/root.tsx index 92cbf54937a..1db144bd982 100644 --- a/web/components/issue-layouts/root.tsx +++ b/web/components/issue-layouts/root.tsx @@ -19,7 +19,42 @@ import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; export const IssuesRoot = observer(() => { - const { issueFilters: issueFilterStore }: RootStore = useMobxStore(); + const { + workspace: workspaceStore, + project: projectStore, + issue: issueStore, + issueFilter: issueFilterStore, + }: RootStore = useMobxStore(); + + // console.log("---"); + // console.log("--- workspace store"); + // console.log("workspaces", workspaceStore?.workspaces); + // console.log("workspace id", workspaceStore?.workspaceId); + // console.log("current workspace", workspaceStore?.currentWorkspace); + // console.log("workspace by id", workspaceStore?.workspaceById("plane")); + // console.log("workspace labels", workspaceStore?.workspaceLabels); + // console.log("workspace label by id", workspaceStore?.workspaceLabelById("1fe1031b-8986-4e6a-86cc-0d2fe3ac272f")); + + // console.log("--- project store"); + // console.log("workspace projects", projectStore?.workspaceProjects); + // console.log("project id", projectStore?.projectId); + // console.log("project state by groups", projectStore?.projectStatesByGroups); + // console.log("project states", projectStore?.projectStates); + // console.log("project labels", projectStore?.projectLabels); + // console.log("project members", projectStore?.projectMembers); + // projectStore?.projectStates && + // console.log("project state by id", projectStore?.projectStateById(projectStore?.projectStates?.[0]?.id)); + // projectStore?.projectLabels && + // console.log("project label by id", projectStore?.projectLabelById(projectStore?.projectLabels?.[0]?.id)); + // projectStore?.projectMembers && + // console.log("project member by id", projectStore?.projectMemberById(projectStore?.projectMembers?.[0]?.id)); + + // console.log("--- issue filter store"); + // console.log("issues filters", issueFilterStore?.issueFilters); + + // console.log("--- issue store"); + // console.log("issues", issueStore?.issues); + // console.log("---"); return (
diff --git a/web/layouts/auth-layout/workspace-authorization-wrapper.tsx b/web/layouts/auth-layout/workspace-authorization-wrapper.tsx index 9d74c91350b..6dbb0cde905 100644 --- a/web/layouts/auth-layout/workspace-authorization-wrapper.tsx +++ b/web/layouts/auth-layout/workspace-authorization-wrapper.tsx @@ -115,9 +115,7 @@ export const WorkspaceAuthorizationLayout: React.FC = ({ noHeader={noHeader} />
-
- {children} -
+
{children}
)} diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx index c068f14f66a..44f143b2257 100644 --- a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx @@ -14,15 +14,26 @@ const KanBanViewRoot = () => { project_slug: string; }; - const store: RootStore = useMobxStore(); - const { issueView: issueViewStore } = store; + const { issue: issueViewStore, workspace: workspaceStore, project: projectStore }: RootStore = useMobxStore(); React.useEffect(() => { console.log("request init--->"); - const init = async () => await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); + const init = async () => { + workspaceStore.setWorkspaceId(workspace_slug); + await workspaceStore.getWorkspaces(); + await workspaceStore.getWorkspaceLabels(workspace_slug); + + projectStore.setProject(project_slug); + await projectStore.getWorkspaceProjects(workspace_slug); + await projectStore.getProjectStates(workspace_slug, project_slug); + await projectStore.getProjectLabels(workspace_slug, project_slug); + await projectStore.getProjectMembers(workspace_slug, project_slug); + + await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); + }; if (workspace_slug && project_slug) init(); console.log("request completed--->"); - }, [workspace_slug, project_slug, issueViewStore]); + }, [workspace_slug, project_slug, issueViewStore, workspaceStore, projectStore]); return (
diff --git a/web/services/project.service.ts b/web/services/project.service.ts index 8f2508b7498..e615457047c 100644 --- a/web/services/project.service.ts +++ b/web/services/project.service.ts @@ -87,11 +87,7 @@ export class ProjectServices extends APIService { }); } - async deleteProject( - workspaceSlug: string, - projectId: string, - user: ICurrentUserResponse | undefined - ): Promise { + async deleteProject(workspaceSlug: string, projectId: string, user: ICurrentUserResponse | undefined): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/`) .then((response) => { trackEventServices.trackProjectEvent({ projectId }, "DELETE_PROJECT", user); @@ -136,11 +132,7 @@ export class ProjectServices extends APIService { }); } - async leaveProject( - workspaceSlug: string, - projectId: string, - user: ICurrentUserResponse - ): Promise { + async leaveProject(workspaceSlug: string, projectId: string, user: ICurrentUserResponse): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/leave/`) .then((response) => { trackEventServices.trackProjectEvent( @@ -175,10 +167,7 @@ export class ProjectServices extends APIService { }); } - async projectMembersWithEmail( - workspaceSlug: string, - projectId: string - ): Promise { + async projectMembersWithEmail(workspaceSlug: string, projectId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/`) .then((response) => response?.data) .catch((error) => { @@ -194,11 +183,7 @@ export class ProjectServices extends APIService { }); } - async getProjectMember( - workspaceSlug: string, - projectId: string, - memberId: string - ): Promise { + async getProjectMember(workspaceSlug: string, projectId: string, memberId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`) .then((response) => response?.data) .catch((error) => { @@ -212,34 +197,22 @@ export class ProjectServices extends APIService { memberId: string, data: Partial ): Promise { - return this.patch( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`, - data - ) + return this.patch(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`, data) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async deleteProjectMember( - workspaceSlug: string, - projectId: string, - memberId: string - ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/` - ) + async deleteProjectMember(workspaceSlug: string, projectId: string, memberId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/members/${memberId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async projectInvitations( - workspaceSlug: string, - projectId: string - ): Promise { + async projectInvitations(workspaceSlug: string, projectId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/`) .then((response) => response?.data) .catch((error) => { @@ -247,10 +220,7 @@ export class ProjectServices extends APIService { }); } - async projectInvitationsWithEmail( - workspaceSlug: string, - projectId: string - ): Promise { + async projectInvitationsWithEmail(workspaceSlug: string, projectId: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/`) .then((response) => response?.data) .catch((error) => { @@ -258,28 +228,16 @@ export class ProjectServices extends APIService { }); } - async updateProjectInvitation( - workspaceSlug: string, - projectId: string, - invitationId: string - ): Promise { - return this.put( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/` - ) + async updateProjectInvitation(workspaceSlug: string, projectId: string, invitationId: string): Promise { + return this.put(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } - async deleteProjectInvitation( - workspaceSlug: string, - projectId: string, - invitationId: string - ): Promise { - return this.delete( - `/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/` - ) + async deleteProjectInvitation(workspaceSlug: string, projectId: string, invitationId: string): Promise { + return this.delete(`/api/workspaces/${workspaceSlug}/projects/${projectId}/invitations/${invitationId}/`) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; @@ -332,11 +290,7 @@ export class ProjectServices extends APIService { }); } - async getProjectGithubRepository( - workspaceSlug: string, - projectId: string, - integrationId: string - ): Promise { + async getProjectGithubRepository(workspaceSlug: string, projectId: string, integrationId: string): Promise { return this.get( `/api/workspaces/${workspaceSlug}/projects/${projectId}/workspace-integrations/${integrationId}/github-repository-sync/` ) diff --git a/web/services/workspace.service.ts b/web/services/workspace.service.ts index a07345522c5..a9a8c4595f7 100644 --- a/web/services/workspace.service.ts +++ b/web/services/workspace.service.ts @@ -37,10 +37,7 @@ export class WorkspaceService extends APIService { }); } - async createWorkspace( - data: Partial, - user: ICurrentUserResponse | undefined - ): Promise { + async createWorkspace(data: Partial, user: ICurrentUserResponse | undefined): Promise { return this.post("/api/workspaces/", data) .then((response) => { trackEventServices.trackWorkspaceEvent(response.data, "CREATE_WORKSPACE", user); @@ -66,10 +63,7 @@ export class WorkspaceService extends APIService { }); } - async deleteWorkspace( - workspaceSlug: string, - user: ICurrentUserResponse | undefined - ): Promise { + async deleteWorkspace(workspaceSlug: string, user: ICurrentUserResponse | undefined): Promise { return this.delete(`/api/workspaces/${workspaceSlug}/`) .then((response) => { trackEventServices.trackWorkspaceEvent({ workspaceSlug }, "DELETE_WORKSPACE", user); @@ -101,13 +95,9 @@ export class WorkspaceService extends APIService { data: any, user: ICurrentUserResponse | undefined ): Promise { - return this.post( - `/api/users/me/invitations/workspaces/${workspaceSlug}/${invitationId}/join/`, - data, - { - headers: {}, - } - ) + return this.post(`/api/users/me/invitations/workspaces/${workspaceSlug}/${invitationId}/join/`, data, { + headers: {}, + }) .then((response) => { trackEventServices.trackWorkspaceEvent(response.data, "WORKSPACE_USER_INVITE_ACCEPT", user); return response?.data; @@ -165,10 +155,7 @@ export class WorkspaceService extends APIService { }); } - async updateWorkspaceView( - workspaceSlug: string, - data: { view_props: IWorkspaceViewProps } - ): Promise { + async updateWorkspaceView(workspaceSlug: string, data: { view_props: IWorkspaceViewProps }): Promise { return this.post(`/api/workspaces/${workspaceSlug}/workspace-views/`, data) .then((response) => response?.data) .catch((error) => { @@ -204,9 +191,7 @@ export class WorkspaceService extends APIService { }); } - async workspaceInvitationsWithEmail( - workspaceSlug: string - ): Promise { + async workspaceInvitationsWithEmail(workspaceSlug: string): Promise { return this.get(`/api/workspaces/${workspaceSlug}/invitations/`) .then((response) => response?.data) .catch((error) => { diff --git a/web/store/cycles.ts b/web/store/cycles.ts new file mode 100644 index 00000000000..90f1395789d --- /dev/null +++ b/web/store/cycles.ts @@ -0,0 +1,55 @@ +import { action, computed, observable, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as IssueServices } from "services/issues.service"; + +export interface ICycleStore { + loader: boolean; + error: any | null; + + cycleId: string | null; + + setCycleId: (cycleSlug: string) => void; +} + +class CycleStore implements ICycleStore { + loader: boolean = false; + error: any | null = null; + + cycleId: string | null = null; + + // root store + rootStore; + // services + projectService; + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + loader: observable, + error: observable.ref, + + cycleId: observable.ref, + + // computed + + // actions + setCycleId: action, + }); + + this.rootStore = _rootStore; + this.projectService = new ProjectServices(); + this.issueService = new IssueServices(); + } + + // computed + + // actions + setCycleId = (cycleSlug: string) => { + this.cycleId = cycleSlug ?? null; + }; +} + +export default CycleStore; diff --git a/web/store/issue-views/issue_data.ts b/web/store/helpers/issue-data.ts similarity index 99% rename from web/store/issue-views/issue_data.ts rename to web/store/helpers/issue-data.ts index 3b127a27248..cd84b5c17d7 100644 --- a/web/store/issue-views/issue_data.ts +++ b/web/store/helpers/issue-data.ts @@ -1,6 +1,6 @@ import { renderDateFormat } from "helpers/date-time.helper"; // types -import { TIssueLayouts, TIssueParams } from "./issue_filters"; +import { TIssueLayouts, TIssueParams } from "../issue-filters"; export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; diff --git a/web/store/issue-filters.ts b/web/store/issue-filters.ts new file mode 100644 index 00000000000..203e836460c --- /dev/null +++ b/web/store/issue-filters.ts @@ -0,0 +1,1085 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services +import { WorkspaceService } from "services/workspace.service"; +import { ProjectIssuesServices } from "services/issues.service"; +import { ProjectStateServices } from "services/state.service"; +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; +import { ProjectCycleServices } from "services/cycles.service"; +import { ViewServices as ProjectViewServices } from "services/views.service"; +// default data +import { + priorities, + stateGroups, + startDateOptions, + dueDateOptions, + groupByOptions, + orderByOptions, + issueTypes, + displayProperties, + extraProperties, + handleIssueQueryParamsByLayout, +} from "./helpers/issue-data"; + +export type TIssueViews = "issues" | "modules" | "views" | "cycles"; +export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; +export type TIssueParams = + | "priority" + | "state_group" + | "state" + | "assignees" + | "created_by" + | "labels" + | "start_date" + | "target_date" + | "group_by" + | "order_by" + | "type" + | "sub_issue" + | "show_empty_groups" + | "calendar_date_range" + | "start_target_date"; + +export interface IIssueFilter { + priority: string[] | undefined; + state_group: string[] | undefined; + state: string[] | undefined; + assignees: string[] | undefined; + created_by: string[] | undefined; + labels: string[] | undefined; + start_date: string[] | undefined; + target_date: string[] | undefined; + [key: string]: any; +} + +export interface IIssueDisplayFilters { + group_by: undefined | string; + order_by: undefined | string; + type: string | undefined; + sub_issue: boolean; + show_empty_groups: boolean; + layout: TIssueLayouts; + calendar_date_range: string | undefined; // only for calendar + start_target_date: boolean; + [key: string]: any; +} + +export interface IIssueDisplayProperties { + assignee: boolean; + attachment_count: boolean; + created_on: boolean; + due_date: boolean; + estimate: boolean; + key: boolean; + labels: boolean; + link: boolean; + priority: boolean; + start_date: boolean; + state: boolean; + sub_issue_count: boolean; + updated_on: boolean; + [key: string]: any; +} + +export interface IIssueFilters { + // project_id + [key: string]: { + issues: { + // project_id + [key: string]: { + filters: IIssueFilter; + }; + }; + cycles: { + // cycle_id + [key: string]: { + filters: IIssueFilter; + }; + }; + modules: { + // module_id + [key: string]: { + filters: IIssueFilter; + }; + }; + views: { + // view_id + [key: string]: { + filters: IIssueFilter; + }; + }; + display_filters: IIssueDisplayFilters; + display_properties_id: string; + display_properties: IIssueDisplayProperties; + }; +} + +export interface IIssueFilterStore { + // static data + priorities: { key: string; title: string }[]; + stateGroups: { key: string; title: string }[]; + startDateOptions: { key: string; title: string }[]; + dueDateOptions: { key: string; title: string }[]; + groupByOptions: { key: string; title: string }[]; + orderByOptions: { key: string; title: string }[]; + issueTypes: { key: string; title: string }[]; + displayProperties: { key: string; title: string }[]; + extraProperties: { key: string; title: string }[]; + + loader: boolean; + error: any | null; + + // current workspace and project id + issueView: TIssueViews | null; + issueFilters: IIssueFilters; + + // actions + // getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; + // updateWorkspaceMyIssuesFilters: (workspaceId: string, data: any) => Promise; + + getProjectDisplayProperties: (workspaceId: string, projectId: string) => Promise; + updateProjectDisplayProperties: ( + workspaceId: string, + projectId: string, + display_properties_id: string, + data: any + ) => Promise; + getProjectDisplayFilters: (workspaceId: string, projectId: string) => Promise; + updateProjectDisplayFilters: (workspaceId: string, projectId: string, data: any) => Promise; + + getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise; + + getProjectIssueModuleFilters: (workspaceId: string, projectId: string, moduleId: string) => Promise; + updateProjectIssueModuleFilters: ( + workspaceId: string, + projectId: string, + moduleId: string, + data: any + ) => Promise; + getProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string) => Promise; + updateProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string, data: any) => Promise; + getProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string) => Promise; + updateProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string, data: any) => Promise; +} + +class IssueFilterStore implements IIssueFilterStore { + // static data + priorities: { key: string; title: string }[] = priorities; + stateGroups: { key: string; title: string }[] = stateGroups; + startDateOptions: { key: string; title: string }[] = startDateOptions; + dueDateOptions: { key: string; title: string }[] = dueDateOptions; + groupByOptions: { key: string; title: string }[] = groupByOptions; + orderByOptions: { key: string; title: string }[] = orderByOptions; + issueTypes: { key: string; title: string }[] = issueTypes; + displayProperties: { key: string; title: string }[] = displayProperties; + extraProperties: { key: string; title: string }[] = extraProperties; + + loader: boolean = false; + error: any | null = null; + + // workspaceId: string | null = null; + // projectId: string | null = null; + // moduleId: string | null = null; + // cycleId: string | null = null; + // viewId: string | null = null; + + issueView: TIssueViews | null = null; + + issueFilters: IIssueFilters = {}; + + // root store + rootStore; + // service + workspaceService; + issueService; + stateService; + projectService; + moduleService; + cycleService; + viewService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + issueView: observable, + + issueFilters: observable.ref, + + // computed + issueLayout: computed, + projectDisplayProperties: computed, + userFilters: computed, + + // actions + getComputedFilters: action, + + handleUserFilter: action, + + // getWorkspaceMyIssuesFilters: action, + // updateWorkspaceMyIssuesFilters: action, + + getProjectDisplayFilters: action, + updateProjectDisplayFilters: action, + + getProjectDisplayProperties: action, + updateProjectDisplayProperties: action, + + getProjectIssueFilters: action, + + getProjectIssueModuleFilters: action, + updateProjectIssueModuleFilters: action, + + getProjectIssueCyclesFilters: action, + updateProjectIssueCyclesFilters: action, + + getProjectIssueViewsFilters: action, + updateProjectIssueViewsFilters: action, + }); + + this.rootStore = _rootStore; + this.workspaceService = new WorkspaceService(); + this.issueService = new ProjectIssuesServices(); + this.stateService = new ProjectStateServices(); + this.projectService = new ProjectServices(); + this.moduleService = new ProjectModuleServices(); + this.cycleService = new ProjectCycleServices(); + this.viewService = new ProjectViewServices(); + } + + // computed + get issueLayout() { + // if (!this.projectId) return null; + // if (!this.projectId) + // return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout || null; + // if (this.projectId) + // return ( + // this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters + // ?.layout || null + // ); + + return null; + } + + get projectDisplayProperties() { + // if (!this.workspaceId || !this.projectId) return null; + // return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties as any; + + return null; + } + + get userFilters() { + if (!this.projectId) return null; + if (this.issueView === "my_issues") + return { + ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, + display_properties_id: null, + }; + + if (!this.projectId) return null; + let _issueFilters: { + filters: IIssueFilter | null; + display_filters: IIssueDisplayFilters; + display_properties_id: string; + display_properties: IIssueDisplayProperties; + } = { + filters: null, + display_filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters, + display_properties_id: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties_id, + display_properties: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties, + }; + + if (this.issueView === "issues") { + _issueFilters = { + ..._issueFilters, + filters: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.filters, + }; + return _issueFilters; + } + + if (this.issueView === "modules" && this.moduleId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[this.moduleId] + ?.filters, + }; + return _issueFilters; + } + + if (this.issueView === "cycles" && this.cycleId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[this.cycleId] + ?.filters, + }; + return _issueFilters; + } + + if (this.issueView === "views" && this.viewId) { + _issueFilters = { + ..._issueFilters, + filters: + this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[this.viewId] + ?.filters, + }; + return _issueFilters; + } + + return null; + } + handleUserFilter = ( + filter_type: "filters" | "display_filters" | "display_properties", + filter_key: string, + value: any + ) => { + // if (!this.workspaceId) return null; + // if (this.issueView === "my_issues") { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // my_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.my_issue_properties?.[filter_type], + // [filter_key]: value, + // }, + // }, + // }, + // }; + // this.updateWorkspaceMyIssuesFilters(this.workspaceId, this.userFilters); + // } + // if (!this.projectId) return null; + // if (filter_type === "display_properties") { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // display_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] + // ?.display_properties, + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }; + // if (this.userFilters?.display_properties_id) { + // this.updateProjectDisplayProperties( + // this.workspaceId, + // this.projectId, + // this.userFilters?.display_properties_id, + // this.userFilters?.display_properties + // ); + // } + // } + // if (filter_type === "display_filters") { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // issues: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ + // filter_type + // ], + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }, + // }; + // this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { + // filters: this.userFilters?.filters, + // display_filters: this.userFilters?.display_filters, + // }); + // } + // if (filter_type === "filters") { + // if (this.issueView === "issues") { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // issues: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ + // filter_type + // ], + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }, + // }; + // this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { + // filters: this.userFilters?.filters, + // display_filters: this.userFilters?.display_filters, + // }); + // } + // if (this.issueView === "modules" && this.moduleId) { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // modules: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules, + // [this.moduleId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ + // this.moduleId + // ], + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ + // this.moduleId + // ]?.[filter_type], + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }, + // }, + // }; + // this.updateProjectIssueModuleFilters( + // this.workspaceId, + // this.projectId, + // this.moduleId, + // this.userFilters?.filters + // ); + // } + // if (this.issueView === "cycles" && this.cycleId) { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // cycles: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles, + // [this.cycleId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ + // this.cycleId + // ], + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ + // this.cycleId + // ]?.[filter_type], + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }, + // }, + // }; + // this.updateProjectIssueCyclesFilters(this.workspaceId, this.projectId, this.cycleId, this.userFilters?.filters); + // } + // if (this.issueView === "views" && this.viewId) { + // this.issueFilters = { + // ...this.issueFilters, + // [this.workspaceId]: { + // ...this.issueFilters?.[this.workspaceId], + // project_issue_properties: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, + // [this.projectId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], + // views: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views, + // [this.viewId]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ + // this.viewId + // ], + // [filter_type]: { + // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ + // this.viewId + // ]?.[filter_type], + // [filter_key]: value, + // }, + // }, + // }, + // }, + // }, + // }, + // }; + // this.updateProjectIssueViewsFilters(this.workspaceId, this.projectId, this.viewId, this.userFilters?.filters); + // } + // } + // if (this.issueView === "my_issues") + // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + // if (this.issueView === "issues") + // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + // if (this.issueView === "modules" && this.moduleId) + // this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); + // if (this.issueView === "cycles" && this.cycleId) + // this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); + // if (this.issueView === "views" && this.viewId) + // this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); + }; + + computedFilter = (filters: any, filteredParams: any) => { + const computedFilters: any = {}; + Object.keys(filters).map((key) => { + if (filters[key] != undefined && filteredParams.includes(key)) + computedFilters[key] = + typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(","); + }); + + return computedFilters; + }; + getComputedFilters = ( + _workspaceId: string | null, + _projectId: string | null, + _moduleId: string | null, + _cycleId: string | null, + _viewId: string | null, + _issueView: TIssueViews + ) => { + this.issueView = _issueView; + + // const _layout = this.userFilters?.display_filters?.layout; + const _layout = ""; + + let filteredRouteParams: any = { + // priority: this.userFilters?.filters?.priority || undefined, + // state_group: this.userFilters?.filters?.state_group || undefined, + // state: this.userFilters?.filters?.state || undefined, + // assignees: this.userFilters?.filters?.assignees || undefined, + // created_by: this.userFilters?.filters?.created_by || undefined, + // labels: this.userFilters?.filters?.labels || undefined, + // start_date: this.userFilters?.filters?.start_date || undefined, + // target_date: this.userFilters?.filters?.target_date || undefined, + // group_by: this.userFilters?.display_filters?.group_by || "state", + // order_by: this.userFilters?.display_filters?.order_by || "-created_at", + // type: this.userFilters?.display_filters?.type || undefined, + // sub_issue: this.userFilters?.display_filters?.sub_issue || true, + // show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, + // calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, + // start_target_date: this.userFilters?.display_filters?.start_target_date || true, + }; + + // start date and target date we have to construct the format here + // in calendar view calendar_date_range send as target_date + // in spreadsheet sub issue is false for sure + // in gantt start_target_date is true for sure + + const filteredParams: TIssueParams[] | null = handleIssueQueryParamsByLayout(_layout); + if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); + + return filteredRouteParams; + }; + + handleIssueFilter = ( + filter_type: "filters" | "display_filters" | "display_properties" | "display_properties_id", + value: any + ) => { + const projectId = this.rootStore?.project?.projectId || null; + const moduleId = this.rootStore?.module?.moduleId || null; + const cycleId = this.rootStore?.cycle?.cycleId || null; + const viewId = this.rootStore?.view?.viewId || null; + const currentView = this.issueView || null; + + console.log("filter_type", filter_type); + console.log("value", value); + + if (!currentView || !projectId || !moduleId || !cycleId || !viewId) return null; + + // let _issueFilters: IIssueFilters = { + // ...this.issueFilters, + // [workspaceId]: { + // ...this.issueFilters?.[workspaceId], + // }, + // }; + + // console.log("_issueFilters", _issueFilters); + }; + + // services + // getWorkspaceMyIssuesFilters = async (workspaceId: string) => { + // try { + // this.loader = true; + // this.error = null; + + // const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); + // if (issuesFiltersResponse) { + // const _issuesFiltersResponse: any = { + // ...this.issueFilters, + // [workspaceId]: { + // ...this?.issueFilters?.[workspaceId], + // my_issue_properties: { + // ...this?.issueFilters?.[workspaceId]?.my_issue_properties, + // filters: { + // priority: issuesFiltersResponse?.view_props?.filters?.priority ?? null, + // state: issuesFiltersResponse?.view_props?.filters?.state ?? null, + // state_group: issuesFiltersResponse?.view_props?.filters?.state_group ?? null, + // assignees: issuesFiltersResponse?.view_props?.filters?.assignees ?? null, + // created_by: issuesFiltersResponse?.view_props?.filters?.created_by ?? null, + // labels: issuesFiltersResponse?.view_props?.filters?.labels ?? null, + // start_date: issuesFiltersResponse?.view_props?.filters?.start_date ?? null, + // target_date: issuesFiltersResponse?.view_props?.filters?.target_date ?? null, + // subscriber: issuesFiltersResponse?.view_props?.filters?.subscriber ?? null, + // }, + // display_filters: { + // group_by: issuesFiltersResponse?.view_props?.display_filters?.group_by ?? null, + // order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null, + // type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null, + // sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false, + // show_empty_groups: issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, + // layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list", + // calendar_date_range: issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, + // start_target_date: issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, + // }, + // display_properties: { + // assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false, + // attachment_count: issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, + // created_on: issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, + // due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false, + // estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false, + // key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false, + // labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false, + // link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false, + // priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false, + // start_date: issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, + // state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false, + // sub_issue_count: issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, + // updated_on: issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, + // }, + // }, + // }, + // }; + // runInAction(() => { + // this.issueFilters = _issuesFiltersResponse; + // this.loader = false; + // this.error = null; + // }); + // } + // return issuesFiltersResponse; + // } catch (error) { + // console.warn("error in fetching workspace level filters", error); + // this.loader = false; + // this.error = null; + // + // } + // }; + // updateWorkspaceMyIssuesFilters = async (workspaceId: string, data: any) => { + // try { + // this.loader = true; + // this.error = null; + + // const payload = { + // view_props: data, + // }; + // const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView(workspaceId, payload); + + // if (issuesFiltersResponse) { + // runInAction(() => { + // this.loader = false; + // this.error = null; + // }); + // } + // } catch (error) { + // console.warn("error in fetching workspace level issue filters", error); + // this.loader = false; + // this.error = null; + // + // } + // }; + + getProjectDisplayProperties = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + await this.rootStore.user.setCurrentUser(); + const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId); + + if (issuesDisplayPropertiesResponse) { + const _issuesDisplayPropertiesResponse: any = { + ...this.issueFilters, + [projectId]: { + ...this?.issueFilters?.[projectId], + display_properties_id: issuesDisplayPropertiesResponse?.id, + display_properties: { + ...issuesDisplayPropertiesResponse?.properties, + }, + }, + }; + + runInAction(() => { + this.issueFilters = _issuesDisplayPropertiesResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesDisplayPropertiesResponse; + } catch (error) { + console.warn("error in fetching project level display properties", error); + this.loader = false; + this.error = null; + } + }; + updateProjectDisplayProperties = async ( + workspaceId: string, + projectId: string, + display_properties_id: string, + data: any + ) => { + try { + this.loader = true; + this.error = null; + + const payload = { + properties: data, + user: this.rootStore?.user?.currentUser?.id, + }; + const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties( + workspaceId, + projectId, + display_properties_id, + payload + ); + + if (issuesDisplayPropertiesResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + + return issuesDisplayPropertiesResponse; + } catch (error) { + console.warn("error in fetching project level display properties", error); + this.loader = false; + this.error = null; + } + }; + + getProjectDisplayFilters = async (workspaceId: string, projectId: string) => { + try { + this.loader = true; + this.error = null; + + const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe(workspaceId, projectId); + + if (issuesDisplayFiltersResponse) { + const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters }; + const _displayFilters = { ...issuesDisplayFiltersResponse?.view_props?.display_filters }; + + const _issuesDisplayFiltersResponse: any = { + ...this.issueFilters, + [projectId]: { + ...this?.issueFilters?.[projectId], + issues: { + ...this?.issueFilters?.[projectId]?.issues, + filters: _filters, + }, + display_filters: _displayFilters, + }, + }; + + console.log("_issuesDisplayFiltersResponse", _issuesDisplayFiltersResponse); + + runInAction(() => { + this.issueFilters = _issuesDisplayFiltersResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesDisplayFiltersResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + updateProjectDisplayFilters = async (workspaceId: string, projectId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const payload: any = { + view_props: data, + }; + const issuesFiltersResponse = await this.projectService.setProjectView(workspaceId, projectId, payload); + + if (issuesFiltersResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + + return issuesFiltersResponse; + } catch (error) { + this.getProjectDisplayFilters(workspaceId, projectId); + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + + getProjectIssueFilters = async (workspaceId: string, projectId: string) => { + try { + await this.getProjectDisplayProperties(workspaceId, projectId); + await this.getProjectDisplayFilters(workspaceId, projectId); + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + } + }; + + getProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string) => { + try { + this.loader = true; + this.error = null; + + await this.getProjectIssueFilters(workspaceId, projectId); + const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails(workspaceId, projectId, moduleId); + if (issuesFiltersModuleResponse) { + const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters }; + const _issuesFiltersModuleResponse = { + ...this.issueFilters, + [projectId]: { + ...this?.issueFilters?.[projectId], + modules: { + ...this?.issueFilters?.[projectId]?.modules, + [moduleId]: { + ...this?.issueFilters?.[projectId]?.modules?.[moduleId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueFilters = _issuesFiltersModuleResponse as any; + this.loader = false; + this.error = null; + }); + } + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + updateProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const payload = { + view_props: { filters: data }, + }; + const issuesFiltersModuleResponse = await this.moduleService.patchModule( + workspaceId, + projectId, + moduleId, + payload, + undefined // TODO: replace this with user + ); + + if (issuesFiltersModuleResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + } catch (error) { + this.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + + getProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string) => { + try { + this.loader = true; + this.error = null; + + await this.getProjectIssueFilters(workspaceId, projectId); + const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails(workspaceId, projectId, cycleId); + if (issuesFiltersCycleResponse) { + const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters }; + const _issuesFiltersCycleResponse = { + ...this.issueFilters, + [projectId]: { + ...this?.issueFilters?.[projectId], + cycles: { + ...this?.issueFilters?.[projectId]?.cycles, + [cycleId]: { + ...this?.issueFilters?.[projectId]?.modules?.[cycleId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueFilters = _issuesFiltersCycleResponse as any; + this.loader = false; + this.error = null; + }); + } + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + updateProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const payload = { + view_props: { filters: data }, + }; + const issuesFiltersCycleResponse = await this.cycleService.patchCycle( + workspaceId, + projectId, + cycleId, + payload, + undefined // TODO: replace this with user + ); + + if (issuesFiltersCycleResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + } catch (error) { + this.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + + getProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string) => { + try { + this.loader = true; + this.error = null; + + await this.getProjectIssueFilters(workspaceId, projectId); + const issuesFiltersViewResponse = await this.viewService.getViewDetails(workspaceId, projectId, viewId); + if (issuesFiltersViewResponse) { + const _filters = { ...issuesFiltersViewResponse?.query_data } as any; + const _issuesFiltersViewResponse = { + ...this.issueFilters, + [projectId]: { + ...this?.issueFilters?.[projectId], + views: { + ...this?.issueFilters?.[projectId]?.views, + [viewId]: { + ...this?.issueFilters?.[projectId]?.modules?.[viewId], + filters: { + priority: _filters?.priority ?? undefined, + state: _filters?.state ?? undefined, + state_group: _filters?.state_group ?? undefined, + assignees: _filters?.assignees ?? undefined, + created_by: _filters?.created_by ?? undefined, + labels: _filters?.labels ?? undefined, + start_date: _filters?.start_date ?? undefined, + target_date: _filters?.target_date ?? undefined, + }, + }, + }, + }, + }; + + runInAction(() => { + this.issueFilters = _issuesFiltersViewResponse as any; + this.loader = false; + this.error = null; + }); + } + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; + updateProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string, data: any) => { + try { + this.loader = true; + this.error = null; + + const payload = { + query_data: data, + }; + const issuesFiltersViewResponse = await this.viewService.patchView( + workspaceId, + projectId, + viewId, + payload, + undefined // TODO: replace this with user + ); + + if (issuesFiltersViewResponse) { + runInAction(() => { + this.loader = false; + this.error = null; + }); + } + + return issuesFiltersViewResponse; + } catch (error) { + console.warn("error in fetching workspace level issue filters", error); + this.loader = false; + this.error = null; + } + }; +} + +export default IssueFilterStore; diff --git a/web/store/issue-store.ts b/web/store/issue-store.ts new file mode 100644 index 00000000000..e28d748f909 --- /dev/null +++ b/web/store/issue-store.ts @@ -0,0 +1,417 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services +import { UserService } from "services/user.service"; +import { ProjectIssuesServices } from "services/issues.service"; +import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; +import { ProjectCycleServices } from "services/cycles.service"; +// types +import { TIssueLayouts, TIssueViews } from "./issue-filters"; + +export interface IIssues { + [key: string]: any; +} + +export interface IIssuesLayout { + list: IIssues[]; + kanban: IIssues[]; + calendar: IIssues[]; + spreadsheet: IIssues[]; + gantt_chart: IIssues[]; +} + +export interface IIssueState { + [key: string]: { + // project_id: layout_view + issues: { + [key: string]: IIssuesLayout; // project_id: layout_key: ...issues, It's always one project id here + }; + cycles: { + [key: string]: IIssuesLayout; // cycle_id: layout_key: ...issues + }; + modules: { + [key: string]: IIssuesLayout; // module_id: layout_key: ...issues + }; + views: { + [key: string]: IIssuesLayout; // view_id: layout_key: ...issues + }; + }; +} + +export interface IIssueStore { + loader: boolean; + error: any | null; + issues: IIssueState; + // computed + getIssues: IIssues | null | undefined; + // actions + updateIssues: (data: any) => void; + getProjectIssuesAsync: (workspaceId: string, projectId: string, fetchFilterToggle?: boolean) => null | Promise; + getIssuesForModulesAsync: ( + workspaceId: string, + projectId: string, + moduleId: string, + fetchFilterToggle: boolean + ) => null | Promise; + getIssuesForCyclesAsync: ( + workspaceId: string, + projectId: string, + cycleId: string, + fetchFilterToggle: boolean + ) => null | Promise; + getIssuesForViewsAsync: ( + workspaceId: string, + projectId: string, + viewId: string, + fetchFilterToggle: boolean + ) => null | Promise; +} + +class IssueStore implements IIssueStore { + loader: boolean = false; + error: any | null = null; + issues: IIssueState = {}; + // root store + rootStore; + // service + issueService; + userService; + modulesService; + cyclesService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + issues: observable.ref, + // computed + getIssues: computed, + // action + updateIssues: action, + getProjectIssuesAsync: action, + getIssuesForModulesAsync: action, + getIssuesForCyclesAsync: action, + getIssuesForViewsAsync: action, + }); + + this.rootStore = _rootStore; + this.issueService = new ProjectIssuesServices(); + this.userService = new UserService(); + this.modulesService = new ProjectModuleServices(); + this.cyclesService = new ProjectCycleServices(); + } + + // computed + get getIssues() { + if (this.issues != null) { + const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView; + const projectId: string | null = this.rootStore.project.projectId; + const moduleId: string | null = this.rootStore.module.moduleId; + const cycleId: string | null = this.rootStore.cycle.cycleId; + const viewId: string | null = this.rootStore.view.viewId; + const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout; + + if (!issueView || !projectId) return null; + + const currentViewIdIndex: string | null = + issueView === "issues" && projectId + ? projectId + : issueView === "modules" && moduleId + ? moduleId + : issueView === "cycles" && cycleId + ? cycleId + : issueView === "cycles" && viewId + ? viewId + : null; + + if (!issueLayout || !currentViewIdIndex) return null; + return this.issues[projectId][issueView][currentViewIdIndex][issueLayout]; + } + + return null; + } + + updateIssues = (data: any) => { + const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView; + const projectId: string | null = this.rootStore.project.projectId; + const moduleId: string | null = this.rootStore.module.moduleId; + const cycleId: string | null = this.rootStore.cycle.cycleId; + const viewId: string | null = this.rootStore.view.viewId; + const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout; + + const { groupId, issueId, issueData } = data as { + groupId?: any; + issueId: string | null; + issueData: any; + }; + + if (!issueView || !projectId) return null; + + const currentViewIdIndex: string | null = + issueView === "issues" && projectId + ? projectId + : issueView === "modules" && moduleId + ? moduleId + : issueView === "cycles" && cycleId + ? cycleId + : issueView === "cycles" && viewId + ? viewId + : null; + + if (!issueLayout || !currentViewIdIndex) return null; + + let _issues = this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout]; + if (groupId && groupId != null && ["list", "kanban"].includes(issueLayout)) { + _issues = { + ..._issues, + [groupId]: + _issues?.[groupId] && _issues?.[groupId].length > 0 + ? _issues?.[groupId]?.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item })) + : [], + }; + } else { + _issues = { + ..._issues, + ..._issues.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item })), + }; + } + + this.issues = { + ...this.issues, + [projectId]: { + ...this?.issues?.[projectId], + [issueView]: { + ...this?.issues?.[projectId]?.[issueView], + [currentViewIdIndex]: { + ...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex], + [issueLayout]: { + ...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout], + ..._issues, + }, + }, + }, + }, + }; + }; + + // fetching project issues + getProjectIssuesAsync = async (workspaceId: string, projectId: string, fetchFilterToggle: boolean = true) => { + try { + this.loader = true; + this.error = null; + + if (fetchFilterToggle) await this.rootStore.issueFilter.getProjectIssueFilters(workspaceId, projectId); + // const filteredParams = this.rootStore.issueFilter.getComputedFilters( + // workspaceId, + // projectId, + // null, + // null, + // null, + // "issues" + // ); + // const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); + + // if (issuesResponse) { + // const _issueResponse: any = { + // ...this.issues, + // [projectId]: { + // ...this?.issues?.[projectId], + // issues: { + // ...this?.issues?.[projectId]?.issues, + // [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, + // }, + // }, + // }; + + // runInAction(() => { + // this.issues = _issueResponse; + // this.loader = false; + // this.error = null; + // }); + // } + + // return issuesResponse; + } catch (error) { + console.warn("error in fetching the project issues", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for modules + getIssuesForModulesAsync = async ( + workspaceId: string, + projectId: string, + moduleId: string, + fetchFilterToggle: boolean = true + ) => { + try { + this.loader = true; + this.error = null; + + if (fetchFilterToggle) + await this.rootStore.issueFilter.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); + const filteredParams = this.rootStore.issueFilter.getComputedFilters( + workspaceId, + projectId, + moduleId, + null, + null, + "modules" + ); + const issuesResponse = await this.modulesService.getModuleIssuesWithParams( + workspaceId, + projectId, + moduleId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [projectId]: { + ...this?.issues?.[projectId], + modules: { + ...this?.issues?.[projectId]?.modules, + [moduleId]: { + ...this?.issues?.[projectId]?.modules?.[moduleId], + [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error in fetching the project module issues", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for cycles + getIssuesForCyclesAsync = async ( + workspaceId: string, + projectId: string, + cycleId: string, + fetchFilterToggle: boolean = true + ) => { + try { + this.loader = true; + this.error = null; + + if (fetchFilterToggle) + await this.rootStore.issueFilter.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); + const filteredParams = this.rootStore.issueFilter.getComputedFilters( + workspaceId, + projectId, + null, + cycleId, + null, + "cycles" + ); + const issuesResponse = await this.cyclesService.getCycleIssuesWithParams( + workspaceId, + projectId, + cycleId, + filteredParams + ); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [projectId]: { + ...this?.issues?.[projectId], + cycles: { + ...this?.issues?.[projectId]?.cycles, + [cycleId]: { + ...this?.issues?.[projectId]?.cycles?.[cycleId], + [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error in fetching the project cycles issues", error); + this.loader = false; + this.error = null; + return error; + } + }; + + // fetching project issues for views + getIssuesForViewsAsync = async ( + workspaceId: string, + projectId: string, + viewId: string, + fetchFilterToggle: boolean = true + ) => { + try { + this.loader = true; + this.error = null; + + if (fetchFilterToggle) + await this.rootStore.issueFilter.getProjectIssueViewsFilters(workspaceId, projectId, viewId); + const filteredParams = this.rootStore.issueFilter.getComputedFilters( + workspaceId, + projectId, + null, + null, + viewId, + "views" + ); + const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); + + if (issuesResponse) { + const _issueResponse: any = { + ...this.issues, + [projectId]: { + ...this?.issues?.[projectId], + views: { + ...this?.issues?.[projectId]?.views, + [viewId]: { + ...this?.issues?.[projectId]?.views?.[viewId], + [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, + }, + }, + }, + }; + + runInAction(() => { + this.issues = _issueResponse; + this.loader = false; + this.error = null; + }); + } + + return issuesResponse; + } catch (error) { + console.warn("error in fetching the project view issues", error); + this.loader = false; + this.error = null; + return error; + } + }; +} + +export default IssueStore; diff --git a/web/store/issue-views/Issues.ts b/web/store/issue-views/Issues.ts deleted file mode 100644 index 7303245fc51..00000000000 --- a/web/store/issue-views/Issues.ts +++ /dev/null @@ -1,524 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "../root"; -// services -import { UserService } from "services/user.service"; -import { ProjectIssuesServices } from "services/issues.service"; -import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; -import { ProjectCycleServices } from "services/cycles.service"; -// types -import { TIssueLayouts, TIssueViews } from "./issue_filters"; - -export interface IIssues { - [key: string]: any; -} - -export interface IIssuesLayout { - list: IIssues[]; - kanban: IIssues[]; - calendar: IIssues[]; - spreadsheet: IIssues[]; - gantt_chart: IIssues[]; -} - -export interface IIssueState { - [key: string]: { - my_issues: IIssuesLayout; - project_issues: { - [key: string]: { - issues: IIssuesLayout; - cycles: { - [key: string]: IIssuesLayout; - }; - modules: { - [key: string]: IIssuesLayout; - }; - views: { - [key: string]: IIssuesLayout; - }; - }; - }; - }; -} - -export interface IIssueViewStore { - loader: boolean; - error: any | null; - issues: IIssueState; - // computed - getIssues: IIssues | null | undefined; - // actions - getMyIssuesAsync: (workspaceId: string, fetchFilterToggle: boolean) => null | Promise; - getProjectIssuesAsync: (workspaceId: string, projectId: string, fetchFilterToggle: boolean) => null | Promise; - getIssuesForModulesAsync: ( - workspaceId: string, - projectId: string, - moduleId: string, - fetchFilterToggle: boolean - ) => null | Promise; - getIssuesForCyclesAsync: ( - workspaceId: string, - projectId: string, - cycleId: string, - fetchFilterToggle: boolean - ) => null | Promise; - getIssuesForViewsAsync: ( - workspaceId: string, - projectId: string, - viewId: string, - fetchFilterToggle: boolean - ) => null | Promise; -} - -class IssueViewStore implements IIssueViewStore { - loader: boolean = false; - error: any | null = null; - issues: IIssueState = {}; - // root store - rootStore; - // service - issueService; - userService; - modulesService; - cyclesService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - issues: observable.ref, - // action - getMyIssuesAsync: action, - getProjectIssuesAsync: action, - getIssuesForModulesAsync: action, - getIssuesForCyclesAsync: action, - getIssuesForViewsAsync: action, - updateIssues: action, - // computed - getIssues: computed, - }); - - this.rootStore = _rootStore; - this.issueService = new ProjectIssuesServices(); - this.userService = new UserService(); - this.modulesService = new ProjectModuleServices(); - this.cyclesService = new ProjectCycleServices(); - } - - // computed - get getIssues() { - if (this.issues != null) { - const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; - const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; - const currentProjectId: string | null = this.rootStore.issueFilters.projectId; - const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; - const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; - const currentViewId: string | null = this.rootStore.issueFilters.viewId; - - if (!currentView || !currentWorkspaceId) return null; - - const currentLayout: TIssueLayouts = currentProjectId - ? this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.project_issue_properties?.[currentProjectId] - ?.issues?.display_filters?.layout - : this.rootStore.issueFilters.issueFilters?.[currentWorkspaceId]?.my_issue_properties?.display_filters?.layout; - - if (currentView === "my_issues") return this.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]; - else if (currentView === "issues" && currentProjectId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[currentLayout]; - else if (currentView === "modules" && currentProjectId && currentModuleId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.modules?.[currentModuleId]?.[ - currentLayout - ]; - else if (currentView === "cycles" && currentProjectId && currentCycleId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.cycles?.[currentCycleId]?.[ - currentLayout - ]; - else if (currentView === "views" && currentProjectId && currentViewId) - return this.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.views?.[currentViewId]?.[ - currentLayout - ]; - } - - return null; - } - - updateIssues = (group_id: any = null, issue_id: string | null, data: any) => { - const currentWorkspaceId: string | null = this.rootStore.issueFilters.workspaceId; - const currentProjectId: string | null = this.rootStore.issueFilters.projectId; - // const currentModuleId: string | null = this.rootStore.issueFilters.moduleId; - // const currentCycleId: string | null = this.rootStore.issueFilters.cycleId; - // const currentViewId: string | null = this.rootStore.issueFilters.viewId; - const currentView: TIssueViews | null = this.rootStore.issueFilters.issueView; - const currentLayout: TIssueLayouts | null = this.rootStore.issueFilters.issueLayout; - - if (!currentView || !currentWorkspaceId || !currentLayout || !issue_id) return null; - - if (currentView === "my_issues") { - if (group_id) { - this.issues = { - ...this.issues, - [currentWorkspaceId]: { - ...this?.issues?.[currentWorkspaceId], - my_issues: { - ...this?.issues?.[currentWorkspaceId]?.my_issues, - [currentLayout]: { - ...this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout], - [group_id]: this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout]?.[group_id].map( - (item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item }) - ), - }, - }, - }, - } as any; - } else { - this.issues = { - ...this.issues, - [currentWorkspaceId]: { - ...this?.issues?.[currentWorkspaceId], - my_issues: { - ...this?.issues?.[currentWorkspaceId]?.my_issues, - [currentLayout]: this?.issues?.[currentWorkspaceId]?.my_issues?.[currentLayout].map((item: any) => - item.id === issue_id ? { ...item, ...data } : { ...item } - ), - }, - }, - } as any; - } - } - - if (!currentProjectId) return null; - if (currentView) { - if (group_id) { - this.issues = { - ...this.issues, - [currentWorkspaceId]: { - ...this?.issues?.[currentWorkspaceId], - project_issues: { - ...this?.issues?.[currentWorkspaceId]?.project_issues, - [currentProjectId]: { - ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId], - [currentView]: { - ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues, - [currentLayout]: { - ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[currentLayout], - [group_id]: this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ - currentLayout - ]?.[group_id].map((item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item })), - }, - }, - }, - }, - }, - } as any; - } else { - this.issues = { - ...this.issues, - [currentWorkspaceId]: { - ...this?.issues?.[currentWorkspaceId], - project_issues: { - ...this?.issues?.[currentWorkspaceId]?.project_issues, - [currentProjectId]: { - ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId], - [currentView]: { - ...this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues, - [currentLayout]: this?.issues?.[currentWorkspaceId]?.project_issues?.[currentProjectId]?.issues?.[ - currentLayout - ].map((item: any) => (item.id === issue_id ? { ...item, ...data } : { ...item })), - }, - }, - }, - }, - } as any; - } - } - }; - - // fetching my issues - getMyIssuesAsync = async (workspaceId: string, fetchFilterToggle: boolean = true) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - null, - null, - null, - null, - "my_issues" - ); - const issuesResponse = await this.userService.userIssues(workspaceId, filteredParams); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [workspaceId]: { - ...this?.issues[workspaceId], - my_issues: { - ...this?.issues[workspaceId]?.my_issues, - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the my issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues - getProjectIssuesAsync = async (workspaceId: string, projectId: string, fetchFilterToggle: boolean = true) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) await this.rootStore.issueFilters.getProjectIssueFilters(workspaceId, projectId); - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - null, - null, - null, - "issues" - ); - const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [workspaceId]: { - ...this?.issues?.[workspaceId], - project_issues: { - ...this?.issues?.[workspaceId]?.project_issues, - [projectId]: { - ...this?.issues?.[workspaceId]?.project_issues?.[projectId], - issues: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.issues, - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for modules - getIssuesForModulesAsync = async ( - workspaceId: string, - projectId: string, - moduleId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - moduleId, - null, - null, - "modules" - ); - const issuesResponse = await this.modulesService.getModuleIssuesWithParams( - workspaceId, - projectId, - moduleId, - filteredParams - ); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [workspaceId]: { - ...this?.issues?.[workspaceId], - project_issues: { - ...this?.issues?.[workspaceId]?.project_issues, - [projectId]: { - ...this?.issues?.[workspaceId]?.project_issues?.[projectId], - modules: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules, - [moduleId]: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.modules?.[moduleId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project module issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for cycles - getIssuesForCyclesAsync = async ( - workspaceId: string, - projectId: string, - cycleId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - null, - cycleId, - null, - "cycles" - ); - const issuesResponse = await this.cyclesService.getCycleIssuesWithParams( - workspaceId, - projectId, - cycleId, - filteredParams - ); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [workspaceId]: { - ...this?.issues?.[workspaceId], - project_issues: { - ...this?.issues?.[workspaceId]?.project_issues, - [projectId]: { - ...this?.issues?.[workspaceId]?.project_issues?.[projectId], - cycles: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles, - [cycleId]: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.cycles?.[cycleId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project cycles issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for views - getIssuesForViewsAsync = async ( - workspaceId: string, - projectId: string, - viewId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilters.getProjectIssueViewsFilters(workspaceId, projectId, viewId); - const filteredParams = this.rootStore.issueFilters.getComputedFilters( - workspaceId, - projectId, - null, - null, - viewId, - "views" - ); - const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [workspaceId]: { - ...this?.issues?.[workspaceId], - project_issues: { - ...this?.issues?.[workspaceId]?.project_issues, - [projectId]: { - ...this?.issues?.[workspaceId]?.project_issues?.[projectId], - views: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views, - [viewId]: { - ...this?.issues[workspaceId]?.project_issues?.[projectId]?.views?.[viewId], - [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project view issues", error); - this.loader = false; - this.error = null; - return error; - } - }; -} - -export default IssueViewStore; diff --git a/web/store/issue-views/issue_filters.ts b/web/store/issue-views/issue_filters.ts deleted file mode 100644 index bfe971b2738..00000000000 --- a/web/store/issue-views/issue_filters.ts +++ /dev/null @@ -1,1408 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "../root"; -// services -import { WorkspaceService } from "services/workspace.service"; -import { ProjectIssuesServices } from "services/issues.service"; -import { ProjectStateServices } from "services/state.service"; -import { ProjectServices } from "services/project.service"; -import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; -import { ProjectCycleServices } from "services/cycles.service"; -import { ViewServices as ProjectViewServices } from "services/views.service"; -// default data -import { - priorities, - stateGroups, - startDateOptions, - dueDateOptions, - groupByOptions, - orderByOptions, - issueTypes, - displayProperties, - extraProperties, - handleIssueQueryParamsByLayout, -} from "./issue_data"; - -export type TIssueViews = "my_issues" | "issues" | "modules" | "views" | "cycles"; - -export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; - -export type TIssueParams = - | "priority" - | "state_group" - | "state" - | "assignees" - | "created_by" - | "labels" - | "start_date" - | "target_date" - | "group_by" - | "order_by" - | "type" - | "sub_issue" - | "show_empty_groups" - | "calendar_date_range" - | "start_target_date"; - -export interface IIssueFilter { - priority: string[] | undefined; - state: string[] | undefined; - state_group: string[] | undefined; - assignees: string[] | undefined; - created_by: string[] | undefined; - labels: string[] | undefined; - start_date: string[] | undefined; - target_date: string[] | undefined; - [key: string]: any; -} - -export interface IIssueDisplayFilters { - group_by: undefined | string; - order_by: undefined | string; - type: string | undefined; - sub_issue: boolean; - show_empty_groups: boolean; - layout: TIssueLayouts; - calendar_date_range: string | undefined; // only for calendar - start_target_date: boolean; - [key: string]: any; -} - -export interface IIssueDisplayProperties { - assignee: boolean; - attachment_count: boolean; - created_on: boolean; - due_date: boolean; - estimate: boolean; - key: boolean; - labels: boolean; - link: boolean; - priority: boolean; - start_date: boolean; - state: boolean; - sub_issue_count: boolean; - updated_on: boolean; - [key: string]: any; -} - -export interface IIssueRenderFilters { - priority: { key: string; title: string }[]; - state_group: { key: string; title: string }[]; - start_date: { key: string; title: string }[]; - due_date: { key: string; title: string }[]; - group_by: { key: string; title: string }[]; - order_by: { key: string; title: string }[]; - issue_type: { key: string; title: string }[]; - display_properties: { key: string; title: string }[]; - extra_properties: { key: string; title: string }[]; - workspace_properties: { - [key: string]: { - projects: any[]; - labels: any[]; - project_properties: { - [key: string]: { - states: any | null; - labels: any[] | null; - members: any[] | null; - }; - }; - }; - }; -} - -export interface IIssueFilters { - [key: string]: { - my_issue_properties: { - filters: IIssueFilter; - display_filters: IIssueDisplayFilters; - display_properties_id: null; - display_properties: IIssueDisplayProperties; - }; - project_issue_properties: { - [key: string]: { - issues: { - filters: IIssueFilter; - display_filters: IIssueDisplayFilters; - }; - cycles: { - [key: string]: { - filters: IIssueFilter; - }; - }; - modules: { - [key: string]: { - filters: IIssueFilter; - }; - }; - views: { - [key: string]: { - filters: IIssueFilter; - }; - }; - display_properties_id: string; - display_properties: IIssueDisplayProperties; - }; - }; - }; -} - -export interface IIssueFilterStore { - loader: boolean; - error: any | null; - - // current workspace and project id - workspaceId: string | null; - projectId: string | null; - moduleId: string | null; - cycleId: string | null; - viewId: string | null; - issueView: TIssueViews | null; - - issueRenderFilters: IIssueRenderFilters; - issueFilters: IIssueFilters; - - // actions - getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; - updateWorkspaceMyIssuesFilters: (workspaceId: string, data: any) => Promise; - - getProjectLevelMembers: (workspaceId: string, projectId: string) => Promise; - getProjectLevelStates: (workspaceId: string, projectId: string) => Promise; - getProjectLevelLabels: (workspaceId: string, projectId: string) => Promise; - getProjectDisplayProperties: (workspaceId: string, projectId: string) => Promise; - updateProjectDisplayProperties: ( - workspaceId: string, - projectId: string, - display_properties_id: string, - data: any - ) => Promise; - getProjectDisplayFilters: (workspaceId: string, projectId: string) => Promise; - updateProjectDisplayFilters: (workspaceId: string, projectId: string, data: any) => Promise; - - getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise; - - getProjectIssueModuleFilters: (workspaceId: string, projectId: string, moduleId: string) => Promise; - updateProjectIssueModuleFilters: ( - workspaceId: string, - projectId: string, - moduleId: string, - data: any - ) => Promise; - getProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string) => Promise; - updateProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string, data: any) => Promise; - getProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string) => Promise; - updateProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string, data: any) => Promise; -} - -class IssueFilterStore implements IIssueFilterStore { - loader: boolean = false; - error: any | null = null; - - workspaceId: string | null = null; - projectId: string | null = null; - moduleId: string | null = null; - cycleId: string | null = null; - viewId: string | null = null; - - issueView: TIssueViews | null = null; - - issueRenderFilters: IIssueRenderFilters = { - priority: priorities, - state_group: stateGroups, - start_date: startDateOptions, - due_date: dueDateOptions, - group_by: groupByOptions, - order_by: orderByOptions, - issue_type: issueTypes, - display_properties: displayProperties, - extra_properties: extraProperties, - workspace_properties: {}, - }; - issueFilters: IIssueFilters = {}; - - // root store - rootStore; - // service - workspaceService; - issueService; - stateService; - projectService; - moduleService; - cycleService; - viewService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - workspaceId: observable, - projectId: observable, - moduleId: observable, - cycleId: observable, - viewId: observable, - - issueView: observable, - - issueRenderFilters: observable.ref, - issueFilters: observable.ref, - - // computed - issueLayout: computed, - workspaceProjects: computed, - workspaceLabels: computed, - projectStates: computed, - projectLabels: computed, - projectMembers: computed, - projectDisplayProperties: computed, - - userFilters: computed, - - // actions - - getProjectStateById: action, - - getComputedFilters: action, - - handleUserFilter: action, - - getWorkspaceMyIssuesFilters: action, - updateWorkspaceMyIssuesFilters: action, - - getProjectLevelMembers: action, - getProjectLevelStates: action, - getProjectLevelLabels: action, - - getProjectDisplayFilters: action, - updateProjectDisplayFilters: action, - - getProjectDisplayProperties: action, - updateProjectDisplayProperties: action, - - getProjectIssueFilters: action, - - getProjectIssueModuleFilters: action, - updateProjectIssueModuleFilters: action, - - getProjectIssueCyclesFilters: action, - updateProjectIssueCyclesFilters: action, - - getProjectIssueViewsFilters: action, - updateProjectIssueViewsFilters: action, - }); - - this.rootStore = _rootStore; - this.workspaceService = new WorkspaceService(); - this.issueService = new ProjectIssuesServices(); - this.stateService = new ProjectStateServices(); - this.projectService = new ProjectServices(); - this.moduleService = new ProjectModuleServices(); - this.cycleService = new ProjectCycleServices(); - this.viewService = new ProjectViewServices(); - } - - // computed - get issueLayout() { - if (!this.workspaceId) return null; - if (!this.projectId) - return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout || null; - if (this.projectId) - return ( - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters - ?.layout || null - ); - - return null; - } - - get workspaceProjects() { - if (!this.workspaceId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.projects || null; - } - get workspaceLabels() { - if (!this.workspaceId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.labels || null; - } - - get projectStates() { - if (!this.workspaceId || !this.projectId) return null; - return ( - this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId]?.states || - null - ); - } - - getProjectStateById = (stateId: string) => { - if (!this.workspaceId || !this.projectId) return null; - const states = - this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId]?.states; - - let stateInfo: any = null; - Object.keys(states).forEach((stateGroupName) => { - if (states[stateGroupName].find((state: any) => state.id === stateId)) { - stateInfo = states[stateGroupName].find((state: any) => state.id === stateId); - } - }); - return stateInfo; - }; - - get projectLabels() { - if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] - ?.labels; - } - get projectMembers() { - if (!this.workspaceId || !this.projectId) return null; - return this.issueRenderFilters?.workspace_properties?.[this.workspaceId]?.project_properties?.[this.projectId] - ?.members; - } - get projectDisplayProperties() { - if (!this.workspaceId || !this.projectId) return null; - return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties as any; - } - - get userFilters() { - if (!this.workspaceId) return null; - if (this.issueView === "my_issues") - return { - ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, - display_properties_id: null, - }; - - if (!this.projectId) return null; - let _issueFilters: { - filters: IIssueFilter | null; - display_filters: IIssueDisplayFilters; - display_properties_id: string; - display_properties: IIssueDisplayProperties; - } = { - filters: null, - display_filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters, - display_properties_id: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties_id, - display_properties: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties, - }; - - if (this.issueView === "issues") { - _issueFilters = { - ..._issueFilters, - filters: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "modules" && this.moduleId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[this.moduleId] - ?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "cycles" && this.cycleId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[this.cycleId] - ?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "views" && this.viewId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[this.viewId] - ?.filters, - }; - return _issueFilters; - } - - return null; - } - handleUserFilter = ( - filter_type: "filters" | "display_filters" | "display_properties", - filter_key: string, - value: any - ) => { - if (!this.workspaceId) return null; - - if (this.issueView === "my_issues") { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - my_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.my_issue_properties?.[filter_type], - [filter_key]: value, - }, - }, - }, - }; - this.updateWorkspaceMyIssuesFilters(this.workspaceId, this.userFilters); - } - - if (!this.projectId) return null; - if (filter_type === "display_properties") { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - display_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - ?.display_properties, - [filter_key]: value, - }, - }, - }, - }, - }; - - if (this.userFilters?.display_properties_id) { - this.updateProjectDisplayProperties( - this.workspaceId, - this.projectId, - this.userFilters?.display_properties_id, - this.userFilters?.display_properties - ); - } - } - - if (filter_type === "display_filters") { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - issues: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ - filter_type - ], - [filter_key]: value, - }, - }, - }, - }, - }, - }; - this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { - filters: this.userFilters?.filters, - display_filters: this.userFilters?.display_filters, - }); - } - - if (filter_type === "filters") { - if (this.issueView === "issues") { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - issues: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ - filter_type - ], - [filter_key]: value, - }, - }, - }, - }, - }, - }; - this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { - filters: this.userFilters?.filters, - display_filters: this.userFilters?.display_filters, - }); - } - - if (this.issueView === "modules" && this.moduleId) { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - modules: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules, - [this.moduleId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ - this.moduleId - ], - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ - this.moduleId - ]?.[filter_type], - [filter_key]: value, - }, - }, - }, - }, - }, - }, - }; - this.updateProjectIssueModuleFilters( - this.workspaceId, - this.projectId, - this.moduleId, - this.userFilters?.filters - ); - } - - if (this.issueView === "cycles" && this.cycleId) { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - cycles: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles, - [this.cycleId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ - this.cycleId - ], - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ - this.cycleId - ]?.[filter_type], - [filter_key]: value, - }, - }, - }, - }, - }, - }, - }; - this.updateProjectIssueCyclesFilters(this.workspaceId, this.projectId, this.cycleId, this.userFilters?.filters); - } - - if (this.issueView === "views" && this.viewId) { - this.issueFilters = { - ...this.issueFilters, - [this.workspaceId]: { - ...this.issueFilters?.[this.workspaceId], - project_issue_properties: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - [this.projectId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - views: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views, - [this.viewId]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ - this.viewId - ], - [filter_type]: { - ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ - this.viewId - ]?.[filter_type], - [filter_key]: value, - }, - }, - }, - }, - }, - }, - }; - this.updateProjectIssueViewsFilters(this.workspaceId, this.projectId, this.viewId, this.userFilters?.filters); - } - } - - if (this.issueView === "my_issues") - this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - if (this.issueView === "issues") - this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - if (this.issueView === "modules" && this.moduleId) - this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); - if (this.issueView === "cycles" && this.cycleId) - this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); - if (this.issueView === "views" && this.viewId) - this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); - }; - - computedFilter = (filters: any, filteredParams: any) => { - const computedFilters: any = {}; - Object.keys(filters).map((key) => { - if (filters[key] != undefined && filteredParams.includes(key)) - computedFilters[key] = - typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(","); - }); - - return computedFilters; - }; - getComputedFilters = ( - _workspaceId: string | null, - _projectId: string | null, - _moduleId: string | null, - _cycleId: string | null, - _viewId: string | null, - _issueView: TIssueViews - ) => { - this.workspaceId = _workspaceId; - this.projectId = _projectId; - this.moduleId = _moduleId; - this.cycleId = _cycleId; - this.viewId = _viewId; - this.issueView = _issueView; - - const _layout = this.userFilters?.display_filters?.layout; - - let filteredRouteParams: any = { - priority: this.userFilters?.filters?.priority || undefined, - state_group: this.userFilters?.filters?.state_group || undefined, - state: this.userFilters?.filters?.state || undefined, - assignees: this.userFilters?.filters?.assignees || undefined, - created_by: this.userFilters?.filters?.created_by || undefined, - labels: this.userFilters?.filters?.labels || undefined, - start_date: this.userFilters?.filters?.start_date || undefined, - target_date: this.userFilters?.filters?.target_date || undefined, - group_by: this.userFilters?.display_filters?.group_by || "state", - order_by: this.userFilters?.display_filters?.order_by || "-created_at", - type: this.userFilters?.display_filters?.type || undefined, - sub_issue: this.userFilters?.display_filters?.sub_issue || true, - show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, - calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, - start_target_date: this.userFilters?.display_filters?.start_target_date || true, - }; - - // start date and target date we have to construct the format here - // in calendar view calendar_date_range send as target_date - // in spreadsheet sub issue is false for sure - // in gantt start_target_date is true for sure - - const filteredParams: TIssueParams[] | null = handleIssueQueryParamsByLayout(_layout); - if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); - - return filteredRouteParams; - }; - - // services - getWorkspaceMyIssuesProjects = async (workspaceId: string) => { - try { - this.loader = true; - this.error = null; - - const params = { is_favorite: false }; - const issuesProjectsResponse = await this.projectService.getProjects(workspaceId, params); - - if (issuesProjectsResponse) { - const _issuesProjectsResponse = { - ...this.issueRenderFilters, - workspace_properties: { - ...this.issueRenderFilters?.workspace_properties, - [workspaceId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId], - projects: issuesProjectsResponse, - }, - }, - }; - - runInAction(() => { - this.issueRenderFilters = _issuesProjectsResponse; - this.loader = false; - this.error = null; - }); - } - return issuesProjectsResponse; - } catch (error) { - console.warn("error in fetching workspace level projects", error); - this.loader = false; - this.error = null; - return error; - } - }; - getWorkspaceMyIssuesLabels = async (workspaceId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesLabelsResponse = await this.issueService.getWorkspaceLabels(workspaceId); - - if (issuesLabelsResponse) { - const _issuesLabelsResponse = { - ...this.issueRenderFilters, - workspace_properties: { - ...this.issueRenderFilters?.workspace_properties, - [workspaceId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId], - labels: issuesLabelsResponse, - }, - }, - }; - - runInAction(() => { - this.issueRenderFilters = _issuesLabelsResponse; - this.loader = false; - this.error = null; - }); - } - return issuesLabelsResponse; - } catch (error) { - console.warn("error in fetching workspace level labels", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getWorkspaceMyIssuesFilters = async (workspaceId: string) => { - try { - this.loader = true; - this.error = null; - - // fetching workspace level issue filters - await this.getWorkspaceMyIssuesProjects(workspaceId); - await this.getWorkspaceMyIssuesLabels(workspaceId); - - const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - if (issuesFiltersResponse) { - const _issuesFiltersResponse: any = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters?.[workspaceId], - my_issue_properties: { - ...this?.issueFilters?.[workspaceId]?.my_issue_properties, - filters: { - priority: issuesFiltersResponse?.view_props?.filters?.priority ?? null, - state: issuesFiltersResponse?.view_props?.filters?.state ?? null, - state_group: issuesFiltersResponse?.view_props?.filters?.state_group ?? null, - assignees: issuesFiltersResponse?.view_props?.filters?.assignees ?? null, - created_by: issuesFiltersResponse?.view_props?.filters?.created_by ?? null, - labels: issuesFiltersResponse?.view_props?.filters?.labels ?? null, - start_date: issuesFiltersResponse?.view_props?.filters?.start_date ?? null, - target_date: issuesFiltersResponse?.view_props?.filters?.target_date ?? null, - subscriber: issuesFiltersResponse?.view_props?.filters?.subscriber ?? null, - }, - display_filters: { - group_by: issuesFiltersResponse?.view_props?.display_filters?.group_by ?? null, - order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null, - type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null, - sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false, - show_empty_groups: issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, - layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list", - calendar_date_range: issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, - start_target_date: issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, - }, - display_properties: { - assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false, - attachment_count: issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, - created_on: issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, - due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false, - estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false, - key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false, - labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false, - link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false, - priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false, - start_date: issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, - state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false, - sub_issue_count: issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, - updated_on: issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, - }, - }, - }, - }; - runInAction(() => { - this.issueFilters = _issuesFiltersResponse; - this.loader = false; - this.error = null; - }); - } - return issuesFiltersResponse; - } catch (error) { - console.warn("error in fetching workspace level filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateWorkspaceMyIssuesFilters = async (workspaceId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - view_props: data, - }; - const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView(workspaceId, payload); - - if (issuesFiltersResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectLevelStates = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesStateResponse = await this.stateService.getStates(workspaceId, projectId); - if (issuesStateResponse) { - const _issuesStateResponse = { - ...this.issueRenderFilters, - workspace_properties: { - ...this.issueRenderFilters?.workspace_properties, - [workspaceId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId], - project_properties: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, - [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], - states: issuesStateResponse, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueRenderFilters = _issuesStateResponse; - this.loader = false; - this.error = null; - }); - } - return issuesStateResponse; - } catch (error) { - console.warn("error in fetching project level states", error); - this.loader = false; - this.error = null; - return error; - } - }; - getProjectLevelLabels = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesLabelsResponse = await this.issueService.getIssueLabels(workspaceId, projectId); - if (issuesLabelsResponse) { - const _issuesLabelsResponse = { - ...this.issueRenderFilters, - workspace_properties: { - ...this.issueRenderFilters?.workspace_properties, - [workspaceId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId], - project_properties: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, - [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], - labels: issuesLabelsResponse, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueRenderFilters = _issuesLabelsResponse; - this.loader = false; - this.error = null; - }); - } - return issuesLabelsResponse; - } catch (error) { - console.warn("error in fetching project level labels", error); - this.loader = false; - this.error = null; - return error; - } - }; - getProjectLevelMembers = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesMembersResponse = await this.projectService.projectMembers(workspaceId, projectId); - if (issuesMembersResponse) { - const _issuesMembersResponse = { - ...this.issueRenderFilters, - workspace_properties: { - ...this.issueRenderFilters?.workspace_properties, - [workspaceId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId], - project_properties: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties, - [projectId]: { - ...this.issueRenderFilters?.workspace_properties?.[workspaceId]?.project_properties?.[projectId], - members: issuesMembersResponse, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueRenderFilters = _issuesMembersResponse; - this.loader = false; - this.error = null; - }); - } - return issuesMembersResponse; - } catch (error) { - console.warn("error in fetching project level members", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectDisplayProperties = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - await this.rootStore.user.setCurrentUser(); - const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId); - - if (issuesDisplayPropertiesResponse) { - const _issuesDisplayPropertiesResponse: any = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - display_properties_id: issuesDisplayPropertiesResponse?.id, - display_properties: { - ...issuesDisplayPropertiesResponse?.properties, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesDisplayPropertiesResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayPropertiesResponse; - } catch (error) { - console.warn("error in fetching project level display properties", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectDisplayProperties = async ( - workspaceId: string, - projectId: string, - display_properties_id: string, - data: any - ) => { - try { - this.loader = true; - this.error = null; - - const payload = { - properties: data, - user: this.rootStore?.user?.currentUser?.id, - }; - const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties( - workspaceId, - projectId, - display_properties_id, - payload - ); - - if (issuesDisplayPropertiesResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayPropertiesResponse; - } catch (error) { - console.warn("error in fetching project level display properties", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectDisplayFilters = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe(workspaceId, projectId); - - if (issuesDisplayFiltersResponse) { - const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters }; - const _displayFilters = { ...issuesDisplayFiltersResponse?.view_props?.display_filters }; - - const _issuesDisplayFiltersResponse: any = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - issues: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.issues, - filters: _filters, - display_filters: _displayFilters, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesDisplayFiltersResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayFiltersResponse; - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectDisplayFilters = async (workspaceId: string, projectId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload: any = { - view_props: data, - }; - const issuesFiltersResponse = await this.projectService.setProjectView(workspaceId, projectId, payload); - - if (issuesFiltersResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesFiltersResponse; - } catch (error) { - this.getProjectDisplayFilters(workspaceId, projectId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectIssueFilters = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectLevelStates(workspaceId, projectId); - await this.getProjectLevelLabels(workspaceId, projectId); - await this.getProjectLevelMembers(workspaceId, projectId); - await this.getProjectDisplayProperties(workspaceId, projectId); - await this.getProjectDisplayFilters(workspaceId, projectId); - - runInAction(() => { - this.loader = false; - this.error = null; - }); - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - - const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails(workspaceId, projectId, moduleId); - - if (issuesFiltersModuleResponse) { - const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters }; - const _issuesFiltersModuleResponse = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - modules: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules, - [moduleId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[moduleId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersModuleResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - view_props: { filters: data }, - }; - const issuesFiltersModuleResponse = await this.moduleService.patchModule( - workspaceId, - projectId, - moduleId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersModuleResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - } catch (error) { - this.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - - const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails(workspaceId, projectId, cycleId); - - if (issuesFiltersCycleResponse) { - const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters }; - const _issuesFiltersCycleResponse = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - cycles: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, - [cycleId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[cycleId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersCycleResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - view_props: { filters: data }, - }; - const issuesFiltersCycleResponse = await this.cycleService.patchCycle( - workspaceId, - projectId, - cycleId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersCycleResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - } catch (error) { - this.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - - getProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - - const issuesFiltersViewResponse = await this.viewService.getViewDetails(workspaceId, projectId, viewId); - - if (issuesFiltersViewResponse) { - const _filters = { ...issuesFiltersViewResponse?.query_data } as any; - const _issuesFiltersViewResponse = { - ...this.issueFilters, - [workspaceId]: { - ...this?.issueFilters[workspaceId], - project_issue_properties: { - ...this?.issueFilters[workspaceId]?.project_issue_properties, - [projectId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId], - views: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.cycles, - [viewId]: { - ...this?.issueFilters[workspaceId]?.project_issue_properties?.[projectId]?.modules?.[viewId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersViewResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; - updateProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - query_data: data, - }; - const issuesFiltersViewResponse = await this.viewService.patchView( - workspaceId, - projectId, - viewId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersViewResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesFiltersViewResponse; - } catch (error) { - this.getProjectIssueViewsFilters(projectId, workspaceId, viewId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - return error; - } - }; -} - -export default IssueFilterStore; diff --git a/web/store/issue-views/project.ts b/web/store/issue-views/project.ts deleted file mode 100644 index ad7c72b848d..00000000000 --- a/web/store/issue-views/project.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { action, computed, makeObservable } from "mobx"; -// types -import { RootStore } from "../root"; - -export interface IIssueProject {} - -class IssueProject implements IIssueProject { - // root store - rootStore; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // computed - // actions - }); - - this.rootStore = _rootStore; - } -} - -export default IssueProject; diff --git a/web/store/issue-views/workspace.ts b/web/store/issue-views/workspace.ts deleted file mode 100644 index 0203e6cfd5b..00000000000 --- a/web/store/issue-views/workspace.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { action, computed, makeObservable } from "mobx"; -// types -import { RootStore } from "../root"; - -export interface IIssueWorkspace {} - -class IssueWorkspace implements IIssueWorkspace { - // root store - rootStore; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // computed - // actions - }); - - this.rootStore = _rootStore; - } -} - -export default IssueWorkspace; diff --git a/web/store/issue-views/issue_detail.ts b/web/store/issue_detail.ts similarity index 99% rename from web/store/issue-views/issue_detail.ts rename to web/store/issue_detail.ts index c1dae8222a7..04fa1fa4def 100644 --- a/web/store/issue-views/issue_detail.ts +++ b/web/store/issue_detail.ts @@ -1,6 +1,6 @@ import { observable, action, makeObservable, runInAction } from "mobx"; // types -import { RootStore } from "../root"; +import { RootStore } from "./root"; // services import { ProjectIssuesServices } from "services/issues.service"; diff --git a/web/store/issues.ts b/web/store/issues.ts index 286d985343e..2c0eaeff429 100644 --- a/web/store/issues.ts +++ b/web/store/issues.ts @@ -31,10 +31,7 @@ class IssuesStore { loadIssues = async (workspaceSlug: string, projectId: string) => { this.isIssuesLoading = true; try { - const issuesResponse: IIssue[] = (await issueService.getIssuesWithParams( - workspaceSlug, - projectId - )) as IIssue[]; + const issuesResponse: IIssue[] = (await issueService.getIssuesWithParams(workspaceSlug, projectId)) as IIssue[]; const issues: { [kye: string]: IIssue } = {}; issuesResponse.forEach((issue) => { @@ -51,11 +48,7 @@ class IssuesStore { } }; - getIssueById = async ( - workspaceSlug: string, - projectId: string, - issueId: string - ): Promise => { + getIssueById = async (workspaceSlug: string, projectId: string, issueId: string): Promise => { if (this.issues[issueId]) return this.issues[issueId]; try { @@ -83,12 +76,7 @@ class IssuesStore { user: ICurrentUserResponse ): Promise => { try { - const issueResponse = await issueService.createIssues( - workspaceSlug, - projectId, - issueForm, - user - ); + const issueResponse = await issueService.createIssues(workspaceSlug, projectId, issueForm, user); const issues = { ...this.issues, @@ -125,13 +113,7 @@ class IssuesStore { }); // make a patch request to update the issue - const issueResponse: IIssue = await issueService.patchIssue( - workspaceSlug, - projectId, - issueId, - issueForm, - user - ); + const issueResponse: IIssue = await issueService.patchIssue(workspaceSlug, projectId, issueId, issueForm, user); const updatedIssues = { ...this.issues }; updatedIssues[issueId] = { ...issueResponse }; @@ -149,12 +131,7 @@ class IssuesStore { } }; - deleteIssue = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - user: ICurrentUserResponse - ) => { + deleteIssue = async (workspaceSlug: string, projectId: string, issueId: string, user: ICurrentUserResponse) => { const issues = { ...this.issues }; delete issues[issueId]; diff --git a/web/store/modules.ts b/web/store/modules.ts new file mode 100644 index 00000000000..61270270068 --- /dev/null +++ b/web/store/modules.ts @@ -0,0 +1,55 @@ +import { action, computed, observable, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as IssueServices } from "services/issues.service"; + +export interface IModuleStore { + loader: boolean; + error: any | null; + + moduleId: string | null; + + setModuleId: (moduleSlug: string) => void; +} + +class ModuleStore implements IModuleStore { + loader: boolean = false; + error: any | null = null; + + moduleId: string | null = null; + + // root store + rootStore; + // services + projectService; + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + loader: observable, + error: observable.ref, + + moduleId: observable.ref, + + // computed + + // actions + setModuleId: action, + }); + + this.rootStore = _rootStore; + this.projectService = new ProjectServices(); + this.issueService = new IssueServices(); + } + + // computed + + // actions + setModuleId = (moduleSlug: string) => { + this.moduleId = moduleSlug ?? null; + }; +} + +export default ModuleStore; diff --git a/web/store/project.ts b/web/store/project.ts deleted file mode 100644 index 0fe842dad84..00000000000 --- a/web/store/project.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "./root"; -// services -import { ProjectServices } from "services/project.service"; - -export interface IProject { - id: string; - name: string; - workspaceSlug: string; -} - -export interface IProjectStore { - loader: boolean; - error: any | null; - - projectLeaveModal: boolean; - projectLeaveDetails: IProject | any; - - handleProjectLeaveModal: (project: IProject | null) => void; - - leaveProject: (workspace_slug: string, project_slug: string, user: any) => Promise; -} - -class ProjectStore implements IProjectStore { - loader: boolean = false; - error: any | null = null; - - projectLeaveModal: boolean = false; - projectLeaveDetails: IProject | null = null; - - // root store - rootStore; - // service - projectService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - projectLeaveModal: observable, - projectLeaveDetails: observable.ref, - // action - handleProjectLeaveModal: action, - leaveProject: action, - // computed - }); - - this.rootStore = _rootStore; - this.projectService = new ProjectServices(); - } - - handleProjectLeaveModal = (project: IProject | null = null) => { - if (project && project?.id) { - this.projectLeaveModal = !this.projectLeaveModal; - this.projectLeaveDetails = project; - } else { - this.projectLeaveModal = !this.projectLeaveModal; - this.projectLeaveDetails = null; - } - }; - - leaveProject = async (workspace_slug: string, project_slug: string, user: any) => { - try { - this.loader = true; - this.error = null; - - const response = await this.projectService.leaveProject(workspace_slug, project_slug, user); - - runInAction(() => { - this.loader = false; - this.error = null; - }); - - return response; - } catch (error) { - this.loader = false; - this.error = error; - return error; - } - }; -} - -export default ProjectStore; diff --git a/web/store/projects.ts b/web/store/projects.ts new file mode 100644 index 00000000000..36c2c9268cd --- /dev/null +++ b/web/store/projects.ts @@ -0,0 +1,309 @@ +import { observable, action, computed, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +import { IProject, IIssueLabels, IProjectMember, IStateResponse, IState } from "types"; +// services +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices } from "services/issues.service"; +import { ProjectStateServices } from "services/state.service"; + +export interface IProjectStore { + loader: boolean; + error: any | null; + + projectLeaveModal: boolean; + projectLeaveDetails: IProject | any; + + projectId: string | null; + projects: { + [key: string]: { [key: string]: IProject }; // workspace_id: project_id: projects + } | null; + states: { + [key: string]: IStateResponse; // project_id: states + } | null; + labels: { + [key: string]: IIssueLabels[]; // project_id: labels + } | null; + members: { + [key: string]: IProjectMember[]; // project_id: members + } | null; + + // computed + projectStatesByGroups: IStateResponse | null; + projectStates: IState[] | null; + projectLabels: IIssueLabels[] | null; + projectMembers: IProjectMember[] | null; + workspaceProjects: { [key: string]: IProject } | null; + + // actions + projectStateById: (stateId: string) => IState | null; + projectLabelById: (labelId: string) => IIssueLabels | null; + projectMemberById: (memberId: string) => IProjectMember | null; + + setProject: (projectSlug: string) => void; + + getWorkspaceProjects: (workspaceSlug: string, is_favorite?: "all" | boolean) => Promise; + getProjectStates: (workspaceSlug: string, projectSlug: string) => Promise; + getProjectLabels: (workspaceSlug: string, projectSlug: string) => Promise; + getProjectMembers: (workspaceSlug: string, projectSlug: string) => Promise; + + handleProjectLeaveModal: (project: IProject | null) => void; + + leaveProject: (workspaceSlug: string, projectSlug: string, user: any) => Promise; +} + +class ProjectStore implements IProjectStore { + loader: boolean = false; + error: any | null = null; + + projectLeaveModal: boolean = false; + projectLeaveDetails: IProject | null = null; + + projectId: string | null = null; + projects: { + [key: string]: { [key: string]: IProject }; // workspace_id: project_id: projects + } | null = null; + states: { + [key: string]: IStateResponse; // project_id: states + } | null = null; + labels: { + [key: string]: IIssueLabels[]; // project_id: labels + } | null = null; + members: { + [key: string]: IProjectMember[]; // project_id: members + } | null = null; + + // root store + rootStore; + // service + projectService; + issueService; + stateService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + // observable + loader: observable, + error: observable, + + projectId: observable.ref, + projects: observable.ref, + states: observable.ref, + labels: observable.ref, + members: observable.ref, + + projectLeaveModal: observable, + projectLeaveDetails: observable.ref, + + // computed + workspaceProjects: computed, + projectStatesByGroups: computed, + projectStates: computed, + projectLabels: computed, + projectMembers: computed, + + // action + setProject: action, + + projectStateById: action, + projectLabelById: action, + projectMemberById: action, + + getWorkspaceProjects: action, + getProjectStates: action, + getProjectLabels: action, + getProjectMembers: action, + + handleProjectLeaveModal: action, + leaveProject: action, + }); + + this.rootStore = _rootStore; + this.projectService = new ProjectServices(); + this.issueService = new ProjectIssuesServices(); + this.stateService = new ProjectStateServices(); + } + + // computed + get workspaceProjects() { + if (!this.rootStore.workspace.workspaceId) return null; + return this.projects?.[this.rootStore.workspace.workspaceId] || null; + } + get projectStatesByGroups() { + if (!this.projectId) return null; + return this.states?.[this.projectId] || null; + } + get projectStates() { + if (!this.projectId) return null; + const stateByGroups: IStateResponse | null = this.projectStatesByGroups; + if (!stateByGroups) return null; + const _states: IState[] = []; + Object.keys(stateByGroups).forEach((_stateGroup: string) => { + stateByGroups[_stateGroup].map((state) => { + _states.push(state); + }); + }); + return _states && _states.length > 0 ? _states : null; + } + get projectLabels() { + if (!this.projectId) return null; + return this.labels?.[this.projectId] || null; + } + get projectMembers() { + if (!this.projectId) return null; + return this.members?.[this.projectId] || null; + } + + // actions + projectStateById = (stateId: string) => { + if (!this.projectId) return null; + const states = this.projectStates; + if (!states) return null; + const stateInfo: IState | null = states.find((state) => state.id === stateId) || null; + return stateInfo; + }; + projectLabelById = (labelId: string) => { + if (!this.projectId) return null; + const labels = this.projectLabels; + if (!labels) return null; + const labelInfo: IIssueLabels | null = labels.find((label) => label.id === labelId) || null; + return labelInfo; + }; + projectMemberById = (memberId: string) => { + if (!this.projectId) return null; + const members = this.projectMembers; + if (!members) return null; + const memberInfo: IProjectMember | null = members.find((member) => member.id === memberId) || null; + return memberInfo; + }; + + setProject = (projectSlug: string) => { + this.projectId = projectSlug ?? null; + }; + + getWorkspaceProjects = async (workspaceSlug: string, is_favorite: "all" | boolean = "all") => { + try { + this.loader = true; + this.error = null; + + const params: { is_favorite: "all" | boolean } = { is_favorite: is_favorite }; + const projectsResponse = await this.projectService.getProjects(workspaceSlug, params); + + let _projects: { [key: string]: IProject } = {}; + projectsResponse.map((project) => { + _projects = { ..._projects, [project.id]: project }; + }); + + runInAction(() => { + this.projects = { + ...this.projects, + [workspaceSlug]: _projects, + }; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.error(error); + this.loader = false; + this.error = error; + } + }; + getProjectStates = async (workspaceSlug: string, projectSlug: string) => { + try { + this.loader = true; + this.error = null; + + const stateResponse = await this.stateService.getStates(workspaceSlug, projectSlug); + const _states = { + ...this.states, + [projectSlug]: stateResponse, + }; + + runInAction(() => { + this.states = _states; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.error(error); + this.loader = false; + this.error = error; + } + }; + getProjectLabels = async (workspaceSlug: string, projectSlug: string) => { + try { + this.loader = true; + this.error = null; + + const labelResponse = await this.issueService.getIssueLabels(workspaceSlug, projectSlug); + const _labels = { + ...this.labels, + [projectSlug]: labelResponse, + }; + + runInAction(() => { + this.labels = _labels; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.error(error); + this.loader = false; + this.error = error; + } + }; + getProjectMembers = async (workspaceSlug: string, projectSlug: string) => { + try { + this.loader = true; + this.error = null; + + const membersResponse = await this.projectService.projectMembers(workspaceSlug, projectSlug); + const _members = { + ...this.members, + [projectSlug]: membersResponse, + }; + + runInAction(() => { + this.members = _members; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.error(error); + this.loader = false; + this.error = error; + } + }; + + handleProjectLeaveModal = (project: IProject | null = null) => { + if (project && project?.id) { + this.projectLeaveModal = !this.projectLeaveModal; + this.projectLeaveDetails = project; + } else { + this.projectLeaveModal = !this.projectLeaveModal; + this.projectLeaveDetails = null; + } + }; + + leaveProject = async (workspaceSlug: string, projectSlug: string, user: any) => { + try { + this.loader = true; + this.error = null; + + const response = await this.projectService.leaveProject(workspaceSlug, projectSlug, user); + + runInAction(() => { + this.loader = false; + this.error = null; + }); + + return response; + } catch (error) { + this.loader = false; + this.error = error; + return error; + } + }; +} + +export default ProjectStore; diff --git a/web/store/root.ts b/web/store/root.ts index 763ac5e31ca..70f092231dc 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -3,15 +3,18 @@ import { enableStaticRendering } from "mobx-react-lite"; // store imports import UserStore from "./user"; import ThemeStore from "./theme"; -import ProjectStore, { IProjectStore } from "./project"; import ProjectPublishStore, { IProjectPublishStore } from "./project-publish"; import IssuesStore from "./issues"; -// issues views and filters -import IssueWorkspace from "./issue-views/workspace"; -import IssueProject from "./issue-views/project"; -import IssueFilterStore from "./issue-views/issue_filters"; -import IssueViewStore from "./issue-views/Issues"; -import IssueViewDetailStore from "./issue-views/issue_detail"; + +import WorkspaceStore, { IWorkspaceStore } from "./workspaces"; +import ProjectStore, { IProjectStore } from "./projects"; +import IssueStore, { IIssueStore } from "./issue-store"; +import ModuleStore, { IModuleStore } from "./modules"; +import CycleStore, { ICycleStore } from "./cycles"; +import ViewStore, { IViewStore } from "./views"; +import IssueFilterStore, { IIssueFilterStore } from "./issue-filters"; + +import IssueViewDetailStore from "./issue_detail"; import IssueKanBanViewStore from "./issue-views/kanban-view"; enableStaticRendering(typeof window === "undefined"); @@ -19,28 +22,33 @@ enableStaticRendering(typeof window === "undefined"); export class RootStore { user; theme; - project: IProjectStore; projectPublish: IProjectPublishStore; issues: IssuesStore; - // issues views and filters - issueWorkspace: IssueWorkspace; - issueProject: IssueProject; - issueFilters: IssueFilterStore; - issueView: IssueViewStore; + + workspace: IWorkspaceStore; + project: IProjectStore; + issue: IIssueStore; + module: IModuleStore; + cycle: ICycleStore; + view: IViewStore; + issueFilter: IIssueFilterStore; issueDetail: IssueViewDetailStore; issueKanBanView: IssueKanBanViewStore; constructor() { this.user = new UserStore(this); this.theme = new ThemeStore(this); - this.project = new ProjectStore(this); this.projectPublish = new ProjectPublishStore(this); this.issues = new IssuesStore(this); - // issues views and filters - this.issueWorkspace = new IssueWorkspace(this); - this.issueProject = new IssueProject(this); - this.issueFilters = new IssueFilterStore(this); - this.issueView = new IssueViewStore(this); + + this.workspace = new WorkspaceStore(this); + this.project = new ProjectStore(this); + this.issue = new IssueStore(this); + this.module = new ModuleStore(this); + this.cycle = new CycleStore(this); + this.view = new ViewStore(this); + this.issueFilter = new IssueFilterStore(this); + this.issueDetail = new IssueViewDetailStore(this); this.issueKanBanView = new IssueKanBanViewStore(this); } diff --git a/web/store/views.ts b/web/store/views.ts new file mode 100644 index 00000000000..c29d8886413 --- /dev/null +++ b/web/store/views.ts @@ -0,0 +1,55 @@ +import { action, computed, observable, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +// services +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as IssueServices } from "services/issues.service"; + +export interface IViewStore { + loader: boolean; + error: any | null; + + viewId: string | null; + + setViewId: (viewSlug: string) => void; +} + +class ViewStore implements IViewStore { + loader: boolean = false; + error: any | null = null; + + viewId: string | null = null; + + // root store + rootStore; + // services + projectService; + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + loader: observable, + error: observable.ref, + + viewId: observable.ref, + + // computed + + // actions + setViewId: action, + }); + + this.rootStore = _rootStore; + this.projectService = new ProjectServices(); + this.issueService = new IssueServices(); + } + + // computed + + // actions + setViewId = (viewSlug: string) => { + this.viewId = viewSlug ?? null; + }; +} + +export default ViewStore; diff --git a/web/store/workspaces.ts b/web/store/workspaces.ts new file mode 100644 index 00000000000..60c2cb3e630 --- /dev/null +++ b/web/store/workspaces.ts @@ -0,0 +1,198 @@ +import { action, computed, observable, makeObservable, runInAction } from "mobx"; +// types +import { RootStore } from "./root"; +import { IIssueLabels, IWorkspace } from "types"; +// services +import { WorkspaceService } from "services/workspace.service"; +import { ProjectServices } from "services/project.service"; +import { ProjectIssuesServices as IssueServices } from "services/issues.service"; + +export interface IWorkspaceStore { + loader: boolean; + error: any | null; + + workspaces: { + [key: string]: IWorkspace; // workspace_id: workspace + } | null; + labels: { [key: string]: { [key: string]: IIssueLabels } } | null; // workspace_id: label_id: labels + workspaceId: string | null; + + // computed + currentWorkspace: IWorkspace | null; + workspaceLabels: { [key: string]: IIssueLabels } | null; + + // actions + setWorkspaceId: (workspaceSlug: string) => void; + + workspaceById: (workspaceId: string) => IWorkspace | null; + workspaceLabelById: (labelId: string) => IIssueLabels | null; + + getWorkspaces: () => Promise; + getWorkspaceLabels: (workspaceSlug: string) => Promise; +} + +class WorkspaceStore implements IWorkspaceStore { + loader: boolean = false; + error: any | null = null; + + workspaces: { + [key: string]: IWorkspace; + } | null = null; + labels: { + [key: string]: { [key: string]: IIssueLabels }; + } | null = null; + workspaceId: string | null = null; + + // root store + rootStore; + // services + workspaceService; + projectService; + issueService; + + constructor(_rootStore: RootStore) { + makeObservable(this, { + loader: observable, + error: observable.ref, + + workspaces: observable.ref, + labels: observable.ref, + workspaceId: observable.ref, + + // computed + currentWorkspace: computed, + workspaceLabels: computed, + + // actions + setWorkspaceId: action, + workspaceById: action, + workspaceLabelById: action, + + getWorkspaces: action, + getWorkspaceLabels: action, + }); + + this.rootStore = _rootStore; + this.workspaceService = new WorkspaceService(); + this.projectService = new ProjectServices(); + this.issueService = new IssueServices(); + } + + // computed + get currentWorkspace() { + if (!this.workspaceId) return null; + return this.workspaces?.[this.workspaceId] || null; + } + get workspaceLabels() { + if (!this.workspaceId) return null; + const _labels = this.labels?.[this.workspaceId]; + return _labels && Object.keys(_labels).length > 0 ? _labels : null; + } + + // actions + workspaceById = (workspaceId: string) => this.workspaces?.[workspaceId] || null; + workspaceLabelById = (labelId: string) => { + if (!this.workspaceId) return null; + return this.labels?.[this.workspaceId]?.[labelId] || null; + }; + + setWorkspaceId = (workspaceSlug: string) => { + this.workspaceId = workspaceSlug ?? null; + }; + + getWorkspaces = async () => { + try { + this.loader = true; + this.error = null; + + const workspaceResponse = await this.workspaceService.userWorkspaces(); + + let _workspaces: { [key: string]: IWorkspace } = {}; + workspaceResponse.map((_workspace) => { + _workspaces = { ..._workspaces, [_workspace.slug]: _workspace }; + }); + + runInAction(() => { + this.workspaces = _workspaces; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.log(error); + this.loader = false; + this.error = error; + } + }; + + getWorkspaceLabels = async (workspaceSlug: string) => { + try { + this.loader = true; + this.error = null; + + const labelsResponse = await this.issueService.getWorkspaceLabels(workspaceSlug); + let _labels: { [key: string]: IIssueLabels } = {}; + labelsResponse.map((_label) => { + _labels = { ..._labels, [_label.id]: _label }; + }); + + runInAction(() => { + this.labels = { + ...this.labels, + [workspaceSlug]: _labels, + }; + this.loader = false; + this.error = null; + }); + } catch (error) { + console.log(error); + this.loader = false; + this.error = error; + } + }; + + // getMyIssuesAsync = async (workspaceId: string, fetchFilterToggle: boolean = true) => { + // try { + // this.loader = true; + // this.error = null; + + // if (fetchFilterToggle) await this.rootStore.issueFilters.getWorkspaceMyIssuesFilters(workspaceId); + // const filteredParams = this.rootStore.issueFilters.getComputedFilters( + // workspaceId, + // null, + // null, + // null, + // null, + // "my_issues" + // ); + // const issuesResponse = await this.userService.userIssues(workspaceId, filteredParams); + + // if (issuesResponse) { + // const _issueResponse: any = { + // ...this.issues, + // [workspaceId]: { + // ...this?.issues[workspaceId], + // my_issues: { + // ...this?.issues[workspaceId]?.my_issues, + // [this.rootStore?.issueFilters?.userFilters?.display_filters?.layout as string]: issuesResponse, + // }, + // }, + // }; + + // runInAction(() => { + // this.issues = _issueResponse; + // this.loader = false; + // this.error = null; + // }); + // } + + // return issuesResponse; + // } catch (error) { + // console.warn("error in fetching the my issues", error); + // this.loader = false; + // this.error = null; + // return error; + // } + // }; +} + +export default WorkspaceStore; From 908f6716fe0234ae04da0007403a29766d8a4f61 Mon Sep 17 00:00:00 2001 From: gurusainath Date: Wed, 20 Sep 2023 12:40:22 +0530 Subject: [PATCH 024/102] user filter --- web/store/issue-filters.ts | 356 ++++++------------------------------- 1 file changed, 59 insertions(+), 297 deletions(-) diff --git a/web/store/issue-filters.ts b/web/store/issue-filters.ts index 203e836460c..a2825bf1775 100644 --- a/web/store/issue-filters.ts +++ b/web/store/issue-filters.ts @@ -212,13 +212,12 @@ class IssueFilterStore implements IIssueFilterStore { // computed issueLayout: computed, - projectDisplayProperties: computed, userFilters: computed, // actions getComputedFilters: action, - handleUserFilter: action, + handleIssueFilter: action, // getWorkspaceMyIssuesFilters: action, // updateWorkspaceMyIssuesFilters: action, @@ -265,286 +264,39 @@ class IssueFilterStore implements IIssueFilterStore { return null; } - get projectDisplayProperties() { - // if (!this.workspaceId || !this.projectId) return null; - // return this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties as any; - - return null; - } - get userFilters() { - if (!this.projectId) return null; - if (this.issueView === "my_issues") - return { - ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, - display_properties_id: null, - }; - - if (!this.projectId) return null; - let _issueFilters: { + const projectId = this.rootStore?.project?.projectId; + const moduleId = this.rootStore?.module?.moduleId; + const cycleId = this.rootStore?.cycle?.cycleId; + const viewId = this.rootStore?.view?.viewId; + const _issueView = this.issueView; + + if (!projectId || !_issueView) return null; + const currentIssueViewId: string | null = + _issueView === "issues" && projectId + ? projectId + : _issueView === "modules" && moduleId + ? moduleId + : _issueView === "cycles" && cycleId + ? cycleId + : _issueView === "cycles" && viewId + ? viewId + : null; + + if (!currentIssueViewId) return null; + const _issueFilters: { filters: IIssueFilter | null; display_filters: IIssueDisplayFilters; display_properties_id: string; display_properties: IIssueDisplayProperties; } = { - filters: null, - display_filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters, - display_properties_id: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties_id, - display_properties: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.display_properties, + filters: this.issueFilters?.[projectId]?.[_issueView]?.[currentIssueViewId]?.filters, + display_filters: this.issueFilters?.[projectId]?.display_filters, + display_properties_id: this.issueFilters?.[projectId]?.display_properties_id, + display_properties: this.issueFilters?.[projectId]?.display_properties, }; - - if (this.issueView === "issues") { - _issueFilters = { - ..._issueFilters, - filters: this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "modules" && this.moduleId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[this.moduleId] - ?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "cycles" && this.cycleId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[this.cycleId] - ?.filters, - }; - return _issueFilters; - } - - if (this.issueView === "views" && this.viewId) { - _issueFilters = { - ..._issueFilters, - filters: - this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[this.viewId] - ?.filters, - }; - return _issueFilters; - } - - return null; + return _issueFilters; } - handleUserFilter = ( - filter_type: "filters" | "display_filters" | "display_properties", - filter_key: string, - value: any - ) => { - // if (!this.workspaceId) return null; - // if (this.issueView === "my_issues") { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // my_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.my_issue_properties, - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.my_issue_properties?.[filter_type], - // [filter_key]: value, - // }, - // }, - // }, - // }; - // this.updateWorkspaceMyIssuesFilters(this.workspaceId, this.userFilters); - // } - // if (!this.projectId) return null; - // if (filter_type === "display_properties") { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // display_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId] - // ?.display_properties, - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }; - // if (this.userFilters?.display_properties_id) { - // this.updateProjectDisplayProperties( - // this.workspaceId, - // this.projectId, - // this.userFilters?.display_properties_id, - // this.userFilters?.display_properties - // ); - // } - // } - // if (filter_type === "display_filters") { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // issues: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ - // filter_type - // ], - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }, - // }; - // this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { - // filters: this.userFilters?.filters, - // display_filters: this.userFilters?.display_filters, - // }); - // } - // if (filter_type === "filters") { - // if (this.issueView === "issues") { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // issues: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues, - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.[ - // filter_type - // ], - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }, - // }; - // this.updateProjectDisplayFilters(this.workspaceId, this.projectId, { - // filters: this.userFilters?.filters, - // display_filters: this.userFilters?.display_filters, - // }); - // } - // if (this.issueView === "modules" && this.moduleId) { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // modules: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules, - // [this.moduleId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ - // this.moduleId - // ], - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.modules?.[ - // this.moduleId - // ]?.[filter_type], - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }, - // }, - // }; - // this.updateProjectIssueModuleFilters( - // this.workspaceId, - // this.projectId, - // this.moduleId, - // this.userFilters?.filters - // ); - // } - // if (this.issueView === "cycles" && this.cycleId) { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // cycles: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles, - // [this.cycleId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ - // this.cycleId - // ], - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.cycles?.[ - // this.cycleId - // ]?.[filter_type], - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }, - // }, - // }; - // this.updateProjectIssueCyclesFilters(this.workspaceId, this.projectId, this.cycleId, this.userFilters?.filters); - // } - // if (this.issueView === "views" && this.viewId) { - // this.issueFilters = { - // ...this.issueFilters, - // [this.workspaceId]: { - // ...this.issueFilters?.[this.workspaceId], - // project_issue_properties: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties, - // [this.projectId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId], - // views: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views, - // [this.viewId]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ - // this.viewId - // ], - // [filter_type]: { - // ...this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.views?.[ - // this.viewId - // ]?.[filter_type], - // [filter_key]: value, - // }, - // }, - // }, - // }, - // }, - // }, - // }; - // this.updateProjectIssueViewsFilters(this.workspaceId, this.projectId, this.viewId, this.userFilters?.filters); - // } - // } - // if (this.issueView === "my_issues") - // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - // if (this.issueView === "issues") - // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - // if (this.issueView === "modules" && this.moduleId) - // this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); - // if (this.issueView === "cycles" && this.cycleId) - // this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); - // if (this.issueView === "views" && this.viewId) - // this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); - }; computedFilter = (filters: any, filteredParams: any) => { const computedFilters: any = {}; @@ -566,25 +318,24 @@ class IssueFilterStore implements IIssueFilterStore { ) => { this.issueView = _issueView; - // const _layout = this.userFilters?.display_filters?.layout; - const _layout = ""; + const _layout = this.userFilters?.display_filters?.layout; let filteredRouteParams: any = { - // priority: this.userFilters?.filters?.priority || undefined, - // state_group: this.userFilters?.filters?.state_group || undefined, - // state: this.userFilters?.filters?.state || undefined, - // assignees: this.userFilters?.filters?.assignees || undefined, - // created_by: this.userFilters?.filters?.created_by || undefined, - // labels: this.userFilters?.filters?.labels || undefined, - // start_date: this.userFilters?.filters?.start_date || undefined, - // target_date: this.userFilters?.filters?.target_date || undefined, - // group_by: this.userFilters?.display_filters?.group_by || "state", - // order_by: this.userFilters?.display_filters?.order_by || "-created_at", - // type: this.userFilters?.display_filters?.type || undefined, - // sub_issue: this.userFilters?.display_filters?.sub_issue || true, - // show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, - // calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, - // start_target_date: this.userFilters?.display_filters?.start_target_date || true, + priority: this.userFilters?.filters?.priority || undefined, + state_group: this.userFilters?.filters?.state_group || undefined, + state: this.userFilters?.filters?.state || undefined, + assignees: this.userFilters?.filters?.assignees || undefined, + created_by: this.userFilters?.filters?.created_by || undefined, + labels: this.userFilters?.filters?.labels || undefined, + start_date: this.userFilters?.filters?.start_date || undefined, + target_date: this.userFilters?.filters?.target_date || undefined, + group_by: this.userFilters?.display_filters?.group_by || "state", + order_by: this.userFilters?.display_filters?.order_by || "-created_at", + type: this.userFilters?.display_filters?.type || undefined, + sub_issue: this.userFilters?.display_filters?.sub_issue || true, + show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, + calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, + start_target_date: this.userFilters?.display_filters?.start_target_date || true, }; // start date and target date we have to construct the format here @@ -602,16 +353,16 @@ class IssueFilterStore implements IIssueFilterStore { filter_type: "filters" | "display_filters" | "display_properties" | "display_properties_id", value: any ) => { - const projectId = this.rootStore?.project?.projectId || null; - const moduleId = this.rootStore?.module?.moduleId || null; - const cycleId = this.rootStore?.cycle?.cycleId || null; - const viewId = this.rootStore?.view?.viewId || null; - const currentView = this.issueView || null; + const projectId = this.rootStore?.project?.projectId; + const moduleId = this.rootStore?.module?.moduleId; + const cycleId = this.rootStore?.cycle?.cycleId; + const viewId = this.rootStore?.view?.viewId; + const _issueView = this.issueView; console.log("filter_type", filter_type); console.log("value", value); - if (!currentView || !projectId || !moduleId || !cycleId || !viewId) return null; + if (!_issueView || !projectId || !moduleId || !cycleId || !viewId) return null; // let _issueFilters: IIssueFilters = { // ...this.issueFilters, @@ -621,6 +372,17 @@ class IssueFilterStore implements IIssueFilterStore { // }; // console.log("_issueFilters", _issueFilters); + + // if (this.issueView === "my_issues") + // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + // if (this.issueView === "issues") + // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); + // if (this.issueView === "modules" && this.moduleId) + // this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); + // if (this.issueView === "cycles" && this.cycleId) + // this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); + // if (this.issueView === "views" && this.viewId) + // this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); }; // services From a328c530d06c1460feae0ac880439f993bb46311 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Wed, 20 Sep 2023 20:33:25 +0530 Subject: [PATCH 025/102] chore: store setup --- .../analytics/custom-analytics/sidebar.tsx | 47 +-- web/components/analytics/project-modal.tsx | 38 +-- .../automation/auto-close-automation.tsx | 26 +- web/components/command-palette/command-k.tsx | 56 +-- .../command-palette/command-pallette.tsx | 23 +- .../issue/change-issue-assignee.tsx | 2 +- .../issue/change-issue-priority.tsx | 8 +- .../issue/change-issue-state.tsx | 21 +- .../core/modals/bulk-delete-issues-modal.tsx | 14 +- .../core/modals/gpt-assistant-modal.tsx | 39 +-- web/components/core/views/all-views.tsx | 18 +- .../core/views/board-view/board-header.tsx | 24 +- .../core/views/board-view/single-issue.tsx | 47 +-- .../core/views/calendar-view/calendar.tsx | 32 +- .../core/views/calendar-view/single-issue.tsx | 21 +- web/components/core/views/issues-view.tsx | 89 ++--- .../core/views/list-view/single-issue.tsx | 61 +--- .../core/views/list-view/single-list.tsx | 46 +-- .../views/spreadsheet-view/single-issue.tsx | 24 +- .../create-update-estimate-modal.tsx | 14 +- web/components/exporter/export-modal.tsx | 48 +-- web/components/exporter/guide.tsx | 43 +-- .../gantt-chart/hooks/block-update.tsx | 5 +- web/components/inbox/inbox-issue-activity.tsx | 38 +-- web/components/inbox/select-duplicate.tsx | 29 +- .../integration/delete-import-modal.tsx | 23 +- .../integration/github/repo-details.tsx | 13 +- web/components/integration/github/root.tsx | 40 +-- web/components/integration/guide.tsx | 28 +- .../integration/jira/jira-project-detail.tsx | 6 +- web/components/integration/jira/root.tsx | 25 +- .../integration/single-integration-card.tsx | 25 +- .../integration/slack/select-channel.tsx | 12 +- .../issue-layouts/layout-selection.tsx | 2 +- .../issues/attachment/attachment-upload.tsx | 13 +- .../issues/attachment/attachments.tsx | 16 +- .../attachment/delete-attachment-modal.tsx | 24 +- .../issues/delete-draft-issue-modal.tsx | 11 +- web/components/issues/delete-issue-modal.tsx | 28 +- web/components/issues/draft-issue-modal.tsx | 5 +- web/components/issues/main-content.tsx | 54 +-- web/components/issues/modal.tsx | 19 +- .../my-issues/my-issues-select-filters.tsx | 13 +- .../issues/my-issues/my-issues-view.tsx | 45 +-- .../issues/peek-overview/issue-activity.tsx | 7 +- web/components/issues/select/label.tsx | 38 +-- web/components/issues/select/state.tsx | 11 +- .../issues/sidebar-select/blocked.tsx | 18 +- .../issues/sidebar-select/blocker.tsx | 12 +- .../issues/sidebar-select/cycle.tsx | 26 +- .../issues/sidebar-select/duplicate.tsx | 2 +- .../issues/sidebar-select/label.tsx | 49 +-- .../issues/sidebar-select/relates-to.tsx | 2 +- .../issues/sidebar-select/state.tsx | 6 +- web/components/issues/sidebar.tsx | 71 ++-- web/components/issues/sub-issues-list.tsx | 16 +- .../issues/view-select/assignee.tsx | 2 +- .../issues/view-select/due-date.tsx | 10 +- .../issues/view-select/estimate.tsx | 2 +- web/components/issues/view-select/label.tsx | 6 +- .../issues/view-select/priority.tsx | 14 +- .../issues/view-select/start-date.tsx | 10 +- web/components/issues/view-select/state.tsx | 18 +- web/components/labels/create-label-modal.tsx | 21 +- .../labels/create-update-label-inline.tsx | 319 +++++++++--------- web/components/labels/delete-label-modal.tsx | 16 +- web/components/labels/labels-list-modal.tsx | 10 +- web/components/labels/single-label-group.tsx | 22 +- web/components/pages/create-block.tsx | 5 +- .../pages/create-update-block-inline.tsx | 23 +- .../pages/create-update-page-modal.tsx | 9 +- web/components/pages/delete-page-modal.tsx | 33 +- .../pages/pages-list/all-pages-list.tsx | 2 +- .../pages/pages-list/favorite-pages-list.tsx | 5 +- .../pages/pages-list/my-pages-list.tsx | 9 +- .../pages/pages-list/other-pages-list.tsx | 9 +- .../pages/pages-list/recent-pages-list.tsx | 10 +- web/components/pages/pages-view.tsx | 23 +- web/components/pages/single-page-block.tsx | 48 +-- .../profile/profile-issues-view.tsx | 38 +-- .../project/publish-project/modal.tsx | 46 +-- web/components/states/create-state-modal.tsx | 12 +- .../states/create-update-state-inline.tsx | 17 +- web/components/states/delete-state-modal.tsx | 17 +- web/components/states/single-state.tsx | 32 +- web/components/views/form.tsx | 25 +- web/components/views/select-filters.tsx | 15 +- .../web-view/create-update-link-form.tsx | 31 +- web/components/web-view/issue-activity.tsx | 65 +--- web/components/web-view/issue-attachments.tsx | 16 +- web/components/web-view/issue-link-list.tsx | 2 +- .../web-view/issue-properties-detail.tsx | 96 ++---- web/components/web-view/select-parent.tsx | 5 +- web/components/web-view/select-state.tsx | 6 +- web/components/web-view/sub-issues.tsx | 5 +- web/hooks/gantt-chart/issue-view.tsx | 5 +- web/hooks/gantt-chart/view-issues-view.tsx | 2 +- web/hooks/use-calendar-issues-view.tsx | 20 +- web/hooks/use-comment-reaction.tsx | 5 +- web/hooks/use-estimate-option.tsx | 2 +- web/hooks/use-issue-properties.tsx | 12 +- web/hooks/use-issue-reaction.tsx | 12 +- web/hooks/use-issues-view.tsx | 33 +- web/hooks/use-spreadsheet-issues-view.tsx | 20 +- web/hooks/use-sub-issue.tsx | 7 +- web/pages/[workspaceSlug]/analytics.tsx | 6 +- web/pages/[workspaceSlug]/editor.tsx | 6 +- .../archived-issues/[archivedIssueId].tsx | 25 +- .../projects/[projectId]/cycles/[cycleId].tsx | 31 +- .../projects/[projectId]/issues/[issueId].tsx | 8 +- .../projects/[projectId]/pages/[pageId].tsx | 113 ++----- .../[projectId]/settings/estimates.tsx | 32 +- .../[projectId]/settings/features.tsx | 50 +-- .../[projectId]/settings/integrations.tsx | 16 +- .../projects/[projectId]/settings/labels.tsx | 16 +- .../projects/[projectId]/settings/states.tsx | 26 +- .../[workspaceSlug]/settings/integrations.tsx | 7 +- web/pages/installations/[provider]/index.tsx | 2 +- .../projects/[projectId]/issues/[issueId].tsx | 14 +- web/services/ai.service.ts | 6 +- web/services/analytics.service.ts | 4 +- web/services/api.service.ts | 88 +++-- ...service.ts => app_installation.service.ts} | 4 +- web/services/authentication.service.ts | 2 +- .../{integration => }/csv.services.ts | 4 +- web/services/cycles.service.ts | 70 +--- web/services/file.service.ts | 17 +- .../{integration => }/github.service.ts | 20 +- web/services/inbox.service.ts | 28 +- web/services/index.ts | 1 + .../index.ts => integration.service.ts} | 8 +- .../{issues.service.ts => issue.service.ts} | 22 +- ...n.service.ts => issue_reaction.service.ts} | 44 +-- .../{integration => }/jira.service.ts | 8 +- web/services/modules.service.ts | 75 +--- web/services/notifications.service.ts | 78 +---- .../{pages.service.ts => page.service.ts} | 41 +-- web/services/project.service.ts | 2 +- ...ervice.ts => project_estimates.service.ts} | 24 +- ....service.ts => project_publish.service.ts} | 13 +- ...te.service.ts => project_state.service.ts} | 12 +- ...vent.service.ts => track_event.service.ts} | 0 web/services/user.service.ts | 12 +- web/services/views.service.ts | 30 +- web/services/workspace.service.ts | 2 +- web/store/cycles.ts | 2 +- web/store/{draft-issue.ts => draft_issue.ts} | 28 +- web/store/helpers/issue-data.ts | 2 +- web/store/issue.ts | 31 ++ web/store/issue_detail.ts | 4 +- ...sue-filters.ts => issue_filters.legacy.ts} | 8 +- web/store/issue_filters.ts | 23 ++ .../{issue-store.ts => issue_store.legacy.ts} | 14 +- web/store/{issues.ts => issues.legacy.ts} | 2 +- web/store/{issue-views => }/kanban-view.ts | 2 +- web/store/modules.ts | 2 +- web/store/{projects.ts => project.ts} | 263 +++++++++++---- ...project-publish.tsx => project_publish.ts} | 28 +- web/store/root.ts | 26 +- web/store/views.ts | 2 +- web/store/{workspaces.ts => workspace.ts} | 145 ++++---- 161 files changed, 1404 insertions(+), 2790 deletions(-) rename web/services/{app-installations.service.ts => app_installation.service.ts} (95%) rename web/services/{integration => }/csv.services.ts (86%) rename web/services/{integration => }/github.service.ts (70%) create mode 100644 web/services/index.ts rename web/services/{integration/index.ts => integration.service.ts} (91%) rename web/services/{issues.service.ts => issue.service.ts} (97%) rename web/services/{reaction.service.ts => issue_reaction.service.ts} (69%) rename web/services/{integration => }/jira.service.ts (83%) rename web/services/{pages.service.ts => page.service.ts} (85%) rename web/services/{estimates.service.ts => project_estimates.service.ts} (77%) rename web/services/{project-publish.service.ts => project_publish.service.ts} (87%) rename web/services/{state.service.ts => project_state.service.ts} (90%) rename web/services/{track-event.service.ts => track_event.service.ts} (100%) rename web/store/{draft-issue.ts => draft_issue.ts} (89%) create mode 100644 web/store/issue.ts rename web/store/{issue-filters.ts => issue_filters.legacy.ts} (99%) create mode 100644 web/store/issue_filters.ts rename web/store/{issue-store.ts => issue_store.legacy.ts} (96%) rename web/store/{issues.ts => issues.legacy.ts} (98%) rename web/store/{issue-views => }/kanban-view.ts (99%) rename web/store/{projects.ts => project.ts} (53%) rename web/store/{project-publish.tsx => project_publish.ts} (92%) rename web/store/{workspaces.ts => workspace.ts} (53%) diff --git a/web/components/analytics/custom-analytics/sidebar.tsx b/web/components/analytics/custom-analytics/sidebar.tsx index 6189f325bd0..787fa79bde9 100644 --- a/web/components/analytics/custom-analytics/sidebar.tsx +++ b/web/components/analytics/custom-analytics/sidebar.tsx @@ -7,19 +7,14 @@ import analyticsService from "services/analytics.service"; import projectService from "services/project.service"; import cyclesService from "services/cycles.service"; import modulesService from "services/modules.service"; -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // hooks import useProjects from "hooks/use-projects"; import useToast from "hooks/use-toast"; // ui import { PrimaryButton, SecondaryButton } from "components/ui"; // icons -import { - ArrowDownTrayIcon, - ArrowPathIcon, - CalendarDaysIcon, - UserGroupIcon, -} from "@heroicons/react/24/outline"; +import { ArrowDownTrayIcon, ArrowPathIcon, CalendarDaysIcon, UserGroupIcon } from "@heroicons/react/24/outline"; import { ContrastIcon, LayerDiagonalIcon } from "components/icons"; // helpers import { renderShortDate } from "helpers/date-time.helper"; @@ -46,13 +41,7 @@ type Props = { user: ICurrentUserResponse | undefined; }; -export const AnalyticsSidebar: React.FC = ({ - analytics, - params, - fullScreen, - isProjectLevel = false, - user, -}) => { +export const AnalyticsSidebar: React.FC = ({ analytics, params, fullScreen, isProjectLevel = false, user }) => { const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId } = router.query; @@ -61,9 +50,7 @@ export const AnalyticsSidebar: React.FC = ({ const { setToastAlert } = useToast(); const { data: projectDetails } = useSWR( - workspaceSlug && projectId && !(cycleId || moduleId) - ? PROJECT_DETAILS(projectId.toString()) - : null, + workspaceSlug && projectId && !(cycleId || moduleId) ? PROJECT_DETAILS(projectId.toString()) : null, workspaceSlug && projectId && !(cycleId || moduleId) ? () => projectService.getProject(workspaceSlug.toString(), projectId.toString()) : null @@ -72,24 +59,14 @@ export const AnalyticsSidebar: React.FC = ({ const { data: cycleDetails } = useSWR( workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null, workspaceSlug && projectId && cycleId - ? () => - cyclesService.getCycleDetails( - workspaceSlug.toString(), - projectId.toString(), - cycleId.toString() - ) + ? () => cyclesService.getCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString()) : null ); const { data: moduleDetails } = useSWR( workspaceSlug && projectId && moduleId ? MODULE_DETAILS(moduleId.toString()) : null, workspaceSlug && projectId && moduleId - ? () => - modulesService.getModuleDetails( - workspaceSlug.toString(), - projectId.toString(), - moduleId.toString() - ) + ? () => modulesService.getModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString()) : null ); @@ -178,8 +155,7 @@ export const AnalyticsSidebar: React.FC = ({ ); }; - const selectedProjects = - params.project && params.project.length > 0 ? params.project : projects?.map((p) => p.id); + const selectedProjects = params.project && params.project.length > 0 ? params.project : projects?.map((p) => p.id); return (
= ({ )}

{truncateText(project.name, 20)}

- - ({project.identifier}) - + ({project.identifier})
@@ -344,10 +318,7 @@ export const AnalyticsSidebar: React.FC = ({
Network
- - {NETWORK_CHOICES.find((n) => n.key === projectDetails?.network)?.label ?? - ""} - + {NETWORK_CHOICES.find((n) => n.key === projectDetails?.network)?.label ?? ""}
diff --git a/web/components/analytics/project-modal.tsx b/web/components/analytics/project-modal.tsx index d8bb841f7d4..356af91685d 100644 --- a/web/components/analytics/project-modal.tsx +++ b/web/components/analytics/project-modal.tsx @@ -13,15 +13,11 @@ import analyticsService from "services/analytics.service"; import projectService from "services/project.service"; import cyclesService from "services/cycles.service"; import modulesService from "services/modules.service"; -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // components import { CustomAnalytics, ScopeAndDemand } from "components/analytics"; // icons -import { - ArrowsPointingInIcon, - ArrowsPointingOutIcon, - XMarkIcon, -} from "@heroicons/react/24/outline"; +import { ArrowsPointingInIcon, ArrowsPointingOutIcon, XMarkIcon } from "@heroicons/react/24/outline"; // types import { IAnalyticsParams, IWorkspace } from "types"; // fetch-keys @@ -67,9 +63,7 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { ); const { data: projectDetails } = useSWR( - workspaceSlug && projectId && !(cycleId || moduleId) - ? PROJECT_DETAILS(projectId.toString()) - : null, + workspaceSlug && projectId && !(cycleId || moduleId) ? PROJECT_DETAILS(projectId.toString()) : null, workspaceSlug && projectId && !(cycleId || moduleId) ? () => projectService.getProject(workspaceSlug.toString(), projectId.toString()) : null @@ -78,24 +72,14 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { const { data: cycleDetails } = useSWR( workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null, workspaceSlug && projectId && cycleId - ? () => - cyclesService.getCycleDetails( - workspaceSlug.toString(), - projectId.toString(), - cycleId.toString() - ) + ? () => cyclesService.getCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString()) : null ); const { data: moduleDetails } = useSWR( workspaceSlug && projectId && moduleId ? MODULE_DETAILS(moduleId.toString()) : null, workspaceSlug && projectId && moduleId - ? () => - modulesService.getModuleDetails( - workspaceSlug.toString(), - projectId.toString(), - moduleId.toString() - ) + ? () => modulesService.getModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId.toString()) : null ); @@ -134,8 +118,7 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { eventPayload.moduleName = moduleDetails.name; } - const eventType = - tab === "Scope and Demand" ? "SCOPE_AND_DEMAND_ANALYTICS" : "CUSTOM_ANALYTICS"; + const eventType = tab === "Scope and Demand" ? "SCOPE_AND_DEMAND_ANALYTICS" : "CUSTOM_ANALYTICS"; trackEventServices.trackAnalyticsEvent( eventPayload, @@ -150,9 +133,9 @@ export const AnalyticsProjectModal: React.FC = ({ isOpen, onClose }) => { return (
= ({ isOpen, onClose }) => { >

- Analytics for{" "} - {cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name} + Analytics for {cycleId ? cycleDetails?.name : moduleId ? moduleDetails?.name : projectDetails?.name}

-
+
{properties.priority && ( = ({ const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; - const { calendarIssues, mutateIssues, params, displayFilters, setDisplayFilters } = - useCalendarIssuesView(); + const { calendarIssues, mutateIssues, params, displayFilters, setDisplayFilters } = useCalendarIssuesView(); const totalDate = eachDayOfInterval({ start: calendarDates.startDate, @@ -80,8 +73,7 @@ export const CalendarView: React.FC = ({ const filterIssue = calendarIssues.length > 0 ? calendarIssues.filter( - (issue) => - issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date) + (issue) => issue.target_date && renderDateFormat(issue.target_date) === renderDateFormat(date) ) : []; return { @@ -155,18 +147,16 @@ export const CalendarView: React.FC = ({ }); setDisplayFilters({ - calendar_date_range: `${renderDateFormat(startDate)};after,${renderDateFormat( - endDate - )};before`, + calendar_date_range: `${renderDateFormat(startDate)};after,${renderDateFormat(endDate)};before`, }); }; useEffect(() => { if (!displayFilters || displayFilters.calendar_date_range === "") setDisplayFilters({ - calendar_date_range: `${renderDateFormat( - startOfWeek(currentDate) - )};after,${renderDateFormat(lastDayOfWeek(currentDate))};before`, + calendar_date_range: `${renderDateFormat(startOfWeek(currentDate))};after,${renderDateFormat( + lastDayOfWeek(currentDate) + )};before`, }); }, [currentDate, displayFilters, setDisplayFilters]); @@ -214,11 +204,7 @@ export const CalendarView: React.FC = ({ : "" }`} > - - {isMonthlyView - ? formatDate(date, "eee").substring(0, 3) - : formatDate(date, "eee")} - + {isMonthlyView ? formatDate(date, "eee").substring(0, 3) : formatDate(date, "eee")} {!isMonthlyView && {formatDate(date, "d")}}
))} diff --git a/web/components/core/views/calendar-view/single-issue.tsx b/web/components/core/views/calendar-view/single-issue.tsx index 3db571c9933..92e2691c6a9 100644 --- a/web/components/core/views/calendar-view/single-issue.tsx +++ b/web/components/core/views/calendar-view/single-issue.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // react-beautiful-dnd import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useCalendarIssuesView from "hooks/use-calendar-issues-view"; import useIssuesProperties from "hooks/use-issue-properties"; @@ -122,13 +122,7 @@ export const SingleCalendarIssue: React.FC = ({ } issuesService - .patchIssue( - workspaceSlug as string, - projectId as string, - issue.id as string, - formData, - user - ) + .patchIssue(workspaceSlug as string, projectId as string, issue.id as string, formData, user) .then(() => { mutate(fetchKey); }) @@ -140,11 +134,8 @@ export const SingleCalendarIssue: React.FC = ({ ); const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}` - ).then(() => { + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", @@ -153,9 +144,7 @@ export const SingleCalendarIssue: React.FC = ({ }); }; - const displayProperties = properties - ? Object.values(properties).some((value) => value === true) - : false; + const displayProperties = properties ? Object.values(properties).some((value) => value === true) : false; const openPeekOverview = () => { const { query } = router; diff --git a/web/components/core/views/issues-view.tsx b/web/components/core/views/issues-view.tsx index 55eefc39696..6b6e1c909d4 100644 --- a/web/components/core/views/issues-view.tsx +++ b/web/components/core/views/issues-view.tsx @@ -7,10 +7,10 @@ import useSWR, { mutate } from "swr"; // react-beautiful-dnd import { DropResult } from "react-beautiful-dnd"; // services -import issuesService from "services/issues.service"; -import stateService from "services/state.service"; +import issuesService from "services/issue.service"; +import stateService from "services/project_state.service"; import modulesService from "services/modules.service"; -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // hooks import useToast from "hooks/use-toast"; import useIssuesView from "hooks/use-issues-view"; @@ -51,10 +51,7 @@ type Props = { disableUserActions?: boolean; }; -export const IssuesView: React.FC = ({ - openIssuesListModal, - disableUserActions = false, -}) => { +export const IssuesView: React.FC = ({ openIssuesListModal, disableUserActions = false }) => { // create issue modal const [createIssueModal, setCreateIssueModal] = useState(false); const [createViewModal, setCreateViewModal] = useState(null); @@ -64,9 +61,7 @@ export const IssuesView: React.FC = ({ // update issue modal const [editIssueModal, setEditIssueModal] = useState(false); - const [issueToEdit, setIssueToEdit] = useState< - (IIssue & { actionType: "edit" | "delete" }) | undefined - >(undefined); + const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined); // delete issue modal const [deleteIssueModal, setDeleteIssueModal] = useState(false); @@ -87,15 +82,12 @@ export const IssuesView: React.FC = ({ const { setToastAlert } = useToast(); - const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } = - useIssuesView(); + const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } = useIssuesView(); const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string); const { data: stateGroups } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const states = getStatesList(stateGroups); @@ -141,12 +133,10 @@ export const IssuesView: React.FC = ({ // check if dropping in the same group if (source.droppableId === destination.droppableId) { // check if dropping at beginning - if (destination.index === 0) - newSortOrder = destinationGroupArray[0].sort_order - 10000; + if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000; // check if dropping at last else if (destination.index === destinationGroupArray.length - 1) - newSortOrder = - destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000; + newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000; else { if (destination.index > source.index) newSortOrder = @@ -161,12 +151,10 @@ export const IssuesView: React.FC = ({ } } else { // check if dropping at beginning - if (destination.index === 0) - newSortOrder = destinationGroupArray[0].sort_order - 10000; + if (destination.index === 0) newSortOrder = destinationGroupArray[0].sort_order - 10000; // check if dropping at last else if (destination.index === destinationGroupArray.length) - newSortOrder = - destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000; + newSortOrder = destinationGroupArray[destinationGroupArray.length - 1].sort_order + 10000; else newSortOrder = (destinationGroupArray[destination.index - 1].sort_order + @@ -180,18 +168,14 @@ export const IssuesView: React.FC = ({ const destinationGroup = destination.droppableId; // destination group id - if ( - displayFilters.order_by === "sort_order" || - source.droppableId !== destination.droppableId - ) { + if (displayFilters.order_by === "sort_order" || source.droppableId !== destination.droppableId) { // different group/column; // source.droppableId !== destination.droppableId -> even if order by is not sort_order, // if the issue is moved to a different group, then we will change the group of the // dragged item(or issue) - if (displayFilters.group_by === "priority") - draggedItem.priority = destinationGroup as TIssuePriorities; + if (displayFilters.group_by === "priority") draggedItem.priority = destinationGroup as TIssuePriorities; else if (displayFilters.group_by === "state") { draggedItem.state = destinationGroup; draggedItem.state_detail = states?.find((s) => s.id === destinationGroup) as IState; @@ -219,14 +203,8 @@ export const IssuesView: React.FC = ({ return { ...prevData, - [sourceGroup]: orderArrayBy( - sourceGroupArray, - displayFilters.order_by ?? "-created_at" - ), - [destinationGroup]: orderArrayBy( - destinationGroupArray, - displayFilters.order_by ?? "-created_at" - ), + [sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"), + [destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"), }; }, false @@ -246,14 +224,9 @@ export const IssuesView: React.FC = ({ user ) .then((response) => { - const sourceStateBeforeDrag = states?.find( - (state) => state.name === source.droppableId - ); - - if ( - sourceStateBeforeDrag?.group !== "completed" && - response?.state_detail?.group === "completed" - ) + const sourceStateBeforeDrag = states?.find((state) => state.name === source.droppableId); + + if (sourceStateBeforeDrag?.group !== "completed" && response?.state_detail?.group === "completed") trackEventServices.trackIssueMarkedAsDoneEvent( { workspaceSlug, @@ -387,12 +360,7 @@ export const IssuesView: React.FC = ({ ); issuesService - .removeIssueFromCycle( - workspaceSlug as string, - projectId as string, - cycleId as string, - bridgeId - ) + .removeIssueFromCycle(workspaceSlug as string, projectId as string, cycleId as string, bridgeId) .then(() => { setToastAlert({ title: "Success", @@ -430,12 +398,7 @@ export const IssuesView: React.FC = ({ ); modulesService - .removeIssueFromModule( - workspaceSlug as string, - projectId as string, - moduleId as string, - bridgeId - ) + .removeIssueFromModule(workspaceSlug as string, projectId as string, moduleId as string, bridgeId) .then(() => { setToastAlert({ title: "Success", @@ -450,12 +413,9 @@ export const IssuesView: React.FC = ({ [displayFilters.group_by, workspaceSlug, projectId, moduleId, params, setToastAlert] ); - const nullFilters = Object.keys(filters).filter( - (key) => filters[key as keyof IIssueFilterOptions] === null - ); + const nullFilters = Object.keys(filters).filter((key) => filters[key as keyof IIssueFilterOptions] === null); - const areFiltersApplied = - Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length; + const areFiltersApplied = Object.keys(filters).length > 0 && nullFilters.length !== Object.keys(filters).length; return ( <> @@ -581,10 +541,7 @@ export const IssuesView: React.FC = ({ : undefined, secondaryButton: cycleId || moduleId ? ( - {})} - > + {})}> Add an existing issue diff --git a/web/components/core/views/list-view/single-issue.tsx b/web/components/core/views/list-view/single-issue.tsx index 943916d34e2..2e88af8d8ca 100644 --- a/web/components/core/views/list-view/single-issue.tsx +++ b/web/components/core/views/list-view/single-issue.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useToast from "hooks/use-toast"; // components @@ -45,12 +45,7 @@ import { UserAuth, } from "types"; // fetch-keys -import { - CYCLE_DETAILS, - MODULE_DETAILS, - SUB_ISSUES, - USER_PROFILE_PROJECT_SEGREGATION, -} from "constants/fetch-keys"; +import { CYCLE_DETAILS, MODULE_DETAILS, SUB_ISSUES, USER_PROFILE_PROJECT_SEGREGATION } from "constants/fetch-keys"; type Props = { type?: string; @@ -140,39 +135,24 @@ export const SingleListIssue: React.FC = ({ ); } - issuesService - .patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user) - .then(() => { - mutateIssues(); + issuesService.patchIssue(workspaceSlug as string, issue.project, issue.id, formData, user).then(() => { + mutateIssues(); - if (userId) - mutate( - USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) - ); + if (userId) + mutate( + USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) + ); - if (cycleId) mutate(CYCLE_DETAILS(cycleId as string)); - if (moduleId) mutate(MODULE_DETAILS(moduleId as string)); - }); + if (cycleId) mutate(CYCLE_DETAILS(cycleId as string)); + if (moduleId) mutate(MODULE_DETAILS(moduleId as string)); + }); }, - [ - displayFilters, - workspaceSlug, - cycleId, - moduleId, - userId, - groupTitle, - index, - mutateIssues, - user, - ] + [displayFilters, workspaceSlug, cycleId, moduleId, userId, groupTitle, index, mutateIssues, user] ); const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}` - ).then(() => { + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", @@ -197,8 +177,7 @@ export const SingleListIssue: React.FC = ({ }); }; - const isNotAllowed = - userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues; + const isNotAllowed = userAuth.isGuest || userAuth.isViewer || disableUserActions || isArchivedIssues; console.log("properties", properties); @@ -243,9 +222,7 @@ export const SingleListIssue: React.FC = ({ Copy issue link - - Open issue in new tab - + Open issue in new tab )} @@ -286,11 +263,7 @@ export const SingleListIssue: React.FC = ({
-
+
{properties.priority && ( = ({ const { data: issueLabels } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, - workspaceSlug && projectId - ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null ); const { data: members } = useSWR( @@ -120,12 +118,7 @@ export const SingleList: React.FC = ({ switch (displayFilters?.group_by) { case "state": icon = currentState && ( - + ); break; case "state_detail.group": @@ -152,14 +145,8 @@ export const SingleList: React.FC = ({ : null); break; case "labels": - const labelColor = - issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000"; - icon = ( - - ); + const labelColor = issueLabels?.find((label) => label.id === groupTitle)?.color ?? "#000000"; + icon = ; break; case "assignees": case "created_by": @@ -181,9 +168,7 @@ export const SingleList: React.FC = ({
- {displayFilters?.group_by !== null && ( -
{getGroupIcon()}
- )} + {displayFilters?.group_by !== null &&
{getGroupIcon()}
} {displayFilters?.group_by !== null ? (

= ({ > Create new {openIssuesListModal && ( - - Add an existing issue - + Add an existing issue )} )} @@ -256,19 +239,14 @@ export const SingleList: React.FC = ({ makeIssueCopy={() => handleIssueAction(issue, "copy")} handleDeleteIssue={() => handleIssueAction(issue, "delete")} handleDraftIssueSelect={ - handleDraftIssueAction - ? () => handleDraftIssueAction(issue, "edit") - : undefined + handleDraftIssueAction ? () => handleDraftIssueAction(issue, "edit") : undefined } handleDraftIssueDelete={ - handleDraftIssueAction - ? () => handleDraftIssueAction(issue, "delete") - : undefined + handleDraftIssueAction ? () => handleDraftIssueAction(issue, "delete") : undefined } handleMyIssueOpen={handleMyIssueOpen} removeIssue={() => { - if (removeIssue !== null && issue.bridge_id) - removeIssue(issue.bridge_id, issue.id); + if (removeIssue !== null && issue.bridge_id) removeIssue(issue.bridge_id, issue.id); }} disableUserActions={disableUserActions} user={user} @@ -277,9 +255,7 @@ export const SingleList: React.FC = ({ /> )) ) : ( -

- No issues. -

+

No issues.

) ) : (
Loading...
diff --git a/web/components/core/views/spreadsheet-view/single-issue.tsx b/web/components/core/views/spreadsheet-view/single-issue.tsx index 731d7f92175..c4519d2dcd7 100644 --- a/web/components/core/views/spreadsheet-view/single-issue.tsx +++ b/web/components/core/views/spreadsheet-view/single-issue.tsx @@ -17,17 +17,12 @@ import { import { Popover2 } from "@blueprintjs/popover2"; // icons import { Icon } from "components/ui"; -import { - EllipsisHorizontalIcon, - LinkIcon, - PencilIcon, - TrashIcon, -} from "@heroicons/react/24/outline"; +import { EllipsisHorizontalIcon, LinkIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; // hooks import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useToast from "hooks/use-toast"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // constant import { CYCLE_DETAILS, @@ -133,13 +128,7 @@ export const SingleSpreadsheetIssue: React.FC = ({ ); issuesService - .patchIssue( - workspaceSlug as string, - projectId as string, - issue.id as string, - formData, - user - ) + .patchIssue(workspaceSlug as string, projectId as string, issue.id as string, formData, user) .then(() => { if (issue.parent) { mutate(SUB_ISSUES(issue.parent as string)); @@ -167,11 +156,8 @@ export const SingleSpreadsheetIssue: React.FC = ({ }; const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}` - ).then(() => { + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", diff --git a/web/components/estimates/create-update-estimate-modal.tsx b/web/components/estimates/create-update-estimate-modal.tsx index c1dfab86f3b..1242742d43a 100644 --- a/web/components/estimates/create-update-estimate-modal.tsx +++ b/web/components/estimates/create-update-estimate-modal.tsx @@ -9,7 +9,7 @@ import { useForm } from "react-hook-form"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import estimatesService from "services/estimates.service"; +import estimatesService from "services/project_estimates.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -119,13 +119,7 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data, ); await estimatesService - .patchEstimate( - workspaceSlug as string, - projectId as string, - data?.id as string, - payload, - user - ) + .patchEstimate(workspaceSlug as string, projectId as string, data?.id as string, payload, user) .then(() => { mutate(ESTIMATES_LIST(projectId.toString())); mutate(ESTIMATE_DETAILS(data.id)); @@ -257,9 +251,7 @@ export const CreateUpdateEstimateModal: React.FC = ({ handleClose, data,
-
- {data ? "Update" : "Create"} Estimate -
+
{data ? "Update" : "Create"} Estimate
void; }; -export const Exporter: React.FC = ({ - isOpen, - handleClose, - user, - provider, - mutateServices, -}) => { +const cvsService = new CSVIntegrationService(); + +export const Exporter: React.FC = ({ isOpen, handleClose, user, provider, mutateServices }) => { const [exportLoading, setExportLoading] = useState(false); const router = useRouter(); const { workspaceSlug } = router.query; @@ -60,7 +55,8 @@ export const Exporter: React.FC = ({ project: value, multiple: multiple, }; - await CSVIntegrationService.exportCSVService(workspaceSlug as string, payload, user) + await cvsService + .exportCSVService(workspaceSlug as string, payload, user) .then(() => { mutateServices(); router.push(`/${workspaceSlug}/settings/exports`); @@ -69,13 +65,7 @@ export const Exporter: React.FC = ({ type: "success", title: "Export Successful", message: `You will be able to download the exported ${ - provider === "csv" - ? "CSV" - : provider === "xlsx" - ? "Excel" - : provider === "json" - ? "JSON" - : "" + provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : "" } from the previous export.`, }); }) @@ -122,13 +112,7 @@ export const Exporter: React.FC = ({

Export to{" "} - {provider === "csv" - ? "CSV" - : provider === "xlsx" - ? "Excel" - : provider === "json" - ? "JSON" - : ""} + {provider === "csv" ? "CSV" : provider === "xlsx" ? "Excel" : provider === "json" ? "JSON" : ""}

@@ -155,22 +139,12 @@ export const Exporter: React.FC = ({ onClick={() => setMultiple(!multiple)} className="flex items-center gap-2 max-w-min cursor-pointer" > - setMultiple(!multiple)} - /> -
- Export the data into separate files -
+ setMultiple(!multiple)} /> +
Export the data into separate files
Cancel - + {exportLoading ? "Exporting..." : "Export"}
diff --git a/web/components/exporter/guide.tsx b/web/components/exporter/guide.tsx index 2643a07cf7a..553c7c19b9c 100644 --- a/web/components/exporter/guide.tsx +++ b/web/components/exporter/guide.tsx @@ -9,7 +9,7 @@ import useSWR, { mutate } from "swr"; // hooks import useUserAuth from "hooks/use-user-auth"; // services -import IntegrationService from "services/integration"; +import IntegrationService from "services/integration.service"; // components import { Exporter, SingleExport } from "components/exporter"; // ui @@ -32,9 +32,7 @@ const IntegrationGuide = () => { const { user } = useUserAuth(); const { data: exporterServices } = useSWR( - workspaceSlug && cursor - ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) - : null, + workspaceSlug && cursor ? EXPORT_SERVICES_LIST(workspaceSlug as string, cursor, `${per_page}`) : null, workspaceSlug && cursor ? () => IntegrationService.getExportsServicesList(workspaceSlug as string, cursor, per_page) : null @@ -57,20 +55,11 @@ const IntegrationGuide = () => {
- {`${service.title} + {`${service.title}
-

- {service.title} -

-

- {service.description} -

+

{service.title}

+

{service.description}

@@ -96,9 +85,9 @@ const IntegrationGuide = () => { className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs outline-none" onClick={() => { setRefreshing(true); - mutate( - EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`) - ).then(() => setRefreshing(false)); + mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`)).then(() => + setRefreshing(false) + ); }} > {" "} @@ -108,9 +97,7 @@ const IntegrationGuide = () => {
) : ( -

- No previous export available. -

+

No previous export available.

) ) : ( @@ -169,9 +152,7 @@ const IntegrationGuide = () => { data={null} user={user} provider={provider} - mutateServices={() => - mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`)) - } + mutateServices={() => mutate(EXPORT_SERVICES_LIST(workspaceSlug as string, `${cursor}`, `${per_page}`))} /> )}
diff --git a/web/components/gantt-chart/hooks/block-update.tsx b/web/components/gantt-chart/hooks/block-update.tsx index 68e1f6d1216..e1ce642ce04 100644 --- a/web/components/gantt-chart/hooks/block-update.tsx +++ b/web/components/gantt-chart/hooks/block-update.tsx @@ -1,7 +1,7 @@ import { KeyedMutator } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // types import { ICurrentUserResponse, IIssue } from "types"; import { IBlockUpdateData } from "../types"; @@ -34,8 +34,7 @@ export const updateGanttIssue = ( const newPayload: any = { ...payload }; - if (newPayload.sort_order && payload.sort_order) - newPayload.sort_order = payload.sort_order.newSortOrder; + if (newPayload.sort_order && payload.sort_order) newPayload.sort_order = payload.sort_order.newSortOrder; issuesService.patchIssue(workspaceSlug, issue.project, issue.id, newPayload, user); }; diff --git a/web/components/inbox/inbox-issue-activity.tsx b/web/components/inbox/inbox-issue-activity.tsx index dfcbf026246..1e796e16b5b 100644 --- a/web/components/inbox/inbox-issue-activity.tsx +++ b/web/components/inbox/inbox-issue-activity.tsx @@ -5,7 +5,7 @@ import useSWR, { mutate } from "swr"; // components import { AddComment, IssueActivitySection } from "components/issues"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; import useToast from "hooks/use-toast"; @@ -25,16 +25,9 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { const { user } = useUser(); const { data: issueActivity, mutate: mutateIssueActivity } = useSWR( + workspaceSlug && projectId && inboxIssueId ? PROJECT_ISSUES_ACTIVITY(inboxIssueId.toString()) : null, workspaceSlug && projectId && inboxIssueId - ? PROJECT_ISSUES_ACTIVITY(inboxIssueId.toString()) - : null, - workspaceSlug && projectId && inboxIssueId - ? () => - issuesService.getIssueActivities( - workspaceSlug.toString(), - projectId.toString(), - inboxIssueId.toString() - ) + ? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), inboxIssueId.toString()) : null ); @@ -42,14 +35,7 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { if (!workspaceSlug || !projectId || !inboxIssueId) return; await issuesService - .patchIssueComment( - workspaceSlug as string, - projectId as string, - inboxIssueId as string, - commentId, - data, - user - ) + .patchIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, data, user) .then(() => mutateIssueActivity()); }; @@ -59,13 +45,7 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false); await issuesService - .deleteIssueComment( - workspaceSlug as string, - projectId as string, - inboxIssueId as string, - commentId, - user - ) + .deleteIssueComment(workspaceSlug as string, projectId as string, inboxIssueId as string, commentId, user) .then(() => mutateIssueActivity()); }; @@ -73,13 +53,7 @@ export const InboxIssueActivity: React.FC = ({ issueDetails }) => { if (!workspaceSlug || !issueDetails) return; await issuesService - .createIssueComment( - workspaceSlug.toString(), - issueDetails.project, - issueDetails.id, - formData, - user - ) + .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); }) diff --git a/web/components/inbox/select-duplicate.tsx b/web/components/inbox/select-duplicate.tsx index 1cc90508096..8dbb58faa24 100644 --- a/web/components/inbox/select-duplicate.tsx +++ b/web/components/inbox/select-duplicate.tsx @@ -11,7 +11,7 @@ import { Combobox, Dialog, Transition } from "@headlessui/react"; // hooks import useToast from "hooks/use-toast"; // services -import issuesServices from "services/issues.service"; +import issuesServices from "services/issue.service"; // ui import { PrimaryButton, SecondaryButton } from "components/ui"; // icons @@ -39,9 +39,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { const { workspaceSlug, projectId, issueId } = router.query; const { data: issues } = useSWR( - workspaceSlug && projectId - ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) - : null, + workspaceSlug && projectId ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string) : null, workspaceSlug && projectId ? () => issuesServices @@ -71,8 +69,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { handleClose(); }; - const filteredIssues = - (query === "" ? issues : issues?.filter((issue) => issue.name.includes(query))) ?? []; + const filteredIssues = (query === "" ? issues : issues?.filter((issue) => issue.name.includes(query))) ?? []; return ( setQuery("")} appear> @@ -128,9 +125,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { {filteredIssues.length > 0 ? (
  • {query === "" && ( -

    - Select issue -

    +

    Select issue

    )}
      {filteredIssues.map((issue) => ( @@ -140,9 +135,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { value={issue.id} className={({ active, selected }) => `flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-3 py-2 text-custom-text-200 ${ - active || selected - ? "bg-custom-background-80 text-custom-text-100" - : "" + active || selected ? "bg-custom-background-80 text-custom-text-100" : "" } ` } > @@ -154,11 +147,8 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => { }} /> - { - issues?.find((i) => i.id === issue.id)?.project_detail - ?.identifier - } - -{issue.sequence_id} + {issues?.find((i) => i.id === issue.id)?.project_detail?.identifier}- + {issue.sequence_id} {issue.name}
  • @@ -171,10 +161,7 @@ export const SelectDuplicateInboxIssueModal: React.FC = (props) => {

    No issues found. Create a new issue with{" "} -
    -                              C
    -                            
    - . +
    C
    .

    )} diff --git a/web/components/integration/delete-import-modal.tsx b/web/components/integration/delete-import-modal.tsx index d869ae2a6ca..23b95664410 100644 --- a/web/components/integration/delete-import-modal.tsx +++ b/web/components/integration/delete-import-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import IntegrationService from "services/integration"; +import IntegrationService from "services/integration.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -92,10 +92,7 @@ export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data,
    -

    Delete Project

    @@ -104,17 +101,13 @@ export const DeleteImportModal: React.FC = ({ isOpen, handleClose, data,

    Are you sure you want to delete import from{" "} - - {data?.service} - - ? All of the data related to the import will be permanently removed. This - action cannot be undone. + {data?.service} + ? All of the data related to the import will be permanently removed. This action cannot be undone.

    - To confirm, type{" "} - delete import below: + To confirm, type delete import below:

    = ({ isOpen, handleClose, data,
    Cancel - + {deleteLoading ? "Deleting..." : "Delete Project"}
    diff --git a/web/components/integration/github/repo-details.tsx b/web/components/integration/github/repo-details.tsx index 8a9c9719375..b53ae2f01ec 100644 --- a/web/components/integration/github/repo-details.tsx +++ b/web/components/integration/github/repo-details.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // react-hook-form import { UseFormSetValue } from "react-hook-form"; // services -import GithubIntegrationService from "services/integration/github.service"; +import GithubIntegrationService from "services/github.service"; // ui import { Loader, PrimaryButton, SecondaryButton } from "components/ui"; // types @@ -22,19 +22,12 @@ type Props = { setValue: UseFormSetValue; }; -export const GithubRepoDetails: FC = ({ - selectedRepo, - handleStepChange, - setUsers, - setValue, -}) => { +export const GithubRepoDetails: FC = ({ selectedRepo, handleStepChange, setUsers, setValue }) => { const router = useRouter(); const { workspaceSlug } = router.query; const { data: repoInfo } = useSWR( - workspaceSlug && selectedRepo - ? GITHUB_REPOSITORY_INFO(workspaceSlug as string, selectedRepo.name) - : null, + workspaceSlug && selectedRepo ? GITHUB_REPOSITORY_INFO(workspaceSlug as string, selectedRepo.name) : null, workspaceSlug && selectedRepo ? () => GithubIntegrationService.getGithubRepoInfo(workspaceSlug as string, { diff --git a/web/components/integration/github/root.tsx b/web/components/integration/github/root.tsx index 2e5d9e0c427..10b5efd76f7 100644 --- a/web/components/integration/github/root.tsx +++ b/web/components/integration/github/root.tsx @@ -9,8 +9,8 @@ import useSWR, { mutate } from "swr"; // react-hook-form import { useForm } from "react-hook-form"; // services -import IntegrationService from "services/integration"; -import GithubIntegrationService from "services/integration/github.service"; +import IntegrationService from "services/integration.service"; +import GithubIntegrationService from "services/github.service"; // hooks import useToast from "hooks/use-toast"; // components @@ -29,18 +29,9 @@ import GithubLogo from "public/services/github.png"; // types import { ICurrentUserResponse, IGithubRepoCollaborator, IGithubServiceImportFormData } from "types"; // fetch-keys -import { - APP_INTEGRATIONS, - IMPORTER_SERVICES_LIST, - WORKSPACE_INTEGRATIONS, -} from "constants/fetch-keys"; +import { APP_INTEGRATIONS, IMPORTER_SERVICES_LIST, WORKSPACE_INTEGRATIONS } from "constants/fetch-keys"; -export type TIntegrationSteps = - | "import-configure" - | "import-data" - | "repo-details" - | "import-users" - | "import-confirm"; +export type TIntegrationSteps = "import-configure" | "import-data" | "repo-details" | "import-users" | "import-confirm"; export interface IIntegrationData { state: TIntegrationSteps; } @@ -108,21 +99,15 @@ export const GithubImporterRoot: React.FC = ({ user }) => { defaultValues: defaultFormValues, }); - const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () => - IntegrationService.getAppIntegrationsList() - ); + const { data: appIntegrations } = useSWR(APP_INTEGRATIONS, () => IntegrationService.getAppIntegrationsList()); const { data: workspaceIntegrations } = useSWR( workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null, - workspaceSlug - ? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) - : null + workspaceSlug ? () => IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null ); const activeIntegrationState = () => { - const currentElementIndex = integrationWorkflowData.findIndex( - (i) => i?.key === currentStep?.state - ); + const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state); return currentElementIndex; }; @@ -133,14 +118,11 @@ export const GithubImporterRoot: React.FC = ({ user }) => { // current integration from all the integrations available const integration = - appIntegrations && - appIntegrations.length > 0 && - appIntegrations.find((i) => i.provider === provider); + appIntegrations && appIntegrations.length > 0 && appIntegrations.find((i) => i.provider === provider); // current integration from workspace integrations const workspaceIntegration = - integration && - workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id); + integration && workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id); const createGithubImporterService = async (formData: TFormValues) => { if (!formData.github || !formData.project) return; @@ -214,9 +196,7 @@ export const GithubImporterRoot: React.FC = ({ user }) => {
    {" "} diff --git a/web/components/integration/guide.tsx b/web/components/integration/guide.tsx index 2ee0e0121fc..3d8e5d39a91 100644 --- a/web/components/integration/guide.tsx +++ b/web/components/integration/guide.tsx @@ -9,14 +9,9 @@ import useSWR, { mutate } from "swr"; // hooks import useUserAuth from "hooks/use-user-auth"; // services -import IntegrationService from "services/integration"; +import IntegrationService from "services/integration.service"; // components -import { - DeleteImportModal, - GithubImporterRoot, - JiraImporterRoot, - SingleImport, -} from "components/integration"; +import { DeleteImportModal, GithubImporterRoot, JiraImporterRoot, SingleImport } from "components/integration"; // ui import { Loader, PrimaryButton } from "components/ui"; // icons @@ -85,18 +80,11 @@ const IntegrationGuide = () => { >
    - {`${service.title} + {`${service.title}

    {service.title}

    -

    - {service.description} -

    +

    {service.description}

    @@ -119,9 +107,7 @@ const IntegrationGuide = () => { className="flex flex-shrink-0 items-center gap-1 rounded bg-custom-background-80 py-1 px-1.5 text-xs outline-none" onClick={() => { setRefreshing(true); - mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() => - setRefreshing(false) - ); + mutate(IMPORTER_SERVICES_LIST(workspaceSlug as string)).then(() => setRefreshing(false)); }} > {" "} @@ -145,9 +131,7 @@ const IntegrationGuide = () => {
    ) : ( -

    - No previous imports available. -

    +

    No previous imports available.

    ) ) : ( diff --git a/web/components/integration/jira/jira-project-detail.tsx b/web/components/integration/jira/jira-project-detail.tsx index f651ad89cfe..edd35231fbb 100644 --- a/web/components/integration/jira/jira-project-detail.tsx +++ b/web/components/integration/jira/jira-project-detail.tsx @@ -10,7 +10,7 @@ import useSWR from "swr"; import { useFormContext, Controller } from "react-hook-form"; // services -import jiraImporterService from "services/integration/jira.service"; +import jiraImporterService from "services/jira.service"; // fetch keys import { JIRA_IMPORTER_DETAIL } from "constants/fetch-keys"; @@ -157,9 +157,7 @@ export const JiraProjectDetail: React.FC = (props) => { ( - - )} + render={({ field: { value, onChange } }) => } />
    diff --git a/web/components/integration/jira/root.tsx b/web/components/integration/jira/root.tsx index 451c2370959..2a4b572ec17 100644 --- a/web/components/integration/jira/root.tsx +++ b/web/components/integration/jira/root.tsx @@ -16,7 +16,7 @@ import { ArrowLeftIcon, ListBulletIcon } from "@heroicons/react/24/outline"; import { CogIcon, UsersIcon, CheckIcon } from "components/icons"; // services -import jiraImporterService from "services/integration/jira.service"; +import jiraImporterService from "services/jira.service"; // fetch keys import { IMPORTER_SERVICES_LIST } from "constants/fetch-keys"; @@ -100,9 +100,7 @@ export const JiraImporterRoot: React.FC = ({ user }) => { }; const activeIntegrationState = () => { - const currentElementIndex = integrationWorkflowData.findIndex( - (i) => i?.key === currentStep?.state - ); + const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state); return currentElementIndex; }; @@ -155,9 +153,7 @@ export const JiraImporterRoot: React.FC = ({ user }) => {
    {" "} @@ -174,10 +170,7 @@ export const JiraImporterRoot: React.FC = ({ user }) => {
    {currentStep.state === "import-configure" && } {currentStep.state === "display-import-data" && ( - + )} {currentStep?.state === "import-users" && } {currentStep?.state === "import-confirmation" && } @@ -199,15 +192,9 @@ export const JiraImporterRoot: React.FC = ({ user }) => { )} { - const currentElementIndex = integrationWorkflowData.findIndex( - (i) => i?.key === currentStep?.state - ); + const currentElementIndex = integrationWorkflowData.findIndex((i) => i?.key === currentStep?.state); if (currentElementIndex === integrationWorkflowData.length - 1) { methods.handleSubmit(onSubmit)(); diff --git a/web/components/integration/single-integration-card.tsx b/web/components/integration/single-integration-card.tsx index fab37b0c8ee..8dbc60bf58d 100644 --- a/web/components/integration/single-integration-card.tsx +++ b/web/components/integration/single-integration-card.tsx @@ -6,7 +6,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import IntegrationService from "services/integration"; +import IntegrationService from "services/integration.service"; // hooks import useToast from "hooks/use-toast"; import useIntegrationPopup from "hooks/use-integration-popup"; @@ -50,25 +50,17 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => { const { data: workspaceIntegrations } = useSWR( workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null, - () => - workspaceSlug - ? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) - : null + () => (workspaceSlug ? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null) ); const handleRemoveIntegration = async () => { if (!workspaceSlug || !integration || !workspaceIntegrations) return; - const workspaceIntegrationId = workspaceIntegrations?.find( - (i) => i.integration === integration.id - )?.id; + const workspaceIntegrationId = workspaceIntegrations?.find((i) => i.integration === integration.id)?.id; setDeletingIntegration(true); - await IntegrationService.deleteWorkspaceIntegration( - workspaceSlug as string, - workspaceIntegrationId ?? "" - ) + await IntegrationService.deleteWorkspaceIntegration(workspaceSlug as string, workspaceIntegrationId ?? "") .then(() => { mutate( WORKSPACE_INTEGRATIONS(workspaceSlug as string), @@ -94,18 +86,13 @@ export const SingleIntegrationCard: React.FC = ({ integration }) => { }); }; - const isInstalled = workspaceIntegrations?.find( - (i: any) => i.integration_detail.id === integration.id - ); + const isInstalled = workspaceIntegrations?.find((i: any) => i.integration_detail.id === integration.id); return (
    - {`${integration.title} + {`${integration.title}

    diff --git a/web/components/integration/slack/select-channel.tsx b/web/components/integration/slack/select-channel.tsx index 712c168df87..728b582f146 100644 --- a/web/components/integration/slack/select-channel.tsx +++ b/web/components/integration/slack/select-channel.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import appinstallationsService from "services/app-installations.service"; +import appinstallationsService from "services/app_installation.service"; // ui import { Loader } from "components/ui"; // hooks @@ -20,8 +20,7 @@ type Props = { }; export const SelectChannel: React.FC = ({ integration }) => { - const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = - useState(false); + const [slackChannelAvailabilityToggle, setSlackChannelAvailabilityToggle] = useState(false); const [slackChannel, setSlackChannel] = useState(null); const router = useRouter(); @@ -65,12 +64,7 @@ export const SelectChannel: React.FC = ({ integration }) => { setSlackChannel(null); }); appinstallationsService - .removeSlackChannel( - workspaceSlug as string, - projectId as string, - integration.id as string, - slackChannel?.id - ) + .removeSlackChannel(workspaceSlug as string, projectId as string, integration.id as string, slackChannel?.id) .catch((err) => console.log(err)); }; diff --git a/web/components/issue-layouts/layout-selection.tsx b/web/components/issue-layouts/layout-selection.tsx index 32ae742d85d..a6629a2aa41 100644 --- a/web/components/issue-layouts/layout-selection.tsx +++ b/web/components/issue-layouts/layout-selection.tsx @@ -7,7 +7,7 @@ import { observer } from "mobx-react-lite"; import { RootStore } from "store/root"; import { useMobxStore } from "lib/mobx/store-provider"; // types and default data -import { TIssueLayouts } from "store/issue-filters"; +import { TIssueLayouts } from "store/issue_filters.legacy"; import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const LayoutSelection = observer(() => { diff --git a/web/components/issues/attachment/attachment-upload.tsx b/web/components/issues/attachment/attachment-upload.tsx index be75f703bb1..592954afa1a 100644 --- a/web/components/issues/attachment/attachment-upload.tsx +++ b/web/components/issues/attachment/attachment-upload.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // react-dropzone import { useDropzone } from "react-dropzone"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useToast from "hooks/use-toast"; // types @@ -44,12 +44,7 @@ export const IssueAttachmentUpload: React.FC = ({ disabled = false }) => setIsLoading(true); issuesService - .uploadIssueAttachment( - workspaceSlug as string, - projectId as string, - issueId as string, - formData - ) + .uploadIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, formData) .then((res) => { mutate( ISSUE_ATTACHMENTS(issueId as string), @@ -83,9 +78,7 @@ export const IssueAttachmentUpload: React.FC = ({ disabled = false }) => }); const fileError = - fileRejections.length > 0 - ? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)` - : null; + fileRejections.length > 0 ? `Invalid file type or size (max ${maxFileSize / 1024 / 1024} MB)` : null; return (
    { const { data: attachments } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_ATTACHMENTS(issueId as string) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.getIssueAttachment( - workspaceSlug as string, - projectId as string, - issueId as string - ) + ? () => issuesService.getIssueAttachment(workspaceSlug as string, projectId as string, issueId as string) : null ); @@ -70,14 +65,11 @@ export const IssueAttachments = () => {
    - - {truncateText(`${getFileName(file.attributes.name)}`, 10)} - + {truncateText(`${getFileName(file.attributes.name)}`, 10)} person.member.id === file.updated_by)?.member - .display_name ?? "" + people?.find((person) => person.member.id === file.updated_by)?.member.display_name ?? "" } uploaded on ${renderLongDateFormat(file.updated_at)}`} > diff --git a/web/components/issues/attachment/delete-attachment-modal.tsx b/web/components/issues/attachment/delete-attachment-modal.tsx index 7c0495dd6c8..62dc3cffe13 100644 --- a/web/components/issues/attachment/delete-attachment-modal.tsx +++ b/web/components/issues/attachment/delete-attachment-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -47,12 +47,7 @@ export const DeleteAttachmentModal: React.FC = ({ isOpen, setIsOpen, data ); await issuesService - .deleteIssueAttachment( - workspaceSlug as string, - projectId as string, - issueId as string, - assetId as string - ) + .deleteIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, assetId as string) .then(() => mutate(PROJECT_ISSUES_ACTIVITY(issueId as string))) .catch(() => { setToastAlert({ @@ -94,24 +89,17 @@ export const DeleteAttachmentModal: React.FC = ({ isOpen, setIsOpen, data
    -
    - + Delete Attachment

    Are you sure you want to delete attachment-{" "} - {getFileName(data.attributes.name)}? - This attachment will be permanently removed. This action cannot be - undone. + {getFileName(data.attributes.name)}? This attachment will + be permanently removed. This action cannot be undone.

    diff --git a/web/components/issues/delete-draft-issue-modal.tsx b/web/components/issues/delete-draft-issue-modal.tsx index 6fc4f42189c..8928fe51c9f 100644 --- a/web/components/issues/delete-draft-issue-modal.tsx +++ b/web/components/issues/delete-draft-issue-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import issueServices from "services/issues.service"; +import issueServices from "services/issue.service"; // hooks import useIssuesView from "hooks/use-issues-view"; import useToast from "hooks/use-toast"; @@ -109,10 +109,7 @@ export const DeleteDraftIssueModal: React.FC = (props) => {
    -

    Delete Draft Issue

    @@ -124,8 +121,8 @@ export const DeleteDraftIssueModal: React.FC = (props) => { {data?.project_detail.identifier}-{data?.sequence_id} - {""}? All of the data related to the draft issue will be permanently removed. - This action cannot be undone. + {""}? All of the data related to the draft issue will be permanently removed. This action cannot + be undone.

    diff --git a/web/components/issues/delete-issue-modal.tsx b/web/components/issues/delete-issue-modal.tsx index d76e5ddd2ed..67e8c88c9a5 100644 --- a/web/components/issues/delete-issue-modal.tsx +++ b/web/components/issues/delete-issue-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import issueServices from "services/issues.service"; +import issueServices from "services/issue.service"; // hooks import useIssuesView from "hooks/use-issues-view"; import useCalendarIssuesView from "hooks/use-calendar-issues-view"; @@ -37,13 +37,7 @@ type Props = { onSubmit?: () => Promise; }; -export const DeleteIssueModal: React.FC = ({ - isOpen, - handleClose, - data, - user, - onSubmit, -}) => { +export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, user, onSubmit }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -82,11 +76,7 @@ export const DeleteIssueModal: React.FC = ({ ? VIEW_ISSUES(viewId.toString(), calendarParams) : PROJECT_ISSUES_LIST_WITH_PARAMS(data.project, calendarParams); - mutate( - calendarFetchKey, - (prevData) => (prevData ?? []).filter((p) => p.id !== data.id), - false - ); + mutate(calendarFetchKey, (prevData) => (prevData ?? []).filter((p) => p.id !== data.id), false); } else if (displayFilters.layout === "spreadsheet") { const spreadsheetFetchKey = cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), spreadsheetParams) @@ -163,8 +153,7 @@ export const DeleteIssueModal: React.FC = ({ }); }; - const handleIssueDelete = () => - isArchivedIssues ? handleArchivedIssueDeletion() : handleDeletion(); + const handleIssueDelete = () => (isArchivedIssues ? handleArchivedIssueDeletion() : handleDeletion()); return ( @@ -196,10 +185,7 @@ export const DeleteIssueModal: React.FC = ({
    -

    Delete Issue

    @@ -211,8 +197,8 @@ export const DeleteIssueModal: React.FC = ({ {data?.project_detail.identifier}-{data?.sequence_id} - {""}? All of the data related to the issue will be permanently removed. This - action cannot be undone. + {""}? All of the data related to the issue will be permanently removed. This action cannot be + undone.

    diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index 3b0664cb804..eafc2a4dfe9 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; import useIssuesView from "hooks/use-issues-view"; @@ -114,8 +114,7 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ return; } - if (prePopulateData && prePopulateData.project) - return setActiveProject(prePopulateData.project); + if (prePopulateData && prePopulateData.project) return setActiveProject(prePopulateData.project); // if data is not present, set active project to the project // in the url. This has the least priority. diff --git a/web/components/issues/main-content.tsx b/web/components/issues/main-content.tsx index b7b154ce2c6..d4dd636cbc7 100644 --- a/web/components/issues/main-content.tsx +++ b/web/components/issues/main-content.tsx @@ -4,7 +4,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUserAuth from "hooks/use-user-auth"; import useToast from "hooks/use-toast"; @@ -37,11 +37,7 @@ type Props = { uneditable?: boolean; }; -export const IssueMainContent: React.FC = ({ - issueDetails, - submitChanges, - uneditable = false, -}) => { +export const IssueMainContent: React.FC = ({ issueDetails, submitChanges, uneditable = false }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId, archivedIssueId } = router.query; @@ -55,12 +51,7 @@ export const IssueMainContent: React.FC = ({ const { data: siblingIssues } = useSWR( workspaceSlug && projectId && issueDetails?.parent ? SUB_ISSUES(issueDetails.parent) : null, workspaceSlug && projectId && issueDetails?.parent - ? () => - issuesService.subIssues( - workspaceSlug as string, - projectId as string, - issueDetails.parent ?? "" - ) + ? () => issuesService.subIssues(workspaceSlug as string, projectId as string, issueDetails.parent ?? "") : null ); const siblingIssuesList = siblingIssues?.sub_issues.filter((i) => i.id !== issueDetails.id); @@ -68,12 +59,7 @@ export const IssueMainContent: React.FC = ({ const { data: issueActivity, mutate: mutateIssueActivity } = useSWR( workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId.toString()) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.getIssueActivities( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString() - ) + ? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null ); @@ -81,14 +67,7 @@ export const IssueMainContent: React.FC = ({ if (!workspaceSlug || !projectId || !issueId) return; await issuesService - .patchIssueComment( - workspaceSlug as string, - projectId as string, - issueId as string, - commentId, - data, - user - ) + .patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, data, user) .then(() => mutateIssueActivity()); }; @@ -98,13 +77,7 @@ export const IssueMainContent: React.FC = ({ mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false); await issuesService - .deleteIssueComment( - workspaceSlug as string, - projectId as string, - issueId as string, - commentId, - user - ) + .deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, user) .then(() => mutateIssueActivity()); }; @@ -112,13 +85,7 @@ export const IssueMainContent: React.FC = ({ if (!workspaceSlug || !issueDetails) return; await issuesService - .createIssueComment( - workspaceSlug.toString(), - issueDetails.project, - issueDetails.id, - formData, - user - ) + .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); }) @@ -148,8 +115,7 @@ export const IssueMainContent: React.FC = ({ }} /> - {issueDetails.parent_detail?.project_detail.identifier}- - {issueDetails.parent_detail?.sequence_id} + {issueDetails.parent_detail?.project_detail.identifier}-{issueDetails.parent_detail?.sequence_id}
    @@ -169,9 +135,7 @@ export const IssueMainContent: React.FC = ({ diff --git a/web/components/issues/modal.tsx b/web/components/issues/modal.tsx index 65580c94ae1..88dc38f7ac1 100644 --- a/web/components/issues/modal.tsx +++ b/web/components/issues/modal.tsx @@ -8,7 +8,7 @@ import { mutate } from "swr"; import { Dialog, Transition } from "@headlessui/react"; // services import modulesService from "services/modules.service"; -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import inboxServices from "services/inbox.service"; // hooks import useUser from "hooks/use-user"; @@ -93,8 +93,10 @@ export const CreateUpdateIssueModal: React.FC = ({ const { groupedIssues, mutateMyIssues } = useMyIssues(workspaceSlug?.toString()); - const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = - useLocalStorage("draftedIssue", {}); + const { setValue: setValueInLocalStorage, clearValue: clearLocalStorageValue } = useLocalStorage( + "draftedIssue", + {} + ); const { setToastAlert } = useToast(); @@ -201,13 +203,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }; await inboxServices - .createInboxIssue( - workspaceSlug.toString(), - activeProject.toString(), - inboxId.toString(), - payload, - user - ) + .createInboxIssue(workspaceSlug.toString(), activeProject.toString(), inboxId.toString(), payload, user) .then((res) => { setToastAlert({ type: "success", @@ -264,8 +260,7 @@ export const CreateUpdateIssueModal: React.FC = ({ .then(async (res) => { mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle); - if (payload.module && payload.module !== "") - await addIssueToModule(res.id, payload.module); + if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module); if (displayFilters.layout === "calendar") mutate(calendarFetchKey); if (displayFilters.layout === "gantt_chart") diff --git a/web/components/issues/my-issues/my-issues-select-filters.tsx b/web/components/issues/my-issues/my-issues-select-filters.tsx index ce8e03797f2..450381e1a30 100644 --- a/web/components/issues/my-issues/my-issues-select-filters.tsx +++ b/web/components/issues/my-issues/my-issues-select-filters.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // components import { DateFilterModal } from "components/core"; // ui @@ -29,12 +29,7 @@ type Props = { height?: "sm" | "md" | "rg" | "lg"; }; -export const MyIssuesSelectFilters: React.FC = ({ - filters, - onSelect, - direction = "right", - height = "md", -}) => { +export const MyIssuesSelectFilters: React.FC = ({ filters, onSelect, direction = "right", height = "md" }) => { const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false); const [dateFilterType, setDateFilterType] = useState<{ title: string; @@ -50,9 +45,7 @@ export const MyIssuesSelectFilters: React.FC = ({ const { data: labels } = useSWR( workspaceSlug && fetchLabels ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, - workspaceSlug && fetchLabels - ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) - : null + workspaceSlug && fetchLabels ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null ); return ( diff --git a/web/components/issues/my-issues/my-issues-view.tsx b/web/components/issues/my-issues/my-issues-view.tsx index ced16b3217b..26e49fa2cb5 100644 --- a/web/components/issues/my-issues/my-issues-view.tsx +++ b/web/components/issues/my-issues/my-issues-view.tsx @@ -7,7 +7,7 @@ import useSWR, { mutate } from "swr"; // react-beautiful-dnd import { DropResult } from "react-beautiful-dnd"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useMyIssues from "hooks/my-issues/use-my-issues"; import useMyIssuesFilters from "hooks/my-issues/use-my-issues-filter"; @@ -28,10 +28,7 @@ type Props = { disableUserActions?: false; }; -export const MyIssuesView: React.FC = ({ - openIssuesListModal, - disableUserActions = false, -}) => { +export const MyIssuesView: React.FC = ({ openIssuesListModal, disableUserActions = false }) => { // create issue modal const [createIssueModal, setCreateIssueModal] = useState(false); const [preloadedData, setPreloadedData] = useState< @@ -40,9 +37,7 @@ export const MyIssuesView: React.FC = ({ // update issue modal const [editIssueModal, setEditIssueModal] = useState(false); - const [issueToEdit, setIssueToEdit] = useState< - (IIssue & { actionType: "edit" | "delete" }) | undefined - >(undefined); + const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined); // delete issue modal const [deleteIssueModal, setDeleteIssueModal] = useState(false); @@ -57,14 +52,10 @@ export const MyIssuesView: React.FC = ({ const { user } = useUserAuth(); const { groupedIssues, mutateMyIssues, isEmpty, params } = useMyIssues(workspaceSlug?.toString()); - const { filters, setFilters, displayFilters, properties } = useMyIssuesFilters( - workspaceSlug?.toString() - ); + const { filters, setFilters, displayFilters, properties } = useMyIssuesFilters(workspaceSlug?.toString()); const { data: labels } = useSWR( - workspaceSlug && (filters?.labels ?? []).length > 0 - ? WORKSPACE_LABELS(workspaceSlug.toString()) - : null, + workspaceSlug && (filters?.labels ?? []).length > 0 ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, workspaceSlug && (filters?.labels ?? []).length > 0 ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null @@ -82,13 +73,7 @@ export const MyIssuesView: React.FC = ({ async (result: DropResult) => { setTrashBox(false); - if ( - !result.destination || - !workspaceSlug || - !groupedIssues || - displayFilters?.group_by !== "priority" - ) - return; + if (!result.destination || !workspaceSlug || !groupedIssues || displayFilters?.group_by !== "priority") return; const { source, destination } = result; @@ -120,14 +105,8 @@ export const MyIssuesView: React.FC = ({ return { ...prevData, - [sourceGroup]: orderArrayBy( - sourceGroupArray, - displayFilters.order_by ?? "-created_at" - ), - [destinationGroup]: orderArrayBy( - destinationGroupArray, - displayFilters.order_by ?? "-created_at" - ), + [sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"), + [destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"), }; }, false @@ -219,15 +198,11 @@ export const MyIssuesView: React.FC = ({ (key) => filtersToDisplay[key as keyof IIssueFilterOptions] === null ); const areFiltersApplied = - Object.keys(filtersToDisplay).length > 0 && - nullFilters.length !== Object.keys(filtersToDisplay).length; + Object.keys(filtersToDisplay).length > 0 && nullFilters.length !== Object.keys(filtersToDisplay).length; const isSubscribedIssuesRoute = router.pathname.includes("subscribed"); const isMySubscribedIssues = - (filters.subscriber && - filters.subscriber.length > 0 && - router.pathname.includes("my-issues")) ?? - false; + (filters.subscriber && filters.subscriber.length > 0 && router.pathname.includes("my-issues")) ?? false; const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues; diff --git a/web/components/issues/peek-overview/issue-activity.tsx b/web/components/issues/peek-overview/issue-activity.tsx index 68e608dbaa5..6639a2473e4 100644 --- a/web/components/issues/peek-overview/issue-activity.tsx +++ b/web/components/issues/peek-overview/issue-activity.tsx @@ -1,7 +1,7 @@ import useSWR, { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; import useToast from "hooks/use-toast"; @@ -78,10 +78,7 @@ export const PeekOverviewIssueActivity: React.FC = ({ workspaceSlug, issu showAccessSpecifier={projectDetails && projectDetails.is_deployed} />
    - +
    diff --git a/web/components/issues/select/label.tsx b/web/components/issues/select/label.tsx index cf960b3a097..a7772a691f7 100644 --- a/web/components/issues/select/label.tsx +++ b/web/components/issues/select/label.tsx @@ -7,17 +7,11 @@ import useSWR from "swr"; // headless ui import { Combobox, Transition } from "@headlessui/react"; // services -import issuesServices from "services/issues.service"; +import issuesServices from "services/issue.service"; // ui import { IssueLabelsList } from "components/ui"; // icons -import { - CheckIcon, - MagnifyingGlassIcon, - PlusIcon, - RectangleGroupIcon, - TagIcon, -} from "@heroicons/react/24/outline"; +import { CheckIcon, MagnifyingGlassIcon, PlusIcon, RectangleGroupIcon, TagIcon } from "@heroicons/react/24/outline"; // types import type { IIssueLabels } from "types"; // fetch-keys @@ -39,24 +33,14 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, const { data: issueLabels } = useSWR( projectId ? PROJECT_ISSUE_LABELS(projectId) : null, - workspaceSlug && projectId - ? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId) - : null + workspaceSlug && projectId ? () => issuesServices.getIssueLabels(workspaceSlug as string, projectId) : null ); const filteredOptions = - query === "" - ? issueLabels - : issueLabels?.filter((l) => l.name.toLowerCase().includes(query.toLowerCase())); + query === "" ? issueLabels : issueLabels?.filter((l) => l.name.toLowerCase().includes(query.toLowerCase())); return ( - onChange(val)} - className="relative flex-shrink-0" - multiple - > + onChange(val)} className="relative flex-shrink-0" multiple> {({ open }: any) => ( <> @@ -129,11 +113,7 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, {label.name}
    - +
    )} @@ -168,11 +148,7 @@ export const IssueLabelSelect: React.FC = ({ setIsOpen, value, onChange, {child.name}
    - +
    )} diff --git a/web/components/issues/select/state.tsx b/web/components/issues/select/state.tsx index 22a4e65324a..ff97fda25eb 100644 --- a/web/components/issues/select/state.tsx +++ b/web/components/issues/select/state.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // ui import { CustomSearchSelect } from "components/ui"; // icons @@ -30,9 +30,7 @@ export const IssueStateSelect: React.FC = ({ setIsOpen, value, onChange, const { data: stateGroups } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId) : null ); const states = getStatesList(stateGroups); @@ -60,10 +58,7 @@ export const IssueStateSelect: React.FC = ({ setIsOpen, value, onChange, {selectedOption ? ( ) : currentDefaultState ? ( - + ) : ( )} diff --git a/web/components/issues/sidebar-select/blocked.tsx b/web/components/issues/sidebar-select/blocked.tsx index d7e448377c8..c65d10437c4 100644 --- a/web/components/issues/sidebar-select/blocked.tsx +++ b/web/components/issues/sidebar-select/blocked.tsx @@ -7,7 +7,7 @@ import { UseFormWatch } from "react-hook-form"; import useToast from "hooks/use-toast"; import useUser from "hooks/use-user"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // components import { ExistingIssuesListModal } from "components/core"; // icons @@ -23,12 +23,7 @@ type Props = { disabled?: boolean; }; -export const SidebarBlockedSelect: React.FC = ({ - issueId, - submitChanges, - watch, - disabled = false, -}) => { +export const SidebarBlockedSelect: React.FC = ({ issueId, submitChanges, watch, disabled = false }) => { const [isBlockedModalOpen, setIsBlockedModalOpen] = useState(false); const { user } = useUser(); @@ -80,10 +75,7 @@ export const SidebarBlockedSelect: React.FC = ({ }) .then((response) => { submitChanges({ - related_issues: [ - ...watch("related_issues")?.filter((i) => i.relation_type !== "blocked_by"), - ...response, - ], + related_issues: [...watch("related_issues")?.filter((i) => i.relation_type !== "blocked_by"), ...response], }); }); @@ -127,9 +119,7 @@ export const SidebarBlockedSelect: React.FC = ({ type="button" className="opacity-0 duration-300 group-hover:opacity-100" onClick={() => { - const updatedRelations = watch("related_issues")?.filter( - (i) => i.id !== relation.id - ); + const updatedRelations = watch("related_issues")?.filter((i) => i.id !== relation.id); submitChanges({ related_issues: updatedRelations, diff --git a/web/components/issues/sidebar-select/blocker.tsx b/web/components/issues/sidebar-select/blocker.tsx index ae8fefa1b35..b7adc0e44d7 100644 --- a/web/components/issues/sidebar-select/blocker.tsx +++ b/web/components/issues/sidebar-select/blocker.tsx @@ -10,7 +10,7 @@ import useUser from "hooks/use-user"; // components import { ExistingIssuesListModal } from "components/core"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // icons import { XMarkIcon } from "@heroicons/react/24/outline"; import { BlockerIcon } from "components/icons"; @@ -24,12 +24,7 @@ type Props = { disabled?: boolean; }; -export const SidebarBlockerSelect: React.FC = ({ - issueId, - submitChanges, - watch, - disabled = false, -}) => { +export const SidebarBlockerSelect: React.FC = ({ issueId, submitChanges, watch, disabled = false }) => { const [isBlockerModalOpen, setIsBlockerModalOpen] = useState(false); const { user } = useUser(); @@ -42,8 +37,7 @@ export const SidebarBlockerSelect: React.FC = ({ setIsBlockerModalOpen(false); }; - const blockerIssue = - watch("issue_relations")?.filter((i) => i.relation_type === "blocked_by") || []; + const blockerIssue = watch("issue_relations")?.filter((i) => i.relation_type === "blocked_by") || []; const onSubmit = async (data: ISearchIssueResponse[]) => { if (data.length === 0) { diff --git a/web/components/issues/sidebar-select/cycle.tsx b/web/components/issues/sidebar-select/cycle.tsx index 8fbfcf70790..3080c1af221 100644 --- a/web/components/issues/sidebar-select/cycle.tsx +++ b/web/components/issues/sidebar-select/cycle.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import cyclesService from "services/cycles.service"; // ui import { Spinner, CustomSelect, Tooltip } from "components/ui"; @@ -22,23 +22,14 @@ type Props = { disabled?: boolean; }; -export const SidebarCycleSelect: React.FC = ({ - issueDetail, - handleCycleChange, - disabled = false, -}) => { +export const SidebarCycleSelect: React.FC = ({ issueDetail, handleCycleChange, disabled = false }) => { const router = useRouter(); const { workspaceSlug, projectId, issueId } = router.query; const { data: incompleteCycles } = useSWR( workspaceSlug && projectId ? INCOMPLETE_CYCLES_LIST(projectId as string) : null, workspaceSlug && projectId - ? () => - cyclesService.getCyclesWithParams( - workspaceSlug as string, - projectId as string, - "incomplete" - ) + ? () => cyclesService.getCyclesWithParams(workspaceSlug as string, projectId as string, "incomplete") : null ); @@ -63,21 +54,14 @@ export const SidebarCycleSelect: React.FC = ({ - + diff --git a/web/components/issues/sidebar-select/duplicate.tsx b/web/components/issues/sidebar-select/duplicate.tsx index db4cae2cd61..1b5c11a5382 100644 --- a/web/components/issues/sidebar-select/duplicate.tsx +++ b/web/components/issues/sidebar-select/duplicate.tsx @@ -12,7 +12,7 @@ import { X, CopyPlus } from "lucide-react"; import { BlockerIcon } from "components/icons"; import { ExistingIssuesListModal } from "components/core"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // types import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types"; diff --git a/web/components/issues/sidebar-select/label.tsx b/web/components/issues/sidebar-select/label.tsx index 3ac2f552e74..2052a0d56ee 100644 --- a/web/components/issues/sidebar-select/label.tsx +++ b/web/components/issues/sidebar-select/label.tsx @@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color"; // headless ui import { Listbox, Popover, Transition } from "@headlessui/react"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; // ui @@ -66,25 +66,21 @@ export const SidebarLabelSelect: React.FC = ({ const { data: issueLabels, mutate: issueLabelMutate } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, - workspaceSlug && projectId - ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null ); const handleNewLabel = async (formData: Partial) => { if (!workspaceSlug || !projectId || isSubmitting) return; - await issuesService - .createIssueLabel(workspaceSlug as string, projectId as string, formData, user) - .then((res) => { - reset(defaultValues); + await issuesService.createIssueLabel(workspaceSlug as string, projectId as string, formData, user).then((res) => { + reset(defaultValues); - issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false); + issueLabelMutate((prevData: any) => [...(prevData ?? []), res], false); - submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] }); + submitChanges({ labels_list: [...(issueDetails?.labels ?? []), res.id] }); - setCreateLabelForm(false); - }); + setCreateLabelForm(false); + }); }; useEffect(() => { @@ -165,9 +161,7 @@ export const SidebarLabelSelect: React.FC = ({ {issueLabels ? ( issueLabels.length > 0 ? ( issueLabels.map((label: IIssueLabels) => { - const children = issueLabels?.filter( - (l) => l.parent === label.id - ); + const children = issueLabels?.filter((l) => l.parent === label.id); if (children.length === 0) { if (!label.parent) @@ -175,9 +169,7 @@ export const SidebarLabelSelect: React.FC = ({ - `${ - active || selected ? "bg-custom-background-90" : "" - } ${ + `${active || selected ? "bg-custom-background-90" : ""} ${ selected ? "" : "text-custom-text-200" } flex cursor-pointer select-none items-center gap-2 truncate p-2` } @@ -186,10 +178,7 @@ export const SidebarLabelSelect: React.FC = ({ {label.name} @@ -207,11 +196,7 @@ export const SidebarLabelSelect: React.FC = ({ - `${ - active || selected - ? "bg-custom-background-100" - : "" - } ${ + `${active || selected ? "bg-custom-background-100" : ""} ${ selected ? "" : "text-custom-text-200" } flex cursor-pointer select-none items-center gap-2 truncate p-2` } @@ -248,9 +233,7 @@ export const SidebarLabelSelect: React.FC = ({ - diff --git a/web/components/issues/sidebar-select/relates-to.tsx b/web/components/issues/sidebar-select/relates-to.tsx index deadf4d2041..2f72d4b98a9 100644 --- a/web/components/issues/sidebar-select/relates-to.tsx +++ b/web/components/issues/sidebar-select/relates-to.tsx @@ -12,7 +12,7 @@ import { BlockerIcon, RelatedIcon } from "components/icons"; // components import { ExistingIssuesListModal } from "components/core"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // types import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types"; diff --git a/web/components/issues/sidebar-select/state.tsx b/web/components/issues/sidebar-select/state.tsx index cf2cfe3b2db..7c7970b5a8e 100644 --- a/web/components/issues/sidebar-select/state.tsx +++ b/web/components/issues/sidebar-select/state.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // ui import { Spinner, CustomSelect } from "components/ui"; // icons @@ -28,9 +28,7 @@ export const SidebarStateSelect: React.FC = ({ value, onChange, disabled const { data: stateGroups } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const states = getStatesList(stateGroups); diff --git a/web/components/issues/sidebar.tsx b/web/components/issues/sidebar.tsx index 5455192fbe8..c1bc6811f7e 100644 --- a/web/components/issues/sidebar.tsx +++ b/web/components/issues/sidebar.tsx @@ -12,7 +12,7 @@ import useUserAuth from "hooks/use-user-auth"; import useUserIssueNotificationSubscription from "hooks/use-issue-notification-subscription"; import useEstimateOption from "hooks/use-estimate-option"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import modulesService from "services/modules.service"; // contexts import { useProjectMyMembership } from "contexts/project-member.context"; @@ -103,8 +103,11 @@ export const IssueDetailsSidebar: React.FC = ({ const { isEstimateActive } = useEstimateOption(); - const { loading, handleSubscribe, handleUnsubscribe, subscribed } = - useUserIssueNotificationSubscription(workspaceSlug, projectId, issueId); + const { loading, handleSubscribe, handleUnsubscribe, subscribed } = useUserIssueNotificationSubscription( + workspaceSlug, + projectId, + issueId + ); const { memberRole } = useProjectMyMembership(); @@ -198,13 +201,7 @@ export const IssueDetailsSidebar: React.FC = ({ ); await issuesService - .updateIssueLink( - workspaceSlug as string, - projectId as string, - issueDetail.id, - linkId, - payload - ) + .updateIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId, payload) .then((res) => { mutate(ISSUE_DETAILS(issueDetail.id)); }) @@ -235,12 +232,9 @@ export const IssueDetailsSidebar: React.FC = ({ }; const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}` - ).then(() => { + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${issueDetail?.id}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", @@ -264,9 +258,7 @@ export const IssueDetailsSidebar: React.FC = ({ fieldsToShow.includes("dueDate"); const showThirdSection = - fieldsToShow.includes("all") || - fieldsToShow.includes("cycle") || - fieldsToShow.includes("module"); + fieldsToShow.includes("all") || fieldsToShow.includes("cycle") || fieldsToShow.includes("module"); const startDate = watchIssue("start_date"); const targetDate = watchIssue("target_date"); @@ -413,30 +405,27 @@ export const IssueDetailsSidebar: React.FC = ({
    )} - {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && - isEstimateActive && ( -
    -
    - -

    Estimate

    -
    -
    - ( - - submitChanges({ estimate_point: val }) - } - disabled={memberRole.isGuest || memberRole.isViewer || uneditable} - /> - )} - /> -
    + {(fieldsToShow.includes("all") || fieldsToShow.includes("estimate")) && isEstimateActive && ( +
    +
    + +

    Estimate

    +
    +
    + ( + submitChanges({ estimate_point: val })} + disabled={memberRole.isGuest || memberRole.isViewer || uneditable} + /> + )} + />
    - )} +
    + )}
    )} {showSecondSection && ( diff --git a/web/components/issues/sub-issues-list.tsx b/web/components/issues/sub-issues-list.tsx index 9ba920ff53f..fbb16d5c8d4 100644 --- a/web/components/issues/sub-issues-list.tsx +++ b/web/components/issues/sub-issues-list.tsx @@ -8,7 +8,7 @@ import useSWR, { mutate } from "swr"; // headless ui import { Disclosure, Transition } from "@headlessui/react"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // contexts import { useProjectMyMembership } from "contexts/project-member.context"; // components @@ -126,10 +126,7 @@ export const SubIssuesList: FC = ({ parentIssue, user, disabled = false }
    - Sub-issues{" "} - - {subIssuesResponse.sub_issues.length} - + Sub-issues {subIssuesResponse.sub_issues.length}
    @@ -186,10 +183,7 @@ export const SubIssuesList: FC = ({ parentIssue, user, disabled = false } > {subIssuesResponse.sub_issues.map((issue) => ( - +
    = ({ parentIssue, user, disabled = false } noChevron > Create new - setSubIssuesListModal(true)}> - Add an existing issue - + setSubIssuesListModal(true)}>Add an existing issue ) )} diff --git a/web/components/issues/view-select/assignee.tsx b/web/components/issues/view-select/assignee.tsx index 1026f240de9..d9dfdd080e8 100644 --- a/web/components/issues/view-select/assignee.tsx +++ b/web/components/issues/view-select/assignee.tsx @@ -6,7 +6,7 @@ import useSWR from "swr"; // services import projectService from "services/project.service"; -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // ui import { AssigneesList, Avatar, CustomSearchSelect, Icon, Tooltip } from "components/ui"; // icons diff --git a/web/components/issues/view-select/due-date.tsx b/web/components/issues/view-select/due-date.tsx index 5cbc2645204..66705b3322a 100644 --- a/web/components/issues/view-select/due-date.tsx +++ b/web/components/issues/view-select/due-date.tsx @@ -5,7 +5,7 @@ import { CustomDatePicker, Tooltip } from "components/ui"; // helpers import { findHowManyDaysLeft, renderShortDateWithYearFormat } from "helpers/date-time.helper"; // services -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // types import { ICurrentUserResponse, IIssue } from "types"; import useIssuesView from "hooks/use-issues-view"; @@ -42,9 +42,7 @@ export const ViewDueDateSelect: React.FC = ({ return (
    = ({ ); }} className={`${issue?.target_date ? "w-[6.5rem]" : "w-[5rem] text-center"} ${ - displayFilters.layout === "kanban" - ? "bg-custom-background-90" - : "bg-custom-background-100" + displayFilters.layout === "kanban" ? "bg-custom-background-90" : "bg-custom-background-100" }`} minDate={minDate ?? undefined} noBorder={noBorder} diff --git a/web/components/issues/view-select/estimate.tsx b/web/components/issues/view-select/estimate.tsx index bef060e772c..4e302426bb7 100644 --- a/web/components/issues/view-select/estimate.tsx +++ b/web/components/issues/view-select/estimate.tsx @@ -3,7 +3,7 @@ import React from "react"; import { useRouter } from "next/router"; // services -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // hooks import useEstimateOption from "hooks/use-estimate-option"; // ui diff --git a/web/components/issues/view-select/label.tsx b/web/components/issues/view-select/label.tsx index 3a75763b27c..bd2396736d7 100644 --- a/web/components/issues/view-select/label.tsx +++ b/web/components/issues/view-select/label.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // component import { CreateLabelModal } from "components/labels"; // ui @@ -45,9 +45,7 @@ export const ViewLabelSelect: React.FC = ({ const { data: issueLabels } = useSWR( projectId ? PROJECT_ISSUE_LABELS(projectId.toString()) : null, - workspaceSlug && projectId - ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null ); const options = issueLabels?.map((label) => ({ diff --git a/web/components/issues/view-select/priority.tsx b/web/components/issues/view-select/priority.tsx index 1bdbf3428e3..31e594a0824 100644 --- a/web/components/issues/view-select/priority.tsx +++ b/web/components/issues/view-select/priority.tsx @@ -3,7 +3,7 @@ import React from "react"; import { useRouter } from "next/router"; // services -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // ui import { CustomSelect, Tooltip } from "components/ui"; // icons @@ -61,9 +61,9 @@ export const ViewPrioritySelect: React.FC = ({ customButton={
    diff --git a/web/components/pages/create-block.tsx b/web/components/pages/create-block.tsx index dd3c63c269c..6f6159ad037 100644 --- a/web/components/pages/create-block.tsx +++ b/web/components/pages/create-block.tsx @@ -9,7 +9,7 @@ import { PaperAirplaneIcon } from "@heroicons/react/24/outline"; // react-hook-form import { useForm } from "react-hook-form"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // hooks import useToast from "hooks/use-toast"; @@ -81,8 +81,7 @@ export const CreateBlock: React.FC = ({ user }) => { }; const handleKeyDown = (e: any) => { - const keyCombination = - ((e.ctrlKey || e.metaKey) && e.key === "Enter") || (e.shiftKey && e.key === "Enter"); + const keyCombination = ((e.ctrlKey || e.metaKey) && e.key === "Enter") || (e.shiftKey && e.key === "Enter"); if (e.key === "Enter" && !keyCombination) { if (watch("name") && watch("name") !== "") { diff --git a/web/components/pages/create-update-block-inline.tsx b/web/components/pages/create-update-block-inline.tsx index cee9fe8e30d..14e5c283e0d 100644 --- a/web/components/pages/create-update-block-inline.tsx +++ b/web/components/pages/create-update-block-inline.tsx @@ -4,8 +4,8 @@ import { mutate } from "swr"; import { SparklesIcon } from "@heroicons/react/24/outline"; import { Controller, useForm } from "react-hook-form"; // services -import pagesService from "services/pages.service"; -import issuesService from "services/issues.service"; +import pagesService from "services/page.service"; +import issuesService from "services/issue.service"; import aiService from "services/ai.service"; // hooks import useToast from "hooks/use-toast"; @@ -195,8 +195,7 @@ export const CreateUpdateBlockInline: React.FC = ({ setToastAlert({ type: "error", title: "Error!", - message: - "You have reached the maximum number of requests of 50 requests per month per user.", + message: "You have reached the maximum number of requests of 50 requests per month per user.", }); else setToastAlert({ @@ -294,9 +293,7 @@ export const CreateUpdateBlockInline: React.FC = ({ /> ); else if (!value || !watch("description_html")) - return ( -
    - ); + return
    ; return ( = ({
    Cancel - {data - ? isSubmitting - ? "Updating..." - : "Update block" - : isSubmitting - ? "Adding..." - : "Add block"} + {data ? (isSubmitting ? "Updating..." : "Update block") : isSubmitting ? "Adding..." : "Add block"}
    @@ -371,9 +362,7 @@ export const CreateUpdateBlockInline: React.FC = ({ onResponse={(response) => { if (data && handleAiAssistance) { handleAiAssistance(response); - editorRef.current?.setEditorValue( - `${watch("description_html")}

    ${response}

    ` ?? "" - ); + editorRef.current?.setEditorValue(`${watch("description_html")}

    ${response}

    ` ?? ""); } else { setValue("description", {}); setValue("description_html", `${watch("description_html")}

    ${response}

    `); diff --git a/web/components/pages/create-update-page-modal.tsx b/web/components/pages/create-update-page-modal.tsx index 4835449e142..6a691274705 100644 --- a/web/components/pages/create-update-page-modal.tsx +++ b/web/components/pages/create-update-page-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // hooks import useToast from "hooks/use-toast"; // components @@ -15,12 +15,7 @@ import { PageForm } from "./page-form"; // types import { ICurrentUserResponse, IPage } from "types"; // fetch-keys -import { - ALL_PAGES_LIST, - FAVORITE_PAGES_LIST, - MY_PAGES_LIST, - RECENT_PAGES_LIST, -} from "constants/fetch-keys"; +import { ALL_PAGES_LIST, FAVORITE_PAGES_LIST, MY_PAGES_LIST, RECENT_PAGES_LIST } from "constants/fetch-keys"; type Props = { isOpen: boolean; diff --git a/web/components/pages/delete-page-modal.tsx b/web/components/pages/delete-page-modal.tsx index 68c2d67322a..15a67090b9e 100644 --- a/web/components/pages/delete-page-modal.tsx +++ b/web/components/pages/delete-page-modal.tsx @@ -7,7 +7,7 @@ import { mutate } from "swr"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -17,12 +17,7 @@ import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; // types import type { ICurrentUserResponse, IPage } from "types"; // fetch-keys -import { - ALL_PAGES_LIST, - FAVORITE_PAGES_LIST, - MY_PAGES_LIST, - RECENT_PAGES_LIST, -} from "constants/fetch-keys"; +import { ALL_PAGES_LIST, FAVORITE_PAGES_LIST, MY_PAGES_LIST, RECENT_PAGES_LIST } from "constants/fetch-keys"; type TConfirmPageDeletionProps = { isOpen: boolean; @@ -31,12 +26,7 @@ type TConfirmPageDeletionProps = { user: ICurrentUserResponse | undefined; }; -export const DeletePageModal: React.FC = ({ - isOpen, - setIsOpen, - data, - user, -}) => { +export const DeletePageModal: React.FC = ({ isOpen, setIsOpen, data, user }) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -121,26 +111,17 @@ export const DeletePageModal: React.FC = ({
    -
    - + Delete Page

    Are you sure you want to delete Page-{" "} - - {data?.name} - - ? All of the data related to the page will be permanently removed. This - action cannot be undone. + {data?.name}? All of the + data related to the page will be permanently removed. This action cannot be undone.

    diff --git a/web/components/pages/pages-list/all-pages-list.tsx b/web/components/pages/pages-list/all-pages-list.tsx index f25d00fd5cd..353fa7b8770 100644 --- a/web/components/pages/pages-list/all-pages-list.tsx +++ b/web/components/pages/pages-list/all-pages-list.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // components import { PagesView } from "components/pages"; // types diff --git a/web/components/pages/pages-list/favorite-pages-list.tsx b/web/components/pages/pages-list/favorite-pages-list.tsx index 2faa4bf7223..e6ba8ec321d 100644 --- a/web/components/pages/pages-list/favorite-pages-list.tsx +++ b/web/components/pages/pages-list/favorite-pages-list.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // components import { PagesView } from "components/pages"; // types @@ -18,8 +18,7 @@ export const FavoritePagesList: React.FC = ({ viewType }) => { const { data: pages } = useSWR( workspaceSlug && projectId ? FAVORITE_PAGES_LIST(projectId as string) : null, workspaceSlug && projectId - ? () => - pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "favorite") + ? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "favorite") : null ); diff --git a/web/components/pages/pages-list/my-pages-list.tsx b/web/components/pages/pages-list/my-pages-list.tsx index c225a0ac5d7..2bd4a20178a 100644 --- a/web/components/pages/pages-list/my-pages-list.tsx +++ b/web/components/pages/pages-list/my-pages-list.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // components import { PagesView } from "components/pages"; // types @@ -18,12 +18,7 @@ export const MyPagesList: React.FC = ({ viewType }) => { const { data: pages } = useSWR( workspaceSlug && projectId ? MY_PAGES_LIST(projectId as string) : null, workspaceSlug && projectId - ? () => - pagesService.getPagesWithParams( - workspaceSlug as string, - projectId as string, - "created_by_me" - ) + ? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "created_by_me") : null ); diff --git a/web/components/pages/pages-list/other-pages-list.tsx b/web/components/pages/pages-list/other-pages-list.tsx index 64764533f5b..72729f9e2da 100644 --- a/web/components/pages/pages-list/other-pages-list.tsx +++ b/web/components/pages/pages-list/other-pages-list.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // components import { PagesView } from "components/pages"; // types @@ -18,12 +18,7 @@ export const OtherPagesList: React.FC = ({ viewType }) => { const { data: pages } = useSWR( workspaceSlug && projectId ? OTHER_PAGES_LIST(projectId as string) : null, workspaceSlug && projectId - ? () => - pagesService.getPagesWithParams( - workspaceSlug as string, - projectId as string, - "created_by_other" - ) + ? () => pagesService.getPagesWithParams(workspaceSlug as string, projectId as string, "created_by_other") : null ); diff --git a/web/components/pages/pages-list/recent-pages-list.tsx b/web/components/pages/pages-list/recent-pages-list.tsx index 34199b27965..6ea8f9d010c 100644 --- a/web/components/pages/pages-list/recent-pages-list.tsx +++ b/web/components/pages/pages-list/recent-pages-list.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; // components import { PagesView } from "components/pages"; // ui @@ -28,9 +28,7 @@ export const RecentPagesList: React.FC = ({ viewType }) => { const { data: pages } = useSWR( workspaceSlug && projectId ? RECENT_PAGES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => pagesService.getRecentPages(workspaceSlug as string, projectId as string) : null ); const isEmpty = pages && Object.keys(pages).every((key) => pages[key].length === 0); @@ -44,9 +42,7 @@ export const RecentPagesList: React.FC = ({ viewType }) => { return (
    -

    - {replaceUnderscoreIfSnakeCase(key)} -

    +

    {replaceUnderscoreIfSnakeCase(key)}

    ); diff --git a/web/components/pages/pages-view.tsx b/web/components/pages/pages-view.tsx index 8178460e18d..b7fc0249c51 100644 --- a/web/components/pages/pages-view.tsx +++ b/web/components/pages/pages-view.tsx @@ -4,18 +4,13 @@ import useSWR, { mutate } from "swr"; import { useRouter } from "next/router"; // services -import pagesService from "services/pages.service"; +import pagesService from "services/page.service"; import projectService from "services/project.service"; // hooks import useToast from "hooks/use-toast"; import useUserAuth from "hooks/use-user-auth"; // components -import { - CreateUpdatePageModal, - DeletePageModal, - SinglePageDetailedItem, - SinglePageListItem, -} from "components/pages"; +import { CreateUpdatePageModal, DeletePageModal, SinglePageDetailedItem, SinglePageListItem } from "components/pages"; // ui import { EmptyState, Loader } from "components/ui"; // icons @@ -91,11 +86,7 @@ export const PagesView: React.FC = ({ pages, viewType }) => { }), false ); - mutate( - FAVORITE_PAGES_LIST(projectId.toString()), - (prevData) => [page, ...(prevData ?? [])], - false - ); + mutate(FAVORITE_PAGES_LIST(projectId.toString()), (prevData) => [page, ...(prevData ?? [])], false); pagesService .addPageToFavorites(workspaceSlug.toString(), projectId.toString(), { @@ -185,11 +176,9 @@ export const PagesView: React.FC = ({ pages, viewType }) => { false ); - pagesService - .patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user) - .then(() => { - mutate(RECENT_PAGES_LIST(projectId.toString())); - }); + pagesService.patchPage(workspaceSlug.toString(), projectId.toString(), page.id, formData, user).then(() => { + mutate(RECENT_PAGES_LIST(projectId.toString())); + }); }; return ( diff --git a/web/components/pages/single-page-block.tsx b/web/components/pages/single-page-block.tsx index e4c1d94acd9..5d784d98a49 100644 --- a/web/components/pages/single-page-block.tsx +++ b/web/components/pages/single-page-block.tsx @@ -10,8 +10,8 @@ import { useForm } from "react-hook-form"; // react-beautiful-dnd import { Draggable } from "react-beautiful-dnd"; // services -import pagesService from "services/pages.service"; -import issuesService from "services/issues.service"; +import pagesService from "services/page.service"; +import issuesService from "services/issue.service"; import aiService from "services/ai.service"; // hooks import useToast from "hooks/use-toast"; @@ -48,13 +48,7 @@ type Props = { user: ICurrentUserResponse | undefined; }; -export const SinglePageBlock: React.FC = ({ - block, - projectDetails, - showBlockDetails, - index, - user, -}) => { +export const SinglePageBlock: React.FC = ({ block, projectDetails, showBlockDetails, index, user }) => { const [isSyncing, setIsSyncing] = useState(false); const [createBlockForm, setCreateBlockForm] = useState(false); const [iAmFeelingLucky, setIAmFeelingLucky] = useState(false); @@ -131,13 +125,7 @@ export const SinglePageBlock: React.FC = ({ if (!workspaceSlug || !projectId || !pageId) return; await pagesService - .convertPageBlockToIssue( - workspaceSlug as string, - projectId as string, - pageId as string, - block.id, - user - ) + .convertPageBlockToIssue(workspaceSlug as string, projectId as string, pageId as string, block.id, user) .then((res: IIssue) => { mutate( PAGE_BLOCKS_LIST(pageId as string), @@ -175,13 +163,7 @@ export const SinglePageBlock: React.FC = ({ ); await pagesService - .deletePageBlock( - workspaceSlug as string, - projectId as string, - pageId as string, - block.id, - user - ) + .deletePageBlock(workspaceSlug as string, projectId as string, pageId as string, block.id, user) .catch(() => { setToastAlert({ type: "error", @@ -221,8 +203,7 @@ export const SinglePageBlock: React.FC = ({ setToastAlert({ type: "error", title: "Error!", - message: - "You have reached the maximum number of requests of 50 requests per month per user.", + message: "You have reached the maximum number of requests of 50 requests per month per user.", }); else setToastAlert({ @@ -283,12 +264,9 @@ export const SinglePageBlock: React.FC = ({ }; const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - copyTextToClipboard( - `${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}` - ).then(() => { + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/issues/${block.issue}`).then(() => { setToastAlert({ type: "success", title: "Link Copied!", @@ -343,11 +321,7 @@ export const SinglePageBlock: React.FC = ({ > {block.issue && block.sync && (
    - {isSyncing ? ( - - ) : ( - - )} + {isSyncing ? : } {isSyncing ? "Syncing..." : "Synced"}
    )} @@ -431,9 +405,7 @@ export const SinglePageBlock: React.FC = ({
    {block.issue && (
    - + {projectDetails?.identifier}-{block.issue_detail?.sequence_id} diff --git a/web/components/profile/profile-issues-view.tsx b/web/components/profile/profile-issues-view.tsx index b0337ecd49b..e5a2096caa1 100644 --- a/web/components/profile/profile-issues-view.tsx +++ b/web/components/profile/profile-issues-view.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // react-beautiful-dnd import { DropResult } from "react-beautiful-dnd"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import userService from "services/user.service"; // hooks import useProfileIssues from "hooks/use-profile-issues"; @@ -31,9 +31,7 @@ export const ProfileIssuesView = () => { // update issue modal const [editIssueModal, setEditIssueModal] = useState(false); - const [issueToEdit, setIssueToEdit] = useState< - (IIssue & { actionType: "edit" | "delete" }) | undefined - >(undefined); + const [issueToEdit, setIssueToEdit] = useState<(IIssue & { actionType: "edit" | "delete" }) | undefined>(undefined); // delete issue modal const [deleteIssueModal, setDeleteIssueModal] = useState(false); @@ -60,19 +58,14 @@ export const ProfileIssuesView = () => { } = useProfileIssues(workspaceSlug?.toString(), userId?.toString()); const { data: profileData } = useSWR( + workspaceSlug && userId ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) : null, workspaceSlug && userId - ? USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString()) - : null, - workspaceSlug && userId - ? () => - userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString()) + ? () => userService.getUserProfileProjectsSegregation(workspaceSlug.toString(), userId.toString()) : null ); const { data: labels } = useSWR( - workspaceSlug && (filters?.labels ?? []).length > 0 - ? WORKSPACE_LABELS(workspaceSlug.toString()) - : null, + workspaceSlug && (filters?.labels ?? []).length > 0 ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, workspaceSlug && (filters?.labels ?? []).length > 0 ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null @@ -90,13 +83,7 @@ export const ProfileIssuesView = () => { async (result: DropResult) => { setTrashBox(false); - if ( - !result.destination || - !workspaceSlug || - !groupedIssues || - displayFilters?.group_by !== "priority" - ) - return; + if (!result.destination || !workspaceSlug || !groupedIssues || displayFilters?.group_by !== "priority") return; const { source, destination } = result; @@ -125,10 +112,7 @@ export const ProfileIssuesView = () => { return { ...prevData, [sourceGroup]: orderArrayBy(sourceGroupArray, displayFilters.order_by ?? "-created_at"), - [destinationGroup]: orderArrayBy( - destinationGroupArray, - displayFilters.order_by ?? "-created_at" - ), + [destinationGroup]: orderArrayBy(destinationGroupArray, displayFilters.order_by ?? "-created_at"), }; }, false); @@ -218,15 +202,11 @@ export const ProfileIssuesView = () => { (key) => filtersToDisplay[key as keyof IIssueFilterOptions] === null ); const areFiltersApplied = - Object.keys(filtersToDisplay).length > 0 && - nullFilters.length !== Object.keys(filtersToDisplay).length; + Object.keys(filtersToDisplay).length > 0 && nullFilters.length !== Object.keys(filtersToDisplay).length; const isSubscribedIssuesRoute = router.pathname.includes("subscribed"); const isMySubscribedIssues = - (filters.subscriber && - filters.subscriber.length > 0 && - router.pathname.includes("my-issues")) ?? - false; + (filters.subscriber && filters.subscriber.length > 0 && router.pathname.includes("my-issues")) ?? false; const disableAddIssueOption = isSubscribedIssuesRoute || isMySubscribedIssues; diff --git a/web/components/project/publish-project/modal.tsx b/web/components/project/publish-project/modal.tsx index 56ed10ee001..b9430285fae 100644 --- a/web/components/project/publish-project/modal.tsx +++ b/web/components/project/publish-project/modal.tsx @@ -6,21 +6,14 @@ import { Controller, useForm } from "react-hook-form"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // ui components -import { - ToggleSwitch, - PrimaryButton, - SecondaryButton, - Icon, - DangerButton, - Loader, -} from "components/ui"; +import { ToggleSwitch, PrimaryButton, SecondaryButton, Icon, DangerButton, Loader } from "components/ui"; import { CustomPopover } from "./popover"; // mobx react lite import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; -import { IProjectPublishSettings, TProjectPublishViews } from "store/project-publish"; +import { IProjectPublishSettings, TProjectPublishViews } from "store/project_publish"; // hooks import useToast from "hooks/use-toast"; import useProjectDetails from "hooks/use-project-details"; @@ -65,8 +58,8 @@ export const PublishProjectModal: React.FC = observer(() => { let plane_deploy_url = process.env.NEXT_PUBLIC_DEPLOY_URL; - if (typeof window !== 'undefined' && !plane_deploy_url) { - plane_deploy_url= window.location.protocol + "//" + window.location.host + "/spaces"; + if (typeof window !== "undefined" && !plane_deploy_url) { + plane_deploy_url = window.location.protocol + "//" + window.location.host + "/spaces"; } const router = useRouter(); @@ -101,10 +94,7 @@ export const PublishProjectModal: React.FC = observer(() => { // prefill form with the saved settings if the project is already published useEffect(() => { - if ( - projectPublish.projectPublishSettings && - projectPublish.projectPublishSettings !== "not-initialized" - ) { + if (projectPublish.projectPublishSettings && projectPublish.projectPublishSettings !== "not-initialized") { let userBoards: TProjectPublishViews[] = []; if (projectPublish.projectPublishSettings?.views) { @@ -143,11 +133,7 @@ export const PublishProjectModal: React.FC = observer(() => { projectPublish.project_id !== null && projectPublish?.projectPublishSettings === "not-initialized" ) { - projectPublish.getProjectSettingsAsync( - workspaceSlug.toString(), - projectPublish.project_id, - null - ); + projectPublish.getProjectSettingsAsync(workspaceSlug.toString(), projectPublish.project_id, null); } }, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]); @@ -202,12 +188,7 @@ export const PublishProjectModal: React.FC = observer(() => { setIsUnpublishing(true); projectPublish - .unPublishProject( - workspaceSlug.toString(), - projectPublish.project_id as string, - publishId, - null - ) + .unPublishProject(workspaceSlug.toString(), projectPublish.project_id as string, publishId, null) .then((res) => { mutateProjectDetails(); @@ -269,11 +250,7 @@ export const PublishProjectModal: React.FC = observer(() => { // check if an update is required or not const checkIfUpdateIsRequired = () => { - if ( - !projectPublish.projectPublishSettings || - projectPublish.projectPublishSettings === "not-initialized" - ) - return; + if (!projectPublish.projectPublishSettings || projectPublish.projectPublishSettings === "not-initialized") return; const currentSettings = projectPublish.projectPublishSettings as IProjectPublishSettings; const newSettings = getValues(); @@ -289,8 +266,7 @@ export const PublishProjectModal: React.FC = observer(() => { let viewCheckFlag = 0; viewOptions.forEach((option) => { - if (currentSettings.views[option.key] !== newSettings.views.includes(option.key)) - viewCheckFlag++; + if (currentSettings.views[option.key] !== newSettings.views.includes(option.key)) viewCheckFlag++; }); if (viewCheckFlag !== 0) { @@ -416,9 +392,7 @@ export const PublishProjectModal: React.FC = observer(() => { }} >
    {option.label}
    -
    +
    {value.length > 0 && value.includes(option.key) && ( )} diff --git a/web/components/states/create-state-modal.tsx b/web/components/states/create-state-modal.tsx index ad7f38c4e80..171f4f17e42 100644 --- a/web/components/states/create-state-modal.tsx +++ b/web/components/states/create-state-modal.tsx @@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color"; // headless ui import { Dialog, Popover, Transition } from "@headlessui/react"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -131,10 +131,7 @@ export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClo
    - + Create State
    @@ -215,10 +212,7 @@ export const CreateStateModal: React.FC = ({ isOpen, projectId, handleClo name="color" control={control} render={({ field: { value, onChange } }) => ( - onChange(value.hex)} - /> + onChange(value.hex)} /> )} /> diff --git a/web/components/states/create-update-state-inline.tsx b/web/components/states/create-update-state-inline.tsx index 87ad1473160..3cd5bfb8d40 100644 --- a/web/components/states/create-update-state-inline.tsx +++ b/web/components/states/create-update-state-inline.tsx @@ -11,7 +11,7 @@ import { TwitterPicker } from "react-color"; // headless ui import { Popover, Transition } from "@headlessui/react"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // hooks import useToast from "hooks/use-toast"; // ui @@ -39,13 +39,7 @@ const defaultValues: Partial = { group: "backlog", }; -export const CreateUpdateStateInline: React.FC = ({ - data, - onClose, - selectedGroup, - user, - groupLength, -}) => { +export const CreateUpdateStateInline: React.FC = ({ data, onClose, selectedGroup, user, groupLength }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -153,8 +147,7 @@ export const CreateUpdateStateInline: React.FC = ({ setToastAlert({ type: "error", title: "Error!", - message: - "Another state exists with the same name. Please try again with another name.", + message: "Another state exists with the same name. Please try again with another name.", }); else setToastAlert({ @@ -230,9 +223,7 @@ export const CreateUpdateStateInline: React.FC = ({ name="group" control={control} render={({ field: { value, onChange } }) => ( - +
    = ({ isOpen, onClose, data, user
    -
    - + Delete State

    Are you sure you want to delete state-{" "} - {data?.name}? - All of the data related to the state will be permanently removed. This - action cannot be undone. + {data?.name}? All of the data + related to the state will be permanently removed. This action cannot be undone.

    diff --git a/web/components/states/single-state.tsx b/web/components/states/single-state.tsx index eb2d9b61065..652f9dae004 100644 --- a/web/components/states/single-state.tsx +++ b/web/components/states/single-state.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import { mutate } from "swr"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // ui import { Tooltip } from "components/ui"; // icons @@ -58,11 +58,7 @@ export const SingleState: React.FC = ({ })); newStatesList = orderArrayBy(newStatesList, "sequence", "ascending"); - mutate( - STATES_LIST(projectId as string), - orderStateGroups(groupBy(newStatesList, "group")), - false - ); + mutate(STATES_LIST(projectId as string), orderStateGroups(groupBy(newStatesList, "group")), false); if (currentDefaultState) stateService @@ -131,11 +127,7 @@ export const SingleState: React.FC = ({ })); newStatesList = orderArrayBy(newStatesList, "sequence", "ascending"); - mutate( - STATES_LIST(projectId as string), - orderStateGroups(groupBy(newStatesList, "group")), - false - ); + mutate(STATES_LIST(projectId as string), orderStateGroups(groupBy(newStatesList, "group")), false); stateService .patchState( @@ -216,26 +208,14 @@ export const SingleState: React.FC = ({ > {state.default ? ( - + ) : groupLength === 1 ? ( - + ) : ( - + )}
    diff --git a/web/components/views/form.tsx b/web/components/views/form.tsx index 0c57a954233..0856bafa4a6 100644 --- a/web/components/views/form.tsx +++ b/web/components/views/form.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // react-hook-form import { useForm } from "react-hook-form"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // hooks import useProjectMembers from "hooks/use-project-members"; // components @@ -20,7 +20,7 @@ import { checkIfArraysHaveSameElements } from "helpers/array.helper"; import { getStatesList } from "helpers/state.helper"; // types import { IQuery, IView } from "types"; -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // fetch-keys import { PROJECT_ISSUE_LABELS, STATES_LIST } from "constants/fetch-keys"; @@ -37,13 +37,7 @@ const defaultValues: Partial = { description: "", }; -export const ViewForm: React.FC = ({ - handleFormSubmit, - handleClose, - status, - data, - preLoadedData, -}) => { +export const ViewForm: React.FC = ({ handleFormSubmit, handleClose, status, data, preLoadedData }) => { const router = useRouter(); const { workspaceSlug, projectId } = router.query; @@ -60,9 +54,7 @@ export const ViewForm: React.FC = ({ const filters = watch("query"); const { data: stateGroups } = useSWR( - workspaceSlug && projectId && (filters?.state ?? []).length > 0 - ? STATES_LIST(projectId as string) - : null, + workspaceSlug && projectId && (filters?.state ?? []).length > 0 ? STATES_LIST(projectId as string) : null, workspaceSlug && (filters?.state ?? []).length > 0 ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null @@ -117,9 +109,7 @@ export const ViewForm: React.FC = ({ return (
    -

    - {status ? "Update" : "Create"} View -

    +

    {status ? "Update" : "Create"} View

    = ({ const key = option.key as keyof typeof filters; if (key === "start_date" || key === "target_date") { - const valueExists = checkIfArraysHaveSameElements( - filters?.[key] ?? [], - option.value - ); + const valueExists = checkIfArraysHaveSameElements(filters?.[key] ?? [], option.value); setValue("query", { ...filters, diff --git a/web/components/views/select-filters.tsx b/web/components/views/select-filters.tsx index 52671f41f14..07a8ed337eb 100644 --- a/web/components/views/select-filters.tsx +++ b/web/components/views/select-filters.tsx @@ -5,9 +5,9 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; import projectService from "services/project.service"; -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // components import { DateFilterModal } from "components/core"; // ui @@ -32,12 +32,7 @@ type Props = { height?: "sm" | "md" | "rg" | "lg"; }; -export const SelectFilters: React.FC = ({ - filters, - onSelect, - direction = "right", - height = "md", -}) => { +export const SelectFilters: React.FC = ({ filters, onSelect, direction = "right", height = "md" }) => { const [isDateFilterModalOpen, setIsDateFilterModalOpen] = useState(false); const [dateFilterType, setDateFilterType] = useState<{ title: string; @@ -52,9 +47,7 @@ export const SelectFilters: React.FC = ({ const { data: states } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const statesList = getStatesList(states); diff --git a/web/components/web-view/create-update-link-form.tsx b/web/components/web-view/create-update-link-form.tsx index fa1a3393906..692ffb9c9e2 100644 --- a/web/components/web-view/create-update-link-form.tsx +++ b/web/components/web-view/create-update-link-form.tsx @@ -11,7 +11,7 @@ import { mutate } from "swr"; import { useForm } from "react-hook-form"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // fetch keys import { ISSUE_DETAILS } from "constants/fetch-keys"; @@ -75,12 +75,7 @@ export const CreateUpdateLinkForm: React.FC = (props) => { if (!data) await issuesService - .createIssueLink( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString(), - payload - ) + .createIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), payload) .then(() => { onSuccess(); mutate(ISSUE_DETAILS(issueId.toString())); @@ -110,20 +105,10 @@ export const CreateUpdateLinkForm: React.FC = (props) => { : l ); - mutate( - ISSUE_DETAILS(issueId.toString()), - (prevData) => ({ ...prevData, issue_link: updatedLinks }), - false - ); + mutate(ISSUE_DETAILS(issueId.toString()), (prevData) => ({ ...prevData, issue_link: updatedLinks }), false); await issuesService - .updateIssueLink( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString(), - data!.id, - payload - ) + .updateIssueLink(workspaceSlug.toString(), projectId.toString(), issueId.toString(), data!.id, payload) .then(() => { onSuccess(); mutate(ISSUE_DETAILS(issueId.toString())); @@ -172,13 +157,7 @@ export const CreateUpdateLinkForm: React.FC = (props) => { loading={isSubmitting} className="w-full !py-2 text-custom-text-300 !text-base flex items-center justify-center" > - {data - ? isSubmitting - ? "Updating Link..." - : "Update Link" - : isSubmitting - ? "Adding Link..." - : "Add Link"} + {data ? (isSubmitting ? "Updating Link..." : "Update Link") : isSubmitting ? "Adding Link..." : "Add Link"}
    diff --git a/web/components/web-view/issue-activity.tsx b/web/components/web-view/issue-activity.tsx index 4bd13eb5c2d..75bfb83e0b6 100644 --- a/web/components/web-view/issue-activity.tsx +++ b/web/components/web-view/issue-activity.tsx @@ -11,7 +11,7 @@ import useSWR, { mutate } from "swr"; import { PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; @@ -45,12 +45,7 @@ export const IssueActivity: React.FC = (props) => { const { data: issueActivities, mutate: mutateIssueActivity } = useSWR( workspaceSlug && projectId && issueId ? PROJECT_ISSUES_ACTIVITY(issueId.toString()) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.getIssueActivities( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString() - ) + ? () => issuesService.getIssueActivities(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null ); @@ -58,14 +53,7 @@ export const IssueActivity: React.FC = (props) => { if (!workspaceSlug || !projectId || !issueId) return; await issuesService - .patchIssueComment( - workspaceSlug as string, - projectId as string, - issueId as string, - comment.id, - comment, - user - ) + .patchIssueComment(workspaceSlug as string, projectId as string, issueId as string, comment.id, comment, user) .then(() => mutateIssueActivity()); }; @@ -75,13 +63,7 @@ export const IssueActivity: React.FC = (props) => { mutateIssueActivity((prevData: any) => prevData?.filter((p: any) => p.id !== commentId), false); await issuesService - .deleteIssueComment( - workspaceSlug as string, - projectId as string, - issueId as string, - commentId, - user - ) + .deleteIssueComment(workspaceSlug as string, projectId as string, issueId as string, commentId, user) .then(() => mutateIssueActivity()); }; @@ -89,13 +71,7 @@ export const IssueActivity: React.FC = (props) => { if (!workspaceSlug || !issueDetails) return; await issuesService - .createIssueComment( - workspaceSlug.toString(), - issueDetails.project, - issueDetails.id, - formData, - user - ) + .createIssueComment(workspaceSlug.toString(), issueDetails.project, issueDetails.id, formData, user) .then(() => { mutate(PROJECT_ISSUES_ACTIVITY(issueDetails.id)); }) @@ -118,11 +94,7 @@ export const IssueActivity: React.FC = (props) => {
      {issueActivities?.map((activityItem, index) => { // determines what type of action is performed - const message = activityItem.field ? ( - - ) : ( - "created the issue." - ); + const message = activityItem.field ? : "created the issue."; if ("field" in activityItem && activityItem.field !== "updated_by") { return ( @@ -141,15 +113,11 @@ export const IssueActivity: React.FC = (props) => {
      {activityItem.field ? ( activityItem.new_value === "restore" ? ( - + ) : ( ) - ) : activityItem.actor_detail.avatar && - activityItem.actor_detail.avatar !== "" ? ( + ) : activityItem.actor_detail.avatar && activityItem.actor_detail.avatar !== "" ? ( {activityItem.actor_detail.display_name} = (props) => {
      - {activityItem.field === "archived_at" && - activityItem.new_value !== "restore" ? ( + {activityItem.field === "archived_at" && activityItem.new_value !== "restore" ? ( Plane ) : activityItem.actor_detail.is_bot ? ( - - {activityItem.actor_detail.first_name} Bot - + {activityItem.actor_detail.first_name} Bot ) : ( )}{" "} - {message}{" "} - - {timeAgo(activityItem.created_at)} - + {message} {timeAgo(activityItem.created_at)}
    @@ -217,10 +179,7 @@ export const IssueActivity: React.FC = (props) => {
    diff --git a/web/components/web-view/issue-attachments.tsx b/web/components/web-view/issue-attachments.tsx index ba454031817..c1dde093754 100644 --- a/web/components/web-view/issue-attachments.tsx +++ b/web/components/web-view/issue-attachments.tsx @@ -9,7 +9,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // react dropzone import { useDropzone } from "react-dropzone"; @@ -61,12 +61,7 @@ export const IssueAttachments: React.FC = (props) => { setIsLoading(true); issuesService - .uploadIssueAttachment( - workspaceSlug as string, - projectId as string, - issueId as string, - formData - ) + .uploadIssueAttachment(workspaceSlug as string, projectId as string, issueId as string, formData) .then((res) => { mutate( ISSUE_ATTACHMENTS(issueId as string), @@ -109,12 +104,7 @@ export const IssueAttachments: React.FC = (props) => { const { data: attachments } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_ATTACHMENTS(issueId as string) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.getIssueAttachment( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString() - ) + ? () => issuesService.getIssueAttachment(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null ); diff --git a/web/components/web-view/issue-link-list.tsx b/web/components/web-view/issue-link-list.tsx index 5f1da6a6297..5df652300df 100644 --- a/web/components/web-view/issue-link-list.tsx +++ b/web/components/web-view/issue-link-list.tsx @@ -9,7 +9,7 @@ import { useRouter } from "next/router"; import { mutate } from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // icons // import { LinkIcon, PlusIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; diff --git a/web/components/web-view/issue-properties-detail.tsx b/web/components/web-view/issue-properties-detail.tsx index 2c745febe03..65a2eb173bb 100644 --- a/web/components/web-view/issue-properties-detail.tsx +++ b/web/components/web-view/issue-properties-detail.tsx @@ -11,7 +11,7 @@ import { mutate } from "swr"; import { Control, Controller, useWatch } from "react-hook-form"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useUser from "hooks/use-user"; @@ -105,10 +105,7 @@ export const IssuePropertiesDetail: React.FC = (props) => { control={control} name="state" render={({ field: { value } }) => ( - submitChanges({ state: val })} - /> + submitChanges({ state: val })} /> )} />
    @@ -117,13 +114,7 @@ export const IssuePropertiesDetail: React.FC = (props) => {
    - + = (props) => { control={control} name="priority" render={({ field: { value } }) => ( - submitChanges({ priority: val })} - /> + submitChanges({ priority: val })} /> )} />
    @@ -157,10 +145,7 @@ export const IssuePropertiesDetail: React.FC = (props) => { control={control} name="assignees_list" render={({ field: { value } }) => ( - submitChanges({ assignees_list: [val] })} - /> + submitChanges({ assignees_list: [val] })} /> )} />
    @@ -180,10 +165,7 @@ export const IssuePropertiesDetail: React.FC = (props) => { control={control} name="estimate_point" render={({ field: { value } }) => ( - submitChanges({ estimate_point: val })} - /> + submitChanges({ estimate_point: val })} /> )} />
    @@ -201,10 +183,7 @@ export const IssuePropertiesDetail: React.FC = (props) => { control={control} name="parent" render={({ field: { value } }) => ( - submitChanges({ parent: val })} - /> + submitChanges({ parent: val })} /> )} />
    @@ -224,22 +203,16 @@ export const IssuePropertiesDetail: React.FC = (props) => { if (!user || !workspaceSlug || !projectId || !issueId) return; issuesService - .createIssueRelation( - workspaceSlug as string, - projectId as string, - issueId as string, - user, - { - related_list: [ - ...val.map((issue: any) => ({ - issue: issue.blocker_issue_detail.id, - relation_type: "blocked_by" as const, - related_issue: issueId as string, - related_issue_detail: issue.blocker_issue_detail, - })), - ], - } - ) + .createIssueRelation(workspaceSlug as string, projectId as string, issueId as string, user, { + related_list: [ + ...val.map((issue: any) => ({ + issue: issue.blocker_issue_detail.id, + relation_type: "blocked_by" as const, + related_issue: issueId as string, + related_issue_detail: issue.blocker_issue_detail, + })), + ], + }) .then((response) => { handleMutation({ issue_relations: [ @@ -315,22 +288,16 @@ export const IssuePropertiesDetail: React.FC = (props) => { if (!user || !workspaceSlug || !projectId || !issueId) return; issuesService - .createIssueRelation( - workspaceSlug as string, - projectId as string, - issueId as string, - user, - { - related_list: [ - ...val.map((issue: any) => ({ - issue: issue.blocked_issue_detail.id, - relation_type: "blocked_by" as const, - related_issue: issueId as string, - related_issue_detail: issue.blocked_issue_detail, - })), - ], - } - ) + .createIssueRelation(workspaceSlug as string, projectId as string, issueId as string, user, { + related_list: [ + ...val.map((issue: any) => ({ + issue: issue.blocked_issue_detail.id, + relation_type: "blocked_by" as const, + related_issue: issueId as string, + related_issue_detail: issue.blocked_issue_detail, + })), + ], + }) .then((response) => { handleMutation({ related_issues: [ @@ -429,13 +396,8 @@ export const IssuePropertiesDetail: React.FC = (props) => { onClick={() => setIsViewAllOpen((prev) => !prev)} className="w-full flex justify-center items-center gap-1 !py-2" > - - {isViewAllOpen ? "View less" : "View all"} - - + {isViewAllOpen ? "View less" : "View all"} +
    diff --git a/web/components/web-view/select-parent.tsx b/web/components/web-view/select-parent.tsx index e5975b7b5a0..5a2f2cf1376 100644 --- a/web/components/web-view/select-parent.tsx +++ b/web/components/web-view/select-parent.tsx @@ -8,7 +8,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // fetch key import { ISSUE_DETAILS } from "constants/fetch-keys"; @@ -37,8 +37,7 @@ export const ParentSelect: React.FC = (props) => { const { data: issueDetails } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId.toString()) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.retrieve(workspaceSlug.toString(), projectId.toString(), issueId.toString()) + ? () => issuesService.retrieve(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null ); diff --git a/web/components/web-view/select-state.tsx b/web/components/web-view/select-state.tsx index c5bfa125733..2012e13f484 100644 --- a/web/components/web-view/select-state.tsx +++ b/web/components/web-view/select-state.tsx @@ -11,7 +11,7 @@ import useSWR from "swr"; import { ChevronDown } from "lucide-react"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // fetch key import { STATES_LIST } from "constants/fetch-keys"; @@ -39,9 +39,7 @@ export const StateSelect: React.FC = (props) => { const { data: stateGroups } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const states = getStatesList(stateGroups); diff --git a/web/components/web-view/sub-issues.tsx b/web/components/web-view/sub-issues.tsx index 4299d9e3a3a..a4e1809716c 100644 --- a/web/components/web-view/sub-issues.tsx +++ b/web/components/web-view/sub-issues.tsx @@ -11,7 +11,7 @@ import useSWR, { mutate } from "swr"; import { X } from "lucide-react"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // fetch key import { SUB_ISSUES } from "constants/fetch-keys"; @@ -41,8 +41,7 @@ export const SubIssueList: React.FC = (props) => { const { data: subIssuesResponse } = useSWR( workspaceSlug && issueDetails ? SUB_ISSUES(issueDetails.id) : null, workspaceSlug && issueDetails - ? () => - issuesService.subIssues(workspaceSlug as string, issueDetails.project, issueDetails.id) + ? () => issuesService.subIssues(workspaceSlug as string, issueDetails.project, issueDetails.id) : null ); diff --git a/web/hooks/gantt-chart/issue-view.tsx b/web/hooks/gantt-chart/issue-view.tsx index 8b24a566c0f..2f9fd9c1869 100644 --- a/web/hooks/gantt-chart/issue-view.tsx +++ b/web/hooks/gantt-chart/issue-view.tsx @@ -1,7 +1,7 @@ import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useIssuesView from "hooks/use-issues-view"; // fetch-keys @@ -28,8 +28,7 @@ const useGanttChartIssues = (workspaceSlug: string | undefined, projectId: strin const { data: ganttIssues, mutate: mutateGanttIssues } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId, params) : null, workspaceSlug && projectId - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); diff --git a/web/hooks/gantt-chart/view-issues-view.tsx b/web/hooks/gantt-chart/view-issues-view.tsx index 8e0bc496b89..fae8ec32623 100644 --- a/web/hooks/gantt-chart/view-issues-view.tsx +++ b/web/hooks/gantt-chart/view-issues-view.tsx @@ -1,7 +1,7 @@ import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // hooks import useIssuesView from "hooks/use-issues-view"; // fetch-keys diff --git a/web/hooks/use-calendar-issues-view.tsx b/web/hooks/use-calendar-issues-view.tsx index 289aed2aca7..21f8a41998c 100644 --- a/web/hooks/use-calendar-issues-view.tsx +++ b/web/hooks/use-calendar-issues-view.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // contexts import { issueViewContext } from "contexts/issue-view.context"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import cyclesService from "services/cycles.service"; import modulesService from "services/modules.service"; // types @@ -45,19 +45,14 @@ const useCalendarIssuesView = () => { }; const { data: projectCalendarIssues, mutate: mutateProjectCalendarIssues } = useSWR( + workspaceSlug && projectId ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params) : null, workspaceSlug && projectId - ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params) - : null, - workspaceSlug && projectId - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); const { data: cycleCalendarIssues, mutate: mutateCycleCalendarIssues } = useSWR( - workspaceSlug && projectId && cycleId - ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) - : null, + workspaceSlug && projectId && cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) : null, workspaceSlug && projectId && cycleId ? () => cyclesService.getCycleIssuesWithParams( @@ -70,9 +65,7 @@ const useCalendarIssuesView = () => { ); const { data: moduleCalendarIssues, mutate: mutateModuleCalendarIssues } = useSWR( - workspaceSlug && projectId && moduleId - ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) - : null, + workspaceSlug && projectId && moduleId ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) : null, workspaceSlug && projectId && moduleId ? () => modulesService.getModuleIssuesWithParams( @@ -87,8 +80,7 @@ const useCalendarIssuesView = () => { const { data: viewCalendarIssues, mutate: mutateViewCalendarIssues } = useSWR( workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null, workspaceSlug && projectId && viewId && params - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); diff --git a/web/hooks/use-comment-reaction.tsx b/web/hooks/use-comment-reaction.tsx index 92b4b9c1791..1aa334e434f 100644 --- a/web/hooks/use-comment-reaction.tsx +++ b/web/hooks/use-comment-reaction.tsx @@ -4,7 +4,7 @@ import useSWR from "swr"; import { COMMENT_REACTION_LIST } from "constants/fetch-keys"; // services -import reactionService from "services/reaction.service"; +import reactionService from "services/issue_reaction.service"; // helpers import { groupReactions } from "helpers/emoji.helper"; @@ -69,8 +69,7 @@ const useCommentReaction = ( if (!workspaceSlug || !projectId || !commendId) return; mutateCommentReactions( - (prevData: any) => - prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [], + (prevData: any) => prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [], false ); diff --git a/web/hooks/use-estimate-option.tsx b/web/hooks/use-estimate-option.tsx index 37b42b9e908..59419058330 100644 --- a/web/hooks/use-estimate-option.tsx +++ b/web/hooks/use-estimate-option.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import estimatesService from "services/estimates.service"; +import estimatesService from "services/project_estimates.service"; // hooks import useProjectDetails from "hooks/use-project-details"; // helpers diff --git a/web/hooks/use-issue-properties.tsx b/web/hooks/use-issue-properties.tsx index 6f4f093e032..98f1e716f10 100644 --- a/web/hooks/use-issue-properties.tsx +++ b/web/hooks/use-issue-properties.tsx @@ -3,7 +3,7 @@ import { useState, useEffect, useCallback } from "react"; import useSWR from "swr"; // services -import issueServices from "services/issues.service"; +import issueServices from "services/issue.service"; // hooks import useUser from "hooks/use-user"; // types @@ -31,12 +31,8 @@ const useIssuesProperties = (workspaceSlug?: string, projectId?: string) => { const { user } = useUser(); const { data: issueProperties, mutate: mutateIssueProperties } = useSWR( - workspaceSlug && projectId - ? `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` - : null, - workspaceSlug && projectId - ? () => issueServices.getIssueProperties(workspaceSlug, projectId) - : null + workspaceSlug && projectId ? `/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-properties/` : null, + workspaceSlug && projectId ? () => issueServices.getIssueProperties(workspaceSlug, projectId) : null ); useEffect(() => { @@ -68,7 +64,7 @@ const useIssuesProperties = (workspaceSlug?: string, projectId?: string) => { ({ ...prev, properties: { ...prev?.properties, [key]: !prev?.properties?.[key] }, - }) as IssuePriorities, + } as IssuePriorities), false ); if (Object.keys(issueProperties).length > 0) { diff --git a/web/hooks/use-issue-reaction.tsx b/web/hooks/use-issue-reaction.tsx index fabab98d285..43c85460a88 100644 --- a/web/hooks/use-issue-reaction.tsx +++ b/web/hooks/use-issue-reaction.tsx @@ -7,7 +7,7 @@ import { ISSUE_REACTION_LIST } from "constants/fetch-keys"; import { groupReactions } from "helpers/emoji.helper"; // services -import reactionService from "services/reaction.service"; +import reactionService from "services/issue_reaction.service"; // hooks import useUser from "./use-user"; @@ -28,12 +28,7 @@ const useIssueReaction = ( ? ISSUE_REACTION_LIST(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null, workspaceSlug && projectId && issueId - ? () => - reactionService.listIssueReactions( - workspaceSlug.toString(), - projectId.toString(), - issueId.toString() - ) + ? () => reactionService.listIssueReactions(workspaceSlug.toString(), projectId.toString(), issueId.toString()) : null ); @@ -69,8 +64,7 @@ const useIssueReaction = ( if (!workspaceSlug || !projectId || !issueId) return; mutateReaction( - (prevData: any) => - prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [], + (prevData: any) => prevData?.filter((r: any) => r.actor !== user?.user?.id || r.reaction !== reaction) || [], false ); diff --git a/web/hooks/use-issues-view.tsx b/web/hooks/use-issues-view.tsx index 80cabda21c2..87283d2f921 100644 --- a/web/hooks/use-issues-view.tsx +++ b/web/hooks/use-issues-view.tsx @@ -7,10 +7,10 @@ import useSWR from "swr"; // contexts import { issueViewContext } from "contexts/issue-view.context"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import cyclesService from "services/cycles.service"; import modulesService from "services/modules.service"; -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // helpers import { getStatesList } from "helpers/state.helper"; // types @@ -56,12 +56,9 @@ const useIssuesView = () => { }; const { data: projectIssues, mutate: mutateProjectIssues } = useSWR( + workspaceSlug && projectId && params ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params) : null, workspaceSlug && projectId && params - ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params) - : null, - workspaceSlug && projectId && params - ? () => - issuesService.getIssuesWithParams(workspaceSlug as string, projectId as string, params) + ? () => issuesService.getIssuesWithParams(workspaceSlug as string, projectId as string, params) : null ); @@ -84,9 +81,7 @@ const useIssuesView = () => { ); const { data: cycleIssues, mutate: mutateCycleIssues } = useSWR( - workspaceSlug && projectId && cycleId && params - ? CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params) - : null, + workspaceSlug && projectId && cycleId && params ? CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params) : null, workspaceSlug && projectId && cycleId && params ? () => cyclesService.getCycleIssuesWithParams( @@ -99,9 +94,7 @@ const useIssuesView = () => { ); const { data: moduleIssues, mutate: mutateModuleIssues } = useSWR( - workspaceSlug && projectId && moduleId && params - ? MODULE_ISSUES_WITH_PARAMS(moduleId as string, params) - : null, + workspaceSlug && projectId && moduleId && params ? MODULE_ISSUES_WITH_PARAMS(moduleId as string, params) : null, workspaceSlug && projectId && moduleId && params ? () => modulesService.getModuleIssuesWithParams( @@ -116,21 +109,16 @@ const useIssuesView = () => { const { data: viewIssues, mutate: mutateViewIssues } = useSWR( workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null, workspaceSlug && projectId && viewId && params - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); const { data: states } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const statesList = getStatesList(states); - const activeStatesList = statesList?.filter( - (state) => state.group === "started" || state.group === "unstarted" - ); + const activeStatesList = statesList?.filter((state) => state.group === "started" || state.group === "unstarted"); const backlogStatesList = statesList?.filter((state) => state.group === "backlog"); const stateIds = @@ -141,8 +129,7 @@ const useIssuesView = () => { : statesList?.map((state) => state.id); const filteredStateIds = - (filters && filters?.state ? stateIds?.filter((s) => filters.state?.includes(s)) : stateIds) ?? - []; + (filters && filters?.state ? stateIds?.filter((s) => filters.state?.includes(s)) : stateIds) ?? []; const emptyStatesObject: { [key: string]: [] } = {}; for (let i = 0; i < filteredStateIds.length; i++) { diff --git a/web/hooks/use-spreadsheet-issues-view.tsx b/web/hooks/use-spreadsheet-issues-view.tsx index 5aa86c600f9..54cc8670a29 100644 --- a/web/hooks/use-spreadsheet-issues-view.tsx +++ b/web/hooks/use-spreadsheet-issues-view.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // contexts import { issueViewContext } from "contexts/issue-view.context"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import cyclesService from "services/cycles.service"; import modulesService from "services/modules.service"; // types @@ -47,19 +47,14 @@ const useSpreadsheetIssuesView = () => { }; const { data: projectSpreadsheetIssues, mutate: mutateProjectSpreadsheetIssues } = useSWR( + workspaceSlug && projectId ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params) : null, workspaceSlug && projectId - ? PROJECT_ISSUES_LIST_WITH_PARAMS(projectId.toString(), params) - : null, - workspaceSlug && projectId - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); const { data: cycleSpreadsheetIssues, mutate: mutateCycleSpreadsheetIssues } = useSWR( - workspaceSlug && projectId && cycleId - ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) - : null, + workspaceSlug && projectId && cycleId ? CYCLE_ISSUES_WITH_PARAMS(cycleId.toString(), params) : null, workspaceSlug && projectId && cycleId ? () => cyclesService.getCycleIssuesWithParams( @@ -72,9 +67,7 @@ const useSpreadsheetIssuesView = () => { ); const { data: moduleSpreadsheetIssues, mutate: mutateModuleSpreadsheetIssues } = useSWR( - workspaceSlug && projectId && moduleId - ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) - : null, + workspaceSlug && projectId && moduleId ? MODULE_ISSUES_WITH_PARAMS(moduleId.toString(), params) : null, workspaceSlug && projectId && moduleId ? () => modulesService.getModuleIssuesWithParams( @@ -89,8 +82,7 @@ const useSpreadsheetIssuesView = () => { const { data: viewSpreadsheetIssues, mutate: mutateViewSpreadsheetIssues } = useSWR( workspaceSlug && projectId && viewId && params ? VIEW_ISSUES(viewId.toString(), params) : null, workspaceSlug && projectId && viewId && params - ? () => - issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) + ? () => issuesService.getIssuesWithParams(workspaceSlug.toString(), projectId.toString(), params) : null ); diff --git a/web/hooks/use-sub-issue.tsx b/web/hooks/use-sub-issue.tsx index 8eb30fd0b4a..64d9f73f6b1 100644 --- a/web/hooks/use-sub-issue.tsx +++ b/web/hooks/use-sub-issue.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // types import { ISubIssueResponse } from "types"; // fetch-keys @@ -19,10 +19,7 @@ const useSubIssue = (issueId: string, isExpanded: boolean) => { const { data: subIssuesResponse, isLoading } = useSWR( shouldFetch ? SUB_ISSUES(issueId as string) : null, - shouldFetch - ? () => - issuesService.subIssues(workspaceSlug as string, projectId as string, issueId as string) - : null + shouldFetch ? () => issuesService.subIssues(workspaceSlug as string, projectId as string, issueId as string) : null ); return { diff --git a/web/pages/[workspaceSlug]/analytics.tsx b/web/pages/[workspaceSlug]/analytics.tsx index 945b27c4ee8..2f6d1bc6958 100644 --- a/web/pages/[workspaceSlug]/analytics.tsx +++ b/web/pages/[workspaceSlug]/analytics.tsx @@ -13,7 +13,7 @@ import useProjects from "hooks/use-projects"; import { Tab } from "@headlessui/react"; // services import analyticsService from "services/analytics.service"; -import trackEventServices from "services/track-event.service"; +import trackEventServices from "services/track_event.service"; // layouts import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components @@ -66,9 +66,7 @@ const Analytics = () => { }; const eventType = - tab === "Scope and Demand" - ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" - : "WORKSPACE_CUSTOM_ANALYTICS"; + tab === "Scope and Demand" ? "WORKSPACE_SCOPE_AND_DEMAND_ANALYTICS" : "WORKSPACE_CUSTOM_ANALYTICS"; trackEventServices.trackAnalyticsEvent(eventPayload, eventType, user); }; diff --git a/web/pages/[workspaceSlug]/editor.tsx b/web/pages/[workspaceSlug]/editor.tsx index 711e4a16678..e52e26d5739 100644 --- a/web/pages/[workspaceSlug]/editor.tsx +++ b/web/pages/[workspaceSlug]/editor.tsx @@ -2,7 +2,7 @@ import { TipTapEditor } from "components/tiptap"; import type { NextPage } from "next"; import { useCallback, useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import { ICurrentUserResponse, IIssue } from "types"; import useReloadConfirmations from "hooks/use-reload-confirmation"; import { Spinner } from "components/ui"; @@ -137,9 +137,7 @@ const Editor: NextPage = () => { { workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId as string) : null, workspaceSlug && projectId && archivedIssueId ? () => - issuesService.retrieveArchivedIssue( - workspaceSlug as string, - projectId as string, - archivedIssueId as string - ) + issuesService.retrieveArchivedIssue(workspaceSlug as string, projectId as string, archivedIssueId as string) : null ); @@ -87,13 +83,7 @@ const ArchivedIssueDetailsPage: NextPage = () => { }; await issuesService - .patchIssue( - workspaceSlug as string, - projectId as string, - archivedIssueId as string, - payload, - user - ) + .patchIssue(workspaceSlug as string, projectId as string, archivedIssueId as string, payload, user) .then(() => { mutateIssueDetails(); mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string)); @@ -111,8 +101,7 @@ const ArchivedIssueDetailsPage: NextPage = () => { mutate(PROJECT_ISSUES_ACTIVITY(archivedIssueId as string)); reset({ ...issueDetails, - assignees_list: - issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id), + assignees_list: issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id), labels_list: issueDetails.labels_list ?? issueDetails.labels, labels: issueDetails.labels_list ?? issueDetails.labels, }); @@ -181,11 +170,7 @@ const ArchivedIssueDetailsPage: NextPage = () => {
    )}
    - +
    diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx index de6ad561ee0..898a9bf806a 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/cycles/[cycleId].tsx @@ -14,7 +14,7 @@ import { IssueViewContextProvider } from "contexts/issue-view.context"; import { ExistingIssuesListModal, IssuesFilterView, IssuesView } from "components/core"; import { CycleDetailsSidebar, TransferIssues, TransferIssuesModal } from "components/cycles"; // services -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; import cycleServices from "services/cycles.service"; // hooks import useToast from "hooks/use-toast"; @@ -57,12 +57,7 @@ const SingleCycle: React.FC = () => { const { data: cycleDetails, error } = useSWR( workspaceSlug && projectId && cycleId ? CYCLE_DETAILS(cycleId.toString()) : null, workspaceSlug && projectId && cycleId - ? () => - cycleServices.getCycleDetails( - workspaceSlug.toString(), - projectId.toString(), - cycleId.toString() - ) + ? () => cycleServices.getCycleDetails(workspaceSlug.toString(), projectId.toString(), cycleId.toString()) : null ); @@ -83,13 +78,7 @@ const SingleCycle: React.FC = () => { }; await issuesService - .addIssueToCycle( - workspaceSlug as string, - projectId as string, - cycleId as string, - payload, - user - ) + .addIssueToCycle(workspaceSlug as string, projectId as string, cycleId as string, payload, user) .catch(() => { setToastAlert({ type: "error", @@ -173,22 +162,14 @@ const SingleCycle: React.FC = () => { /> ) : ( <> - setTransferIssuesModal(false)} - isOpen={transferIssuesModal} - /> - setAnalyticsModal(false)} - /> + setTransferIssuesModal(false)} isOpen={transferIssuesModal} /> + setAnalyticsModal(false)} />
    - {cycleStatus === "completed" && ( - setTransferIssuesModal(true)} /> - )} + {cycleStatus === "completed" && setTransferIssuesModal(true)} />} { } = useSWR( workspaceSlug && projectId && issueId ? ISSUE_DETAILS(issueId as string) : null, workspaceSlug && projectId && issueId - ? () => - issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string) + ? () => issuesService.retrieve(workspaceSlug as string, projectId as string, issueId as string) : null ); @@ -108,8 +107,7 @@ const IssueDetailsPage: NextPage = () => { mutate(PROJECT_ISSUES_ACTIVITY(issueId as string)); reset({ ...issueDetails, - assignees_list: - issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id), + assignees_list: issueDetails.assignees_list ?? issueDetails.assignee_details?.map((user) => user.id), labels_list: issueDetails.labels_list ?? issueDetails.labels, labels: issueDetails.labels_list ?? issueDetails.labels, }); diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx index d79bfb613f8..688eeaca8ad 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/pages/[pageId].tsx @@ -15,8 +15,8 @@ import { DragDropContext, DropResult } from "react-beautiful-dnd"; import StrictModeDroppable from "components/dnd/StrictModeDroppable"; // services import projectService from "services/project.service"; -import pagesService from "services/pages.service"; -import issuesService from "services/issues.service"; +import pagesService from "services/page.service"; +import issuesService from "services/issue.service"; // hooks import useToast from "hooks/use-toast"; import useUser from "hooks/use-user"; @@ -28,14 +28,7 @@ import { CreateLabelModal } from "components/labels"; import { CreateBlock } from "components/pages/create-block"; // ui import { BreadcrumbItem, Breadcrumbs } from "components/breadcrumbs"; -import { - CustomSearchSelect, - EmptyState, - Loader, - TextArea, - ToggleSwitch, - Tooltip, -} from "components/ui"; +import { CustomSearchSelect, EmptyState, Loader, TextArea, ToggleSwitch, Tooltip } from "components/ui"; // images import emptyPage from "public/empty-state/page.svg"; // icons @@ -86,40 +79,26 @@ const SinglePage: NextPage = () => { const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, - workspaceSlug && projectId - ? () => projectService.getProject(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); const { data: pageDetails, error } = useSWR( workspaceSlug && projectId && pageId ? PAGE_DETAILS(pageId as string) : null, workspaceSlug && projectId - ? () => - pagesService.getPageDetails( - workspaceSlug as string, - projectId as string, - pageId as string - ) + ? () => pagesService.getPageDetails(workspaceSlug as string, projectId as string, pageId as string) : null ); const { data: pageBlocks } = useSWR( workspaceSlug && projectId && pageId ? PAGE_BLOCKS_LIST(pageId as string) : null, workspaceSlug && projectId - ? () => - pagesService.listPageBlocks( - workspaceSlug as string, - projectId as string, - pageId as string - ) + ? () => pagesService.listPageBlocks(workspaceSlug as string, projectId as string, pageId as string) : null ); const { data: labels } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, - workspaceSlug && projectId - ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null ); const { data: memberDetails } = useSWR( @@ -209,11 +188,7 @@ const SinglePage: NextPage = () => { }); }); - pagesService.removePageFromFavorites( - workspaceSlug as string, - projectId as string, - pageId as string - ); + pagesService.removePageFromFavorites(workspaceSlug as string, projectId as string, pageId as string); }; const handleOnDragEnd = (result: DropResult) => { @@ -228,15 +203,9 @@ const SinglePage: NextPage = () => { newSortOrder = pageBlocks[pageBlocks.length - 1].sort_order + 10000; else { if (destination.index > source.index) - newSortOrder = - (pageBlocks[destination.index].sort_order + - pageBlocks[destination.index + 1].sort_order) / - 2; + newSortOrder = (pageBlocks[destination.index].sort_order + pageBlocks[destination.index + 1].sort_order) / 2; else if (destination.index < source.index) - newSortOrder = - (pageBlocks[destination.index - 1].sort_order + - pageBlocks[destination.index].sort_order) / - 2; + newSortOrder = (pageBlocks[destination.index - 1].sort_order + pageBlocks[destination.index].sort_order) / 2; } const newBlocksList = pageBlocks.map((p) => ({ @@ -262,18 +231,15 @@ const SinglePage: NextPage = () => { }; const handleCopyText = () => { - const originURL = - typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; - - copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${pageId}`).then( - () => { - setToastAlert({ - type: "success", - title: "Link Copied!", - message: "Page link copied to clipboard.", - }); - } - ); + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + + copyTextToClipboard(`${originURL}/${workspaceSlug}/projects/${projectId}/pages/${pageId}`).then(() => { + setToastAlert({ + type: "success", + title: "Link Copied!", + message: "Page link copied to clipboard.", + }); + }); }; const handleShowBlockToggle = async () => { @@ -288,9 +254,7 @@ const SinglePage: NextPage = () => { }; mutate( - (workspaceSlug as string) && (projectId as string) - ? USER_PROJECT_VIEW(projectId as string) - : null, + (workspaceSlug as string) && (projectId as string) ? USER_PROJECT_VIEW(projectId as string) : null, (prevData) => { if (!prevData) return prevData; @@ -302,15 +266,13 @@ const SinglePage: NextPage = () => { false ); - await projectService - .setProjectView(workspaceSlug as string, projectId as string, payload) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "Something went wrong. Please try again.", - }); + await projectService.setProjectView(workspaceSlug as string, projectId as string, payload).catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Something went wrong. Please try again.", }); + }); }; const options = labels?.map((label) => ({ @@ -406,16 +368,13 @@ const SinglePage: NextPage = () => { partialUpdatePage({ labels_list: updatedLabels }); }} style={{ - backgroundColor: `${ - label?.color && label.color !== "" ? label.color : "#000000" - }20`, + backgroundColor: `${label?.color && label.color !== "" ? label.color : "#000000"}20`, }} > {label.name} @@ -492,9 +451,7 @@ const SinglePage: NextPage = () => {
    - - Show full block content - + Show full block content { @@ -594,11 +551,7 @@ const SinglePage: NextPage = () => { ) : ( - )} @@ -649,11 +602,7 @@ const SinglePage: NextPage = () => { {createBlockForm && (
    - setCreateBlockForm(false)} - focus="name" - user={user} - /> + setCreateBlockForm(false)} focus="name" user={user} />
    )} {labelModal && typeof projectId === "string" && ( diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx index 21e68563a3a..b9a21f793ca 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/estimates.tsx @@ -5,7 +5,7 @@ import { useRouter } from "next/router"; import useSWR, { mutate } from "swr"; // services -import estimatesService from "services/estimates.service"; +import estimatesService from "services/project_estimates.service"; import projectService from "services/project.service"; // hooks import useProjectDetails from "hooks/use-project-details"; @@ -67,15 +67,13 @@ const EstimatesSettings: NextPage = () => { false ); - estimatesService - .deleteEstimate(workspaceSlug as string, projectId as string, estimateId, user) - .catch(() => { - setToastAlert({ - type: "error", - title: "Error!", - message: "Error: Estimate could not be deleted. Please try again", - }); + estimatesService.deleteEstimate(workspaceSlug as string, projectId as string, estimateId, user).catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Error: Estimate could not be deleted. Please try again", }); + }); }; const disableEstimates = () => { @@ -91,15 +89,13 @@ const EstimatesSettings: NextPage = () => { false ); - projectService - .updateProject(workspaceSlug as string, projectId as string, { estimate: null }, user) - .catch(() => - setToastAlert({ - type: "error", - title: "Error!", - message: "Estimate could not be disabled. Please try again", - }) - ); + projectService.updateProject(workspaceSlug as string, projectId as string, { estimate: null }, user).catch(() => + setToastAlert({ + type: "error", + title: "Error!", + message: "Estimate could not be disabled. Please try again", + }) + ); }; return ( diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx index 499aaea866c..2dd4ab564be 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/features.tsx @@ -6,7 +6,7 @@ import useSWR, { mutate } from "swr"; // services import projectService from "services/project.service"; -import trackEventServices, { MiscellaneousEventType } from "services/track-event.service"; +import trackEventServices, { MiscellaneousEventType } from "services/track_event.service"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // hooks @@ -32,39 +32,32 @@ import { truncateText } from "helpers/string.helper"; const featuresList = [ { title: "Cycles", - description: - "Cycles are enabled for all the projects in this workspace. Access them from the sidebar.", - icon: ( - - ), + description: "Cycles are enabled for all the projects in this workspace. Access them from the sidebar.", + icon: , property: "cycle_view", }, { title: "Modules", - description: - "Modules are enabled for all the projects in this workspace. Access it from the sidebar.", + description: "Modules are enabled for all the projects in this workspace. Access it from the sidebar.", icon: , property: "module_view", }, { title: "Views", - description: - "Views are enabled for all the projects in this workspace. Access it from the sidebar.", + description: "Views are enabled for all the projects in this workspace. Access it from the sidebar.", icon: , property: "issue_views_view", }, { title: "Pages", - description: - "Pages are enabled for all the projects in this workspace. Access it from the sidebar.", + description: "Pages are enabled for all the projects in this workspace. Access it from the sidebar.", icon: , property: "page_view", }, { title: "Inbox", - description: - "Inbox are enabled for all the projects in this workspace. Access it from the issues views page.", + description: "Inbox are enabled for all the projects in this workspace. Access it from the issues views page.", icon: , property: "inbox_view", }, @@ -97,9 +90,7 @@ const FeaturesSettings: NextPage = () => { const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, - workspaceSlug && projectId - ? () => projectService.getProject(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); const handleSubmit = async (formData: Partial) => { @@ -129,15 +120,13 @@ const FeaturesSettings: NextPage = () => { message: "Project feature updated successfully.", }); - await projectService - .updateProject(workspaceSlug as string, projectId as string, formData, user) - .catch(() => - setToastAlert({ - type: "error", - title: "Error!", - message: "Project feature could not be updated. Please try again.", - }) - ); + await projectService.updateProject(workspaceSlug as string, projectId as string, formData, user).catch(() => + setToastAlert({ + type: "error", + title: "Error!", + message: "Project feature could not be updated. Please try again.", + }) + ); }; return ( @@ -173,9 +162,7 @@ const FeaturesSettings: NextPage = () => {

    {feature.title}

    -

    - {feature.description} -

    +

    {feature.description}

    { projectIdentifier: projectDetails?.identifier, projectName: projectDetails?.name, }, - getEventType( - feature.title, - !projectDetails?.[feature.property as keyof IProject] - ), + getEventType(feature.title, !projectDetails?.[feature.property as keyof IProject]), user ); handleSubmit({ diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx index ca64b8e220e..9fc2fe7bf68 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/integrations.tsx @@ -7,7 +7,7 @@ import useSWR from "swr"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // services -import IntegrationService from "services/integration"; +import IntegrationService from "services/integration.service"; import projectService from "services/project.service"; // components import { SettingsSidebar, SingleIntegration } from "components/project"; @@ -32,17 +32,12 @@ const ProjectIntegrations: NextPage = () => { const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, - workspaceSlug && projectId - ? () => projectService.getProject(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); const { data: workspaceIntegrations } = useSWR( workspaceSlug ? WORKSPACE_INTEGRATIONS(workspaceSlug as string) : null, - () => - workspaceSlug - ? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) - : null + () => (workspaceSlug ? IntegrationService.getWorkspaceIntegrationsList(workspaceSlug as string) : null) ); return ( @@ -70,10 +65,7 @@ const ProjectIntegrations: NextPage = () => { workspaceIntegrations.length > 0 ? (
    {workspaceIntegrations.map((integration) => ( - + ))}
    ) : ( diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx index 13b29015271..a6198acd2ee 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/labels.tsx @@ -8,7 +8,7 @@ import useSWR from "swr"; import useUserAuth from "hooks/use-user-auth"; // services import projectService from "services/project.service"; -import issuesService from "services/issues.service"; +import issuesService from "services/issue.service"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components @@ -59,16 +59,12 @@ const LabelsSettings: NextPage = () => { const { data: projectDetails } = useSWR( workspaceSlug && projectId ? PROJECT_DETAILS(projectId as string) : null, - workspaceSlug && projectId - ? () => projectService.getProject(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => projectService.getProject(workspaceSlug as string, projectId as string) : null ); const { data: issueLabels } = useSWR( workspaceSlug && projectId ? PROJECT_ISSUE_LABELS(projectId as string) : null, - workspaceSlug && projectId - ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) : null ); const newLabel = () => { @@ -121,11 +117,7 @@ const LabelsSettings: NextPage = () => {

    Labels

    - + Add label
    diff --git a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx index 88be296c480..7037ec8ea8a 100644 --- a/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx +++ b/web/pages/[workspaceSlug]/projects/[projectId]/settings/states.tsx @@ -5,19 +5,14 @@ import { useRouter } from "next/router"; import useSWR from "swr"; // services -import stateService from "services/state.service"; +import stateService from "services/project_state.service"; // hooks import useProjectDetails from "hooks/use-project-details"; import useUserAuth from "hooks/use-user-auth"; // layouts import { ProjectAuthorizationWrapper } from "layouts/auth-layout"; // components -import { - CreateUpdateStateInline, - DeleteStateModal, - SingleState, - StateGroup, -} from "components/states"; +import { CreateUpdateStateInline, DeleteStateModal, SingleState, StateGroup } from "components/states"; import { SettingsSidebar } from "components/project"; // ui import { Loader } from "components/ui"; @@ -46,9 +41,7 @@ const StatesSettings: NextPage = () => { const { data: states } = useSWR( workspaceSlug && projectId ? STATES_LIST(projectId as string) : null, - workspaceSlug && projectId - ? () => stateService.getStates(workspaceSlug as string, projectId as string) - : null + workspaceSlug && projectId ? () => stateService.getStates(workspaceSlug as string, projectId as string) : null ); const orderedStateGroups = orderStateGroups(states); const statesList = getStatesList(orderedStateGroups); @@ -88,9 +81,7 @@ const StatesSettings: NextPage = () => { return (
    -

    - {key} -

    +

    {key}

    )} - {displayFilters.layout !== "calendar" && - displayFilters.layout !== "spreadsheet" && ( -
    -

    Order by

    -
    - option.key === displayFilters.order_by - )?.name ?? "Select" - } - className="!w-full" - buttonClassName="w-full" - > - {ORDER_BY_OPTIONS.map((option) => - displayFilters.group_by === "priority" && - option.key === "priority" ? null : ( - { - setDisplayFilters({ order_by: option.key }); - }} - > - {option.name} - - ) - )} - -
    + {displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && ( +
    +

    Order by

    +
    + option.key === displayFilters.order_by)?.title ?? + "Select" + } + className="!w-full" + buttonClassName="w-full" + > + {ISSUE_ORDER_BY_OPTIONS.map((option) => + displayFilters.group_by === "priority" && option.key === "priority" ? null : ( + { + // setDisplayFilters({ order_by: option.key }); + }} + > + {option.title} + + ) + )} +
    - )} +
    + )}

    Issue type

    option.key === displayFilters.type - )?.name ?? "Select" + ISSUE_FILTER_OPTIONS.find((option) => option.key === displayFilters.type)?.title ?? "Select" } className="!w-full" buttonClassName="w-full" > - {FILTER_ISSUE_OPTIONS.map((option) => ( + {ISSUE_FILTER_OPTIONS.map((option) => ( - setDisplayFilters({ - type: option.key, - }) - } + onClick={() => { + // setDisplayFilters({ + // type: option.key, + // }) + }} > - {option.name} + {option.title} ))}
    - {displayFilters.layout !== "calendar" && - displayFilters.layout !== "spreadsheet" && ( -
    -

    Show sub-issues

    -
    - - setDisplayFilters({ sub_issue: !displayFilters.sub_issue }) - } - /> -
    + {displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && ( +
    +

    Show sub-issues

    +
    + setDisplayFilters({ sub_issue: !displayFilters.sub_issue })} + />
    - )} +
    + )} {displayFilters.layout !== "calendar" && displayFilters.layout !== "spreadsheet" && displayFilters.layout !== "gantt_chart" && ( @@ -358,16 +333,11 @@ export const IssuesFilterView: React.FC = () => { if ( displayFilters.layout === "spreadsheet" && - (key === "attachment_count" || - key === "link" || - key === "sub_issue_count") + (key === "attachment_count" || key === "link" || key === "sub_issue_count") ) return null; - if ( - displayFilters.layout !== "spreadsheet" && - (key === "created_on" || key === "updated_on") - ) + if (displayFilters.layout !== "spreadsheet" && (key === "created_on" || key === "updated_on")) return null; return ( diff --git a/web/components/core/views/board-view/single-issue.tsx b/web/components/core/views/board-view/single-issue.tsx index ecadc015fc7..1e818ae7e90 100644 --- a/web/components/core/views/board-view/single-issue.tsx +++ b/web/components/core/views/board-view/single-issue.tsx @@ -36,7 +36,7 @@ import { } from "@heroicons/react/24/outline"; import { LayerDiagonalIcon } from "components/icons"; // helpers -import { handleIssuesMutation } from "constants/issue"; +import { handleIssuesMutation } from "helpers/issue.helper"; import { copyTextToClipboard } from "helpers/string.helper"; // types import { ICurrentUserResponse, IIssue, IIssueViewProps, ISubIssueResponse, UserAuth } from "types"; diff --git a/web/components/core/views/list-view/single-issue.tsx b/web/components/core/views/list-view/single-issue.tsx index 2e88af8d8ca..34f7272222b 100644 --- a/web/components/core/views/list-view/single-issue.tsx +++ b/web/components/core/views/list-view/single-issue.tsx @@ -34,7 +34,7 @@ import { import { LayerDiagonalIcon } from "components/icons"; // helpers import { copyTextToClipboard } from "helpers/string.helper"; -import { handleIssuesMutation } from "constants/issue"; +import { handleIssuesMutation } from "helpers/issue.helper"; // types import { ICurrentUserResponse, diff --git a/web/components/exporter/export-modal.tsx b/web/components/exporter/export-modal.tsx index 853df190d95..f0e055e9cee 100644 --- a/web/components/exporter/export-modal.tsx +++ b/web/components/exporter/export-modal.tsx @@ -3,7 +3,7 @@ import { useRouter } from "next/router"; // headless ui import { Dialog, Transition } from "@headlessui/react"; // services -import CSVIntegrationService from "services/csv.services"; +import { CSVIntegrationService } from "services/csv.services"; // hooks import useToast from "hooks/use-toast"; // ui diff --git a/web/components/issue-layouts/display-filters/display-properties.tsx b/web/components/issue-layouts/display-filters/display-properties.tsx index 309763c3f18..402c5064f95 100644 --- a/web/components/issue-layouts/display-filters/display-properties.tsx +++ b/web/components/issue-layouts/display-filters/display-properties.tsx @@ -6,15 +6,16 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import { ISSUE_DISPLAY_PROPERTIES } from "constants/issue"; export const FilterDisplayProperties = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleDisplayProperties = (key: string, value: boolean) => { - issueFilterStore.handleUserFilter("display_properties", key, !value); + // issueFilterStore.handleUserFilter("display_properties", key, !value); }; return ( @@ -26,26 +27,24 @@ export const FilterDisplayProperties = observer(() => { /> {previewEnabled && (
    - {issueFilterStore?.issueRenderFilters?.display_properties && - issueFilterStore?.issueRenderFilters?.display_properties.length > 0 && - issueFilterStore?.issueRenderFilters?.display_properties.map((_displayProperties) => ( -
    - handleDisplayProperties( - _displayProperties?.key, - issueFilterStore?.userFilters?.display_properties?.[_displayProperties?.key] - ) - } - > - {_displayProperties?.title} -
    - ))} + {ISSUE_DISPLAY_PROPERTIES.map((displayProperty) => ( +
    { + handleDisplayProperties( + displayProperty?.key, + issueFilterStore?.userDisplayProperties?.[displayProperty?.key] + ); + }} + > + {displayProperty?.title} +
    + ))}
    )}
    diff --git a/web/components/issue-layouts/display-filters/extra-options.tsx b/web/components/issue-layouts/display-filters/extra-options.tsx index e4f127627f3..d05703c9ba6 100644 --- a/web/components/issue-layouts/display-filters/extra-options.tsx +++ b/web/components/issue-layouts/display-filters/extra-options.tsx @@ -7,25 +7,27 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import { ISSUE_EXTRA_PROPERTIES } from "constants/issue"; // default data -import { issueFilterVisibilityData } from "store/helpers/issue-data"; +// import { issueFilterVisibilityData } from "helpers/issue.helper"; export const FilterExtraOptions = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleExtraOptions = (key: string, value: boolean) => { - issueFilterStore.handleUserFilter("display_filters", key, !value); + // issueFilterStore.handleUserFilter("display_filters", key, !value); }; - const handleExtraOptionsSectionVisibility = (key: string) => - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ - issueFilterStore?.issueLayout - ].values?.includes(key); + const handleExtraOptionsSectionVisibility = (key: string) => { + // issueFilterStore?.issueView && + // issueFilterStore?.issueLayout && + // issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ + // issueFilterStore?.issueLayout + // ].values?.includes(key); + }; return (
    @@ -36,24 +38,16 @@ export const FilterExtraOptions = observer(() => { /> {previewEnabled && (
    - {issueFilterStore?.issueRenderFilters?.extra_properties && - issueFilterStore?.issueRenderFilters?.extra_properties.length > 0 && - issueFilterStore?.issueRenderFilters?.extra_properties.map( - (_extraProperties) => - handleExtraOptionsSectionVisibility(_extraProperties?.key) && ( - - handleExtraOptions( - _extraProperties?.key, - issueFilterStore?.userFilters?.display_filters?.[_extraProperties?.key] - ) - } - title={_extraProperties.title} - /> - ) - )} + {ISSUE_EXTRA_PROPERTIES.map((_extraProperties) => ( + + handleExtraOptions(_extraProperties?.key, issueFilterStore?.userDisplayFilters?.[_extraProperties?.key]) + } + title={_extraProperties.title} + /> + ))}
    )}
    diff --git a/web/components/issue-layouts/display-filters/group-by.tsx b/web/components/issue-layouts/display-filters/group-by.tsx index 026ad68daf0..676717adc6b 100644 --- a/web/components/issue-layouts/display-filters/group-by.tsx +++ b/web/components/issue-layouts/display-filters/group-by.tsx @@ -7,15 +7,16 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import { ISSUE_GROUP_BY_OPTIONS } from "constants/issue"; export const FilterGroupBy = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleGroupBy = (key: string, value: string) => { - issueFilterStore.handleUserFilter("display_filters", key, value); + // issueFilterStore.handleUserFilter("display_filters", key, value); }; return ( @@ -27,17 +28,15 @@ export const FilterGroupBy = observer(() => { /> {previewEnabled && (
    - {issueFilterStore?.issueRenderFilters?.group_by && - issueFilterStore?.issueRenderFilters?.group_by.length > 0 && - issueFilterStore?.issueRenderFilters?.group_by.map((_groupBy) => ( - handleGroupBy("group_by", _groupBy?.key)} - title={_groupBy.title} - multiple={false} - /> - ))} + {ISSUE_GROUP_BY_OPTIONS.map((_groupBy) => ( + handleGroupBy("group_by", _groupBy?.key)} + title={_groupBy.title} + multiple={false} + /> + ))}
    )}
    diff --git a/web/components/issue-layouts/display-filters/index.tsx b/web/components/issue-layouts/display-filters/index.tsx index b8de6e51300..708d52241aa 100644 --- a/web/components/issue-layouts/display-filters/index.tsx +++ b/web/components/issue-layouts/display-filters/index.tsx @@ -11,70 +11,71 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/helpers/issue-data"; +// import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const DisplayFiltersSelection = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; - const handleDisplayPropertiesSectionVisibility = - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"] - ?.display_properties?.[issueFilterStore?.issueLayout]; + // const handleDisplayPropertiesSectionVisibility = + // issueFilterStore?.issueView && + // issueFilterStore?.issueLayout && + // issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"] + // ?.display_properties?.[issueFilterStore?.issueLayout]; - const handleDisplayFilterSectionVisibility = (section_key: string) => - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.display_filters?.[ - issueFilterStore?.issueLayout - ].includes(section_key); + const handleDisplayFilterSectionVisibility = (section_key: string) => { + // issueFilterStore?.issueView && + // issueFilterStore?.issueLayout && + // issueFilterVisibilityData[ + // issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues" + // ]?.display_filters?.[issueFilterStore?.issueLayout].includes(section_key); + }; - const handleExtraOptionsSectionVisibility = - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ - issueFilterStore?.issueLayout - ].access; + // const handleExtraOptionsSectionVisibility = + // issueFilterStore?.issueView && + // issueFilterStore?.issueLayout && + // issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.extra_options?.[ + // issueFilterStore?.issueLayout + // ].access; return (
    Search container
    {/* display properties */} - {handleDisplayPropertiesSectionVisibility && ( + {/* {handleDisplayPropertiesSectionVisibility && (
    - )} + )} */} {/* group by */} - {handleDisplayFilterSectionVisibility("group_by") && ( + {/* {handleDisplayFilterSectionVisibility("group_by") && (
    - )} + )} */} {/* order by */} - {handleDisplayFilterSectionVisibility("order_by") && ( + {/* {handleDisplayFilterSectionVisibility("order_by") && (
    - )} + )} */} {/* issue type */} - {handleDisplayFilterSectionVisibility("issue_type") && ( + {/* {handleDisplayFilterSectionVisibility("issue_type") && (
    - )} + )} */} {/* Options */} - {handleExtraOptionsSectionVisibility && ( + {/* {handleExtraOptionsSectionVisibility && (
    - )} + )} */}
    ); diff --git a/web/components/issue-layouts/display-filters/issue-type.tsx b/web/components/issue-layouts/display-filters/issue-type.tsx index cdf5dd34263..b9c3ace847e 100644 --- a/web/components/issue-layouts/display-filters/issue-type.tsx +++ b/web/components/issue-layouts/display-filters/issue-type.tsx @@ -1,21 +1,21 @@ import React from "react"; +import { observer } from "mobx-react-lite"; // components import { FilterHeader } from "../helpers/filter-header"; import { FilterOption } from "../helpers/filter-option"; -// mobx react lite -import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import { ISSUE_FILTER_OPTIONS } from "constants/issue"; export const FilterIssueType = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleIssueType = (key: string, value: string) => { - issueFilterStore.handleUserFilter("display_filters", key, value); + // issueFilterStore.handleUserFilter("display_filters", key, value); }; return ( @@ -27,17 +27,15 @@ export const FilterIssueType = observer(() => { /> {previewEnabled && (
    - {issueFilterStore?.issueRenderFilters?.issue_type && - issueFilterStore?.issueRenderFilters?.issue_type.length > 0 && - issueFilterStore?.issueRenderFilters?.issue_type.map((_issueType) => ( - handleIssueType("type", _issueType?.key)} - title={_issueType.title} - multiple={false} - /> - ))} + {ISSUE_FILTER_OPTIONS.map((_issueType) => ( + handleIssueType("type", _issueType?.key)} + title={_issueType.title} + multiple={false} + /> + ))}
    )}
    diff --git a/web/components/issue-layouts/display-filters/order-by.tsx b/web/components/issue-layouts/display-filters/order-by.tsx index b575ed45eda..8159dc64140 100644 --- a/web/components/issue-layouts/display-filters/order-by.tsx +++ b/web/components/issue-layouts/display-filters/order-by.tsx @@ -7,15 +7,16 @@ import { observer } from "mobx-react-lite"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import { ISSUE_ORDER_BY_OPTIONS } from "constants/issue"; export const FilterOrderBy = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleOrderBy = (key: string, value: string) => { - issueFilterStore.handleUserFilter("display_filters", key, value); + // issueFilterStore.handleUserFilter("display_filters", key, value); }; return ( @@ -27,17 +28,15 @@ export const FilterOrderBy = observer(() => { /> {previewEnabled && (
    - {issueFilterStore?.issueRenderFilters?.order_by && - issueFilterStore?.issueRenderFilters?.order_by.length > 0 && - issueFilterStore?.issueRenderFilters?.order_by.map((_orderBy) => ( - handleOrderBy("order_by", _orderBy?.key)} - title={_orderBy.title} - multiple={false} - /> - ))} + {ISSUE_ORDER_BY_OPTIONS.map((_orderBy) => ( + handleOrderBy("order_by", _orderBy?.key)} + title={_orderBy.title} + multiple={false} + /> + ))}
    )}
    diff --git a/web/components/issue-layouts/filters/assignees.tsx b/web/components/issue-layouts/filters/assignees.tsx index f5f49eee70e..7c2d449932b 100644 --- a/web/components/issue-layouts/filters/assignees.tsx +++ b/web/components/issue-layouts/filters/assignees.tsx @@ -22,19 +22,19 @@ export const MemberIcons = ({ display_name, avatar }: { display_name: string; av export const FilterAssignees = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; const [previewEnabled, setPreviewEnabled] = React.useState(true); const handleFilter = (key: string, value: string) => { - let _value = - issueFilterStore?.userFilters?.filters?.[key] != null - ? issueFilterStore?.userFilters?.filters?.[key].includes(value) - ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) - : [...issueFilterStore?.userFilters?.filters?.[key], value] - : [value]; - _value = _value && _value.length > 0 ? _value : null; - issueFilterStore.handleUserFilter("filters", key, _value); + // let _value = + // issueFilterStore?.userFilters?.filters?.[key] != null + // ? issueFilterStore?.userFilters?.filters?.[key].includes(value) + // ? issueFilterStore?.userFilters?.filters?.[key].filter((p: string) => p != value) + // : [...issueFilterStore?.userFilters?.filters?.[key], value] + // : [value]; + // _value = _value && _value.length > 0 ? _value : null; + // issueFilterStore.handleUserFilter("filters", key, _value); }; return ( diff --git a/web/constants/issue.ts b/web/constants/issue.ts index ff931707095..ccd4ab101e2 100644 --- a/web/constants/issue.ts +++ b/web/constants/issue.ts @@ -1,121 +1,182 @@ -export const GROUP_BY_OPTIONS: Array<{ - name: string; - key: TIssueGroupByOptions; -}> = [ - { name: "States", key: "state" }, - { name: "State Groups", key: "state_detail.group" }, - { name: "Priority", key: "priority" }, - { name: "Project", key: "project" }, - { name: "Labels", key: "labels" }, - { name: "Assignees", key: "assignees" }, - { name: "Created by", key: "created_by" }, - { name: "None", key: null }, -]; - -export const ORDER_BY_OPTIONS: Array<{ - name: string; - key: TIssueOrderByOptions; -}> = [ - { name: "Manual", key: "sort_order" }, - { name: "Last created", key: "-created_at" }, - { name: "Last updated", key: "-updated_at" }, - { name: "Start date", key: "start_date" }, - { name: "Priority", key: "priority" }, -]; - -export const FILTER_ISSUE_OPTIONS: Array<{ - name: string; - key: "active" | "backlog" | null; -}> = [ - { - name: "All", - key: null, +export const ISSUE_PRIORITIES = [ + { key: "urgent", title: "Urgent" }, + { key: "high", title: "High" }, + { key: "medium", title: "Medium" }, + { key: "low", title: "Low" }, + { key: "none", title: "None" }, +]; + +export const ISSUE_STATE_GROUPS = [ + { key: "backlog", title: "Backlog" }, + { key: "unstarted", title: "Unstarted" }, + { key: "started", title: "Started" }, + { key: "completed", title: "Completed" }, + { key: "cancelled", title: "Cancelled" }, +]; + +export const ISSUE_START_DATE_OPTIONS = [ + { key: "last_week", title: "Last Week" }, + { key: "2_weeks_from_now", title: "2 weeks from now" }, + { key: "1_month_from_now", title: "1 month from now" }, + { key: "2_months_from_now", title: "2 months from now" }, + { key: "custom", title: "Custom" }, +]; + +export const ISSUE_DUE_DATE_OPTIONS = [ + { key: "last_week", title: "Last Week" }, + { key: "2_weeks_from_now", title: "2 weeks from now" }, + { key: "1_month_from_now", title: "1 month from now" }, + { key: "2_months_from_now", title: "2 months from now" }, + { key: "custom", title: "Custom" }, +]; + +export const ISSUE_GROUP_BY_OPTIONS = [ + { key: "state", title: "States" }, + { key: "state_detail.group", title: "State Groups" }, + { key: "priority", title: "Priority" }, + { key: "project", title: "Project" }, // required this on my issues + { key: "labels", title: "Labels" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, +]; + +export const ISSUE_ORDER_BY_OPTIONS = [ + { key: "sort_order", title: "Manual" }, + { key: "created_at", title: "Last Created" }, + { key: "updated_at", title: "Last Updated" }, + { key: "start_date", title: "Start Date" }, + { key: "priority", title: "Priority" }, +]; + +export const ISSUE_FILTER_OPTIONS = [ + { key: "all", title: "All" }, + { key: "active", title: "Active Issues" }, + { key: "backlog", title: "Backlog Issues" }, + // { key: "draft", title: "Draft Issues" }, +]; + +export const ISSUE_DISPLAY_PROPERTIES = [ + { key: "assignee", title: "Assignee" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, + { key: "key", title: "ID" }, + { key: "labels", title: "Labels" }, + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "sub_issue_count", title: "Sub Issue Count" }, + { key: "attachment_count", title: "Attachment Count" }, + { key: "link", title: "Link" }, + { key: "estimate", title: "Estimate" }, +]; + +export const ISSUE_EXTRA_PROPERTIES = [ + { key: "sub_issue", title: "Show sub-issues" }, // in spreadsheet its always false + { key: "show_empty_groups", title: "Show empty states" }, // filter on front-end + { key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after + { key: "start_target_date", title: "Start target Date" }, // gantt always be true +]; + +export const ISSUE_LAYOUTS = [ + { key: "list", title: "List View" }, + { key: "kanban", title: "Kanban View" }, + { key: "calendar", title: "Calendar View" }, + { key: "spreadsheet", title: "Spreadsheet View" }, + { key: "gantt_chart", title: "Gantt Chart View" }, +]; + +export const ISSUE_LIST_FILTERS = [ + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, + { key: "labels", title: "Labels" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, +]; + +export const ISSUE_KANBAN_FILTERS = [ + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, + { key: "labels", title: "Labels" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, +]; + +export const ISSUE_CALENDER_FILTERS = [ + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, + { key: "labels", title: "Labels" }, +]; + +export const ISSUE_SPREADSHEET_FILTERS = [ + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, + { key: "labels", title: "Labels" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, +]; + +export const ISSUE_GANTT_FILTERS = [ + { key: "priority", title: "Priority" }, + { key: "state", title: "State" }, + { key: "assignees", title: "Assignees" }, + { key: "created_by", title: "Created By" }, + { key: "labels", title: "Labels" }, + { key: "start_date", title: "Start Date" }, + { key: "due_date", title: "Due Date" }, +]; + +export const ISSUE_LIST_DISPLAY_FILTERS = [ + { key: "group_by", title: "Group By" }, + { key: "order_by", title: "Order By" }, + { key: "issue_type", title: "Issue Type" }, + { key: "sub_issue", title: "Sub Issue" }, + { key: "show_empty_groups", title: "Show Empty Groups" }, +]; + +export const ISSUE_KANBAN_DISPLAY_FILTERS = [ + { key: "group_by", title: "Group By" }, + { key: "order_by", title: "Order By" }, + { key: "issue_type", title: "Issue Type" }, + { key: "sub_issue", title: "Sub Issue" }, + { key: "show_empty_groups", title: "Show Empty Groups" }, +]; + +export const ISSUE_CALENDER_DISPLAY_FILTERS = [{ key: "issue_type", title: "Issue Type" }]; + +export const ISSUE_SPREADSHEET_DISPLAY_FILTERS = [{ key: "issue_type", title: "Issue Type" }]; + +export const ISSUE_GANTT_DISPLAY_FILTERS = [ + { key: "order_by", title: "Order By" }, + { key: "issue_type", title: "Issue Type" }, + { key: "sub_issue", title: "Sub Issue" }, +]; + +export const ISSUE_EXTRA_DISPLAY_PROPERTIES = { + list: { + access: true, + values: ["show_empty_groups", "sub_issue"], }, - { - name: "Active Issues", - key: "active", + kanban: { + access: true, + values: ["show_empty_groups", "sub_issue"], }, - { - name: "Backlog Issues", - key: "backlog", + calendar: { + access: false, + values: [], + }, + spreadsheet: { + access: false, + values: [], + }, + gantt_chart: { + access: true, + values: ["sub_issue"], }, -]; - -import { orderArrayBy } from "helpers/array.helper"; -import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types"; - -type THandleIssuesMutation = ( - formData: Partial, - oldGroupTitle: string, - selectedGroupBy: TIssueGroupByOptions, - issueIndex: number, - orderBy: TIssueOrderByOptions, - prevData?: - | { - [key: string]: IIssue[]; - } - | IIssue[] -) => - | { - [key: string]: IIssue[]; - } - | IIssue[] - | undefined; - -export const handleIssuesMutation: THandleIssuesMutation = ( - formData, - oldGroupTitle, - selectedGroupBy, - issueIndex, - orderBy, - prevData -) => { - if (!prevData) return prevData; - - if (Array.isArray(prevData)) { - const updatedIssue = { - ...prevData[issueIndex], - ...formData, - assignees: formData?.assignees_list ?? prevData[issueIndex]?.assignees, - labels: formData?.labels_list ?? prevData[issueIndex]?.labels, - }; - - prevData.splice(issueIndex, 1, updatedIssue); - - return [...prevData]; - } else { - const oldGroup = prevData[oldGroupTitle ?? ""] ?? []; - - let newGroup: IIssue[] = []; - - if (selectedGroupBy === "priority") newGroup = prevData[formData.priority ?? ""] ?? []; - else if (selectedGroupBy === "state") newGroup = prevData[formData.state ?? ""] ?? []; - - const updatedIssue = { - ...oldGroup[issueIndex], - ...formData, - assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees, - labels: formData?.labels_list ?? oldGroup[issueIndex]?.labels, - }; - - if (selectedGroupBy !== Object.keys(formData)[0]) - return { - ...prevData, - [oldGroupTitle ?? ""]: orderArrayBy( - oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)), - orderBy - ), - }; - - const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state; - - return { - ...prevData, - [oldGroupTitle ?? ""]: orderArrayBy( - oldGroup.filter((i) => i.id !== updatedIssue.id), - orderBy - ), - [groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy), - }; - } }; diff --git a/web/helpers/issue.helper.ts b/web/helpers/issue.helper.ts new file mode 100644 index 00000000000..203e8fb2893 --- /dev/null +++ b/web/helpers/issue.helper.ts @@ -0,0 +1,199 @@ +import { orderArrayBy } from "helpers/array.helper"; +import { renderDateFormat } from "helpers/date-time.helper"; +// types +import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types"; + +type THandleIssuesMutation = ( + formData: Partial, + oldGroupTitle: string, + selectedGroupBy: TIssueGroupByOptions, + issueIndex: number, + orderBy: TIssueOrderByOptions, + prevData?: + | { + [key: string]: IIssue[]; + } + | IIssue[] +) => + | { + [key: string]: IIssue[]; + } + | IIssue[] + | undefined; + +export const handleIssuesMutation: THandleIssuesMutation = ( + formData, + oldGroupTitle, + selectedGroupBy, + issueIndex, + orderBy, + prevData +) => { + if (!prevData) return prevData; + + if (Array.isArray(prevData)) { + const updatedIssue = { + ...prevData[issueIndex], + ...formData, + assignees: formData?.assignees_list ?? prevData[issueIndex]?.assignees, + labels: formData?.labels_list ?? prevData[issueIndex]?.labels, + }; + + prevData.splice(issueIndex, 1, updatedIssue); + + return [...prevData]; + } else { + const oldGroup = prevData[oldGroupTitle ?? ""] ?? []; + + let newGroup: IIssue[] = []; + + if (selectedGroupBy === "priority") newGroup = prevData[formData.priority ?? ""] ?? []; + else if (selectedGroupBy === "state") newGroup = prevData[formData.state ?? ""] ?? []; + + const updatedIssue = { + ...oldGroup[issueIndex], + ...formData, + assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees, + labels: formData?.labels_list ?? oldGroup[issueIndex]?.labels, + }; + + if (selectedGroupBy !== Object.keys(formData)[0]) + return { + ...prevData, + [oldGroupTitle ?? ""]: orderArrayBy( + oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)), + orderBy + ), + }; + + const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state; + + return { + ...prevData, + [oldGroupTitle ?? ""]: orderArrayBy( + oldGroup.filter((i) => i.id !== updatedIssue.id), + orderBy + ), + [groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy), + }; + } +}; + +export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; +export type TIssueParams = + | "priority" + | "state_group" + | "state" + | "assignees" + | "created_by" + | "labels" + | "start_date" + | "target_date" + | "group_by" + | "order_by" + | "type" + | "sub_issue" + | "show_empty_groups" + | "calendar_date_range" + | "start_target_date"; + +export const handleIssueQueryParamsByLayout = (_layout: TIssueLayouts | undefined): TIssueParams[] | null => { + if (_layout === "list") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "group_by", + "order_by", + "type", + "sub_issue", + "show_empty_groups", + ]; + if (_layout === "kanban") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "group_by", + "order_by", + "type", + "sub_issue", + "show_empty_groups", + ]; + if (_layout === "calendar") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "calendar_date_range", + ]; + if (_layout === "spreadsheet") + return [ + "priority", + "state_group", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "type", + "sub_issue", + ]; + if (_layout === "gantt_chart") + return [ + "priority", + "state", + "assignees", + "created_by", + "labels", + "start_date", + "target_date", + "order_by", + "type", + "sub_issue", + "start_target_date", + ]; + + return null; +}; + +export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => { + if (key === "last_week") + return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat( + new Date() + )};before`; + + if (key === "2_weeks_from_now") + return `${renderDateFormat(new Date())};after, + ${renderDateFormat(new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000))};before`; + + if (key === "1_month_from_now") + return `${renderDateFormat(new Date())};after,${renderDateFormat( + new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()) + )};before`; + + if (key === "2_months_from_now") + return `${renderDateFormat(new Date())};after,${renderDateFormat( + new Date(new Date().getFullYear(), new Date().getMonth() + 2, new Date().getDate()) + )};before`; + + if (key === "custom" && start_date && target_date) + return `${renderDateFormat(start_date)};after,${renderDateFormat(target_date)};before`; +}; diff --git a/web/services/jira.service.ts b/web/services/jira.service.ts index 6195653f16d..ff1aa595d68 100644 --- a/web/services/jira.service.ts +++ b/web/services/jira.service.ts @@ -34,5 +34,5 @@ export class JiraImporterService extends APIService { }); } } - -export default JiraImporterService; +const jiraService = new JiraImporterService(); +export default jiraService; diff --git a/web/store/helpers/issue-data.ts b/web/store/helpers/issue-data.ts deleted file mode 100644 index a364c9f38ea..00000000000 --- a/web/store/helpers/issue-data.ts +++ /dev/null @@ -1,257 +0,0 @@ -import { renderDateFormat } from "helpers/date-time.helper"; -// types -import { TIssueLayouts, TIssueParams } from "../issue_filters.legacy"; - -export type TStateGroup = "backlog" | "unstarted" | "started" | "completed" | "cancelled"; - -export const priorities: { key: string; title: string }[] = [ - { key: "urgent", title: "Urgent" }, - { key: "high", title: "High" }, - { key: "medium", title: "Medium" }, - { key: "low", title: "Low" }, - { key: "none", title: "None" }, -]; - -export const stateGroups: { key: TStateGroup; title: string }[] = [ - { key: "backlog", title: "Backlog" }, - { key: "unstarted", title: "Unstarted" }, - { key: "started", title: "Started" }, - { key: "completed", title: "Completed" }, - { key: "cancelled", title: "Cancelled" }, -]; - -export const startDateOptions: { key: string; title: string }[] = [ - { key: "last_week", title: "Last Week" }, - { key: "2_weeks_from_now", title: "2 weeks from now" }, - { key: "1_month_from_now", title: "1 month from now" }, - { key: "2_months_from_now", title: "2 months from now" }, - { key: "custom", title: "Custom" }, -]; - -export const dueDateOptions: { key: string; title: string }[] = [ - { key: "last_week", title: "Last Week" }, - { key: "2_weeks_from_now", title: "2 weeks from now" }, - { key: "1_month_from_now", title: "1 month from now" }, - { key: "2_months_from_now", title: "2 months from now" }, - { key: "custom", title: "Custom" }, -]; - -export const groupByOptions: { key: string; title: string }[] = [ - { key: "state", title: "States" }, - { key: "state_detail.group", title: "State Groups" }, - { key: "priority", title: "Priority" }, - { key: "project", title: "Project" }, // required this on my issues - { key: "labels", title: "Labels" }, - { key: "assignees", title: "Assignees" }, - { key: "created_by", title: "Created By" }, -]; - -export const orderByOptions: { key: string; title: string }[] = [ - { key: "sort_order", title: "Manual" }, - { key: "created_at", title: "Last Created" }, - { key: "updated_at", title: "Last Updated" }, - { key: "start_date", title: "Start Date" }, - { key: "priority", title: "Priority" }, -]; - -export const issueTypes: { key: string; title: string }[] = [ - { key: "all", title: "All" }, - { key: "active", title: "Active Issues" }, - { key: "backlog", title: "Backlog Issues" }, -]; - -export const displayProperties: { key: string; title: string }[] = [ - { key: "assignee", title: "Assignee" }, - { key: "start_date", title: "Start Date" }, - { key: "due_date", title: "Due Date" }, - { key: "key", title: "ID" }, - { key: "labels", title: "Labels" }, - { key: "priority", title: "Priority" }, - { key: "state", title: "State" }, - { key: "sub_issue_count", title: "Sub Issue Count" }, - { key: "attachment_count", title: "Attachment Count" }, - { key: "link", title: "Link" }, - { key: "estimate", title: "Estimate" }, -]; - -export const extraProperties: { key: string; title: string }[] = [ - { key: "sub_issue", title: "Show sub-issues" }, // in spreadsheet its always false - { key: "show_empty_groups", title: "Show empty states" }, // filter on front-end - { key: "calendar_date_range", title: "Calendar Date Range" }, // calendar date range yyyy-mm-dd;before range yyyy-mm-dd;after - { key: "start_target_date", title: "Start target Date" }, // gantt always be true -]; - -export const issueFilterVisibilityData: any = { - my_issues: { - layout: ["list", "kanban"], - filters: { - list: ["priority", "state_group", "labels", "start_date", "due_date"], - kanban: ["priority", "state_group", "labels", "start_date", "due_date"], - }, - display_properties: { - list: true, - kanban: true, - }, - display_filters: { - list: ["group_by", "order_by", "issue_type"], - kanban: ["group_by", "order_by", "issue_type"], - }, - extra_options: { - list: { - access: true, - values: ["show_empty_groups"], - }, - kanban: { - access: true, - values: ["show_empty_groups"], - }, - }, - }, - issues: { - layout: ["list", "kanban", "calendar", "spreadsheet", "gantt_chart"], - filters: { - list: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], - kanban: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], - calendar: ["priority", "state", "assignees", "created_by", "labels"], - spreadsheet: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], - gantt_chart: ["priority", "state", "assignees", "created_by", "labels", "start_date", "due_date"], - }, - display_properties: { - list: true, - kanban: true, - calendar: true, - spreadsheet: true, - gantt_chart: false, - }, - display_filters: { - list: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], - kanban: ["group_by", "order_by", "issue_type", "sub_issue", "show_empty_groups"], - calendar: ["issue_type"], - spreadsheet: ["issue_type"], - gantt_chart: ["order_by", "issue_type", "sub_issue"], - }, - extra_options: { - list: { - access: true, - values: ["show_empty_groups", "sub_issue"], - }, - kanban: { - access: true, - values: ["show_empty_groups", "sub_issue"], - }, - calendar: { - access: false, - values: [], - }, - spreadsheet: { - access: false, - values: [], - }, - gantt_chart: { - access: true, - values: ["sub_issue"], - }, - }, - }, -}; - -export const handleIssueQueryParamsByLayout = (_layout: TIssueLayouts | undefined): TIssueParams[] | null => { - if (_layout === "list") - return [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "group_by", - "order_by", - "type", - "sub_issue", - "show_empty_groups", - ]; - if (_layout === "kanban") - return [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "group_by", - "order_by", - "type", - "sub_issue", - "show_empty_groups", - ]; - if (_layout === "calendar") - return [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "type", - "calendar_date_range", - ]; - if (_layout === "spreadsheet") - return [ - "priority", - "state_group", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "type", - "sub_issue", - ]; - if (_layout === "gantt_chart") - return [ - "priority", - "state", - "assignees", - "created_by", - "labels", - "start_date", - "target_date", - "order_by", - "type", - "sub_issue", - "start_target_date", - ]; - - return null; -}; - -export const handleIssueParamsDateFormat = (key: string, start_date: any | null, target_date: any | null) => { - if (key === "last_week") - return `${renderDateFormat(new Date(new Date().getTime() - 7 * 24 * 60 * 60 * 1000))};after,${renderDateFormat( - new Date() - )};before`; - - if (key === "2_weeks_from_now") - return `${renderDateFormat(new Date())};after, - ${renderDateFormat(new Date(new Date().getTime() + 14 * 24 * 60 * 60 * 1000))};before`; - - if (key === "1_month_from_now") - return `${renderDateFormat(new Date())};after,${renderDateFormat( - new Date(new Date().getFullYear(), new Date().getMonth() + 1, new Date().getDate()) - )};before`; - - if (key === "2_months_from_now") - return `${renderDateFormat(new Date())};after,${renderDateFormat( - new Date(new Date().getFullYear(), new Date().getMonth() + 2, new Date().getDate()) - )};before`; - - if (key === "custom" && start_date && target_date) - return `${renderDateFormat(start_date)};after,${renderDateFormat(target_date)};before`; -}; diff --git a/web/store/issue.ts b/web/store/issue.ts index 1414ebadd4f..dc9dfa588a0 100644 --- a/web/store/issue.ts +++ b/web/store/issue.ts @@ -1,5 +1,6 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"; import { IIssue } from "types"; +import { RootStore } from "./root"; export interface IIssueStore { loader: boolean; @@ -16,13 +17,16 @@ class IssueStore implements IIssueStore { }; } = {}; - constructor() { + rootStore; + + constructor(_rootStore: RootStore) { makeObservable(this, { // observable loader: observable.ref, error: observable.ref, issues: observable.ref, }); + this.rootStore = _rootStore; } fetchIssuesWithParams() {} diff --git a/web/store/draft_issue.ts b/web/store/issue_draft.ts similarity index 100% rename from web/store/draft_issue.ts rename to web/store/issue_draft.ts diff --git a/web/store/issue_filters.legacy.ts b/web/store/issue_filters.legacy.ts deleted file mode 100644 index 8cbaae329f2..00000000000 --- a/web/store/issue_filters.legacy.ts +++ /dev/null @@ -1,847 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "./root"; -// services -import { WorkspaceService } from "services/workspace.service"; -import { ProjectIssuesServices } from "services/issue.service"; -import { ProjectStateServices } from "services/project_state.service"; -import { ProjectServices } from "services/project.service"; -import { ProjectIssuesServices as ProjectModuleServices } from "services/modules.service"; -import { ProjectCycleServices } from "services/cycles.service"; -import { ViewService } from "services/views.service"; -// default data -import { - priorities, - stateGroups, - startDateOptions, - dueDateOptions, - groupByOptions, - orderByOptions, - issueTypes, - displayProperties, - extraProperties, - handleIssueQueryParamsByLayout, -} from "./helpers/issue-data"; - -export type TIssueViews = "issues" | "modules" | "views" | "cycles"; -export type TIssueLayouts = "list" | "kanban" | "calendar" | "spreadsheet" | "gantt_chart"; -export type TIssueParams = - | "priority" - | "state_group" - | "state" - | "assignees" - | "created_by" - | "labels" - | "start_date" - | "target_date" - | "group_by" - | "order_by" - | "type" - | "sub_issue" - | "show_empty_groups" - | "calendar_date_range" - | "start_target_date"; - -export interface IIssueFilter { - priority: string[] | undefined; - state_group: string[] | undefined; - state: string[] | undefined; - assignees: string[] | undefined; - created_by: string[] | undefined; - labels: string[] | undefined; - start_date: string[] | undefined; - target_date: string[] | undefined; - [key: string]: any; -} - -export interface IIssueDisplayFilters { - group_by: undefined | string; - order_by: undefined | string; - type: string | undefined; - sub_issue: boolean; - show_empty_groups: boolean; - layout: TIssueLayouts; - calendar_date_range: string | undefined; // only for calendar - start_target_date: boolean; - [key: string]: any; -} - -export interface IIssueDisplayProperties { - assignee: boolean; - attachment_count: boolean; - created_on: boolean; - due_date: boolean; - estimate: boolean; - key: boolean; - labels: boolean; - link: boolean; - priority: boolean; - start_date: boolean; - state: boolean; - sub_issue_count: boolean; - updated_on: boolean; - [key: string]: any; -} - -export interface IIssueFilters { - // project_id - [key: string]: { - issues: { - // project_id - [key: string]: { - filters: IIssueFilter; - }; - }; - cycles: { - // cycle_id - [key: string]: { - filters: IIssueFilter; - }; - }; - modules: { - // module_id - [key: string]: { - filters: IIssueFilter; - }; - }; - views: { - // view_id - [key: string]: { - filters: IIssueFilter; - }; - }; - display_filters: IIssueDisplayFilters; - display_properties_id: string; - display_properties: IIssueDisplayProperties; - }; -} - -export interface IIssueFilterStore { - // static data - priorities: { key: string; title: string }[]; - stateGroups: { key: string; title: string }[]; - startDateOptions: { key: string; title: string }[]; - dueDateOptions: { key: string; title: string }[]; - groupByOptions: { key: string; title: string }[]; - orderByOptions: { key: string; title: string }[]; - issueTypes: { key: string; title: string }[]; - displayProperties: { key: string; title: string }[]; - extraProperties: { key: string; title: string }[]; - - loader: boolean; - error: any | null; - - // current workspace and project id - issueView: TIssueViews | null; - issueFilters: IIssueFilters; - - // actions - // getWorkspaceMyIssuesFilters: (workspaceId: string) => Promise; - // updateWorkspaceMyIssuesFilters: (workspaceId: string, data: any) => Promise; - - getProjectDisplayProperties: (workspaceId: string, projectId: string) => Promise; - updateProjectDisplayProperties: ( - workspaceId: string, - projectId: string, - display_properties_id: string, - data: any - ) => Promise; - getProjectDisplayFilters: (workspaceId: string, projectId: string) => Promise; - updateProjectDisplayFilters: (workspaceId: string, projectId: string, data: any) => Promise; - - getProjectIssueFilters: (workspaceId: string, projectId: string) => Promise; - - getProjectIssueModuleFilters: (workspaceId: string, projectId: string, moduleId: string) => Promise; - updateProjectIssueModuleFilters: ( - workspaceId: string, - projectId: string, - moduleId: string, - data: any - ) => Promise; - getProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string) => Promise; - updateProjectIssueCyclesFilters: (workspaceId: string, projectId: string, cycleId: string, data: any) => Promise; - getProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string) => Promise; - updateProjectIssueViewsFilters: (workspaceId: string, projectId: string, viewId: string, data: any) => Promise; -} - -class IssueFilterStore implements IIssueFilterStore { - // static data - priorities: { key: string; title: string }[] = priorities; - stateGroups: { key: string; title: string }[] = stateGroups; - startDateOptions: { key: string; title: string }[] = startDateOptions; - dueDateOptions: { key: string; title: string }[] = dueDateOptions; - groupByOptions: { key: string; title: string }[] = groupByOptions; - orderByOptions: { key: string; title: string }[] = orderByOptions; - issueTypes: { key: string; title: string }[] = issueTypes; - displayProperties: { key: string; title: string }[] = displayProperties; - extraProperties: { key: string; title: string }[] = extraProperties; - - loader: boolean = false; - error: any | null = null; - - // workspaceId: string | null = null; - // projectId: string | null = null; - // moduleId: string | null = null; - // cycleId: string | null = null; - // viewId: string | null = null; - - issueView: TIssueViews | null = null; - - issueFilters: IIssueFilters = {}; - - // root store - rootStore; - // service - workspaceService; - issueService; - stateService; - projectService; - moduleService; - cycleService; - viewService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - - issueView: observable, - - issueFilters: observable.ref, - - // computed - issueLayout: computed, - userFilters: computed, - - // actions - getComputedFilters: action, - - handleIssueFilter: action, - - // getWorkspaceMyIssuesFilters: action, - // updateWorkspaceMyIssuesFilters: action, - - getProjectDisplayFilters: action, - updateProjectDisplayFilters: action, - - getProjectDisplayProperties: action, - updateProjectDisplayProperties: action, - - getProjectIssueFilters: action, - - getProjectIssueModuleFilters: action, - updateProjectIssueModuleFilters: action, - - getProjectIssueCyclesFilters: action, - updateProjectIssueCyclesFilters: action, - - getProjectIssueViewsFilters: action, - updateProjectIssueViewsFilters: action, - }); - - this.rootStore = _rootStore; - this.workspaceService = new WorkspaceService(); - this.issueService = new ProjectIssuesServices(); - this.stateService = new ProjectStateServices(); - this.projectService = new ProjectServices(); - this.moduleService = new ProjectModuleServices(); - this.cycleService = new ProjectCycleServices(); - this.viewService = new ViewService(); - } - - // computed - get issueLayout() { - // if (!this.projectId) return null; - // if (!this.projectId) - // return this.issueFilters?.[this.workspaceId]?.my_issue_properties?.display_filters?.layout || null; - // if (this.projectId) - // return ( - // this.issueFilters?.[this.workspaceId]?.project_issue_properties?.[this.projectId]?.issues?.display_filters - // ?.layout || null - // ); - - return null; - } - - get userFilters() { - const projectId = this.rootStore?.project?.projectId; - const moduleId = this.rootStore?.module?.moduleId; - const cycleId = this.rootStore?.cycle?.cycleId; - const viewId = this.rootStore?.view?.viewId; - const _issueView = this.issueView; - - if (!projectId || !_issueView) return null; - const currentIssueViewId: string | null = - _issueView === "issues" && projectId - ? projectId - : _issueView === "modules" && moduleId - ? moduleId - : _issueView === "cycles" && cycleId - ? cycleId - : _issueView === "cycles" && viewId - ? viewId - : null; - - if (!currentIssueViewId) return null; - const _issueFilters: { - filters: IIssueFilter | null; - display_filters: IIssueDisplayFilters; - display_properties_id: string; - display_properties: IIssueDisplayProperties; - } = { - filters: this.issueFilters?.[projectId]?.[_issueView]?.[currentIssueViewId]?.filters, - display_filters: this.issueFilters?.[projectId]?.display_filters, - display_properties_id: this.issueFilters?.[projectId]?.display_properties_id, - display_properties: this.issueFilters?.[projectId]?.display_properties, - }; - return _issueFilters; - } - - computedFilter = (filters: any, filteredParams: any) => { - const computedFilters: any = {}; - Object.keys(filters).map((key) => { - if (filters[key] != undefined && filteredParams.includes(key)) - computedFilters[key] = - typeof filters[key] === "string" || typeof filters[key] === "boolean" ? filters[key] : filters[key].join(","); - }); - - return computedFilters; - }; - getComputedFilters = ( - _workspaceId: string | null, - _projectId: string | null, - _moduleId: string | null, - _cycleId: string | null, - _viewId: string | null, - _issueView: TIssueViews - ) => { - this.issueView = _issueView; - - const _layout = this.userFilters?.display_filters?.layout; - - let filteredRouteParams: any = { - priority: this.userFilters?.filters?.priority || undefined, - state_group: this.userFilters?.filters?.state_group || undefined, - state: this.userFilters?.filters?.state || undefined, - assignees: this.userFilters?.filters?.assignees || undefined, - created_by: this.userFilters?.filters?.created_by || undefined, - labels: this.userFilters?.filters?.labels || undefined, - start_date: this.userFilters?.filters?.start_date || undefined, - target_date: this.userFilters?.filters?.target_date || undefined, - group_by: this.userFilters?.display_filters?.group_by || "state", - order_by: this.userFilters?.display_filters?.order_by || "-created_at", - type: this.userFilters?.display_filters?.type || undefined, - sub_issue: this.userFilters?.display_filters?.sub_issue || true, - show_empty_groups: this.userFilters?.display_filters?.show_empty_groups || true, - calendar_date_range: this.userFilters?.display_filters?.calendar_date_range || undefined, - start_target_date: this.userFilters?.display_filters?.start_target_date || true, - }; - - // start date and target date we have to construct the format here - // in calendar view calendar_date_range send as target_date - // in spreadsheet sub issue is false for sure - // in gantt start_target_date is true for sure - - const filteredParams: TIssueParams[] | null = handleIssueQueryParamsByLayout(_layout); - if (filteredParams) filteredRouteParams = this.computedFilter(filteredRouteParams, filteredParams); - - return filteredRouteParams; - }; - - handleIssueFilter = ( - filter_type: "filters" | "display_filters" | "display_properties" | "display_properties_id", - value: any - ) => { - const projectId = this.rootStore?.project?.projectId; - const moduleId = this.rootStore?.module?.moduleId; - const cycleId = this.rootStore?.cycle?.cycleId; - const viewId = this.rootStore?.view?.viewId; - const _issueView = this.issueView; - - console.log("filter_type", filter_type); - console.log("value", value); - - if (!_issueView || !projectId || !moduleId || !cycleId || !viewId) return null; - - // let _issueFilters: IIssueFilters = { - // ...this.issueFilters, - // [workspaceId]: { - // ...this.issueFilters?.[workspaceId], - // }, - // }; - - // console.log("_issueFilters", _issueFilters); - - // if (this.issueView === "my_issues") - // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - // if (this.issueView === "issues") - // this.rootStore?.issueView?.getProjectIssuesAsync(this.workspaceId, this.projectId, false); - // if (this.issueView === "modules" && this.moduleId) - // this.rootStore?.issueView?.getIssuesForModulesAsync(this.workspaceId, this.projectId, this.moduleId, false); - // if (this.issueView === "cycles" && this.cycleId) - // this.rootStore?.issueView?.getIssuesForCyclesAsync(this.workspaceId, this.projectId, this.cycleId, false); - // if (this.issueView === "views" && this.viewId) - // this.rootStore?.issueView?.getIssuesForViewsAsync(this.workspaceId, this.projectId, this.viewId, false); - }; - - // services - // getWorkspaceMyIssuesFilters = async (workspaceId: string) => { - // try { - // this.loader = true; - // this.error = null; - - // const issuesFiltersResponse = await this.workspaceService.workspaceMemberMe(workspaceId); - // if (issuesFiltersResponse) { - // const _issuesFiltersResponse: any = { - // ...this.issueFilters, - // [workspaceId]: { - // ...this?.issueFilters?.[workspaceId], - // my_issue_properties: { - // ...this?.issueFilters?.[workspaceId]?.my_issue_properties, - // filters: { - // priority: issuesFiltersResponse?.view_props?.filters?.priority ?? null, - // state: issuesFiltersResponse?.view_props?.filters?.state ?? null, - // state_group: issuesFiltersResponse?.view_props?.filters?.state_group ?? null, - // assignees: issuesFiltersResponse?.view_props?.filters?.assignees ?? null, - // created_by: issuesFiltersResponse?.view_props?.filters?.created_by ?? null, - // labels: issuesFiltersResponse?.view_props?.filters?.labels ?? null, - // start_date: issuesFiltersResponse?.view_props?.filters?.start_date ?? null, - // target_date: issuesFiltersResponse?.view_props?.filters?.target_date ?? null, - // subscriber: issuesFiltersResponse?.view_props?.filters?.subscriber ?? null, - // }, - // display_filters: { - // group_by: issuesFiltersResponse?.view_props?.display_filters?.group_by ?? null, - // order_by: issuesFiltersResponse?.view_props?.display_filters?.order_by ?? null, - // type: issuesFiltersResponse?.view_props?.display_filters?.type ?? null, - // sub_issue: issuesFiltersResponse?.view_props?.display_filters?.sub_issue ?? false, - // show_empty_groups: issuesFiltersResponse?.view_props?.display_filters?.show_empty_groups ?? false, - // layout: issuesFiltersResponse?.view_props?.display_filters?.layout ?? "list", - // calendar_date_range: issuesFiltersResponse?.view_props?.display_filters?.calendar_date_range ?? false, - // start_target_date: issuesFiltersResponse?.view_props?.display_filters?.start_target_date ?? true, - // }, - // display_properties: { - // assignee: issuesFiltersResponse?.view_props?.display_properties?.assignee ?? false, - // attachment_count: issuesFiltersResponse?.view_props?.display_properties?.attachment_count ?? false, - // created_on: issuesFiltersResponse?.view_props?.display_properties?.created_on ?? false, - // due_date: issuesFiltersResponse?.view_props?.display_properties?.due_date ?? false, - // estimate: issuesFiltersResponse?.view_props?.display_properties?.estimate ?? false, - // key: issuesFiltersResponse?.view_props?.display_properties?.key ?? false, - // labels: issuesFiltersResponse?.view_props?.display_properties?.labels ?? false, - // link: issuesFiltersResponse?.view_props?.display_properties?.link ?? false, - // priority: issuesFiltersResponse?.view_props?.display_properties?.priority ?? false, - // start_date: issuesFiltersResponse?.view_props?.display_properties?.start_date ?? false, - // state: issuesFiltersResponse?.view_props?.display_properties?.state ?? false, - // sub_issue_count: issuesFiltersResponse?.view_props?.display_properties?.sub_issue_count ?? false, - // updated_on: issuesFiltersResponse?.view_props?.display_properties?.updated_on ?? false, - // }, - // }, - // }, - // }; - // runInAction(() => { - // this.issueFilters = _issuesFiltersResponse; - // this.loader = false; - // this.error = null; - // }); - // } - // return issuesFiltersResponse; - // } catch (error) { - // console.warn("error in fetching workspace level filters", error); - // this.loader = false; - // this.error = null; - // - // } - // }; - // updateWorkspaceMyIssuesFilters = async (workspaceId: string, data: any) => { - // try { - // this.loader = true; - // this.error = null; - - // const payload = { - // view_props: data, - // }; - // const issuesFiltersResponse = await this.workspaceService.updateWorkspaceView(workspaceId, payload); - - // if (issuesFiltersResponse) { - // runInAction(() => { - // this.loader = false; - // this.error = null; - // }); - // } - // } catch (error) { - // console.warn("error in fetching workspace level issue filters", error); - // this.loader = false; - // this.error = null; - // - // } - // }; - - getProjectDisplayProperties = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - await this.rootStore.user.setCurrentUser(); - const issuesDisplayPropertiesResponse = await this.issueService.getIssueProperties(workspaceId, projectId); - - if (issuesDisplayPropertiesResponse) { - const _issuesDisplayPropertiesResponse: any = { - ...this.issueFilters, - [projectId]: { - ...this?.issueFilters?.[projectId], - display_properties_id: issuesDisplayPropertiesResponse?.id, - display_properties: { - ...issuesDisplayPropertiesResponse?.properties, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesDisplayPropertiesResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayPropertiesResponse; - } catch (error) { - console.warn("error in fetching project level display properties", error); - this.loader = false; - this.error = null; - } - }; - updateProjectDisplayProperties = async ( - workspaceId: string, - projectId: string, - display_properties_id: string, - data: any - ) => { - try { - this.loader = true; - this.error = null; - - const payload = { - properties: data, - user: this.rootStore?.user?.currentUser?.id, - }; - const issuesDisplayPropertiesResponse = await this.issueService.patchIssueProperties( - workspaceId, - projectId, - display_properties_id, - payload - ); - - if (issuesDisplayPropertiesResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayPropertiesResponse; - } catch (error) { - console.warn("error in fetching project level display properties", error); - this.loader = false; - this.error = null; - } - }; - - getProjectDisplayFilters = async (workspaceId: string, projectId: string) => { - try { - this.loader = true; - this.error = null; - - const issuesDisplayFiltersResponse = await this.projectService.projectMemberMe(workspaceId, projectId); - - if (issuesDisplayFiltersResponse) { - const _filters = { ...issuesDisplayFiltersResponse?.view_props?.filters }; - const _displayFilters = { ...issuesDisplayFiltersResponse?.view_props?.display_filters }; - - const _issuesDisplayFiltersResponse: any = { - ...this.issueFilters, - [projectId]: { - ...this?.issueFilters?.[projectId], - issues: { - ...this?.issueFilters?.[projectId]?.issues, - filters: _filters, - }, - display_filters: _displayFilters, - }, - }; - - console.log("_issuesDisplayFiltersResponse", _issuesDisplayFiltersResponse); - - runInAction(() => { - this.issueFilters = _issuesDisplayFiltersResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesDisplayFiltersResponse; - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - updateProjectDisplayFilters = async (workspaceId: string, projectId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload: any = { - view_props: data, - }; - const issuesFiltersResponse = await this.projectService.setProjectView(workspaceId, projectId, payload); - - if (issuesFiltersResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesFiltersResponse; - } catch (error) { - this.getProjectDisplayFilters(workspaceId, projectId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - - getProjectIssueFilters = async (workspaceId: string, projectId: string) => { - try { - await this.getProjectDisplayProperties(workspaceId, projectId); - await this.getProjectDisplayFilters(workspaceId, projectId); - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - } - }; - - getProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersModuleResponse = await this.moduleService.getModuleDetails(workspaceId, projectId, moduleId); - if (issuesFiltersModuleResponse) { - const _filters = { ...issuesFiltersModuleResponse?.view_props?.filters }; - const _issuesFiltersModuleResponse = { - ...this.issueFilters, - [projectId]: { - ...this?.issueFilters?.[projectId], - modules: { - ...this?.issueFilters?.[projectId]?.modules, - [moduleId]: { - ...this?.issueFilters?.[projectId]?.modules?.[moduleId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersModuleResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - updateProjectIssueModuleFilters = async (workspaceId: string, projectId: string, moduleId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - view_props: { filters: data }, - }; - const issuesFiltersModuleResponse = await this.moduleService.patchModule( - workspaceId, - projectId, - moduleId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersModuleResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - } catch (error) { - this.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - - getProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersCycleResponse = await this.cycleService.getCycleDetails(workspaceId, projectId, cycleId); - if (issuesFiltersCycleResponse) { - const _filters = { ...issuesFiltersCycleResponse?.view_props?.filters }; - const _issuesFiltersCycleResponse = { - ...this.issueFilters, - [projectId]: { - ...this?.issueFilters?.[projectId], - cycles: { - ...this?.issueFilters?.[projectId]?.cycles, - [cycleId]: { - ...this?.issueFilters?.[projectId]?.modules?.[cycleId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersCycleResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - updateProjectIssueCyclesFilters = async (workspaceId: string, projectId: string, cycleId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - view_props: { filters: data }, - }; - const issuesFiltersCycleResponse = await this.cycleService.patchCycle( - workspaceId, - projectId, - cycleId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersCycleResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - } catch (error) { - this.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - - getProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string) => { - try { - this.loader = true; - this.error = null; - - await this.getProjectIssueFilters(workspaceId, projectId); - const issuesFiltersViewResponse = await this.viewService.getViewDetails(workspaceId, projectId, viewId); - if (issuesFiltersViewResponse) { - const _filters = { ...issuesFiltersViewResponse?.query_data } as any; - const _issuesFiltersViewResponse = { - ...this.issueFilters, - [projectId]: { - ...this?.issueFilters?.[projectId], - views: { - ...this?.issueFilters?.[projectId]?.views, - [viewId]: { - ...this?.issueFilters?.[projectId]?.modules?.[viewId], - filters: { - priority: _filters?.priority ?? undefined, - state: _filters?.state ?? undefined, - state_group: _filters?.state_group ?? undefined, - assignees: _filters?.assignees ?? undefined, - created_by: _filters?.created_by ?? undefined, - labels: _filters?.labels ?? undefined, - start_date: _filters?.start_date ?? undefined, - target_date: _filters?.target_date ?? undefined, - }, - }, - }, - }, - }; - - runInAction(() => { - this.issueFilters = _issuesFiltersViewResponse as any; - this.loader = false; - this.error = null; - }); - } - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; - updateProjectIssueViewsFilters = async (workspaceId: string, projectId: string, viewId: string, data: any) => { - try { - this.loader = true; - this.error = null; - - const payload = { - query_data: data, - }; - const issuesFiltersViewResponse = await this.viewService.patchView( - workspaceId, - projectId, - viewId, - payload, - undefined // TODO: replace this with user - ); - - if (issuesFiltersViewResponse) { - runInAction(() => { - this.loader = false; - this.error = null; - }); - } - - return issuesFiltersViewResponse; - } catch (error) { - console.warn("error in fetching workspace level issue filters", error); - this.loader = false; - this.error = null; - } - }; -} - -export default IssueFilterStore; diff --git a/web/store/issue_filters.ts b/web/store/issue_filters.ts index b0556d6f9ab..ca01e7e9ce6 100644 --- a/web/store/issue_filters.ts +++ b/web/store/issue_filters.ts @@ -2,11 +2,19 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx" // types import { RootStore } from "./root"; -export interface IIssueFilterStore {} +export interface IIssueFilterStore { + loader: boolean; + error: any | null; + userDisplayProperties: any; + userDisplayFilters: any; +} class IssueFilterStore implements IIssueFilterStore { loader: boolean = false; error: any | null = null; + // observables + userDisplayProperties: any = {}; + userDisplayFilters: any = {}; // root store rootStore; @@ -14,6 +22,8 @@ class IssueFilterStore implements IIssueFilterStore { makeObservable(this, { loader: observable.ref, error: observable.ref, + userDisplayProperties: observable.ref, + userDisplayFilters: observable.ref, }); this.rootStore = _rootStore; diff --git a/web/store/issue_store.legacy.ts b/web/store/issue_store.legacy.ts deleted file mode 100644 index 1eaf7de042e..00000000000 --- a/web/store/issue_store.legacy.ts +++ /dev/null @@ -1,417 +0,0 @@ -import { observable, action, computed, makeObservable, runInAction } from "mobx"; -// types -import { RootStore } from "./root"; -// services -import { UserService } from "services/user.service"; -import { IssueServices } from "services/issue.service"; -import { ModuleService } from "services/modules.service"; -import { CycleService } from "services/cycles.service"; -// types -import { TIssueLayouts, TIssueViews } from "./issue_filters.legacy"; - -export interface IIssues { - [key: string]: any; -} - -export interface IIssuesLayout { - list: IIssues[]; - kanban: IIssues[]; - calendar: IIssues[]; - spreadsheet: IIssues[]; - gantt_chart: IIssues[]; -} - -export interface IIssueState { - [key: string]: { - // project_id: layout_view - issues: { - [key: string]: IIssuesLayout; // project_id: layout_key: ...issues, It's always one project id here - }; - cycles: { - [key: string]: IIssuesLayout; // cycle_id: layout_key: ...issues - }; - modules: { - [key: string]: IIssuesLayout; // module_id: layout_key: ...issues - }; - views: { - [key: string]: IIssuesLayout; // view_id: layout_key: ...issues - }; - }; -} - -export interface IIssueStore { - loader: boolean; - error: any | null; - issues: IIssueState; - // computed - getIssues: IIssues | null | undefined; - // actions - updateIssues: (data: any) => void; - getProjectIssuesAsync: (workspaceId: string, projectId: string, fetchFilterToggle?: boolean) => null | Promise; - getIssuesForModulesAsync: ( - workspaceId: string, - projectId: string, - moduleId: string, - fetchFilterToggle: boolean - ) => null | Promise; - getIssuesForCyclesAsync: ( - workspaceId: string, - projectId: string, - cycleId: string, - fetchFilterToggle: boolean - ) => null | Promise; - getIssuesForViewsAsync: ( - workspaceId: string, - projectId: string, - viewId: string, - fetchFilterToggle: boolean - ) => null | Promise; -} - -class IssueStore implements IIssueStore { - loader: boolean = false; - error: any | null = null; - issues: IIssueState = {}; - // root store - rootStore; - // service - issueService; - userService; - modulesService; - cyclesService; - - constructor(_rootStore: RootStore) { - makeObservable(this, { - // observable - loader: observable, - error: observable, - issues: observable.ref, - // computed - getIssues: computed, - // action - updateIssues: action, - getProjectIssuesAsync: action, - getIssuesForModulesAsync: action, - getIssuesForCyclesAsync: action, - getIssuesForViewsAsync: action, - }); - - this.rootStore = _rootStore; - this.issueService = new IssueServices(); - this.userService = new UserService(); - this.modulesService = new ModuleService(); - this.cyclesService = new CycleService(); - } - - // computed - get getIssues() { - if (this.issues != null) { - const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView; - const projectId: string | null = this.rootStore.project.projectId; - const moduleId: string | null = this.rootStore.module.moduleId; - const cycleId: string | null = this.rootStore.cycle.cycleId; - const viewId: string | null = this.rootStore.view.viewId; - const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout; - - if (!issueView || !projectId) return null; - - const currentViewIdIndex: string | null = - issueView === "issues" && projectId - ? projectId - : issueView === "modules" && moduleId - ? moduleId - : issueView === "cycles" && cycleId - ? cycleId - : issueView === "cycles" && viewId - ? viewId - : null; - - if (!issueLayout || !currentViewIdIndex) return null; - return this.issues[projectId][issueView][currentViewIdIndex][issueLayout]; - } - - return null; - } - - updateIssues = (data: any) => { - const issueView: TIssueViews | null = this.rootStore.issueFilter.issueView; - const projectId: string | null = this.rootStore.project.projectId; - const moduleId: string | null = this.rootStore.module.moduleId; - const cycleId: string | null = this.rootStore.cycle.cycleId; - const viewId: string | null = this.rootStore.view.viewId; - const issueLayout: TIssueLayouts | null = this.rootStore.issueFilter.issueLayout; - - const { groupId, issueId, issueData } = data as { - groupId?: any; - issueId: string | null; - issueData: any; - }; - - if (!issueView || !projectId) return null; - - const currentViewIdIndex: string | null = - issueView === "issues" && projectId - ? projectId - : issueView === "modules" && moduleId - ? moduleId - : issueView === "cycles" && cycleId - ? cycleId - : issueView === "cycles" && viewId - ? viewId - : null; - - if (!issueLayout || !currentViewIdIndex) return null; - - let _issues = this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout]; - if (groupId && groupId != null && ["list", "kanban"].includes(issueLayout)) { - _issues = { - ..._issues, - [groupId]: - _issues?.[groupId] && _issues?.[groupId].length > 0 - ? _issues?.[groupId]?.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item })) - : [], - }; - } else { - _issues = { - ..._issues, - ..._issues.map((item: any) => (item.id === issueId ? { ...item, ...issueData } : { ...item })), - }; - } - - this.issues = { - ...this.issues, - [projectId]: { - ...this?.issues?.[projectId], - [issueView]: { - ...this?.issues?.[projectId]?.[issueView], - [currentViewIdIndex]: { - ...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex], - [issueLayout]: { - ...this?.issues?.[projectId]?.[issueView]?.[currentViewIdIndex]?.[issueLayout], - ..._issues, - }, - }, - }, - }, - }; - }; - - // fetching project issues - getProjectIssuesAsync = async (workspaceId: string, projectId: string, fetchFilterToggle: boolean = true) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) await this.rootStore.issueFilter.getProjectIssueFilters(workspaceId, projectId); - // const filteredParams = this.rootStore.issueFilter.getComputedFilters( - // workspaceId, - // projectId, - // null, - // null, - // null, - // "issues" - // ); - // const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); - - // if (issuesResponse) { - // const _issueResponse: any = { - // ...this.issues, - // [projectId]: { - // ...this?.issues?.[projectId], - // issues: { - // ...this?.issues?.[projectId]?.issues, - // [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, - // }, - // }, - // }; - - // runInAction(() => { - // this.issues = _issueResponse; - // this.loader = false; - // this.error = null; - // }); - // } - - // return issuesResponse; - } catch (error) { - console.warn("error in fetching the project issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for modules - getIssuesForModulesAsync = async ( - workspaceId: string, - projectId: string, - moduleId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilter.getProjectIssueModuleFilters(workspaceId, projectId, moduleId); - const filteredParams = this.rootStore.issueFilter.getComputedFilters( - workspaceId, - projectId, - moduleId, - null, - null, - "modules" - ); - const issuesResponse = await this.modulesService.getModuleIssuesWithParams( - workspaceId, - projectId, - moduleId, - filteredParams - ); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [projectId]: { - ...this?.issues?.[projectId], - modules: { - ...this?.issues?.[projectId]?.modules, - [moduleId]: { - ...this?.issues?.[projectId]?.modules?.[moduleId], - [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project module issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for cycles - getIssuesForCyclesAsync = async ( - workspaceId: string, - projectId: string, - cycleId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilter.getProjectIssueCyclesFilters(workspaceId, projectId, cycleId); - const filteredParams = this.rootStore.issueFilter.getComputedFilters( - workspaceId, - projectId, - null, - cycleId, - null, - "cycles" - ); - const issuesResponse = await this.cyclesService.getCycleIssuesWithParams( - workspaceId, - projectId, - cycleId, - filteredParams - ); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [projectId]: { - ...this?.issues?.[projectId], - cycles: { - ...this?.issues?.[projectId]?.cycles, - [cycleId]: { - ...this?.issues?.[projectId]?.cycles?.[cycleId], - [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project cycles issues", error); - this.loader = false; - this.error = null; - return error; - } - }; - - // fetching project issues for views - getIssuesForViewsAsync = async ( - workspaceId: string, - projectId: string, - viewId: string, - fetchFilterToggle: boolean = true - ) => { - try { - this.loader = true; - this.error = null; - - if (fetchFilterToggle) - await this.rootStore.issueFilter.getProjectIssueViewsFilters(workspaceId, projectId, viewId); - const filteredParams = this.rootStore.issueFilter.getComputedFilters( - workspaceId, - projectId, - null, - null, - viewId, - "views" - ); - const issuesResponse = await this.issueService.getIssuesWithParams(workspaceId, projectId, filteredParams); - - if (issuesResponse) { - const _issueResponse: any = { - ...this.issues, - [projectId]: { - ...this?.issues?.[projectId], - views: { - ...this?.issues?.[projectId]?.views, - [viewId]: { - ...this?.issues?.[projectId]?.views?.[viewId], - [this.rootStore?.issueFilter?.userFilters?.display_filters?.layout as string]: issuesResponse, - }, - }, - }, - }; - - runInAction(() => { - this.issues = _issueResponse; - this.loader = false; - this.error = null; - }); - } - - return issuesResponse; - } catch (error) { - console.warn("error in fetching the project view issues", error); - this.loader = false; - this.error = null; - return error; - } - }; -} - -export default IssueStore; diff --git a/web/store/issues.legacy.ts b/web/store/issues.legacy.ts deleted file mode 100644 index 3421a684baa..00000000000 --- a/web/store/issues.legacy.ts +++ /dev/null @@ -1,150 +0,0 @@ -// mobx -import { action, observable, runInAction, makeAutoObservable } from "mobx"; -// services -import issueService from "services/issue.service"; -// types -import type { ICurrentUserResponse, IIssue } from "types"; - -class IssuesStore { - issues: { [key: string]: IIssue } = {}; - isIssuesLoading: boolean = false; - rootStore: any | null = null; - - constructor(_rootStore: any | null = null) { - makeAutoObservable(this, { - issues: observable.ref, - loadIssues: action, - getIssueById: action, - isIssuesLoading: observable, - createIssue: action, - updateIssue: action, - deleteIssue: action, - }); - - this.rootStore = _rootStore; - } - - /** - * @description Fetch all issues of a project and hydrate issues field - */ - - loadIssues = async (workspaceSlug: string, projectId: string) => { - this.isIssuesLoading = true; - try { - const issuesResponse: IIssue[] = (await issueService.getIssuesWithParams(workspaceSlug, projectId)) as IIssue[]; - - const issues: { [kye: string]: IIssue } = {}; - issuesResponse.forEach((issue) => { - issues[issue.id] = issue; - }); - - runInAction(() => { - this.issues = issues; - this.isIssuesLoading = false; - }); - } catch (error) { - this.isIssuesLoading = false; - console.error("Fetching issues error", error); - } - }; - - getIssueById = async (workspaceSlug: string, projectId: string, issueId: string): Promise => { - if (this.issues[issueId]) return this.issues[issueId]; - - try { - const issueResponse: IIssue = await issueService.retrieve(workspaceSlug, projectId, issueId); - - const issues = { - ...this.issues, - [issueId]: { ...issueResponse }, - }; - - runInAction(() => { - this.issues = issues; - }); - - return issueResponse; - } catch (error) { - throw error; - } - }; - - createIssue = async ( - workspaceSlug: string, - projectId: string, - issueForm: IIssue, - user: ICurrentUserResponse - ): Promise => { - try { - const issueResponse = await issueService.createIssues(workspaceSlug, projectId, issueForm, user); - - const issues = { - ...this.issues, - [issueResponse.id]: { ...issueResponse }, - }; - - runInAction(() => { - this.issues = issues; - }); - return issueResponse; - } catch (error) { - console.error("Creating issue error", error); - throw error; - } - }; - - updateIssue = async ( - workspaceSlug: string, - projectId: string, - issueId: string, - issueForm: Partial, - user: ICurrentUserResponse - ) => { - // keep a copy of the issue in the store - const originalIssue = { ...this.issues[issueId] }; - - // immediately update the issue in the store - const updatedIssue = { ...this.issues[issueId], ...issueForm }; - if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list; - - try { - runInAction(() => { - this.issues[issueId] = { ...updatedIssue }; - }); - - // make a patch request to update the issue - const issueResponse: IIssue = await issueService.patchIssue(workspaceSlug, projectId, issueId, issueForm, user); - - const updatedIssues = { ...this.issues }; - updatedIssues[issueId] = { ...issueResponse }; - - runInAction(() => { - this.issues = updatedIssues; - }); - } catch (error) { - // if there is an error, revert the changes - runInAction(() => { - this.issues[issueId] = originalIssue; - }); - - return error; - } - }; - - deleteIssue = async (workspaceSlug: string, projectId: string, issueId: string, user: ICurrentUserResponse) => { - const issues = { ...this.issues }; - delete issues[issueId]; - - try { - runInAction(() => { - this.issues = issues; - }); - - issueService.deleteIssue(workspaceSlug, projectId, issueId, user); - } catch (error) { - console.error("Deleting issue error", error); - } - }; -} - -export default IssuesStore; diff --git a/web/store/kanban-view.ts b/web/store/kanban_view.ts similarity index 100% rename from web/store/kanban-view.ts rename to web/store/kanban_view.ts diff --git a/web/store/root.ts b/web/store/root.ts index 30dd57aa6e9..2ec0099d3e9 100644 --- a/web/store/root.ts +++ b/web/store/root.ts @@ -4,8 +4,8 @@ import { enableStaticRendering } from "mobx-react-lite"; import UserStore from "./user"; import ThemeStore from "./theme"; import ProjectPublishStore, { IProjectPublishStore } from "./project_publish"; -import IssueStore, { IIssueStore } from "./issue_store.legacy"; -import DraftIssuesStore from "./draft_issue"; +import IssueStore, { IIssueStore } from "./issue"; +import DraftIssuesStore from "./issue_draft"; import WorkspaceStore, { IWorkspaceStore } from "./workspace"; import ProjectStore, { IProjectStore } from "./project"; import ModuleStore, { IModuleStore } from "./modules"; @@ -13,7 +13,7 @@ import CycleStore, { ICycleStore } from "./cycles"; import ViewStore, { IViewStore } from "./views"; import IssueFilterStore, { IIssueFilterStore } from "./issue_filters"; import IssueViewDetailStore from "./issue_detail"; -import IssueKanBanViewStore from "./kanban-view"; +import IssueKanBanViewStore from "./kanban_view"; enableStaticRendering(typeof window === "undefined"); From f69d34698afed4e82f67b4382f4a1b5594d8e73b Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 21 Sep 2023 15:00:19 +0530 Subject: [PATCH 027/102] chore: store setup for build fixes --- .../issue-layouts/filters-preview/index.tsx | 17 +++--- .../[project_slug]/issues.tsx | 44 ++++++++++------ web/services/issue.service.ts | 6 +-- web/services/project.service.ts | 4 +- web/services/project_publish.service.ts | 4 +- web/store/cycles.ts | 8 +-- web/store/issue_detail.ts | 4 +- web/store/issue_filters.ts | 52 +++++++++++++++++++ web/store/modules.ts | 8 +-- web/store/project.ts | 14 ++--- web/store/project_publish.ts | 4 +- web/store/views.ts | 8 +-- web/store/workspace.ts | 8 +-- 13 files changed, 123 insertions(+), 58 deletions(-) diff --git a/web/components/issue-layouts/filters-preview/index.tsx b/web/components/issue-layouts/filters-preview/index.tsx index 2ecdc590923..758dbc71cb7 100644 --- a/web/components/issue-layouts/filters-preview/index.tsx +++ b/web/components/issue-layouts/filters-preview/index.tsx @@ -14,18 +14,19 @@ import { observer } from "mobx-react-lite"; import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; // default data -import { issueFilterVisibilityData } from "store/helpers/issue-data"; +// import { issueFilterVisibilityData } from "store/helpers/issue-data"; export const FilterPreview = observer(() => { const store: RootStore = useMobxStore(); - const { issueFilters: issueFilterStore } = store; + const { issueFilter: issueFilterStore } = store; - const handleFilterSectionVisibility = (section_key: string) => - issueFilterStore?.issueView && - issueFilterStore?.issueLayout && - issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.filters?.[ - issueFilterStore?.issueLayout - ]?.includes(section_key); + const handleFilterSectionVisibility = (section_key: string) => { + // issueFilterStore?.issueView && + // issueFilterStore?.issueLayout && + // issueFilterVisibilityData[issueFilterStore?.issueView === "my_issues" ? "my_issues" : "issues"]?.filters?.[ + // issueFilterStore?.issueLayout + // ]?.includes(section_key); + }; const validateFiltersAvailability = issueFilterStore?.userFilters?.filters != null && diff --git a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx index 44f143b2257..de4a857bdc9 100644 --- a/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx +++ b/web/pages/m-store/[workspace_slug]/[project_slug]/issues.tsx @@ -6,6 +6,7 @@ import { IssuesRoot } from "components/issue-layouts/root"; // mobx store import { useMobxStore } from "lib/mobx/store-provider"; import { RootStore } from "store/root"; +import useSWR from "swr"; const KanBanViewRoot = () => { const router = useRouter(); @@ -14,32 +15,41 @@ const KanBanViewRoot = () => { project_slug: string; }; - const { issue: issueViewStore, workspace: workspaceStore, project: projectStore }: RootStore = useMobxStore(); + const { + issue: issueViewStore, + workspace: workspaceStore, + project: projectStore, + issueFilter: issueFilterStore, + }: RootStore = useMobxStore(); + + useSWR( + workspace_slug && project_slug ? "USER_FILTERS" : null, + workspace_slug && project_slug + ? () => { + console.log("sdad"); + issueFilterStore.fetchUserFilters(workspace_slug.toString(), project_slug.toString()); + } + : null + ); React.useEffect(() => { console.log("request init--->"); const init = async () => { - workspaceStore.setWorkspaceId(workspace_slug); - await workspaceStore.getWorkspaces(); - await workspaceStore.getWorkspaceLabels(workspace_slug); - - projectStore.setProject(project_slug); - await projectStore.getWorkspaceProjects(workspace_slug); - await projectStore.getProjectStates(workspace_slug, project_slug); - await projectStore.getProjectLabels(workspace_slug, project_slug); - await projectStore.getProjectMembers(workspace_slug, project_slug); - - await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); + // workspaceStore.setWorkspaceId(workspace_slug); + // await workspaceStore.getWorkspaces(); + // await workspaceStore.getWorkspaceLabels(workspace_slug); + // projectStore.setProject(project_slug); + // await projectStore.getWorkspaceProjects(workspace_slug); + // await projectStore.getProjectStates(workspace_slug, project_slug); + // await projectStore.getProjectLabels(workspace_slug, project_slug); + // await projectStore.getProjectMembers(workspace_slug, project_slug); + // await issueViewStore.getProjectIssuesAsync(workspace_slug, project_slug); }; if (workspace_slug && project_slug) init(); console.log("request completed--->"); }, [workspace_slug, project_slug, issueViewStore, workspaceStore, projectStore]); - return ( -
    - -
    - ); + return
    {/* */}
    ; }; export default KanBanViewRoot; diff --git a/web/services/issue.service.ts b/web/services/issue.service.ts index 10b4383c640..f14a4eefe26 100644 --- a/web/services/issue.service.ts +++ b/web/services/issue.service.ts @@ -12,7 +12,7 @@ import type { } from "types"; import { API_BASE_URL } from "helpers/common.helper"; -export class IssueServices extends APIService { +export class IssueService extends APIService { constructor() { super(API_BASE_URL); } @@ -607,6 +607,6 @@ export class IssueServices extends APIService { } } -const issuesServices = new IssueServices(); +const issueService = new IssueService(); -export default issuesServices; +export default issueService; diff --git a/web/services/project.service.ts b/web/services/project.service.ts index 4a1b4c582be..5275349b553 100644 --- a/web/services/project.service.ts +++ b/web/services/project.service.ts @@ -16,7 +16,7 @@ import type { TProjectIssuesSearchParams, } from "types"; -export class ProjectServices extends APIService { +export class ProjectService extends APIService { constructor() { super(API_BASE_URL); } @@ -336,4 +336,4 @@ export class ProjectServices extends APIService { } } -export default new ProjectServices(); +export default new ProjectService(); diff --git a/web/services/project_publish.service.ts b/web/services/project_publish.service.ts index 1304e79243b..4be1215aabe 100644 --- a/web/services/project_publish.service.ts +++ b/web/services/project_publish.service.ts @@ -6,7 +6,7 @@ import trackEventServices from "services/track_event.service"; import { ICurrentUserResponse } from "types"; import { IProjectPublishSettings } from "store/project_publish"; -class ProjectServices extends APIService { +export class ProjectPublishServices extends APIService { constructor() { super(API_BASE_URL); } @@ -98,4 +98,4 @@ class ProjectServices extends APIService { } } -export default ProjectServices; +export default new ProjectPublishServices(); diff --git a/web/store/cycles.ts b/web/store/cycles.ts index 058e8309482..5530548c44c 100644 --- a/web/store/cycles.ts +++ b/web/store/cycles.ts @@ -2,8 +2,8 @@ import { action, computed, observable, makeObservable, runInAction } from "mobx" // types import { RootStore } from "./root"; // services -import { ProjectServices } from "services/project.service"; -import { IssueServices } from "services/issue.service"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; export interface ICycleStore { loader: boolean; @@ -40,8 +40,8 @@ class CycleStore implements ICycleStore { }); this.rootStore = _rootStore; - this.projectService = new ProjectServices(); - this.issueService = new IssueServices(); + this.projectService = new ProjectService(); + this.issueService = new IssueService(); } // computed diff --git a/web/store/issue_detail.ts b/web/store/issue_detail.ts index c2c0237a834..352769810f2 100644 --- a/web/store/issue_detail.ts +++ b/web/store/issue_detail.ts @@ -2,7 +2,7 @@ import { observable, action, makeObservable, runInAction } from "mobx"; // types import { RootStore } from "./root"; // services -import { IssueServices } from "services/issue.service"; +import { IssueService } from "services/issue.service"; export type IPeekMode = "side" | "modal" | "full"; @@ -80,7 +80,7 @@ class IssueViewDetailStore implements IIssueViewDetailStore { }); this.rootStore = _rootStore; - this.issueService = new IssueServices(); + this.issueService = new IssueService(); } setPeekId = (issueId: string | null) => (this.peekId = issueId); diff --git a/web/store/issue_filters.ts b/web/store/issue_filters.ts index ca01e7e9ce6..35186be56d9 100644 --- a/web/store/issue_filters.ts +++ b/web/store/issue_filters.ts @@ -1,12 +1,19 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx"; // types import { RootStore } from "./root"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; export interface IIssueFilterStore { loader: boolean; error: any | null; userDisplayProperties: any; userDisplayFilters: any; + userFilters: any; + defaultDisplayFilters: any; + defaultFilters: any; + + fetchUserFilters: (workspaceSlug: string, projectSlug: string) => void; } class IssueFilterStore implements IIssueFilterStore { @@ -15,19 +22,64 @@ class IssueFilterStore implements IIssueFilterStore { // observables userDisplayProperties: any = {}; userDisplayFilters: any = {}; + userFilters: any = {}; + defaultDisplayFilters: any = {}; + defaultFilters: any = {}; + defaultDisplayProperties: any = { + assignee: true, + due_date: true, + key: true, + labels: true, + priority: true, + start_date: true, + state: true, + sub_issue_count: true, + }; // root store rootStore; + projectService; + issueService; + constructor(_rootStore: RootStore) { makeObservable(this, { loader: observable.ref, error: observable.ref, + defaultDisplayFilters: observable.ref, + defaultFilters: observable.ref, userDisplayProperties: observable.ref, userDisplayFilters: observable.ref, + userFilters: observable.ref, + fetchUserFilters: action, }); this.rootStore = _rootStore; + + this.projectService = new ProjectService(); + this.issueService = new IssueService(); } + + fetchUserFilters = async (workspaceSlug: string, projectId: string) => { + try { + const memberResponse = await this.projectService.projectMemberMe(workspaceSlug, projectId); + const issueProperties = await this.issueService.getIssueProperties(workspaceSlug, projectId); + + console.log("memberResponse", memberResponse); + + console.log("issueProperties", issueProperties); + + runInAction(() => { + this.userFilters = memberResponse?.view_props?.filters; + this.userDisplayFilters = memberResponse?.view_props?.display_filters; + this.userDisplayProperties = issueProperties?.properties || this.defaultDisplayProperties; + // default props from api + this.defaultFilters = memberResponse.default_props.filters; + this.defaultDisplayFilters = memberResponse.default_props.display_filters; + }); + } catch (error) { + console.log("Failed to fetch user filters in issue filter store", error); + } + }; } export default IssueFilterStore; diff --git a/web/store/modules.ts b/web/store/modules.ts index 42fe102a39c..c0ef31ee1d2 100644 --- a/web/store/modules.ts +++ b/web/store/modules.ts @@ -2,8 +2,8 @@ import { action, computed, observable, makeObservable, runInAction } from "mobx" // types import { RootStore } from "./root"; // services -import { ProjectServices } from "services/project.service"; -import { IssueServices } from "services/issue.service"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; export interface IModuleStore { loader: boolean; @@ -40,8 +40,8 @@ class ModuleStore implements IModuleStore { }); this.rootStore = _rootStore; - this.projectService = new ProjectServices(); - this.issueService = new IssueServices(); + this.projectService = new ProjectService(); + this.issueService = new IssueService(); } // computed diff --git a/web/store/project.ts b/web/store/project.ts index 31cceb387bd..6fbf1d6479e 100644 --- a/web/store/project.ts +++ b/web/store/project.ts @@ -3,10 +3,10 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx" import { RootStore } from "./root"; import { IProject, IIssueLabels, IProjectMember, IStateResponse, IState, ICycle, IModule, IView, IPage } from "types"; // services -import { ProjectServices } from "services/project.service"; -import { IssueServices } from "services/issue.service"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; import { ProjectStateServices } from "services/project_state.service"; -import CycleService from "services/cycles.service"; +import { CycleService } from "services/cycles.service"; import { ModuleService } from "services/modules.service"; import { ViewService } from "services/views.service"; import { PageService } from "services/page.service"; @@ -110,6 +110,7 @@ class ProjectStore implements IProjectStore { moduleService; viewService; pageService; + cycleService; constructor(_rootStore: RootStore) { makeObservable(this, { @@ -148,12 +149,13 @@ class ProjectStore implements IProjectStore { }); this.rootStore = _rootStore; - this.projectService = new ProjectServices(); - this.issueService = new IssueServices(); + this.projectService = new ProjectService(); + this.issueService = new IssueService(); this.stateService = new ProjectStateServices(); this.moduleService = new ModuleService(); this.viewService = new ViewService(); this.pageService = new PageService(); + this.cycleService = new CycleService(); } get projectStatesByGroups() { @@ -307,7 +309,7 @@ class ProjectStore implements IProjectStore { this.loader = true; this.error = null; - const cyclesResponse = await CycleService.getCyclesWithParams(workspaceSlug, projectSlug, "all"); + const cyclesResponse = await this.cycleService.getCyclesWithParams(workspaceSlug, projectSlug, "all"); runInAction(() => { this.cycles = { diff --git a/web/store/project_publish.ts b/web/store/project_publish.ts index 6ce8dbc5b31..593200712c0 100644 --- a/web/store/project_publish.ts +++ b/web/store/project_publish.ts @@ -2,7 +2,7 @@ import { observable, action, computed, makeObservable, runInAction } from "mobx" // types import { RootStore } from "./root"; // services -import ProjectServices from "services/project_publish.service"; +import { ProjectPublishServices } from "services/project_publish.service"; export type TProjectPublishViews = "list" | "gantt" | "kanban" | "calendar" | "spreadsheet"; @@ -87,7 +87,7 @@ class ProjectPublishStore implements IProjectPublishStore { }); this.rootStore = _rootStore; - this.projectPublishService = new ProjectServices(); + this.projectPublishService = new ProjectPublishServices(); } handleProjectModal = (project_id: string | null = null) => { diff --git a/web/store/views.ts b/web/store/views.ts index 7edabf6a826..0748a54561b 100644 --- a/web/store/views.ts +++ b/web/store/views.ts @@ -2,8 +2,8 @@ import { action, computed, observable, makeObservable, runInAction } from "mobx" // types import { RootStore } from "./root"; // services -import { ProjectServices } from "services/project.service"; -import { IssueServices } from "services/issue.service"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; export interface IViewStore { loader: boolean; @@ -40,8 +40,8 @@ class ViewStore implements IViewStore { }); this.rootStore = _rootStore; - this.projectService = new ProjectServices(); - this.issueService = new IssueServices(); + this.projectService = new ProjectService(); + this.issueService = new IssueService(); } // computed diff --git a/web/store/workspace.ts b/web/store/workspace.ts index 50928cad3a5..5f27ab2f7f5 100644 --- a/web/store/workspace.ts +++ b/web/store/workspace.ts @@ -4,8 +4,8 @@ import { RootStore } from "./root"; import { IIssueLabels, IProject, IWorkspace } from "types"; // services import { WorkspaceService } from "services/workspace.service"; -import { ProjectServices } from "services/project.service"; -import { IssueServices } from "services/issue.service"; +import { ProjectService } from "services/project.service"; +import { IssueService } from "services/issue.service"; export interface IWorkspaceStore { loader: boolean; @@ -64,8 +64,8 @@ class WorkspaceStore implements IWorkspaceStore { this.rootStore = _rootStore; this.workspaceService = new WorkspaceService(); - this.projectService = new ProjectServices(); - this.issueService = new IssueServices(); + this.projectService = new ProjectService(); + this.issueService = new IssueService(); } /** From 2dcaccd4ec4d932b4f9243a3cf984d040f70e7a5 Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 21 Sep 2023 15:00:57 +0530 Subject: [PATCH 028/102] fix: merge conflicts (#2231) * chore: dynamic position dropdown (#2138) * chore: dynamic position state dropdown for issue view * style: state select dropdown styling * fix: state icon attribute names * chore: state select dynamic dropdown * chore: member select dynamic dropdown * chore: label select dynamic dropdown * chore: priority select dynamic dropdown * chore: label select dropdown improvement * refactor: state dropdown location * chore: dropdown improvement and code refactor * chore: dynamic dropdown hook type added --------- Co-authored-by: Aaryan Khandelwal * fix: fields not getting selected in the create issue form (#2212) * fix: hydration error and draft issue workflow * fix: build error * fix: properties getting de-selected after create, module & cycle not getting auto-select on the form * fix: display layout, props being updated directly * chore: sub issues count in individual issue (#2221) * fix: service imports * chore: rename csv service file --------- Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> --- apiserver/plane/api/views/issue.py | 7 +- .../core/views/board-view/board-header.tsx | 2 - .../core/views/board-view/single-issue.tsx | 150 ++++++++--- .../core/views/calendar-view/single-issue.tsx | 142 ++++++++--- web/components/core/views/issues-view.tsx | 16 +- .../core/views/list-view/single-issue.tsx | 142 ++++++++--- .../views/spreadsheet-view/single-issue.tsx | 149 ++++++++--- .../cycles/active-cycle-details.tsx | 2 +- web/components/cycles/cycles-view.tsx | 2 +- web/components/exporter/export-modal.tsx | 2 +- .../issues/confirm-issue-discard.tsx | 2 +- web/components/issues/draft-issue-form.tsx | 40 ++- web/components/issues/draft-issue-modal.tsx | 172 +++++++++++-- web/components/issues/form.tsx | 2 + web/components/issues/modal.tsx | 62 ++++- web/components/issues/view-select/index.ts | 3 +- web/components/issues/view-select/state.tsx | 130 ---------- web/components/project/index.ts | 3 + web/components/project/label-select.tsx | 239 ++++++++++++++++++ web/components/project/members-select.tsx | 191 ++++++++++++++ web/components/project/priority-select.tsx | 173 +++++++++++++ web/components/states/index.ts | 1 + web/components/states/state-select.tsx | 169 +++++++++++++ .../workspace/sidebar-quick-action.tsx | 91 +++---- web/hooks/use-dynamic-dropdown.tsx | 64 +++++ .../{csv.services.ts => csv.service.ts} | 0 26 files changed, 1578 insertions(+), 378 deletions(-) delete mode 100644 web/components/issues/view-select/state.tsx create mode 100644 web/components/project/label-select.tsx create mode 100644 web/components/project/members-select.tsx create mode 100644 web/components/project/priority-select.tsx create mode 100644 web/components/states/state-select.tsx create mode 100644 web/hooks/use-dynamic-dropdown.tsx rename web/services/{csv.services.ts => csv.service.ts} (100%) diff --git a/apiserver/plane/api/views/issue.py b/apiserver/plane/api/views/issue.py index 8d2ed9b96c0..e653f3d447d 100644 --- a/apiserver/plane/api/views/issue.py +++ b/apiserver/plane/api/views/issue.py @@ -330,7 +330,12 @@ def create(self, request, slug, project_id): def retrieve(self, request, slug, project_id, pk=None): try: - issue = Issue.issue_objects.get( + issue = Issue.issue_objects.annotate( + sub_issues_count=Issue.issue_objects.filter(parent=OuterRef("id")) + .order_by() + .annotate(count=Func(F("id"), function="Count")) + .values("count") + ).get( workspace__slug=slug, project_id=project_id, pk=pk ) return Response(IssueSerializer(issue).data, status=status.HTTP_200_OK) diff --git a/web/components/core/views/board-view/board-header.tsx b/web/components/core/views/board-view/board-header.tsx index 2bf811d45dd..93aee9ce7b2 100644 --- a/web/components/core/views/board-view/board-header.tsx +++ b/web/components/core/views/board-view/board-header.tsx @@ -50,8 +50,6 @@ export const BoardHeader: React.FC = ({ const { displayFilters, groupedIssues } = viewProps; - console.log("dF", displayFilters); - const { data: issueLabels } = useSWR( workspaceSlug && projectId && displayFilters?.group_by === "labels" ? PROJECT_ISSUE_LABELS(projectId.toString()) diff --git a/web/components/core/views/board-view/single-issue.tsx b/web/components/core/views/board-view/single-issue.tsx index 1e818ae7e90..29cfe2c3598 100644 --- a/web/components/core/views/board-view/single-issue.tsx +++ b/web/components/core/views/board-view/single-issue.tsx @@ -8,19 +8,14 @@ import { mutate } from "swr"; import { DraggableProvided, DraggableStateSnapshot, DraggingStyle, NotDraggingStyle } from "react-beautiful-dnd"; // services import issuesService from "services/issue.service"; +import trackEventServices from "services/track_event.service"; // hooks import useToast from "hooks/use-toast"; import useOutsideClickDetector from "hooks/use-outside-click-detector"; // components -import { - ViewAssigneeSelect, - ViewDueDateSelect, - ViewEstimateSelect, - ViewIssueLabel, - ViewPrioritySelect, - ViewStartDateSelect, - ViewStateSelect, -} from "components/issues"; +import { ViewDueDateSelect, ViewEstimateSelect, ViewStartDateSelect } from "components/issues"; +import { MembersSelect, LabelSelect, PrioritySelect } from "components/project"; +import { StateSelect } from "components/states"; // ui import { ContextMenu, CustomMenu, Tooltip } from "components/ui"; // icons @@ -39,7 +34,15 @@ import { LayerDiagonalIcon } from "components/icons"; import { handleIssuesMutation } from "helpers/issue.helper"; import { copyTextToClipboard } from "helpers/string.helper"; // types -import { ICurrentUserResponse, IIssue, IIssueViewProps, ISubIssueResponse, UserAuth } from "types"; +import { + ICurrentUserResponse, + IIssue, + IIssueViewProps, + IState, + ISubIssueResponse, + TIssuePriorities, + UserAuth, +} from "types"; // fetch-keys import { CYCLE_DETAILS, MODULE_DETAILS, SUB_ISSUES } from "constants/fetch-keys"; @@ -175,6 +178,86 @@ export const SingleBoardIssue: React.FC = ({ }); }; + const handleStateChange = (data: string, states: IState[] | undefined) => { + const oldState = states?.find((s) => s.id === issue.state); + const newState = states?.find((s) => s.id === data); + + partialUpdateIssue( + { + state: data, + state_detail: newState, + }, + issue + ); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_STATE", + user + ); + if (oldState?.group !== "completed" && newState?.group !== "completed") { + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); + } + }; + + const handleAssigneeChange = (data: any) => { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: data }, issue); + + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user + ); + }; + + const handleLabelChange = (data: any) => { + partialUpdateIssue({ labels_list: data }, issue); + }; + + const handlePriorityChange = (data: TIssuePriorities) => { + partialUpdateIssue({ priority: data }, issue); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user + ); + }; + useEffect(() => { if (snapshot.isDragging) handleTrashBox(snapshot.isDragging); }, [snapshot, handleTrashBox]); @@ -326,33 +409,30 @@ export const SingleBoardIssue: React.FC = ({ )}
    {properties.priority && ( - )} {properties.state && ( - )} {properties.start_date && issue.start_date && ( @@ -376,16 +456,22 @@ export const SingleBoardIssue: React.FC = ({ /> )} {properties.labels && issue.labels.length > 0 && ( - + )} {properties.assignee && ( - )} {properties.estimate && issue.estimate_point !== null && ( diff --git a/web/components/core/views/calendar-view/single-issue.tsx b/web/components/core/views/calendar-view/single-issue.tsx index 92e2691c6a9..161c68a1a92 100644 --- a/web/components/core/views/calendar-view/single-issue.tsx +++ b/web/components/core/views/calendar-view/single-issue.tsx @@ -8,28 +8,23 @@ import { mutate } from "swr"; import { DraggableProvided, DraggableStateSnapshot } from "react-beautiful-dnd"; // services import issuesService from "services/issue.service"; +import trackEventServices from "services/track_event.service"; // hooks import useCalendarIssuesView from "hooks/use-calendar-issues-view"; import useIssuesProperties from "hooks/use-issue-properties"; import useToast from "hooks/use-toast"; // components import { CustomMenu, Tooltip } from "components/ui"; -import { - ViewAssigneeSelect, - ViewDueDateSelect, - ViewEstimateSelect, - ViewLabelSelect, - ViewPrioritySelect, - ViewStartDateSelect, - ViewStateSelect, -} from "components/issues"; +import { ViewDueDateSelect, ViewEstimateSelect, ViewStartDateSelect } from "components/issues"; +import { LabelSelect, MembersSelect, PrioritySelect } from "components/project"; +import { StateSelect } from "components/states"; // icons import { LinkIcon, PaperClipIcon, PencilIcon, TrashIcon } from "@heroicons/react/24/outline"; import { LayerDiagonalIcon } from "components/icons"; // helper import { copyTextToClipboard, truncateText } from "helpers/string.helper"; // type -import { ICurrentUserResponse, IIssue, ISubIssueResponse } from "types"; +import { ICurrentUserResponse, IIssue, IState, ISubIssueResponse, TIssuePriorities } from "types"; // fetch-keys import { CYCLE_ISSUES_WITH_PARAMS, @@ -144,6 +139,86 @@ export const SingleCalendarIssue: React.FC = ({ }); }; + const handleStateChange = (data: string, states: IState[] | undefined) => { + const oldState = states?.find((s) => s.id === issue.state); + const newState = states?.find((s) => s.id === data); + + partialUpdateIssue( + { + state: data, + state_detail: newState, + }, + issue + ); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_STATE", + user + ); + if (oldState?.group !== "completed" && newState?.group !== "completed") { + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); + } + }; + + const handleAssigneeChange = (data: any) => { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: data }, issue); + + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user + ); + }; + + const handleLabelChange = (data: any) => { + partialUpdateIssue({ labels_list: data }, issue); + }; + + const handlePriorityChange = (data: TIssuePriorities) => { + partialUpdateIssue({ priority: data }, issue); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user + ); + }; + const displayProperties = properties ? Object.values(properties).some((value) => value === true) : false; const openPeekOverview = () => { @@ -214,22 +289,19 @@ export const SingleCalendarIssue: React.FC = ({ {displayProperties && (
    {properties.priority && ( - )} {properties.state && ( - )} {properties.start_date && issue.start_date && ( @@ -249,21 +321,23 @@ export const SingleCalendarIssue: React.FC = ({ /> )} {properties.labels && issue.labels.length > 0 && ( - )} {properties.assignee && ( - )} {properties.estimate && issue.estimate_point !== null && ( diff --git a/web/components/core/views/issues-view.tsx b/web/components/core/views/issues-view.tsx index 6b6e1c909d4..521318e40b7 100644 --- a/web/components/core/views/issues-view.tsx +++ b/web/components/core/views/issues-view.tsx @@ -1,4 +1,4 @@ -import { useCallback, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/router"; @@ -82,7 +82,8 @@ export const IssuesView: React.FC = ({ openIssuesListModal, disableUserAc const { setToastAlert } = useToast(); - const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params } = useIssuesView(); + const { groupedByIssues, mutateIssues, displayFilters, filters, isEmpty, setFilters, params, setDisplayFilters } = + useIssuesView(); const [properties] = useIssuesProperties(workspaceSlug as string, projectId as string); const { data: stateGroups } = useSWR( @@ -100,6 +101,17 @@ export const IssuesView: React.FC = ({ openIssuesListModal, disableUserAc const { members } = useProjectMembers(workspaceSlug?.toString(), projectId?.toString()); + useEffect(() => { + if (!isDraftIssues) return; + + if ( + displayFilters.layout === "calendar" || + displayFilters.layout === "gantt_chart" || + displayFilters.layout === "spreadsheet" + ) + setDisplayFilters({ layout: "list" }); + }, [isDraftIssues, displayFilters, setDisplayFilters]); + const handleDeleteIssue = useCallback( (issue: IIssue) => { setDeleteIssueModal(true); diff --git a/web/components/core/views/list-view/single-issue.tsx b/web/components/core/views/list-view/single-issue.tsx index 34f7272222b..54ef1a15baf 100644 --- a/web/components/core/views/list-view/single-issue.tsx +++ b/web/components/core/views/list-view/single-issue.tsx @@ -6,19 +6,13 @@ import { mutate } from "swr"; // services import issuesService from "services/issue.service"; +import trackEventServices from "services/track_event.service"; // hooks import useToast from "hooks/use-toast"; // components -import { - ViewAssigneeSelect, - ViewDueDateSelect, - ViewEstimateSelect, - ViewIssueLabel, - ViewPrioritySelect, - ViewStartDateSelect, - ViewStateSelect, - CreateUpdateDraftIssueModal, -} from "components/issues"; +import { ViewDueDateSelect, ViewEstimateSelect, ViewStartDateSelect } from "components/issues"; +import { LabelSelect, MembersSelect, PrioritySelect } from "components/project"; +import { StateSelect } from "components/states"; // ui import { Tooltip, CustomMenu, ContextMenu } from "components/ui"; // icons @@ -40,8 +34,10 @@ import { ICurrentUserResponse, IIssue, IIssueViewProps, + IState, ISubIssueResponse, IUserProfileProjectSegregation, + TIssuePriorities, UserAuth, } from "types"; // fetch-keys @@ -161,6 +157,86 @@ export const SingleListIssue: React.FC = ({ }); }; + const handleStateChange = (data: string, states: IState[] | undefined) => { + const oldState = states?.find((s) => s.id === issue.state); + const newState = states?.find((s) => s.id === data); + + partialUpdateIssue( + { + state: data, + state_detail: newState, + }, + issue + ); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_STATE", + user + ); + if (oldState?.group !== "completed" && newState?.group !== "completed") { + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); + } + }; + + const handleAssigneeChange = (data: any) => { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: data }, issue); + + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user + ); + }; + + const handleLabelChange = (data: any) => { + partialUpdateIssue({ labels_list: data }, issue); + }; + + const handlePriorityChange = (data: TIssuePriorities) => { + partialUpdateIssue({ priority: data }, issue); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user + ); + }; + const issuePath = isArchivedIssues ? `/${workspaceSlug}/projects/${issue.project}/archived-issues/${issue.id}` : isDraftIssues @@ -265,21 +341,19 @@ export const SingleListIssue: React.FC = ({
    {properties.priority && ( - )} {properties.state && ( - )} {properties.start_date && issue.start_date && ( @@ -298,14 +372,24 @@ export const SingleListIssue: React.FC = ({ isNotAllowed={isNotAllowed} /> )} - {properties.labels && } - {properties.assignee && ( - + )} + {properties.assignee && ( + )} {properties.estimate && issue.estimate_point !== null && ( diff --git a/web/components/core/views/spreadsheet-view/single-issue.tsx b/web/components/core/views/spreadsheet-view/single-issue.tsx index c4519d2dcd7..f9c9f1ceebf 100644 --- a/web/components/core/views/spreadsheet-view/single-issue.tsx +++ b/web/components/core/views/spreadsheet-view/single-issue.tsx @@ -5,15 +5,9 @@ import { useRouter } from "next/router"; import { mutate } from "swr"; // components -import { - ViewAssigneeSelect, - ViewDueDateSelect, - ViewEstimateSelect, - ViewIssueLabel, - ViewPrioritySelect, - ViewStartDateSelect, - ViewStateSelect, -} from "components/issues"; +import { ViewDueDateSelect, ViewEstimateSelect, ViewStartDateSelect } from "components/issues"; +import { LabelSelect, MembersSelect, PrioritySelect } from "components/project"; +import { StateSelect } from "components/states"; import { Popover2 } from "@blueprintjs/popover2"; // icons import { Icon } from "components/ui"; @@ -23,6 +17,7 @@ import useSpreadsheetIssuesView from "hooks/use-spreadsheet-issues-view"; import useToast from "hooks/use-toast"; // services import issuesService from "services/issue.service"; +import trackEventServices from "services/track_event.service"; // constant import { CYCLE_DETAILS, @@ -34,7 +29,7 @@ import { VIEW_ISSUES, } from "constants/fetch-keys"; // types -import { ICurrentUserResponse, IIssue, ISubIssueResponse, Properties, UserAuth } from "types"; +import { ICurrentUserResponse, IIssue, IState, ISubIssueResponse, Properties, TIssuePriorities, UserAuth } from "types"; // helper import { copyTextToClipboard } from "helpers/string.helper"; import { renderLongDetailDateFormat } from "helpers/date-time.helper"; @@ -166,6 +161,86 @@ export const SingleSpreadsheetIssue: React.FC = ({ }); }; + const handleStateChange = (data: string, states: IState[] | undefined) => { + const oldState = states?.find((s) => s.id === issue.state); + const newState = states?.find((s) => s.id === data); + + partialUpdateIssue( + { + state: data, + state_detail: newState, + }, + issue + ); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_STATE", + user + ); + if (oldState?.group !== "completed" && newState?.group !== "completed") { + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); + } + }; + + const handlePriorityChange = (data: TIssuePriorities) => { + partialUpdateIssue({ priority: data }, issue); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user + ); + }; + + const handleAssigneeChange = (data: any) => { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: data }, issue); + + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user + ); + }; + + const handleLabelChange = (data: any) => { + partialUpdateIssue({ labels_list: data }, issue); + }; + const paddingLeft = `${nestingLevel * 68}px`; const tooltipPosition = index === 0 ? "bottom" : "top"; @@ -269,47 +344,49 @@ export const SingleSpreadsheetIssue: React.FC = ({
    {properties.state && (
    -
    )} {properties.priority && (
    -
    )} {properties.assignee && (
    -
    )} {properties.labels && (
    - +
    )} diff --git a/web/components/cycles/active-cycle-details.tsx b/web/components/cycles/active-cycle-details.tsx index 062dd57e74c..7816f0edba1 100644 --- a/web/components/cycles/active-cycle-details.tsx +++ b/web/components/cycles/active-cycle-details.tsx @@ -127,7 +127,7 @@ export const ActiveCycleDetails: React.FC = () => { cy="34.375" r="22" stroke="rgb(var(--color-text-400))" - stroke-linecap="round" + strokeLinecap="round" /> = ({ cycles, mutateCycles, viewType }) cy="34.375" r="22" stroke="rgb(var(--color-text-400))" - stroke-linecap="round" + strokeLinecap="round" /> = (props) => {
    -
    +
    = { }; interface IssueFormProps { - handleFormSubmit: (formData: Partial) => Promise; + handleFormSubmit: ( + formData: Partial, + action?: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" + ) => Promise; data?: Partial | null; prePopulatedData?: Partial | null; projectId: string; @@ -134,12 +137,16 @@ export const DraftIssueForm: FC = (props) => { const handleCreateUpdateIssue = async ( formData: Partial, - action: "saveDraft" | "createToNewIssue" = "saveDraft" + action: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" = "createDraft" ) => { - await handleFormSubmit({ - ...formData, - is_draft: action === "saveDraft", - }); + await handleFormSubmit( + { + ...(data ?? {}), + ...formData, + is_draft: action === "createDraft" || action === "updateDraft", + }, + action + ); setGptAssistantModal(false); @@ -263,7 +270,9 @@ export const DraftIssueForm: FC = (props) => { )}
    handleCreateUpdateIssue(formData, "createToNewIssue"))} + onSubmit={handleSubmit((formData) => + handleCreateUpdateIssue(formData, "convertToNewIssue") + )} >
    @@ -563,15 +572,20 @@ export const DraftIssueForm: FC = (props) => { Discard handleCreateUpdateIssue(formData, "saveDraft"))} + onClick={handleSubmit((formData) => + handleCreateUpdateIssue(formData, data?.id ? "updateDraft" : "createDraft") + )} > {isSubmitting ? "Saving..." : "Save Draft"} - {data && ( - - {isSubmitting ? "Saving..." : "Add Issue"} - - )} + + handleCreateUpdateIssue(formData, data ? "convertToNewIssue" : "createNewIssue") + )} + > + {isSubmitting ? "Saving..." : "Add Issue"} +
    diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index eafc2a4dfe9..97d1c18a62a 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -31,7 +31,10 @@ import { MODULE_ISSUES_WITH_PARAMS, VIEW_ISSUES, PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS, + CYCLE_DETAILS, + MODULE_DETAILS, } from "constants/fetch-keys"; +import modulesService from "services/modules.service"; interface IssuesModalProps { data?: IIssue | null; @@ -56,18 +59,21 @@ interface IssuesModalProps { onSubmit?: (data: Partial) => Promise | void; } -export const CreateUpdateDraftIssueModal: React.FC = ({ - data, - handleClose, - isOpen, - isUpdatingSingleIssue = false, - prePopulateData, - fieldsToShow = ["all"], - onSubmit, -}) => { +export const CreateUpdateDraftIssueModal: React.FC = (props) => { + const { + data, + handleClose, + isOpen, + isUpdatingSingleIssue = false, + prePopulateData: prePopulateDataProps, + fieldsToShow = ["all"], + onSubmit, + } = props; + // states const [createMore, setCreateMore] = useState(false); const [activeProject, setActiveProject] = useState(null); + const [prePopulateData, setPreloadedData] = useState | undefined>(undefined); const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId } = router.query; @@ -86,19 +92,40 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ const { setToastAlert } = useToast(); - if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string }; - if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string }; - if (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) - prePopulateData = { - ...prePopulateData, - assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""], - }; - const onClose = () => { handleClose(); setActiveProject(null); }; + useEffect(() => { + setPreloadedData(prePopulateDataProps ?? {}); + + if (cycleId && !prePopulateDataProps?.cycle) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + cycle: cycleId.toString(), + })); + } + if (moduleId && !prePopulateDataProps?.module) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + module: moduleId.toString(), + })); + } + if ( + (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) && + !prePopulateDataProps?.assignees + ) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + assignees: prePopulateDataProps?.assignees ?? [user?.id ?? ""], + })); + } + }, [prePopulateDataProps, cycleId, moduleId, router.asPath, user?.id]); + useEffect(() => { // if modal is closed, reset active project to null // and return to avoid activeProject being set to some other project @@ -109,10 +136,10 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ // if data is present, set active project to the project of the // issue. This has more priority than the project in the url. - if (data && data.project) { - setActiveProject(data.project); - return; - } + if (data && data.project) return setActiveProject(data.project); + + if (prePopulateData && prePopulateData.project && !activeProject) + return setActiveProject(prePopulateData.project); if (prePopulateData && prePopulateData.project) return setActiveProject(prePopulateData.project); @@ -146,7 +173,7 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ ? VIEW_ISSUES(viewId.toString(), viewGanttParams) : PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject?.toString() ?? ""); - const createIssue = async (payload: Partial) => { + const createDraftIssue = async (payload: Partial) => { if (!workspaceSlug || !activeProject || !user) return; await issuesService @@ -186,7 +213,7 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ if (!createMore) onClose(); }; - const updateIssue = async (payload: Partial) => { + const updateDraftIssue = async (payload: Partial) => { if (!user) return; await issuesService @@ -202,6 +229,11 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ mutate(PROJECT_DRAFT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); } + if (!payload.is_draft) { + if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); + if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); + } + if (!createMore) onClose(); setToastAlert({ @@ -219,7 +251,93 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ }); }; - const handleFormSubmit = async (formData: Partial) => { + const addIssueToCycle = async (issueId: string, cycleId: string) => { + if (!workspaceSlug || !activeProject) return; + + await issuesService + .addIssueToCycle( + workspaceSlug as string, + activeProject ?? "", + cycleId, + { + issues: [issueId], + }, + user + ) + .then(() => { + if (cycleId) { + mutate(CYCLE_ISSUES_WITH_PARAMS(cycleId, params)); + mutate(CYCLE_DETAILS(cycleId as string)); + } + }); + }; + + const addIssueToModule = async (issueId: string, moduleId: string) => { + if (!workspaceSlug || !activeProject) return; + + await modulesService + .addIssuesToModule( + workspaceSlug as string, + activeProject ?? "", + moduleId as string, + { + issues: [issueId], + }, + user + ) + .then(() => { + if (moduleId) { + mutate(MODULE_ISSUES_WITH_PARAMS(moduleId as string, params)); + mutate(MODULE_DETAILS(moduleId as string)); + } + }); + }; + + const createIssue = async (payload: Partial) => { + if (!workspaceSlug || !activeProject) return; + + await issuesService + .createIssues(workspaceSlug as string, activeProject ?? "", payload, user) + .then(async (res) => { + mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(activeProject ?? "", params)); + if (payload.cycle && payload.cycle !== "") await addIssueToCycle(res.id, payload.cycle); + if (payload.module && payload.module !== "") await addIssueToModule(res.id, payload.module); + + if (displayFilters.layout === "calendar") mutate(calendarFetchKey); + if (displayFilters.layout === "gantt_chart") + mutate(ganttFetchKey, { + start_target_date: true, + order_by: "sort_order", + }); + if (displayFilters.layout === "spreadsheet") mutate(spreadsheetFetchKey); + if (groupedIssues) mutateMyIssues(); + + setToastAlert({ + type: "success", + title: "Success!", + message: "Issue created successfully.", + }); + + if (!createMore) onClose(); + + if (payload.assignees_list?.some((assignee) => assignee === user?.id)) + mutate(USER_ISSUE(workspaceSlug as string)); + + if (payload.parent && payload.parent !== "") mutate(SUB_ISSUES(payload.parent)); + }) + .catch(() => { + setToastAlert({ + type: "error", + title: "Error!", + message: "Issue could not be created. Please try again.", + }); + }); + }; + + const handleFormSubmit = async ( + formData: Partial, + action: "createDraft" | "createNewIssue" | "updateDraft" | "convertToNewIssue" = "createDraft" + ) => { if (!workspaceSlug || !activeProject) return; const payload: Partial = { @@ -230,8 +348,10 @@ export const CreateUpdateDraftIssueModal: React.FC = ({ description_html: formData.description_html ?? "

    ", }; - if (!data) await createIssue(payload); - else await updateIssue(payload); + if (action === "createDraft") await createDraftIssue(payload); + else if (action === "updateDraft" || action === "convertToNewIssue") + await updateDraftIssue(payload); + else if (action === "createNewIssue") await createIssue(payload); clearDraftIssueLocalStorage(); diff --git a/web/components/issues/form.tsx b/web/components/issues/form.tsx index 2e53f38666e..c92c3d332ed 100644 --- a/web/components/issues/form.tsx +++ b/web/components/issues/form.tsx @@ -139,6 +139,8 @@ export const IssueForm: FC = (props) => { target_date: getValues("target_date"), project: getValues("project"), parent: getValues("parent"), + cycle: getValues("cycle"), + module: getValues("module"), }; useEffect(() => { diff --git a/web/components/issues/modal.tsx b/web/components/issues/modal.tsx index 88dc38f7ac1..9ea5f18712d 100644 --- a/web/components/issues/modal.tsx +++ b/web/components/issues/modal.tsx @@ -69,7 +69,7 @@ export const CreateUpdateIssueModal: React.FC = ({ handleClose, isOpen, isUpdatingSingleIssue = false, - prePopulateData, + prePopulateData: prePopulateDataProps, fieldsToShow = ["all"], onSubmit, }) => { @@ -78,6 +78,7 @@ export const CreateUpdateIssueModal: React.FC = ({ const [formDirtyState, setFormDirtyState] = useState(null); const [showConfirmDiscard, setShowConfirmDiscard] = useState(false); const [activeProject, setActiveProject] = useState(null); + const [prePopulateData, setPreloadedData] = useState>({}); const router = useRouter(); const { workspaceSlug, projectId, cycleId, moduleId, viewId, inboxId } = router.query; @@ -100,11 +101,40 @@ export const CreateUpdateIssueModal: React.FC = ({ const { setToastAlert } = useToast(); - if (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) - prePopulateData = { - ...prePopulateData, - assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""], - }; + useEffect(() => { + setPreloadedData(prePopulateDataProps ?? {}); + + if (cycleId && !prePopulateDataProps?.cycle) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + cycle: cycleId.toString(), + })); + } + if (moduleId && !prePopulateDataProps?.module) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + module: moduleId.toString(), + })); + } + if ( + (router.asPath.includes("my-issues") || router.asPath.includes("assigned")) && + !prePopulateDataProps?.assignees + ) { + setPreloadedData((prevData) => ({ + ...(prevData ?? {}), + ...prePopulateDataProps, + assignees: prePopulateDataProps?.assignees ?? [user?.id ?? ""], + })); + } + }, [prePopulateDataProps, cycleId, moduleId, router.asPath, user?.id]); + + /** + * + * @description This function is used to close the modals. This function will show a confirm discard modal if the form is dirty. + * @returns void + */ const onClose = () => { if (!showConfirmDiscard) handleClose(); @@ -113,6 +143,22 @@ export const CreateUpdateIssueModal: React.FC = ({ setValueInLocalStorage(data); }; + /** + * @description This function is used to close the modals. This function is to be used when the form is submitted, + * meaning we don't need to show the confirm discard modal or store the form data in local storage. + */ + + const onFormSubmitClose = () => { + setFormDirtyState(null); + handleClose(); + }; + + /** + * @description This function is used to close the modals. This function is to be used when we click outside the modal, + * meaning we don't need to show the confirm discard modal but will store the form data in local storage. + * Use this function when you want to store the form data in local storage. + */ + const onDiscardClose = () => { if (formDirtyState !== null) { setShowConfirmDiscard(true); @@ -290,7 +336,7 @@ export const CreateUpdateIssueModal: React.FC = ({ }); }); - if (!createMore) onDiscardClose(); + if (!createMore) onFormSubmitClose(); }; const createDraftIssue = async () => { @@ -349,7 +395,7 @@ export const CreateUpdateIssueModal: React.FC = ({ if (payload.cycle && payload.cycle !== "") addIssueToCycle(res.id, payload.cycle); if (payload.module && payload.module !== "") addIssueToModule(res.id, payload.module); - if (!createMore) onDiscardClose(); + if (!createMore) onFormSubmitClose(); setToastAlert({ type: "success", diff --git a/web/components/issues/view-select/index.ts b/web/components/issues/view-select/index.ts index d78a82ed35e..99191eb3d21 100644 --- a/web/components/issues/view-select/index.ts +++ b/web/components/issues/view-select/index.ts @@ -3,5 +3,4 @@ export * from "./due-date"; export * from "./estimate"; export * from "./label"; export * from "./priority"; -export * from "./start-date"; -export * from "./state"; +export * from "./start-date"; \ No newline at end of file diff --git a/web/components/issues/view-select/state.tsx b/web/components/issues/view-select/state.tsx deleted file mode 100644 index 2b2f16467c9..00000000000 --- a/web/components/issues/view-select/state.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { useState } from "react"; - -import { useRouter } from "next/router"; - -import useSWR from "swr"; - -// services -import stateService from "services/project_state.service"; -import trackEventServices from "services/track_event.service"; -// ui -import { CustomSearchSelect, Tooltip } from "components/ui"; -// icons -import { StateGroupIcon } from "components/icons"; -// helpers -import { getStatesList } from "helpers/state.helper"; -// types -import { ICurrentUserResponse, IIssue } from "types"; -// fetch-keys -import { STATES_LIST } from "constants/fetch-keys"; - -type Props = { - issue: IIssue; - partialUpdateIssue: (formData: Partial, issue: IIssue) => void; - position?: "left" | "right"; - tooltipPosition?: "top" | "bottom"; - className?: string; - selfPositioned?: boolean; - customButton?: boolean; - user: ICurrentUserResponse | undefined; - isNotAllowed: boolean; -}; - -export const ViewStateSelect: React.FC = ({ - issue, - partialUpdateIssue, - position = "left", - tooltipPosition = "top", - className = "", - selfPositioned = false, - customButton = false, - user, - isNotAllowed, -}) => { - const [fetchStates, setFetchStates] = useState(false); - - const router = useRouter(); - const { workspaceSlug } = router.query; - - const { data: stateGroups } = useSWR( - workspaceSlug && issue && fetchStates ? STATES_LIST(issue.project) : null, - workspaceSlug && issue && fetchStates ? () => stateService.getStates(workspaceSlug as string, issue.project) : null - ); - const states = getStatesList(stateGroups); - - const options = states?.map((state) => ({ - value: state.id, - query: state.name, - content: ( -
    - - {state.name} -
    - ), - })); - - const selectedOption = issue.state_detail; - - const stateLabel = ( - -
    - - {selectedOption && } - - {selectedOption?.name ?? "State"} -
    -
    - ); - - return ( - { - const oldState = states?.find((s) => s.id === issue.state); - const newState = states?.find((s) => s.id === data); - - partialUpdateIssue( - { - state: data, - state_detail: newState, - }, - issue - ); - trackEventServices.trackIssuePartialPropertyUpdateEvent( - { - workspaceSlug, - workspaceId: issue.workspace, - projectId: issue.project_detail.id, - projectIdentifier: issue.project_detail.identifier, - projectName: issue.project_detail.name, - issueId: issue.id, - }, - "ISSUE_PROPERTY_UPDATE_STATE", - user - ); - - if (oldState?.group !== "completed" && newState?.group !== "completed") { - trackEventServices.trackIssueMarkedAsDoneEvent( - { - workspaceSlug: issue.workspace_detail.slug, - workspaceId: issue.workspace_detail.id, - projectId: issue.project_detail.id, - projectIdentifier: issue.project_detail.identifier, - projectName: issue.project_detail.name, - issueId: issue.id, - }, - user - ); - } - }} - options={options} - {...(customButton ? { customButton: stateLabel } : { label: stateLabel })} - position={position} - disabled={isNotAllowed} - onOpen={() => setFetchStates(true)} - noChevron - selfPositioned={selfPositioned} - /> - ); -}; diff --git a/web/components/project/index.ts b/web/components/project/index.ts index 23ad6ddbad1..329e826a82b 100644 --- a/web/components/project/index.ts +++ b/web/components/project/index.ts @@ -7,3 +7,6 @@ export * from "./single-project-card"; export * from "./single-sidebar-project"; export * from "./confirm-project-leave-modal"; export * from "./member-select"; +export * from "./members-select"; +export * from "./label-select"; +export * from "./priority-select"; diff --git a/web/components/project/label-select.tsx b/web/components/project/label-select.tsx new file mode 100644 index 00000000000..56c1aef5e7a --- /dev/null +++ b/web/components/project/label-select.tsx @@ -0,0 +1,239 @@ +import React, { useRef, useState } from "react"; + +import useSWR from "swr"; + +import { useRouter } from "next/router"; + +// services +import issuesService from "services/issue.service"; +// hooks +import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; +// headless ui +import { Combobox } from "@headlessui/react"; +// component +import { CreateLabelModal } from "components/labels"; +// icons +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { PlusIcon } from "lucide-react"; +// types +import { Tooltip } from "components/ui"; +import { ICurrentUserResponse, IIssueLabels } from "types"; +// constants +import { PROJECT_ISSUE_LABELS } from "constants/fetch-keys"; + +type Props = { + value: string[]; + onChange: (data: any) => void; + labelsDetails: any[]; + className?: string; + buttonClassName?: string; + optionsClassName?: string; + maxRender?: number; + hideDropdownArrow?: boolean; + disabled?: boolean; + user: ICurrentUserResponse | undefined; +}; + +export const LabelSelect: React.FC = ({ + value, + onChange, + labelsDetails, + className = "", + buttonClassName = "", + optionsClassName = "", + maxRender = 2, + hideDropdownArrow = false, + disabled = false, + user, +}) => { + const [query, setQuery] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const [fetchStates, setFetchStates] = useState(false); + + const [labelModal, setLabelModal] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const dropdownBtn = useRef(null); + const dropdownOptions = useRef(null); + + const { data: issueLabels } = useSWR( + projectId && fetchStates ? PROJECT_ISSUE_LABELS(projectId.toString()) : null, + workspaceSlug && projectId && fetchStates + ? () => issuesService.getIssueLabels(workspaceSlug as string, projectId as string) + : null + ); + + const options = issueLabels?.map((label) => ({ + value: label.id, + query: label.name, + content: ( +
    + + {label.name} +
    + ), + })); + + const filteredOptions = + query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + + const label = ( +
    + {labelsDetails.length > 0 ? ( + labelsDetails.length <= maxRender ? ( + <> + {labelsDetails.map((label) => ( +
    +
    + + {label.name} +
    +
    + ))} + + ) : ( +
    + l.name).join(", ")} + > +
    + + {`${value.length} Labels`} +
    +
    +
    + ) + ) : ( + "" + )} +
    + ); + + useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); + + const footerOption = ( + + ); + + return ( + <> + {projectId && ( + setLabelModal(false)} + projectId={projectId.toString()} + user={user} + /> + )} + + {({ open }: { open: boolean }) => { + if (open) { + if (!isOpen) setIsOpen(true); + setFetchStates(true); + } else if (isOpen) setIsOpen(false); + + return ( + <> + + {label} + {!hideDropdownArrow && !disabled && +
    + +
    + + setQuery(e.target.value)} + placeholder="Search" + displayValue={(assigned: any) => assigned?.name} + /> +
    +
    + {filteredOptions ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active && !selected ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( + +

    No matching results

    +
    + ) + ) : ( +

    Loading...

    + )} +
    + {footerOption} +
    +
    + + ); + }} +
    + + ); +}; diff --git a/web/components/project/members-select.tsx b/web/components/project/members-select.tsx new file mode 100644 index 00000000000..f99d8517488 --- /dev/null +++ b/web/components/project/members-select.tsx @@ -0,0 +1,191 @@ +import React, { useRef, useState } from "react"; + +import { useRouter } from "next/router"; + +// hooks +import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; +import useProjectMembers from "hooks/use-project-members"; +import useWorkspaceMembers from "hooks/use-workspace-members"; +// headless ui +import { Combobox } from "@headlessui/react"; +// components +import { AssigneesList, Avatar, Icon, Tooltip } from "components/ui"; +// icons +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +// types +import { IUser } from "types"; + +type Props = { + value: string | string[]; + onChange: (data: any) => void; + membersDetails: IUser[]; + renderWorkspaceMembers?: boolean; + className?: string; + buttonClassName?: string; + optionsClassName?: string; + hideDropdownArrow?: boolean; + disabled?: boolean; +}; + +export const MembersSelect: React.FC = ({ + value, + onChange, + membersDetails, + renderWorkspaceMembers = false, + className = "", + buttonClassName = "", + optionsClassName = "", + hideDropdownArrow = false, + disabled = false, +}) => { + const [query, setQuery] = useState(""); + const [isOpen, setIsOpen] = useState(false); + const [fetchStates, setFetchStates] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const dropdownBtn = useRef(null); + const dropdownOptions = useRef(null); + + const { members } = useProjectMembers( + workspaceSlug?.toString(), + projectId?.toString(), + fetchStates && !renderWorkspaceMembers + ); + + const { workspaceMembers } = useWorkspaceMembers( + workspaceSlug?.toString() ?? "", + fetchStates && renderWorkspaceMembers + ); + + const membersOptions = renderWorkspaceMembers ? workspaceMembers : members; + + const options = membersOptions?.map((member) => ({ + value: member.member.id, + query: member.member.display_name, + content: ( +
    + + {member.member.display_name} +
    + ), + })); + + const filteredOptions = + query === "" + ? options + : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + + const label = ( + 0 + ? membersDetails.map((assignee) => assignee?.display_name).join(", ") + : "No Assignee" + } + position="top" + > +
    + {value && value.length > 0 && Array.isArray(value) ? ( + + ) : ( + + + + )} +
    +
    + ); + + useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); + + return ( + + {({ open }: { open: boolean }) => { + if (open) { + if (!isOpen) setIsOpen(true); + setFetchStates(true); + } else if (isOpen) setIsOpen(false); + + return ( + <> + + {label} + {!hideDropdownArrow && !disabled && ( + +
    + +
    + + setQuery(e.target.value)} + placeholder="Search" + displayValue={(assigned: any) => assigned?.name} + /> +
    +
    + {filteredOptions ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active && !selected ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( + +

    No matching results

    +
    + ) + ) : ( +

    Loading...

    + )} +
    +
    +
    + + ); + }} +
    + ); +}; diff --git a/web/components/project/priority-select.tsx b/web/components/project/priority-select.tsx new file mode 100644 index 00000000000..4db844b5d44 --- /dev/null +++ b/web/components/project/priority-select.tsx @@ -0,0 +1,173 @@ +import React, { useRef, useState } from "react"; + +// hooks +import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; +// headless ui +import { Combobox } from "@headlessui/react"; +// icons +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { PriorityIcon } from "components/icons"; +// components +import { Tooltip } from "components/ui"; +// types +import { TIssuePriorities } from "types"; +// constants +import { PRIORITIES } from "constants/project"; + +type Props = { + value: TIssuePriorities; + onChange: (data: any) => void; + className?: string; + buttonClassName?: string; + optionsClassName?: string; + hideDropdownArrow?: boolean; + disabled?: boolean; +}; + +export const PrioritySelect: React.FC = ({ + value, + onChange, + className = "", + buttonClassName = "", + optionsClassName = "", + hideDropdownArrow = false, + disabled = false, +}) => { + const [query, setQuery] = useState(""); + const [isOpen, setIsOpen] = useState(false); + + const dropdownBtn = useRef(null); + const dropdownOptions = useRef(null); + + const options = PRIORITIES?.map((priority) => ({ + value: priority, + query: priority, + content: ( +
    + + {priority ?? "None"} +
    + ), + })); + + const filteredOptions = + query === "" + ? options + : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + + const selectedOption = value ?? "None"; + + const label = ( + +
    + + + +
    +
    + ); + + useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); + + return ( + + {({ open }: { open: boolean }) => { + if (open) { + if (!isOpen) setIsOpen(true); + } else if (isOpen) setIsOpen(false); + + return ( + <> + + {label} + {!hideDropdownArrow && !disabled && ( + +
    + +
    + + setQuery(e.target.value)} + placeholder="Search" + displayValue={(assigned: any) => assigned?.name} + /> +
    +
    + {filteredOptions ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active && !selected ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( + +

    No matching results

    +
    + ) + ) : ( +

    Loading...

    + )} +
    +
    +
    + + ); + }} +
    + ); +}; diff --git a/web/components/states/index.ts b/web/components/states/index.ts index 39285a77f5d..96c26eee34e 100644 --- a/web/components/states/index.ts +++ b/web/components/states/index.ts @@ -2,3 +2,4 @@ export * from "./create-update-state-inline"; export * from "./create-state-modal"; export * from "./delete-state-modal"; export * from "./single-state"; +export * from "./state-select"; diff --git a/web/components/states/state-select.tsx b/web/components/states/state-select.tsx new file mode 100644 index 00000000000..22e4ef11511 --- /dev/null +++ b/web/components/states/state-select.tsx @@ -0,0 +1,169 @@ +import React, { useRef, useState } from "react"; + +import { useRouter } from "next/router"; + +import useSWR from "swr"; + +// hooks +import useDynamicDropdownPosition from "hooks/use-dynamic-dropdown"; +// services +import projectStateService from "services/project_state.service"; +// headless ui +import { Combobox } from "@headlessui/react"; +// icons +import { ChevronDownIcon } from "@heroicons/react/20/solid"; +import { CheckIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; +import { StateGroupIcon } from "components/icons"; +// types +import { Tooltip } from "components/ui"; +// constants +import { IState } from "types"; +import { STATES_LIST } from "constants/fetch-keys"; +// helper +import { getStatesList } from "helpers/state.helper"; + +type Props = { + value: IState; + onChange: (data: any, states: IState[] | undefined) => void; + className?: string; + buttonClassName?: string; + optionsClassName?: string; + hideDropdownArrow?: boolean; + disabled?: boolean; +}; + +export const StateSelect: React.FC = ({ + value, + onChange, + className = "", + buttonClassName = "", + optionsClassName = "", + hideDropdownArrow = false, + disabled = false, +}) => { + const [query, setQuery] = useState(""); + const [isOpen, setIsOpen] = useState(false); + + const dropdownBtn = useRef(null); + const dropdownOptions = useRef(null); + + const [fetchStates, setFetchStates] = useState(false); + + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + const { data: stateGroups } = useSWR( + workspaceSlug && projectId && fetchStates ? STATES_LIST(projectId as string) : null, + workspaceSlug && projectId && fetchStates + ? () => projectStateService.getStates(workspaceSlug as string, projectId as string) + : null + ); + + const states = getStatesList(stateGroups); + + const options = states?.map((state) => ({ + value: state.id, + query: state.name, + content: ( +
    + + {state.name} +
    + ), + })); + + const filteredOptions = + query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + + const label = ( + +
    + {value && } + {value?.name ?? "State"} +
    +
    + ); + + useDynamicDropdownPosition(isOpen, () => setIsOpen(false), dropdownBtn, dropdownOptions); + + return ( + { + onChange(data, states); + }} + disabled={disabled} + > + {({ open }: { open: boolean }) => { + if (open) { + if (!isOpen) setIsOpen(true); + setFetchStates(true); + } else if (isOpen) setIsOpen(false); + + return ( + <> + + {label} + {!hideDropdownArrow && !disabled && +
    + +
    + + setQuery(e.target.value)} + placeholder="Search" + displayValue={(assigned: any) => assigned?.name} + /> +
    +
    + {filteredOptions ? ( + filteredOptions.length > 0 ? ( + filteredOptions.map((option) => ( + + `flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active && !selected ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ selected }) => ( + <> + {option.content} + {selected && } + + )} + + )) + ) : ( + +

    No matching results

    +
    + ) + ) : ( +

    Loading...

    + )} +
    +
    +
    + + ); + }} +
    + ); +}; diff --git a/web/components/workspace/sidebar-quick-action.tsx b/web/components/workspace/sidebar-quick-action.tsx index 4c7dda3b99b..8923abc141e 100644 --- a/web/components/workspace/sidebar-quick-action.tsx +++ b/web/components/workspace/sidebar-quick-action.tsx @@ -3,8 +3,6 @@ import React, { useState } from "react"; // ui import { Icon } from "components/ui"; import { ChevronDown, PenSquare } from "lucide-react"; -// headless ui -import { Menu, Transition } from "@headlessui/react"; // hooks import useLocalStorage from "hooks/use-local-storage"; // components @@ -17,10 +15,7 @@ export const WorkspaceSidebarQuickAction = () => { const [isDraftIssueModalOpen, setIsDraftIssueModalOpen] = useState(false); - const { storedValue, clearValue } = useLocalStorage( - "draftedIssue", - JSON.stringify(undefined) - ); + const { storedValue, clearValue } = useLocalStorage("draftedIssue", JSON.stringify({})); return ( <> @@ -31,18 +26,17 @@ export const WorkspaceSidebarQuickAction = () => { onSubmit={() => { localStorage.removeItem("draftedIssue"); clearValue(); - setIsDraftIssueModalOpen(false); }} fieldsToShow={["all"]} />
    { > - {storedValue &&
    } + {storedValue && Object.keys(JSON.parse(storedValue)).length > 0 && ( + <> +
    + + - {storedValue && ( -
    - - {({ open }) => ( - <> -
    - - - -
    - - -
    - - - -
    -
    -
    - - )} -
    -
    +
    +
    + +
    +
    + )}
    diff --git a/web/hooks/use-dynamic-dropdown.tsx b/web/hooks/use-dynamic-dropdown.tsx new file mode 100644 index 00000000000..7bee1bd0cef --- /dev/null +++ b/web/hooks/use-dynamic-dropdown.tsx @@ -0,0 +1,64 @@ +import React, { useCallback, useEffect } from "react"; + +// hook +import useOutsideClickDetector from "./use-outside-click-detector"; + +/** + * Custom hook for dynamic dropdown position calculation. + * @param isOpen - Indicates whether the dropdown is open. + * @param handleClose - Callback to handle closing the dropdown. + * @param buttonRef - Ref object for the button triggering the dropdown. + * @param dropdownRef - Ref object for the dropdown element. + */ + +const useDynamicDropdownPosition = ( + isOpen: boolean, + handleClose: () => void, + buttonRef: React.RefObject, + dropdownRef: React.RefObject +) => { + const handlePosition = useCallback(() => { + const button = buttonRef.current; + const dropdown = dropdownRef.current; + + if (!dropdown || !button) return; + + const buttonRect = button.getBoundingClientRect(); + const dropdownRect = dropdown.getBoundingClientRect(); + + const { innerHeight, innerWidth, scrollX, scrollY } = window; + + let top: number = buttonRect.bottom + scrollY; + if (top + dropdownRect.height > innerHeight) top = innerHeight - dropdownRect.height; + + let left: number = buttonRect.left + scrollX + (buttonRect.width - dropdownRect.width) / 2; + if (left + dropdownRect.width > innerWidth) left = innerWidth - dropdownRect.width; + + dropdown.style.top = `${Math.max(top, 5)}px`; + dropdown.style.left = `${Math.max(left, 5)}px`; + }, [buttonRef, dropdownRef]); + + useEffect(() => { + if (isOpen) handlePosition(); + }, [handlePosition, isOpen]); + + useOutsideClickDetector(dropdownRef, () => { + if (isOpen) handleClose(); + }); + + const handleResize = useCallback(() => { + if (isOpen) { + handlePosition(); + } + }, [handlePosition, isOpen]); + + useEffect(() => { + window.addEventListener("resize", handleResize); + + return () => { + window.removeEventListener("resize", handleResize); + }; + }, [isOpen, handleResize]); +}; + +export default useDynamicDropdownPosition; diff --git a/web/services/csv.services.ts b/web/services/csv.service.ts similarity index 100% rename from web/services/csv.services.ts rename to web/services/csv.service.ts From 9b41b5baf56f0c65f73f841ef5357d82f1851c78 Mon Sep 17 00:00:00 2001 From: sriram veeraghanta Date: Thu, 21 Sep 2023 16:54:11 +0530 Subject: [PATCH 029/102] chore: store fixes --- .../issues/peek-overview/layout.tsx | 274 +++++++++--------- web/store/issue_detail.ts | 77 +++-- 2 files changed, 169 insertions(+), 182 deletions(-) diff --git a/web/components/issues/peek-overview/layout.tsx b/web/components/issues/peek-overview/layout.tsx index 57bcb904c6d..1ae0c3aa8a4 100644 --- a/web/components/issues/peek-overview/layout.tsx +++ b/web/components/issues/peek-overview/layout.tsx @@ -26,110 +26,121 @@ type Props = { export type TPeekOverviewModes = "side" | "modal" | "full"; -export const IssuePeekOverview: React.FC = observer( - ({ handleMutation, projectId, readOnly, workspaceSlug }) => { - const [isSidePeekOpen, setIsSidePeekOpen] = useState(false); - const [isModalPeekOpen, setIsModalPeekOpen] = useState(false); - const [peekOverviewMode, setPeekOverviewMode] = useState("side"); - const [deleteIssueModal, setDeleteIssueModal] = useState(false); +export const IssuePeekOverview: React.FC = observer(({ handleMutation, projectId, readOnly, workspaceSlug }) => { + const [isSidePeekOpen, setIsSidePeekOpen] = useState(false); + const [isModalPeekOpen, setIsModalPeekOpen] = useState(false); + const [peekOverviewMode, setPeekOverviewMode] = useState("side"); + const [deleteIssueModal, setDeleteIssueModal] = useState(false); - const router = useRouter(); - const { peekIssue } = router.query; + const router = useRouter(); + const { peekIssue } = router.query; - const { issues: issuesStore } = useMobxStore(); - const { deleteIssue, getIssueById, issues, updateIssue } = issuesStore; + const { issueDetail: issueDetailStore } = useMobxStore(); + const { deleteIssue, getIssueById, issues, updateIssue } = issueDetailStore; - const issue = issues[peekIssue?.toString() ?? ""]; + const issue = issues[peekIssue?.toString() ?? ""]; - const { user } = useUser(); + const { user } = useUser(); - const handleClose = () => { - const { query } = router; - delete query.peekIssue; + const handleClose = () => { + const { query } = router; + delete query.peekIssue; - router.push({ - pathname: router.pathname, - query: { ...query }, - }); - }; + router.push({ + pathname: router.pathname, + query: { ...query }, + }); + }; - const handleUpdateIssue = async (formData: Partial) => { - if (!issue || !user) return; + const handleUpdateIssue = async (formData: Partial) => { + if (!issue || !user) return; - await updateIssue(workspaceSlug, projectId, issue.id, formData, user); - mutate(PROJECT_ISSUES_ACTIVITY(issue.id)); - handleMutation(); - }; + await updateIssue(workspaceSlug, projectId, issue.id, formData, user); + mutate(PROJECT_ISSUES_ACTIVITY(issue.id)); + handleMutation(); + }; - const handleDeleteIssue = async () => { - if (!issue || !user) return; + const handleDeleteIssue = async () => { + if (!issue || !user) return; - await deleteIssue(workspaceSlug, projectId, issue.id, user); - handleMutation(); + await deleteIssue(workspaceSlug, projectId, issue.id, user); + handleMutation(); - handleClose(); - }; + handleClose(); + }; - useEffect(() => { - if (!peekIssue) return; + useEffect(() => { + if (!peekIssue) return; - getIssueById(workspaceSlug, projectId, peekIssue.toString()); - }, [getIssueById, peekIssue, projectId, workspaceSlug]); + getIssueById(workspaceSlug, projectId, peekIssue.toString()); + }, [getIssueById, peekIssue, projectId, workspaceSlug]); - useEffect(() => { - if (peekIssue) { - if (peekOverviewMode === "side") { - setIsSidePeekOpen(true); - setIsModalPeekOpen(false); - } else { - setIsModalPeekOpen(true); - setIsSidePeekOpen(false); - } + useEffect(() => { + if (peekIssue) { + if (peekOverviewMode === "side") { + setIsSidePeekOpen(true); + setIsModalPeekOpen(false); } else { + setIsModalPeekOpen(true); setIsSidePeekOpen(false); - setIsModalPeekOpen(false); } - }, [peekIssue, peekOverviewMode]); - - return ( - <> - setDeleteIssueModal(false)} - data={issue ? { ...issue } : null} - onSubmit={handleDeleteIssue} - user={user} - /> - - -
    - - - setDeleteIssueModal(true)} - handleUpdateIssue={handleUpdateIssue} - issue={issue} - mode={peekOverviewMode} - readOnly={readOnly} - setMode={(mode) => setPeekOverviewMode(mode)} - workspaceSlug={workspaceSlug} - /> - - -
    -
    -
    - - + } else { + setIsSidePeekOpen(false); + setIsModalPeekOpen(false); + } + }, [peekIssue, peekOverviewMode]); + + return ( + <> + setDeleteIssueModal(false)} + data={issue ? { ...issue } : null} + onSubmit={handleDeleteIssue} + user={user} + /> + + +
    + + + setDeleteIssueModal(true)} + handleUpdateIssue={handleUpdateIssue} + issue={issue} + mode={peekOverviewMode} + readOnly={readOnly} + setMode={(mode) => setPeekOverviewMode(mode)} + workspaceSlug={workspaceSlug} + /> + + +
    +
    +
    + + + +
    + +
    = observer( leaveFrom="opacity-100" leaveTo="opacity-0" > -
    + +
    + {peekOverviewMode === "modal" && ( + setDeleteIssueModal(true)} + handleUpdateIssue={handleUpdateIssue} + issue={issue} + mode={peekOverviewMode} + readOnly={readOnly} + setMode={(mode) => setPeekOverviewMode(mode)} + workspaceSlug={workspaceSlug} + /> + )} + {peekOverviewMode === "full" && ( + setDeleteIssueModal(true)} + handleUpdateIssue={handleUpdateIssue} + issue={issue} + mode={peekOverviewMode} + readOnly={readOnly} + setMode={(mode) => setPeekOverviewMode(mode)} + workspaceSlug={workspaceSlug} + /> + )} +
    +
    -
    - - -
    - {peekOverviewMode === "modal" && ( - setDeleteIssueModal(true)} - handleUpdateIssue={handleUpdateIssue} - issue={issue} - mode={peekOverviewMode} - readOnly={readOnly} - setMode={(mode) => setPeekOverviewMode(mode)} - workspaceSlug={workspaceSlug} - /> - )} - {peekOverviewMode === "full" && ( - setDeleteIssueModal(true)} - handleUpdateIssue={handleUpdateIssue} - issue={issue} - mode={peekOverviewMode} - readOnly={readOnly} - setMode={(mode) => setPeekOverviewMode(mode)} - workspaceSlug={workspaceSlug} - /> - )} -
    -
    -
    -
    -
    -
    - - ); - } -); +
    + + + + ); +}); diff --git a/web/store/issue_detail.ts b/web/store/issue_detail.ts index 352769810f2..ea5a31d21c8 100644 --- a/web/store/issue_detail.ts +++ b/web/store/issue_detail.ts @@ -3,57 +3,43 @@ import { observable, action, makeObservable, runInAction } from "mobx"; import { RootStore } from "./root"; // services import { IssueService } from "services/issue.service"; +import { IIssue } from "types"; export type IPeekMode = "side" | "modal" | "full"; -export interface IIssueViewDetailStore { +export interface IIssueDetailStore { loader: boolean; error: any | null; peekId: string | null; peekMode: IPeekMode | null; - issue_detail: { - workspace: { - [key: string]: { - issues: { - [key: string]: any; - }; - }; - }; + issues: { + [key: string]: IIssue; }; setPeekId: (issueId: string | null) => void; setPeekMode: (issueId: IPeekMode | null) => void; - // fetch issue details - fetchIssueDetailsAsync: (workspaceId: string, projectId: string, issueId: string) => void; + fetchIssueDetails: (workspaceId: string, projectId: string, issueId: string) => void; // creating issue - createIssueAsync: (workspaceId: string, projectId: string, issueId: string, data: any) => void; + createIssue: (workspaceId: string, projectId: string, issueId: string, data: any) => void; // updating issue - updateIssueAsync: (workspaceId: string, projectId: string, issueId: string, data: any) => void; + updateIssue: (workspaceId: string, projectId: string, issueId: string, data: any) => void; // deleting issue - deleteIssueAsync: (workspaceId: string, projectId: string, issueId: string) => void; + deleteIssue: (workspaceId: string, projectId: string, issueId: string) => void; } -class IssueViewDetailStore implements IIssueViewDetailStore { +class IssueDetailStore implements IIssueDetailStore { loader: boolean = false; error: any | null = null; peekId: string | null = null; peekMode: IPeekMode | null = null; - issue_detail: { - workspace: { - [key: string]: { - issues: { - [key: string]: any; - }; - }; - }; - } = { - workspace: {}, - }; + issues: { + [key: string]: IIssue; + } = {}; // root store rootStore; @@ -63,20 +49,21 @@ class IssueViewDetailStore implements IIssueViewDetailStore { constructor(_rootStore: RootStore) { makeObservable(this, { // observable - loader: observable, - error: observable, + loader: observable.ref, + error: observable.ref, + + peekId: observable.ref, + peekMode: observable.ref, - peekId: observable, - peekMode: observable, - issue_detail: observable, + issues: observable.ref, setPeekId: action, setPeekMode: action, - fetchIssueDetailsAsync: action, - createIssueAsync: action, - updateIssueAsync: action, - deleteIssueAsync: action, + fetchIssueDetails: action, + createIssue: action, + updateIssue: action, + deleteIssue: action, }); this.rootStore = _rootStore; @@ -84,20 +71,22 @@ class IssueViewDetailStore implements IIssueViewDetailStore { } setPeekId = (issueId: string | null) => (this.peekId = issueId); + setPeekMode = (mode: IPeekMode | null) => (this.peekMode = mode); - fetchIssueDetailsAsync = async (workspaceId: string, projectId: string, issueId: string) => { + fetchIssueDetails = async (workspaceId: string, projectId: string, issueId: string) => { try { this.loader = true; this.error = null; - console.log("workspaceId", workspaceId); - console.log("projectId", projectId); - console.log("issueId", issueId); + const issueDetailsResponse = await this.issueService.retrieve(workspaceId, projectId, issueId); runInAction(() => { this.loader = false; this.error = null; + this.issues = { + [issueId]: issueDetailsResponse, + }; }); } catch (error) { console.log("error in fetching issue details", error); @@ -107,7 +96,7 @@ class IssueViewDetailStore implements IIssueViewDetailStore { } }; - createIssueAsync = async (workspaceId: string, projectId: string, issueId: string, data: any) => { + createIssue = async (workspaceId: string, projectId: string, issueId: string, data: any) => { try { this.loader = true; this.error = null; @@ -129,12 +118,12 @@ class IssueViewDetailStore implements IIssueViewDetailStore { } }; - updateIssueAsync = async (workspaceId: string, projectId: string, issueId: string, data: any) => { + updateIssue = async (workspaceId: string, projectId: string, issueId: string, data: any) => { try { this.loader = true; this.error = null; - const filteredParams = this.rootStore.issueFilters.getComputedFilters( + const filteredParams = this.rootStore.issueFilter.getComputedFilters( workspaceId, projectId, null, @@ -161,7 +150,7 @@ class IssueViewDetailStore implements IIssueViewDetailStore { } }; - deleteIssueAsync = async (workspaceId: string, projectId: string, issueId: string) => { + deleteIssue = async (workspaceId: string, projectId: string, issueId: string) => { try { this.loader = true; this.error = null; @@ -183,4 +172,4 @@ class IssueViewDetailStore implements IIssueViewDetailStore { }; } -export default IssueViewDetailStore; +export default IssueDetailStore; From daa3094911616eb34b89786dff6d540bdac8f71b Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal <65252264+aaryan610@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:50:43 +0530 Subject: [PATCH 030/102] chore: update issue detail store to handle peek overview (#2237) * chore: dynamic position dropdown (#2138) * chore: dynamic position state dropdown for issue view * style: state select dropdown styling * fix: state icon attribute names * chore: state select dynamic dropdown * chore: member select dynamic dropdown * chore: label select dynamic dropdown * chore: priority select dynamic dropdown * chore: label select dropdown improvement * refactor: state dropdown location * chore: dropdown improvement and code refactor * chore: dynamic dropdown hook type added --------- Co-authored-by: Aaryan Khandelwal * fix: fields not getting selected in the create issue form (#2212) * fix: hydration error and draft issue workflow * fix: build error * fix: properties getting de-selected after create, module & cycle not getting auto-select on the form * fix: display layout, props being updated directly * chore: sub issues count in individual issue (#2221) * Implemented nested issues in the sub issues section in issue detail page (#2233) * feat: subissues infinte level * feat: updated UI for sub issues * feat: subissues new ui and nested sub issues in issue detail * chore: removed repeated code * refactor: product updates modal layout (#2225) * fix: handle no issues in custom analytics (#2226) * fix: activity label color (#2227) * fix: profile issues layout switch (#2228) * chore: update service imports * chore: update issue detail store to handle peek overview --------- Co-authored-by: Anmol Singh Bhatia <121005188+anmolsinghbhatia@users.noreply.github.com> Co-authored-by: Dakshesh Jain <65905942+dakshesh14@users.noreply.github.com> Co-authored-by: Bavisetti Narayan <72156168+NarayanBavisetti@users.noreply.github.com> Co-authored-by: guru_sainath --- .../custom-analytics/graph/index.tsx | 1 - web/components/core/activity.tsx | 86 +++--- .../core/views/board-view/all-boards.tsx | 2 +- web/components/issues/delete-issue-modal.tsx | 12 +- web/components/issues/draft-issue-modal.tsx | 6 +- web/components/issues/index.ts | 1 - web/components/issues/main-content.tsx | 4 +- .../issues/peek-overview/layout.tsx | 6 +- web/components/issues/sub-issues/index.ts | 1 + web/components/issues/sub-issues/issue.tsx | 171 +++++++++++ .../issues/sub-issues/issues-list.tsx | 80 ++++++ .../issues/sub-issues/progressbar.tsx | 25 ++ .../issues/sub-issues/properties.tsx | 193 +++++++++++++ web/components/issues/sub-issues/root.tsx | 269 ++++++++++++++++++ .../profile/profile-issues-view.tsx | 1 - web/components/project/members-select.tsx | 14 +- web/components/ui/product-updates-modal.tsx | 108 ++++--- web/contexts/profile-issues-context.tsx | 7 +- web/helpers/array.helper.ts | 7 +- web/store/issue.ts | 64 ++++- web/store/issue_detail.ts | 145 ++++++---- 21 files changed, 1022 insertions(+), 181 deletions(-) create mode 100644 web/components/issues/sub-issues/index.ts create mode 100644 web/components/issues/sub-issues/issue.tsx create mode 100644 web/components/issues/sub-issues/issues-list.tsx create mode 100644 web/components/issues/sub-issues/progressbar.tsx create mode 100644 web/components/issues/sub-issues/properties.tsx create mode 100644 web/components/issues/sub-issues/root.tsx diff --git a/web/components/analytics/custom-analytics/graph/index.tsx b/web/components/analytics/custom-analytics/graph/index.tsx index 349f9884db0..733d1743729 100644 --- a/web/components/analytics/custom-analytics/graph/index.tsx +++ b/web/components/analytics/custom-analytics/graph/index.tsx @@ -9,7 +9,6 @@ import { findStringWithMostCharacters } from "helpers/array.helper"; import { generateBarColor } from "helpers/analytics.helper"; // types import { IAnalyticsParams, IAnalyticsResponse } from "types"; -// constants type Props = { analytics: IAnalyticsResponse; diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index 7c2798e7a92..3a011d49f25 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -1,5 +1,9 @@ import { useRouter } from "next/router"; +import useSWR from "swr"; + +// services +import issuesService from "services/issue.service"; // icons import { Icon, Tooltip } from "components/ui"; import { CopyPlus } from "lucide-react"; @@ -10,26 +14,22 @@ import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { capitalizeFirstLetter } from "helpers/string.helper"; // types import { IIssueActivity } from "types"; +// fetch-keys +import { WORKSPACE_LABELS } from "constants/fetch-keys"; const IssueLink = ({ activity }: { activity: IIssueActivity }) => { const router = useRouter(); const { workspaceSlug } = router.query; return ( - + - {activity.issue_detail - ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` - : "Issue"} + {activity.issue_detail ? `${activity.project_detail.identifier}-${activity.issue_detail.sequence_id}` : "Issue"} @@ -52,13 +52,29 @@ const UserLink = ({ activity }: { activity: IIssueActivity }) => { ); }; +const LabelPill = ({ labelId }: { labelId: string }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { data: labels } = useSWR( + workspaceSlug ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, + workspaceSlug ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null + ); + + return ( + l.id === labelId)?.color ?? "#000000", + }} + aria-hidden="true" + /> + ); +}; + const activityDetails: { [key: string]: { - message: ( - activity: IIssueActivity, - showIssue: boolean, - workspaceSlug: string - ) => React.ReactNode; + message: (activity: IIssueActivity, showIssue: boolean, workspaceSlug: string) => React.ReactNode; icon: React.ReactNode; }; } = { @@ -151,8 +167,7 @@ const activityDetails: { else return ( <> - removed the blocking issue{" "} - {activity.old_value}. + removed the blocking issue {activity.old_value}. ); }, @@ -208,8 +223,7 @@ const activityDetails: { else return ( <> - removed the relation from{" "} - {activity.old_value}. + removed the relation from {activity.old_value}. ); }, @@ -298,8 +312,7 @@ const activityDetails: { else return ( <> - set the estimate point to{" "} - {activity.new_value} + set the estimate point to {activity.new_value} {showIssue && ( <> {" "} @@ -325,14 +338,8 @@ const activityDetails: { return ( <> added a new label{" "} - -
    +
    {Object.keys(groupedIssues).map((singleGroup, index) => { const currentState = displayFilters?.group_by === "state" diff --git a/web/components/issues/delete-issue-modal.tsx b/web/components/issues/delete-issue-modal.tsx index 67e8c88c9a5..81e2d62634d 100644 --- a/web/components/issues/delete-issue-modal.tsx +++ b/web/components/issues/delete-issue-modal.tsx @@ -35,9 +35,17 @@ type Props = { data: IIssue | null; user: ICurrentUserResponse | undefined; onSubmit?: () => Promise; + redirection?: boolean; }; -export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, user, onSubmit }) => { +export const DeleteIssueModal: React.FC = ({ + isOpen, + handleClose, + data, + user, + onSubmit, + redirection = true, +}) => { const [isDeleteLoading, setIsDeleteLoading] = useState(false); const router = useRouter(); @@ -122,7 +130,7 @@ export const DeleteIssueModal: React.FC = ({ isOpen, handleClose, data, u message: "Issue deleted successfully", }); - if (issueId) router.back(); + if (issueId && redirection) router.back(); }) .catch((error) => { console.log(error); diff --git a/web/components/issues/draft-issue-modal.tsx b/web/components/issues/draft-issue-modal.tsx index 97d1c18a62a..b1dcf0cc06c 100644 --- a/web/components/issues/draft-issue-modal.tsx +++ b/web/components/issues/draft-issue-modal.tsx @@ -138,8 +138,7 @@ export const CreateUpdateDraftIssueModal: React.FC = (props) = // issue. This has more priority than the project in the url. if (data && data.project) return setActiveProject(data.project); - if (prePopulateData && prePopulateData.project && !activeProject) - return setActiveProject(prePopulateData.project); + if (prePopulateData && prePopulateData.project && !activeProject) return setActiveProject(prePopulateData.project); if (prePopulateData && prePopulateData.project) return setActiveProject(prePopulateData.project); @@ -349,8 +348,7 @@ export const CreateUpdateDraftIssueModal: React.FC = (props) = }; if (action === "createDraft") await createDraftIssue(payload); - else if (action === "updateDraft" || action === "convertToNewIssue") - await updateDraftIssue(payload); + else if (action === "updateDraft" || action === "convertToNewIssue") await updateDraftIssue(payload); else if (action === "createNewIssue") await createIssue(payload); clearDraftIssueLocalStorage(); diff --git a/web/components/issues/index.ts b/web/components/issues/index.ts index 1c51031f36c..6b83e7ef438 100644 --- a/web/components/issues/index.ts +++ b/web/components/issues/index.ts @@ -12,7 +12,6 @@ export * from "./main-content"; export * from "./modal"; export * from "./parent-issues-list-modal"; export * from "./sidebar"; -export * from "./sub-issues-list"; export * from "./label"; export * from "./issue-reaction"; export * from "./peek-overview"; diff --git a/web/components/issues/main-content.tsx b/web/components/issues/main-content.tsx index d4dd636cbc7..e5f2c651cd0 100644 --- a/web/components/issues/main-content.tsx +++ b/web/components/issues/main-content.tsx @@ -18,9 +18,9 @@ import { IssueAttachmentUpload, IssueAttachments, IssueDescriptionForm, - SubIssuesList, IssueReaction, } from "components/issues"; +import { SubIssuesRoot } from "./sub-issues"; // ui import { CustomMenu } from "components/ui"; // icons @@ -170,7 +170,7 @@ export const IssueMainContent: React.FC = ({ issueDetails, submitChanges,
    - +
    diff --git a/web/components/issues/peek-overview/layout.tsx b/web/components/issues/peek-overview/layout.tsx index 1ae0c3aa8a4..101cb1857ca 100644 --- a/web/components/issues/peek-overview/layout.tsx +++ b/web/components/issues/peek-overview/layout.tsx @@ -36,7 +36,7 @@ export const IssuePeekOverview: React.FC = observer(({ handleMutation, pr const { peekIssue } = router.query; const { issueDetail: issueDetailStore } = useMobxStore(); - const { deleteIssue, getIssueById, issues, updateIssue } = issueDetailStore; + const { deleteIssue, fetchIssueDetails, issues, updateIssue } = issueDetailStore; const issue = issues[peekIssue?.toString() ?? ""]; @@ -72,8 +72,8 @@ export const IssuePeekOverview: React.FC = observer(({ handleMutation, pr useEffect(() => { if (!peekIssue) return; - getIssueById(workspaceSlug, projectId, peekIssue.toString()); - }, [getIssueById, peekIssue, projectId, workspaceSlug]); + fetchIssueDetails(workspaceSlug, projectId, peekIssue.toString()); + }, [fetchIssueDetails, peekIssue, projectId, workspaceSlug]); useEffect(() => { if (peekIssue) { diff --git a/web/components/issues/sub-issues/index.ts b/web/components/issues/sub-issues/index.ts new file mode 100644 index 00000000000..1efe34c51ec --- /dev/null +++ b/web/components/issues/sub-issues/index.ts @@ -0,0 +1 @@ +export * from "./root"; diff --git a/web/components/issues/sub-issues/issue.tsx b/web/components/issues/sub-issues/issue.tsx new file mode 100644 index 00000000000..2e3d8acdbb3 --- /dev/null +++ b/web/components/issues/sub-issues/issue.tsx @@ -0,0 +1,171 @@ +import React from "react"; +// next imports +import Link from "next/link"; +// lucide icons +import { + ChevronDown, + ChevronRight, + X, + Pencil, + Trash, + Link as LinkIcon, + Loader, +} from "lucide-react"; +// components +import { SubIssuesRootList } from "./issues-list"; +import { IssueProperty } from "./properties"; +// ui +import { Tooltip, CustomMenu } from "components/ui"; + +// types +import { ICurrentUserResponse, IIssue } from "types"; + +export interface ISubIssues { + workspaceSlug: string; + projectId: string; + parentIssue: IIssue; + issue: any; + spacingLeft?: number; + user: ICurrentUserResponse | undefined; + editable: boolean; + removeIssueFromSubIssues: (parentIssueId: string, issue: IIssue) => void; + issuesVisibility: string[]; + handleIssuesVisibility: (issueId: string) => void; + copyText: (text: string) => void; + handleIssueCrudOperation: ( + key: "create" | "existing" | "edit" | "delete", + issueId: string, + issue?: IIssue | null + ) => void; +} + +export const SubIssues: React.FC = ({ + workspaceSlug, + projectId, + parentIssue, + issue, + spacingLeft = 0, + user, + editable, + removeIssueFromSubIssues, + issuesVisibility, + handleIssuesVisibility, + copyText, + handleIssueCrudOperation, +}) => ( +
    + {issue && ( +
    +
    + {issue?.sub_issues_count > 0 && ( + <> + {true ? ( +
    handleIssuesVisibility(issue?.id)} + > + {issuesVisibility && issuesVisibility.includes(issue?.id) ? ( + + ) : ( + + )} +
    + ) : ( + + )} + + )} +
    + + +
    +
    +
    + {issue.project_detail.identifier}-{issue?.sequence_id} +
    + +
    {issue?.name}
    +
    +
    + + +
    + +
    + +
    + + {editable && ( + handleIssueCrudOperation("edit", parentIssue?.id, issue)} + > +
    + + Edit issue +
    +
    + )} + + {editable && ( + handleIssueCrudOperation("delete", parentIssue?.id, issue)} + > +
    + + Delete issue +
    +
    + )} + + +
    + + Copy issue link +
    +
    +
    +
    + + {editable && ( +
    removeIssueFromSubIssues(parentIssue?.id, issue)} + > + +
    + )} +
    + )} + + {issuesVisibility.includes(issue?.id) && issue?.sub_issues_count > 0 && ( + + )} +
    +); diff --git a/web/components/issues/sub-issues/issues-list.tsx b/web/components/issues/sub-issues/issues-list.tsx new file mode 100644 index 00000000000..01df9c34932 --- /dev/null +++ b/web/components/issues/sub-issues/issues-list.tsx @@ -0,0 +1,80 @@ +import React from "react"; +// swr +import useSWR from "swr"; +// components +import { SubIssues } from "./issue"; +// types +import { ICurrentUserResponse, IIssue } from "types"; +// services +import issuesService from "services/issue.service"; +// fetch keys +import { SUB_ISSUES } from "constants/fetch-keys"; + +export interface ISubIssuesRootList { + workspaceSlug: string; + projectId: string; + parentIssue: IIssue; + spacingLeft?: number; + user: ICurrentUserResponse | undefined; + editable: boolean; + removeIssueFromSubIssues: (parentIssueId: string, issue: IIssue) => void; + issuesVisibility: string[]; + handleIssuesVisibility: (issueId: string) => void; + copyText: (text: string) => void; + handleIssueCrudOperation: ( + key: "create" | "existing" | "edit" | "delete", + issueId: string, + issue?: IIssue | null + ) => void; +} + +export const SubIssuesRootList: React.FC = ({ + workspaceSlug, + projectId, + parentIssue, + spacingLeft = 10, + user, + editable, + removeIssueFromSubIssues, + issuesVisibility, + handleIssuesVisibility, + copyText, + handleIssueCrudOperation, +}) => { + const { data: issues, isLoading } = useSWR( + workspaceSlug && projectId && parentIssue && parentIssue?.id ? SUB_ISSUES(parentIssue?.id) : null, + workspaceSlug && projectId && parentIssue && parentIssue?.id + ? () => issuesService.subIssues(workspaceSlug, projectId, parentIssue.id) + : null + ); + + return ( +
    + {issues && + issues.sub_issues && + issues.sub_issues.length > 0 && + issues.sub_issues.map((issue: IIssue) => ( + + ))} + +
    10 ? `border-l border-custom-border-100` : ``}`} + style={{ left: `${spacingLeft - 12}px` }} + /> +
    + ); +}; diff --git a/web/components/issues/sub-issues/progressbar.tsx b/web/components/issues/sub-issues/progressbar.tsx new file mode 100644 index 00000000000..368078a3d09 --- /dev/null +++ b/web/components/issues/sub-issues/progressbar.tsx @@ -0,0 +1,25 @@ +export interface IProgressBar { + total: number; + done: number; +} + +export const ProgressBar = ({ total = 0, done = 0 }: IProgressBar) => { + const calPercentage = (doneValue: number, totalValue: number): string => { + if (doneValue === 0 || totalValue === 0) return (0).toFixed(0); + return ((100 * doneValue) / totalValue).toFixed(0); + }; + + return ( +
    +
    +
    +
    +
    +
    +
    {calPercentage(done, total)}% Done
    +
    + ); +}; diff --git a/web/components/issues/sub-issues/properties.tsx b/web/components/issues/sub-issues/properties.tsx new file mode 100644 index 00000000000..278992cd52e --- /dev/null +++ b/web/components/issues/sub-issues/properties.tsx @@ -0,0 +1,193 @@ +import React from "react"; +// swr +import { mutate } from "swr"; +// services +import issuesService from "services/issue.service"; +import trackEventServices from "services/track_event.service"; +// components +import { ViewDueDateSelect, ViewStartDateSelect } from "components/issues"; +import { MembersSelect, PrioritySelect } from "components/project"; +import { StateSelect } from "components/states"; +// hooks +import useIssuesProperties from "hooks/use-issue-properties"; +// types +import { ICurrentUserResponse, IIssue, IState } from "types"; +// fetch-keys +import { SUB_ISSUES } from "constants/fetch-keys"; + +export interface IIssueProperty { + workspaceSlug: string; + projectId: string; + parentIssue: IIssue; + issue: IIssue; + user: ICurrentUserResponse | undefined; + editable: boolean; +} + +export const IssueProperty: React.FC = ({ + workspaceSlug, + projectId, + parentIssue, + issue, + user, + editable, +}) => { + const [properties] = useIssuesProperties(workspaceSlug, projectId); + + const handlePriorityChange = (data: any) => { + partialUpdateIssue({ priority: data }); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_PRIORITY", + user + ); + }; + + const handleStateChange = (data: string, states: IState[] | undefined) => { + const oldState = states?.find((s) => s.id === issue.state); + const newState = states?.find((s) => s.id === data); + + partialUpdateIssue({ + state: data, + state_detail: newState, + }); + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_STATE", + user + ); + if (oldState?.group !== "completed" && newState?.group !== "completed") { + trackEventServices.trackIssueMarkedAsDoneEvent( + { + workspaceSlug: issue.workspace_detail.slug, + workspaceId: issue.workspace_detail.id, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + user + ); + } + }; + + const handleAssigneeChange = (data: any) => { + const newData = issue.assignees ?? []; + + if (newData.includes(data)) newData.splice(newData.indexOf(data), 1); + else newData.push(data); + + partialUpdateIssue({ assignees_list: data }); + + trackEventServices.trackIssuePartialPropertyUpdateEvent( + { + workspaceSlug, + workspaceId: issue.workspace, + projectId: issue.project_detail.id, + projectIdentifier: issue.project_detail.identifier, + projectName: issue.project_detail.name, + issueId: issue.id, + }, + "ISSUE_PROPERTY_UPDATE_ASSIGNEE", + user + ); + }; + + const partialUpdateIssue = async (data: Partial) => { + mutate( + workspaceSlug && parentIssue ? SUB_ISSUES(parentIssue.id) : null, + (elements: any) => { + const _elements = { ...elements }; + const _issues = _elements.sub_issues.map((element: IIssue) => + element.id === issue.id ? { ...element, ...data } : element + ); + _elements["sub_issues"] = [..._issues]; + return _elements; + }, + false + ); + + const issueResponse = await issuesService.patchIssue(workspaceSlug as string, issue.project, issue.id, data, user); + + mutate( + SUB_ISSUES(parentIssue.id), + (elements: any) => { + const _elements = elements.sub_issues.map((element: IIssue) => + element.id === issue.id ? issueResponse : element + ); + elements["sub_issues"] = _elements; + return elements; + }, + true + ); + }; + + return ( +
    + {properties.priority && ( +
    + +
    + )} + + {properties.state && ( +
    + +
    + )} + + {properties.start_date && issue.start_date && ( +
    + +
    + )} + + {properties.due_date && issue.target_date && ( +
    + +
    + )} + + {properties.assignee && ( +
    + +
    + )} +
    + ); +}; diff --git a/web/components/issues/sub-issues/root.tsx b/web/components/issues/sub-issues/root.tsx new file mode 100644 index 00000000000..3b32a0df903 --- /dev/null +++ b/web/components/issues/sub-issues/root.tsx @@ -0,0 +1,269 @@ +import React from "react"; +// next imports +import { useRouter } from "next/router"; +// swr +import useSWR, { mutate } from "swr"; +// lucide icons +import { Plus, ChevronRight, ChevronDown } from "lucide-react"; +// components +import { ExistingIssuesListModal } from "components/core"; +import { CreateUpdateIssueModal, DeleteIssueModal } from "components/issues"; +import { SubIssuesRootList } from "./issues-list"; +import { ProgressBar } from "./progressbar"; +// ui +import { CustomMenu } from "components/ui"; +// hooks +import { useProjectMyMembership } from "contexts/project-member.context"; +// helpers +import { copyTextToClipboard } from "helpers/string.helper"; +// types +import { ICurrentUserResponse, IIssue, ISearchIssueResponse } from "types"; +// services +import issuesService from "services/issue.service"; +// fetch keys +import { SUB_ISSUES } from "constants/fetch-keys"; + +export interface ISubIssuesRoot { + parentIssue: IIssue; + + user: ICurrentUserResponse | undefined; + editable: boolean; +} + +export const SubIssuesRoot: React.FC = ({ parentIssue, user, editable }) => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query as { workspaceSlug: string; projectId: string }; + + const { memberRole } = useProjectMyMembership(); + + const { data: issues } = useSWR( + workspaceSlug && projectId && parentIssue && parentIssue?.id ? SUB_ISSUES(parentIssue?.id) : null, + workspaceSlug && projectId && parentIssue && parentIssue?.id + ? () => issuesService.subIssues(workspaceSlug, projectId, parentIssue.id) + : null + ); + + const [issuesVisibility, setIssuesVisibility] = React.useState([parentIssue?.id]); + const handleIssuesVisibility = (issueId: string) => { + if (issuesVisibility.includes(issueId)) { + setIssuesVisibility(issuesVisibility.filter((i: string) => i !== issueId)); + } else { + setIssuesVisibility([...issuesVisibility, issueId]); + } + }; + + const [issueCrudOperation, setIssueCrudOperation] = React.useState<{ + create: { toggle: boolean; issueId: string | null }; + existing: { toggle: boolean; issueId: string | null }; + edit: { toggle: boolean; issueId: string | null; issue: IIssue | null }; + delete: { toggle: boolean; issueId: string | null; issue: IIssue | null }; + }>({ + create: { + toggle: false, + issueId: null, + }, + existing: { + toggle: false, + issueId: null, + }, + edit: { + toggle: false, + issueId: null, // parent issue id for mutation + issue: null, + }, + delete: { + toggle: false, + issueId: null, // parent issue id for mutation + issue: null, + }, + }); + const handleIssueCrudOperation = ( + key: "create" | "existing" | "edit" | "delete", + issueId: string | null, + issue: IIssue | null = null + ) => { + setIssueCrudOperation({ + ...issueCrudOperation, + [key]: { + toggle: !issueCrudOperation[key].toggle, + issueId: issueId, + issue: issue, + }, + }); + }; + + const addAsSubIssueFromExistingIssues = async (data: ISearchIssueResponse[]) => { + if (!workspaceSlug || !parentIssue || issueCrudOperation?.existing?.issueId === null) return; + const issueId = issueCrudOperation?.existing?.issueId; + const payload = { + sub_issue_ids: data.map((i) => i.id), + }; + + await issuesService.addSubIssues(workspaceSlug, projectId, issueId, payload).finally(() => { + if (issueId) mutate(SUB_ISSUES(issueId)); + }); + }; + + const removeIssueFromSubIssues = async (parentIssueId: string, issue: IIssue) => { + if (!workspaceSlug || !parentIssue || !issue?.id) return; + issuesService.patchIssue(workspaceSlug, projectId, issue.id, { parent: null }, user).finally(() => { + if (parentIssueId) mutate(SUB_ISSUES(parentIssueId)); + }); + }; + + const copyText = (text: string) => { + const originURL = typeof window !== "undefined" && window.location.origin ? window.location.origin : ""; + copyTextToClipboard(`${originURL}/${text}`).then(() => { + // setToastAlert({ + // type: "success", + // title: "Link Copied!", + // message: "Issue link copied to clipboard.", + // }); + }); + }; + + const isEditable = memberRole?.isGuest || memberRole?.isViewer ? false : true; + + const mutateSubIssues = (parentIssueId: string | null) => { + if (parentIssueId) mutate(SUB_ISSUES(parentIssueId)); + }; + + return ( +
    + {parentIssue && parentIssue?.sub_issues_count > 0 ? ( + <> + {/* header */} +
    +
    handleIssuesVisibility(parentIssue?.id)} + > +
    + {issuesVisibility.includes(parentIssue?.id) ? ( + + ) : ( + + )} +
    +
    Sub-issues
    +
    ({parentIssue?.sub_issues_count})
    +
    + +
    + +
    + + {isEditable && issuesVisibility.includes(parentIssue?.id) && ( +
    +
    handleIssueCrudOperation("create", parentIssue?.id)} + > + Add sub-issue +
    +
    handleIssueCrudOperation("existing", parentIssue?.id)} + > + Add an existing issue +
    +
    + )} +
    + + {/* issues */} + {issuesVisibility.includes(parentIssue?.id) && ( +
    + +
    + )} + + ) : ( + isEditable && ( +
    +
    No sub issues are available
    + <> + + + Add sub-issue + + } + buttonClassName="whitespace-nowrap" + position="left" + noBorder + noChevron + > + handleIssueCrudOperation("create", parentIssue?.id)}> + Create new + + handleIssueCrudOperation("existing", parentIssue?.id)}> + Add an existing issue + + + +
    + ) + )} + + {isEditable && issueCrudOperation?.create?.toggle && ( + handleIssueCrudOperation("create", null)} + /> + )} + + {isEditable && issueCrudOperation?.existing?.toggle && issueCrudOperation?.existing?.issueId && ( + handleIssueCrudOperation("existing", null)} + searchParams={{ sub_issue: true, issue_id: issueCrudOperation?.existing?.issueId }} + handleOnSubmit={addAsSubIssueFromExistingIssues} + workspaceLevelToggle + /> + )} + + {isEditable && issueCrudOperation?.edit?.toggle && issueCrudOperation?.edit?.issueId && ( + { + mutateSubIssues(issueCrudOperation?.edit?.issueId); + handleIssueCrudOperation("edit", null, null); + }} + data={issueCrudOperation?.edit?.issue} + /> + )} + + {isEditable && issueCrudOperation?.delete?.toggle && issueCrudOperation?.delete?.issueId && ( + { + mutateSubIssues(issueCrudOperation?.delete?.issueId); + handleIssueCrudOperation("delete", null, null); + }} + data={issueCrudOperation?.delete?.issue} + user={user} + redirection={false} + /> + )} +
    + ); +}; diff --git a/web/components/profile/profile-issues-view.tsx b/web/components/profile/profile-issues-view.tsx index e5a2096caa1..8d1c5e37401 100644 --- a/web/components/profile/profile-issues-view.tsx +++ b/web/components/profile/profile-issues-view.tsx @@ -49,7 +49,6 @@ export const ProfileIssuesView = () => { groupedIssues, mutateProfileIssues, displayFilters, - setDisplayFilters, isEmpty, filters, setFilters, diff --git a/web/components/project/members-select.tsx b/web/components/project/members-select.tsx index f99d8517488..1ac216446c3 100644 --- a/web/components/project/members-select.tsx +++ b/web/components/project/members-select.tsx @@ -74,15 +74,13 @@ export const MembersSelect: React.FC = ({ })); const filteredOptions = - query === "" - ? options - : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); + query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); const label = ( 0 + membersDetails && membersDetails.length > 0 ? membersDetails.map((assignee) => assignee?.display_name).join(", ") : "No Assignee" } @@ -126,15 +124,11 @@ export const MembersSelect: React.FC = ({ ref={dropdownBtn} type="button" className={`flex items-center justify-between gap-1 w-full text-xs ${ - disabled - ? "cursor-not-allowed text-custom-text-200" - : "cursor-pointer hover:bg-custom-background-80" + disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80" } ${buttonClassName}`} > {label} - {!hideDropdownArrow && !disabled && ( -