From 9d0056cfee474eb78d3676bc314e5cd0978a1349 Mon Sep 17 00:00:00 2001 From: Lakhan Baheti <94619783+1akhanBaheti@users.noreply.github.com> Date: Wed, 13 Dec 2023 23:07:26 +0530 Subject: [PATCH] fix: spreadsheet layout sub-issues property update (#3110) * fix: spreadsheet subissues property update * fix: hover effect for sub-issues * refactor: mutate sub-issues --- .../spreadsheet/columns/assignee-column.tsx | 13 ++++++--- .../spreadsheet/columns/attachment-column.tsx | 2 +- .../spreadsheet/columns/created-on-column.tsx | 2 +- .../spreadsheet/columns/due-date-column.tsx | 13 ++++++--- .../spreadsheet/columns/estimate-column.tsx | 13 ++++++--- .../spreadsheet/columns/label-column.tsx | 13 ++++++--- .../spreadsheet/columns/link-column.tsx | 2 +- .../spreadsheet/columns/priority-column.tsx | 13 ++++++--- .../spreadsheet/columns/start-date-column.tsx | 13 ++++++--- .../spreadsheet/columns/state-column.tsx | 13 +++++++-- .../spreadsheet/columns/sub-issue-column.tsx | 2 +- .../spreadsheet/columns/updated-on-column.tsx | 2 +- .../spreadsheet/spreadsheet-column.tsx | 21 ++++++-------- web/hooks/use-sub-issue.tsx | 28 +++++++++++++++++-- 14 files changed, 103 insertions(+), 47 deletions(-) diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/assignee-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/assignee-column.tsx index 6a5732a13..3d2e96499 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/assignee-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/assignee-column.tsx @@ -10,7 +10,7 @@ import { IIssue, IUserLite } from "types"; type Props = { issue: IIssue; members: IUserLite[] | undefined; - onChange: (data: Partial) => void; + onChange: (issue: IIssue, data: Partial) => void; expandedIssues: string[]; disabled: boolean; }; @@ -18,7 +18,7 @@ type Props = { export const SpreadsheetAssigneeColumn: React.FC = ({ issue, members, onChange, expandedIssues, disabled }) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> @@ -26,8 +26,13 @@ export const SpreadsheetAssigneeColumn: React.FC = ({ issue, members, onC projectId={issue.project_detail?.id ?? null} value={issue.assignees} defaultOptions={issue?.assignee_details ? issue.assignee_details : []} - onChange={(data) => onChange({ assignees: data })} - className="h-11 w-full border-b-[0.5px] border-custom-border-200" + onChange={(data) => { + onChange(issue, { assignees: data }); + if (issue.parent) { + mutateSubIssues(issue, { assignees: data }); + } + }} + className="h-11 w-full border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1 " noLabelBorder hideDropdownArrow diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/attachment-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/attachment-column.tsx index 8c1788a9a..d8d4964a8 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/attachment-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/attachment-column.tsx @@ -18,7 +18,7 @@ export const SpreadsheetAttachmentColumn: React.FC = (props) => { return ( <> -
+
{issue.attachment_count} {issue.attachment_count === 1 ? "attachment" : "attachments"}
diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/created-on-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/created-on-column.tsx index 4360cee11..dfe0e5513 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/created-on-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/created-on-column.tsx @@ -19,7 +19,7 @@ export const SpreadsheetCreatedOnColumn: React.FC = ({ issue, expandedIss return ( <> -
+
{renderLongDetailDateFormat(issue.created_at)}
diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/due-date-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/due-date-column.tsx index 1c151cc47..73d761cf9 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/due-date-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/due-date-column.tsx @@ -9,7 +9,7 @@ import { IIssue } from "types"; type Props = { issue: IIssue; - onChange: (data: Partial) => void; + onChange: (issue: IIssue, data: Partial) => void; expandedIssues: string[]; disabled: boolean; }; @@ -17,14 +17,19 @@ type Props = { export const SpreadsheetDueDateColumn: React.FC = ({ issue, onChange, expandedIssues, disabled }) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> onChange({ target_date: val })} - className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200" + onChange={(val) => { + onChange(issue, { target_date: val }); + if (issue.parent) { + mutateSubIssues(issue, { target_date: val }); + } + }} + className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" noBorder disabled={disabled} /> diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/estimate-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/estimate-column.tsx index f0042db8e..f902c82df 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/estimate-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/estimate-column.tsx @@ -7,7 +7,7 @@ import { IIssue } from "types"; type Props = { issue: IIssue; - onChange: (formData: Partial) => void; + onChange: (issue: IIssue, formData: Partial) => void; expandedIssues: string[]; disabled: boolean; }; @@ -17,15 +17,20 @@ export const SpreadsheetEstimateColumn: React.FC = (props) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> onChange({ estimate_point: data })} - className="h-11 w-full border-b-[0.5px] border-custom-border-200" + onChange={(data) => { + onChange(issue, { estimate_point: data }); + if (issue.parent) { + mutateSubIssues(issue, { estimate_point: data }); + } + }} + className="h-11 w-full border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" buttonClassName="h-full w-full px-2.5 py-1 !shadow-none !border-0" hideDropdownArrow disabled={disabled} diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/label-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/label-column.tsx index 0fa2abee1..b034afd9f 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/label-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/label-column.tsx @@ -9,7 +9,7 @@ import { IIssue, IIssueLabel } from "types"; type Props = { issue: IIssue; - onChange: (formData: Partial) => void; + onChange: (issue: IIssue, formData: Partial) => void; labels: IIssueLabel[] | undefined; expandedIssues: string[]; disabled: boolean; @@ -20,7 +20,7 @@ export const SpreadsheetLabelColumn: React.FC = (props) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> @@ -28,8 +28,13 @@ export const SpreadsheetLabelColumn: React.FC = (props) => { projectId={issue.project_detail?.id ?? null} value={issue.labels} defaultOptions={issue?.label_details ? issue.label_details : []} - onChange={(data) => onChange({ labels: data })} - className="h-11 w-full border-b-[0.5px] border-custom-border-200" + onChange={(data) => { + onChange(issue, { labels: data }); + if (issue.parent) { + mutateSubIssues(issue, { assignees: data }); + } + }} + className="h-11 w-full border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" buttonClassName="px-2.5 h-full" hideDropdownArrow maxRender={1} diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/link-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/link-column.tsx index aa9337e75..13713f630 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/link-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/link-column.tsx @@ -18,7 +18,7 @@ export const SpreadsheetLinkColumn: React.FC = (props) => { return ( <> -
+
{issue.link_count} {issue.link_count === 1 ? "link" : "links"}
diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/priority-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/priority-column.tsx index 09e9c53a0..116579a70 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/priority-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/priority-column.tsx @@ -9,7 +9,7 @@ import { IIssue } from "types"; type Props = { issue: IIssue; - onChange: (data: Partial) => void; + onChange: (issue: IIssue, data: Partial) => void; expandedIssues: string[]; disabled: boolean; }; @@ -17,14 +17,19 @@ type Props = { export const SpreadsheetPriorityColumn: React.FC = ({ issue, onChange, expandedIssues, disabled }) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> onChange({ priority: data })} - className="h-11 w-full border-b-[0.5px] border-custom-border-200" + onChange={(data) => { + onChange(issue, { priority: data }); + if (issue.parent) { + mutateSubIssues(issue, { priority: data }); + } + }} + className="h-11 w-full border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1" showTitle highlightUrgentPriority={false} diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/start-date-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/start-date-column.tsx index f3dc3d5b0..3233baadb 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/start-date-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/start-date-column.tsx @@ -9,7 +9,7 @@ import { IIssue } from "types"; type Props = { issue: IIssue; - onChange: (formData: Partial) => void; + onChange: (issue: IIssue, formData: Partial) => void; expandedIssues: string[]; disabled: boolean; }; @@ -17,14 +17,19 @@ type Props = { export const SpreadsheetStartDateColumn: React.FC = ({ issue, onChange, expandedIssues, disabled }) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> onChange({ start_date: val })} - className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200" + onChange={(val) => { + onChange(issue, { start_date: val }); + if (issue.parent) { + mutateSubIssues(issue, { start_date: val }); + } + }} + className="flex !h-11 !w-full max-w-full items-center px-2.5 py-1 border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80" noBorder disabled={disabled} /> diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx index af935f1d6..3a3922c2b 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/state-column.tsx @@ -6,10 +6,12 @@ import { IssuePropertyState } from "../../properties"; import useSubIssue from "hooks/use-sub-issue"; // types import { IIssue, IState } from "types"; +import { mutate } from "swr"; +import { SUB_ISSUES } from "constants/fetch-keys"; type Props = { issue: IIssue; - onChange: (data: Partial) => void; + onChange: (issue: IIssue, data: Partial) => void; states: IState[] | undefined; expandedIssues: string[]; disabled: boolean; @@ -20,7 +22,7 @@ export const SpreadsheetStateColumn: React.FC = (props) => { const isExpanded = expandedIssues.indexOf(issue.id) > -1; - const { subIssues, isLoading } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); + const { subIssues, isLoading, mutateSubIssues } = useSubIssue(issue.project_detail?.id, issue.id, isExpanded); return ( <> @@ -28,7 +30,12 @@ export const SpreadsheetStateColumn: React.FC = (props) => { projectId={issue.project_detail?.id ?? null} value={issue.state} defaultOptions={issue?.state_detail ? [issue.state_detail] : []} - onChange={(data) => onChange({ state: data.id, state_detail: data })} + onChange={(data) => { + onChange(issue, { state: data.id, state_detail: data }); + if (issue.parent) { + mutateSubIssues(issue, { state: data.id, state_detail: data }); + } + }} className="w-full !h-11 border-b-[0.5px] border-custom-border-200" buttonClassName="!shadow-none !border-0 h-full w-full" hideDropdownArrow diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/sub-issue-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/sub-issue-column.tsx index 2122a674f..5f4b8c234 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/sub-issue-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/sub-issue-column.tsx @@ -18,7 +18,7 @@ export const SpreadsheetSubIssueColumn: React.FC = (props) => { return ( <> -
+
{issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
diff --git a/web/components/issues/issue-layouts/spreadsheet/columns/updated-on-column.tsx b/web/components/issues/issue-layouts/spreadsheet/columns/updated-on-column.tsx index f2c49c279..97cc0fcff 100644 --- a/web/components/issues/issue-layouts/spreadsheet/columns/updated-on-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/columns/updated-on-column.tsx @@ -21,7 +21,7 @@ export const SpreadsheetUpdatedOnColumn: React.FC = (props) => { return ( <> -
+
{renderLongDetailDateFormat(issue.updated_at)}
diff --git a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-column.tsx b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-column.tsx index 8b5c8c7a2..7e8cad64a 100644 --- a/web/components/issues/issue-layouts/spreadsheet/spreadsheet-column.tsx +++ b/web/components/issues/issue-layouts/spreadsheet/spreadsheet-column.tsx @@ -163,18 +163,13 @@ export const SpreadsheetColumn: React.FC = (props) => { {issues?.map((issue) => { const disableUserActions = !canEditProperties(issue.project); return ( -
+
{property === "state" ? ( ) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} states={states} /> ) : property === "priority" ? ( @@ -182,14 +177,14 @@ export const SpreadsheetColumn: React.FC = (props) => { disabled={disableUserActions} expandedIssues={expandedIssues} issue={issue} - onChange={(data: Partial) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "estimate" ? ( ) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "assignee" ? ( = (props) => { expandedIssues={expandedIssues} issue={issue} members={members} - onChange={(data: Partial) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "labels" ? ( = (props) => { expandedIssues={expandedIssues} issue={issue} labels={labels} - onChange={(data: Partial) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "start_date" ? ( ) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "due_date" ? ( ) => handleUpdateIssue(issue, data)} + onChange={(issue: IIssue, data: Partial) => handleUpdateIssue(issue, data)} /> ) : property === "created_on" ? ( diff --git a/web/hooks/use-sub-issue.tsx b/web/hooks/use-sub-issue.tsx index a1d2e281c..9da539ee7 100644 --- a/web/hooks/use-sub-issue.tsx +++ b/web/hooks/use-sub-issue.tsx @@ -1,11 +1,11 @@ import { useRouter } from "next/router"; -import useSWR from "swr"; +import useSWR, { mutate } from "swr"; // services import { IssueService } from "services/issue"; // types -import { ISubIssueResponse } from "types"; +import { IIssue, ISubIssueResponse } from "types"; // fetch-keys import { SUB_ISSUES } from "constants/fetch-keys"; @@ -22,9 +22,33 @@ const useSubIssue = (projectId: string, issueId: string, isExpanded: boolean) => shouldFetch ? () => issueService.subIssues(workspaceSlug as string, projectId as string, issueId as string) : null ); + const mutateSubIssues = (issue: IIssue, data: Partial) => { + if (!issue.parent) return; + + mutate( + SUB_ISSUES(issue.parent!), + (prev_data: any) => { + return { + ...prev_data, + sub_issues: prev_data.sub_issues.map((sub_issue: any) => { + if (sub_issue.id === issue.id) { + return { + ...sub_issue, + ...data, + }; + } + return sub_issue; + }), + }; + }, + false + ); + }; + return { subIssues: subIssuesResponse?.sub_issues ?? [], isLoading, + mutateSubIssues, }; };