From fadda7cf040c8b476fc46afaa9d9a2d81c0565f1 Mon Sep 17 00:00:00 2001 From: rahulramesha <71900764+rahulramesha@users.noreply.github.com> Date: Tue, 16 Jan 2024 21:16:12 +0530 Subject: [PATCH] fix: refactor related bugs (#3384) * fix sub issues inside issue detail * close peek over view after opening issue detail * fix error while opening peek overview * fix saving project views --------- Co-authored-by: Rahul R --- .../issues/issue-detail/subscription.tsx | 2 +- .../roots/project-view-root.tsx | 50 +++++++++------- .../issue-layouts/properties/labels.tsx | 24 ++++---- .../issues/issue-layouts/save-filter-view.tsx | 2 +- web/components/issues/peek-overview/view.tsx | 1 + .../issues/sub-issues/issue-list-item.tsx | 8 ++- .../issues/sub-issues/issues-list.tsx | 15 +---- web/components/issues/sub-issues/root.tsx | 33 ++++++----- web/components/views/form.tsx | 16 +++-- web/components/views/view-list-item.tsx | 2 +- .../issue/issue-details/relation.store.ts | 1 - web/store/issue/issue-details/root.store.ts | 7 +-- .../issue/issue-details/sub_issues.store.ts | 58 +++++-------------- web/store/issue/project-views/filter.store.ts | 2 +- web/store/issue/project-views/issue.store.ts | 8 ++- 15 files changed, 105 insertions(+), 124 deletions(-) diff --git a/web/components/issues/issue-detail/subscription.tsx b/web/components/issues/issue-detail/subscription.tsx index 7093f8627..d20bc53cf 100644 --- a/web/components/issues/issue-detail/subscription.tsx +++ b/web/components/issues/issue-detail/subscription.tsx @@ -51,7 +51,7 @@ export const IssueSubscription: FC = observer((props) => { } }; - if (issue?.created_by === currentUserId || issue?.assignee_ids.includes(currentUserId)) return <>; + if (issue?.created_by === currentUserId || issue?.assignee_ids?.includes(currentUserId)) return <>; return (
diff --git a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx index ffbae9ac8..6748676b5 100644 --- a/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx +++ b/web/components/issues/issue-layouts/filters/applied-filters/roots/project-view-root.tsx @@ -28,9 +28,9 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { project: { projectLabels }, } = useLabel(); const { projectStates } = useProjectState(); - const { getViewById, updateView } = useProjectView(); + const { viewMap, updateView } = useProjectView(); // derived values - const viewDetails = viewId ? getViewById(viewId.toString()) : null; + const viewDetails = viewId ? viewMap[viewId.toString()] : null; const userFilters = issueFilters?.filters; // filters whose value not null or empty array const appliedFilters: IIssueFilterOptions = {}; @@ -43,18 +43,30 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => { if (!workspaceSlug || !projectId) return; if (!value) { - updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { - [key]: null, - }); + updateFilters( + workspaceSlug, + projectId, + EIssueFilterType.FILTERS, + { + [key]: null, + }, + viewId + ); return; } let newValues = issueFilters?.filters?.[key] ?? []; newValues = newValues.filter((val) => val !== value); - updateFilters(workspaceSlug, projectId, EIssueFilterType.FILTERS, { - [key]: newValues, - }); + updateFilters( + workspaceSlug, + projectId, + EIssueFilterType.FILTERS, + { + [key]: newValues, + }, + viewId + ); }; const handleClearAllFilters = () => { @@ -67,14 +79,14 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { }; // return if no filters are applied - if (Object.keys(appliedFilters).length === 0) return null; + if (Object.keys(appliedFilters).length === 0 && !areFiltersDifferent(appliedFilters, viewDetails?.filters ?? {})) + return null; const handleUpdateView = () => { if (!workspaceSlug || !projectId || !viewId || !viewDetails) return; updateView(workspaceSlug.toString(), projectId.toString(), viewId.toString(), { - query_data: { - ...viewDetails.query_data, + filters: { ...(appliedFilters ?? {}), }, }); @@ -90,15 +102,13 @@ export const ProjectViewAppliedFiltersRoot: React.FC = observer(() => { states={projectStates} /> - {appliedFilters && - viewDetails?.query_data && - areFiltersDifferent(appliedFilters, viewDetails?.query_data ?? {}) && ( -
- -
- )} + {viewDetails?.filters && areFiltersDifferent(appliedFilters, viewDetails?.filters ?? {}) && ( +
+ +
+ )}
); }); diff --git a/web/components/issues/issue-layouts/properties/labels.tsx b/web/components/issues/issue-layouts/properties/labels.tsx index b22083c07..67295af0f 100644 --- a/web/components/issues/issue-layouts/properties/labels.tsx +++ b/web/components/issues/issue-layouts/properties/labels.tsx @@ -62,6 +62,18 @@ export const IssuePropertyLabels: React.FC = observer((pro if (workspaceSlug && projectId) fetchProjectLabels(workspaceSlug, projectId).then(() => setIsLoading(false)); }; + const { styles, attributes } = usePopper(referenceElement, popperElement, { + placement: placement ?? "bottom-start", + modifiers: [ + { + name: "preventOverflow", + options: { + padding: 12, + }, + }, + ], + }); + if (!value) return null; let projectLabels: IIssueLabel[] = defaultOptions; @@ -86,18 +98,6 @@ export const IssuePropertyLabels: React.FC = observer((pro const filteredOptions = query === "" ? options : options?.filter((option) => option.query.toLowerCase().includes(query.toLowerCase())); - const { styles, attributes } = usePopper(referenceElement, popperElement, { - placement: placement ?? "bottom-start", - modifiers: [ - { - name: "preventOverflow", - options: { - padding: 12, - }, - }, - ], - }); - const label = (
{value.length > 0 ? ( diff --git a/web/components/issues/issue-layouts/save-filter-view.tsx b/web/components/issues/issue-layouts/save-filter-view.tsx index 42fac26ef..8bf2cb211 100644 --- a/web/components/issues/issue-layouts/save-filter-view.tsx +++ b/web/components/issues/issue-layouts/save-filter-view.tsx @@ -20,7 +20,7 @@ export const SaveFilterView: FC = (props) => { setViewModal(false)} /> diff --git a/web/components/issues/peek-overview/view.tsx b/web/components/issues/peek-overview/view.tsx index fbe4d01a5..d422d91e0 100644 --- a/web/components/issues/peek-overview/view.tsx +++ b/web/components/issues/peek-overview/view.tsx @@ -84,6 +84,7 @@ export const IssueView: FC = observer((props) => { router.push({ pathname: `/${workspaceSlug}/projects/${projectId}/${is_archived ? "archived-issues" : "issues"}/${issueId}`, }); + removeRoutePeekId(); }; const handleCopyText = (e: React.MouseEvent) => { diff --git a/web/components/issues/sub-issues/issue-list-item.tsx b/web/components/issues/sub-issues/issue-list-item.tsx index cd25fc10b..0e8fe76a2 100644 --- a/web/components/issues/sub-issues/issue-list-item.tsx +++ b/web/components/issues/sub-issues/issue-list-item.tsx @@ -80,8 +80,12 @@ export const IssueListItem: React.FC = observer((props) => { ) : (
{ - setSubIssueHelpers(parentIssueId, "preview_loader", issue.id); + onClick={async () => { + if (!subIssueHelpers.issue_visibility.includes(issue.id)) { + setSubIssueHelpers(parentIssueId, "preview_loader", issue.id); + await subIssueOperations.fetchSubIssues(workspaceSlug, projectId, issue.id); + setSubIssueHelpers(parentIssueId, "preview_loader", issue.id); + } setSubIssueHelpers(parentIssueId, "issue_visibility", issue.id); }} > diff --git a/web/components/issues/sub-issues/issues-list.tsx b/web/components/issues/sub-issues/issues-list.tsx index 1d9e1ed95..eaa3e098e 100644 --- a/web/components/issues/sub-issues/issues-list.tsx +++ b/web/components/issues/sub-issues/issues-list.tsx @@ -7,7 +7,6 @@ import { IssueListItem } from "./issue-list-item"; // types import { TIssue } from "@plane/types"; import { TSubIssueOperations } from "./root"; -import useSWR from "swr"; export interface IIssueList { workspaceSlug: string; @@ -38,24 +37,12 @@ export const IssueList: FC = observer((props) => { subIssues: { subIssuesByIssueId, subIssueHelpersByIssueId }, } = useIssueDetail(); - useSWR( - workspaceSlug && projectId && parentIssueId - ? `ISSUE_DETAIL_SUB_ISSUES_${workspaceSlug}_${projectId}_${parentIssueId}` - : null, - async () => { - workspaceSlug && - projectId && - parentIssueId && - (await subIssueOperations.fetchSubIssues(workspaceSlug, projectId, parentIssueId)); - } - ); - const subIssueIds = subIssuesByIssueId(parentIssueId); const subIssueHelpers = subIssueHelpersByIssueId(parentIssueId); return ( <> - {subIssueHelpers.preview_loader.includes(parentIssueId) ? "Loading..." : "Hello"} + {subIssueHelpers.preview_loader.includes(parentIssueId) ? "Loading..." : null}
{subIssueIds && diff --git a/web/components/issues/sub-issues/root.tsx b/web/components/issues/sub-issues/root.tsx index a39277e93..967df8541 100644 --- a/web/components/issues/sub-issues/root.tsx +++ b/web/components/issues/sub-issues/root.tsx @@ -1,6 +1,7 @@ import { FC, useMemo, useState } from "react"; import { observer } from "mobx-react-lite"; import { Plus, ChevronRight, ChevronDown, Loader } from "lucide-react"; +import useSWR from "swr"; // hooks import { useIssueDetail } from "hooks/store"; import useToast from "hooks/use-toast"; @@ -33,9 +34,7 @@ export type TSubIssueOperations = { projectId: string, parentIssueId: string, issueId: string, - currentIssue: Partial, - oldIssue?: Partial | undefined, - fromModal?: boolean + data: Partial ) => Promise; removeSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise; deleteSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise; @@ -85,6 +84,18 @@ export const SubIssuesRoot: FC = observer((props) => { }, }); + useSWR( + workspaceSlug && projectId && parentIssueId + ? `ISSUE_DETAIL_SUB_ISSUES_${workspaceSlug}_${projectId}_${parentIssueId}` + : null, + async () => { + workspaceSlug && + projectId && + parentIssueId && + (await subIssueOperations.fetchSubIssues(workspaceSlug, projectId, parentIssueId)); + } + ); + const handleIssueCrudState = ( key: "create" | "existing" | "update" | "delete", _parentIssueId: string | null, @@ -144,13 +155,11 @@ export const SubIssuesRoot: FC = observer((props) => { projectId: string, parentIssueId: string, issueId: string, - currentIssue: Partial, - oldIssue: Partial | undefined = undefined, - fromModal: boolean = false + data: Partial ) => { try { setSubIssueHelpers(parentIssueId, "issue_loader", issueId); - await updateSubIssue(workspaceSlug, projectId, parentIssueId, issueId, currentIssue, oldIssue, fromModal); + await updateSubIssue(workspaceSlug, projectId, parentIssueId, issueId, data); setToastAlert({ type: "success", title: "Sub-issue updated successfully", @@ -386,15 +395,7 @@ export const SubIssuesRoot: FC = observer((props) => { }} data={issueCrudState?.update?.issue ?? undefined} onSubmit={async (_issue: TIssue) => { - await subIssueOperations.updateSubIssue( - workspaceSlug, - projectId, - parentIssueId, - _issue.id, - _issue, - issueCrudState?.update?.issue, - true - ); + await subIssueOperations.updateSubIssue(workspaceSlug, projectId, parentIssueId, _issue.id, _issue); }} /> diff --git a/web/components/views/form.tsx b/web/components/views/form.tsx index ad38a470c..c20354b3d 100644 --- a/web/components/views/form.tsx +++ b/web/components/views/form.tsx @@ -47,7 +47,7 @@ export const ProjectViewForm: React.FC = observer((props) => { }); const selectedFilters: IIssueFilterOptions = {}; - Object.entries(watch("query_data") ?? {}).forEach(([key, value]) => { + Object.entries(watch("filters") ?? {}).forEach(([key, value]) => { if (!value) return; if (Array.isArray(value) && value.length === 0) return; @@ -59,7 +59,7 @@ export const ProjectViewForm: React.FC = observer((props) => { const handleRemoveFilter = (key: keyof IIssueFilterOptions, value: string | null) => { // If value is null then remove all the filters of that key if (!value) { - setValue("query_data", { + setValue("filters", { ...selectedFilters, [key]: null, }); @@ -76,14 +76,18 @@ export const ProjectViewForm: React.FC = observer((props) => { if (selectedFilters?.[key]?.includes(value)) newValues.splice(newValues.indexOf(value), 1); } - setValue("query_data", { + setValue("filters", { ...selectedFilters, [key]: newValues, }); }; const handleCreateUpdateView = async (formData: IProjectView) => { - await handleFormSubmit(formData); + await handleFormSubmit({ + name: formData.name, + description: formData.description, + filters: formData.filters, + } as IProjectView); reset({ ...defaultValues, @@ -93,7 +97,7 @@ export const ProjectViewForm: React.FC = observer((props) => { const clearAllFilters = () => { if (!selectedFilters) return; - setValue("query_data", {}); + setValue("filters", {}); }; useEffect(() => { @@ -156,7 +160,7 @@ export const ProjectViewForm: React.FC = observer((props) => {
( = observer((props) => { }); }; - const totalFilters = calculateTotalFilters(view.query_data ?? {}); + const totalFilters = calculateTotalFilters(view.filters ?? {}); const isEditingAllowed = !!currentProjectRole && currentProjectRole >= EUserProjectRoles.MEMBER; diff --git a/web/store/issue/issue-details/relation.store.ts b/web/store/issue/issue-details/relation.store.ts index f9e0ac5f0..fa32798de 100644 --- a/web/store/issue/issue-details/relation.store.ts +++ b/web/store/issue/issue-details/relation.store.ts @@ -94,7 +94,6 @@ export class IssueRelationStore implements IIssueRelationStore { const relation_key = key as TIssueRelationTypes; const relation_issues = response[relation_key]; const issues = relation_issues.flat().map((issue) => issue.issue_detail); - if (issues && issues.length > 0) this.rootIssueDetailStore.rootIssueStore.issues.addIssue(issues); set( this.relationMap, [issueId, relation_key], diff --git a/web/store/issue/issue-details/root.store.ts b/web/store/issue/issue-details/root.store.ts index 2e8497e01..c03c92130 100644 --- a/web/store/issue/issue-details/root.store.ts +++ b/web/store/issue/issue-details/root.store.ts @@ -208,11 +208,8 @@ export class IssueDetail implements IIssueDetail { projectId: string, parentIssueId: string, issueId: string, - oldIssue: Partial, - currentIssue?: Partial, - fromModal?: boolean - ) => - this.subIssues.updateSubIssue(workspaceSlug, projectId, parentIssueId, issueId, oldIssue, currentIssue, fromModal); + data: Partial + ) => this.subIssues.updateSubIssue(workspaceSlug, projectId, parentIssueId, issueId, data); removeSubIssue = async (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => this.subIssues.removeSubIssue(workspaceSlug, projectId, parentIssueId, issueId); deleteSubIssue = async (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => diff --git a/web/store/issue/issue-details/sub_issues.store.ts b/web/store/issue/issue-details/sub_issues.store.ts index 964c32742..a1bd3f818 100644 --- a/web/store/issue/issue-details/sub_issues.store.ts +++ b/web/store/issue/issue-details/sub_issues.store.ts @@ -28,9 +28,7 @@ export interface IIssueSubIssuesStoreActions { projectId: string, parentIssueId: string, issueId: string, - currentIssue: Partial, - oldIssue?: Partial | undefined, - fromModal?: boolean + data: Partial ) => Promise; removeSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise; deleteSubIssue: (workspaceSlug: string, projectId: string, parentIssueId: string, issueId: string) => Promise; @@ -118,16 +116,15 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore { this.rootIssueDetailStore.rootIssueStore.issues.addIssue(subIssues); - if (subIssues.length > 0) { - runInAction(() => { - set(this.subIssuesStateDistribution, parentIssueId, subIssuesStateDistribution); - set( - this.subIssues, - parentIssueId, - subIssues.map((issue) => issue.id) - ); - }); - } + runInAction(() => { + set(this.subIssuesStateDistribution, parentIssueId, subIssuesStateDistribution); + set( + this.subIssues, + parentIssueId, + subIssues.map((issue) => issue.id) + ); + }); + return response; } catch (error) { throw error; @@ -172,39 +169,16 @@ export class IssueSubIssuesStore implements IIssueSubIssuesStore { projectId: string, parentIssueId: string, issueId: string, - currentIssue: Partial, - oldIssue: Partial | undefined = undefined, - fromModal: boolean = false + data: Partial ) => { try { - if (!fromModal) - await this.rootIssueDetailStore.rootIssueStore.projectIssues.updateIssue( - workspaceSlug, - projectId, - issueId, - currentIssue - ); + await this.rootIssueDetailStore.rootIssueStore.projectIssues.updateIssue(workspaceSlug, projectId, issueId, data); - if (!oldIssue) return; - - if (currentIssue.state_id != oldIssue.state_id) { + if (data.hasOwnProperty("parent_id") && data.parent_id !== parentIssueId) { + runInAction(() => { + pull(this.subIssues[parentIssueId], issueId); + }); } - - if (currentIssue.parent_id != oldIssue.parent_id) { - } - // const updateResponse = await this.rootIssueDetailStore.rootIssueStore.projectIssues.updateIssue( - // workspaceSlug, - // projectId, - // issueId, - // oldIssue - // ); - - // console.log("---"); - // console.log("parentIssueId", parentIssueId); - // console.log("fromModal", fromModal); - // console.log("updateResponse", updateResponse); - // console.log("---"); - return; } catch (error) { throw error; diff --git a/web/store/issue/project-views/filter.store.ts b/web/store/issue/project-views/filter.store.ts index 83bc2e79e..d01f27434 100644 --- a/web/store/issue/project-views/filter.store.ts +++ b/web/store/issue/project-views/filter.store.ts @@ -139,7 +139,7 @@ export class ProjectViewIssuesFilter extends IssueFilterHelperStore implements I try { if (!viewId) throw new Error("View id is required"); - if (isEmpty(this.filters) || isEmpty(this.filters[projectId]) || isEmpty(filters)) return; + if (isEmpty(this.filters) || isEmpty(this.filters[viewId]) || isEmpty(filters)) return; const _filters = { filters: this.filters[viewId].filters as IIssueFilterOptions, diff --git a/web/store/issue/project-views/issue.store.ts b/web/store/issue/project-views/issue.store.ts index 263877849..1908b8a10 100644 --- a/web/store/issue/project-views/issue.store.ts +++ b/web/store/issue/project-views/issue.store.ts @@ -130,11 +130,15 @@ export class ProjectViewIssues extends IssueHelperStore implements IProjectViewI const response = await this.issueService.getIssues(workspaceSlug, projectId, params); runInAction(() => { - set(this.issues, [viewId], Object.keys(response)); + set( + this.issues, + [viewId], + response.map((issue) => issue.id) + ); this.loader = undefined; }); - this.rootIssueStore.issues.addIssue(Object.values(response)); + this.rootIssueStore.issues.addIssue(response); return response; } catch (error) {