fix: spreadsheet layout sub-issues property update (#3110)

* fix: spreadsheet subissues property update

* fix: hover effect for sub-issues

* refactor: mutate sub-issues
This commit is contained in:
Lakhan Baheti 2023-12-13 23:07:26 +05:30 committed by GitHub
parent 4bb99d5fbf
commit 9d0056cfee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 103 additions and 47 deletions

View File

@ -10,7 +10,7 @@ import { IIssue, IUserLite } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
members: IUserLite[] | undefined; members: IUserLite[] | undefined;
onChange: (data: Partial<IIssue>) => void; onChange: (issue: IIssue, data: Partial<IIssue>) => void;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
}; };
@ -18,7 +18,7 @@ type Props = {
export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onChange, expandedIssues, disabled }) => { export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onChange, expandedIssues, disabled }) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
@ -26,8 +26,13 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onC
projectId={issue.project_detail?.id ?? null} projectId={issue.project_detail?.id ?? null}
value={issue.assignees} value={issue.assignees}
defaultOptions={issue?.assignee_details ? issue.assignee_details : []} defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
onChange={(data) => onChange({ assignees: data })} onChange={(data) => {
className="h-11 w-full border-b-[0.5px] border-custom-border-200" 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 " buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1 "
noLabelBorder noLabelBorder
hideDropdownArrow hideDropdownArrow

View File

@ -18,7 +18,7 @@ export const SpreadsheetAttachmentColumn: React.FC<Props> = (props) => {
return ( return (
<> <>
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200"> <div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80">
{issue.attachment_count} {issue.attachment_count === 1 ? "attachment" : "attachments"} {issue.attachment_count} {issue.attachment_count === 1 ? "attachment" : "attachments"}
</div> </div>

View File

@ -19,7 +19,7 @@ export const SpreadsheetCreatedOnColumn: React.FC<Props> = ({ issue, expandedIss
return ( return (
<> <>
<div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200"> <div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80">
{renderLongDetailDateFormat(issue.created_at)} {renderLongDetailDateFormat(issue.created_at)}
</div> </div>

View File

@ -9,7 +9,7 @@ import { IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (data: Partial<IIssue>) => void; onChange: (issue: IIssue, data: Partial<IIssue>) => void;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
}; };
@ -17,14 +17,19 @@ type Props = {
export const SpreadsheetDueDateColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => { export const SpreadsheetDueDateColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
<ViewDueDateSelect <ViewDueDateSelect
issue={issue} issue={issue}
onChange={(val) => onChange({ target_date: val })} onChange={(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(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 noBorder
disabled={disabled} disabled={disabled}
/> />

View File

@ -7,7 +7,7 @@ import { IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (formData: Partial<IIssue>) => void; onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
}; };
@ -17,15 +17,20 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = (props) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
<IssuePropertyEstimates <IssuePropertyEstimates
projectId={issue.project_detail?.id ?? null} projectId={issue.project_detail?.id ?? null}
value={issue.estimate_point} value={issue.estimate_point}
onChange={(data) => onChange({ estimate_point: data })} onChange={(data) => {
className="h-11 w-full border-b-[0.5px] border-custom-border-200" 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" buttonClassName="h-full w-full px-2.5 py-1 !shadow-none !border-0"
hideDropdownArrow hideDropdownArrow
disabled={disabled} disabled={disabled}

View File

@ -9,7 +9,7 @@ import { IIssue, IIssueLabel } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (formData: Partial<IIssue>) => void; onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
labels: IIssueLabel[] | undefined; labels: IIssueLabel[] | undefined;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
@ -20,7 +20,7 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (props) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
@ -28,8 +28,13 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (props) => {
projectId={issue.project_detail?.id ?? null} projectId={issue.project_detail?.id ?? null}
value={issue.labels} value={issue.labels}
defaultOptions={issue?.label_details ? issue.label_details : []} defaultOptions={issue?.label_details ? issue.label_details : []}
onChange={(data) => onChange({ labels: data })} onChange={(data) => {
className="h-11 w-full border-b-[0.5px] border-custom-border-200" 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" buttonClassName="px-2.5 h-full"
hideDropdownArrow hideDropdownArrow
maxRender={1} maxRender={1}

View File

@ -18,7 +18,7 @@ export const SpreadsheetLinkColumn: React.FC<Props> = (props) => {
return ( return (
<> <>
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200"> <div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80">
{issue.link_count} {issue.link_count === 1 ? "link" : "links"} {issue.link_count} {issue.link_count === 1 ? "link" : "links"}
</div> </div>

View File

@ -9,7 +9,7 @@ import { IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (data: Partial<IIssue>) => void; onChange: (issue: IIssue, data: Partial<IIssue>) => void;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
}; };
@ -17,14 +17,19 @@ type Props = {
export const SpreadsheetPriorityColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => { export const SpreadsheetPriorityColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
<PrioritySelect <PrioritySelect
value={issue.priority} value={issue.priority}
onChange={(data) => onChange({ priority: data })} onChange={(data) => {
className="h-11 w-full border-b-[0.5px] border-custom-border-200" 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" buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1"
showTitle showTitle
highlightUrgentPriority={false} highlightUrgentPriority={false}

View File

@ -9,7 +9,7 @@ import { IIssue } from "types";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (formData: Partial<IIssue>) => void; onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
}; };
@ -17,14 +17,19 @@ type Props = {
export const SpreadsheetStartDateColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => { export const SpreadsheetStartDateColumn: React.FC<Props> = ({ issue, onChange, expandedIssues, disabled }) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
<ViewStartDateSelect <ViewStartDateSelect
issue={issue} issue={issue}
onChange={(val) => onChange({ start_date: val })} onChange={(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(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 noBorder
disabled={disabled} disabled={disabled}
/> />

View File

@ -6,10 +6,12 @@ import { IssuePropertyState } from "../../properties";
import useSubIssue from "hooks/use-sub-issue"; import useSubIssue from "hooks/use-sub-issue";
// types // types
import { IIssue, IState } from "types"; import { IIssue, IState } from "types";
import { mutate } from "swr";
import { SUB_ISSUES } from "constants/fetch-keys";
type Props = { type Props = {
issue: IIssue; issue: IIssue;
onChange: (data: Partial<IIssue>) => void; onChange: (issue: IIssue, data: Partial<IIssue>) => void;
states: IState[] | undefined; states: IState[] | undefined;
expandedIssues: string[]; expandedIssues: string[];
disabled: boolean; disabled: boolean;
@ -20,7 +22,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = (props) => {
const isExpanded = expandedIssues.indexOf(issue.id) > -1; 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 ( return (
<> <>
@ -28,7 +30,12 @@ export const SpreadsheetStateColumn: React.FC<Props> = (props) => {
projectId={issue.project_detail?.id ?? null} projectId={issue.project_detail?.id ?? null}
value={issue.state} value={issue.state}
defaultOptions={issue?.state_detail ? [issue.state_detail] : []} 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" className="w-full !h-11 border-b-[0.5px] border-custom-border-200"
buttonClassName="!shadow-none !border-0 h-full w-full" buttonClassName="!shadow-none !border-0 h-full w-full"
hideDropdownArrow hideDropdownArrow

View File

@ -18,7 +18,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = (props) => {
return ( return (
<> <>
<div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200"> <div className="flex h-11 w-full items-center px-2.5 py-1 text-xs border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80">
{issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"} {issue.sub_issues_count} {issue.sub_issues_count === 1 ? "sub-issue" : "sub-issues"}
</div> </div>

View File

@ -21,7 +21,7 @@ export const SpreadsheetUpdatedOnColumn: React.FC<Props> = (props) => {
return ( return (
<> <>
<div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200"> <div className="flex h-11 w-full items-center justify-center text-xs border-b-[0.5px] border-custom-border-200 hover:bg-custom-background-80">
{renderLongDetailDateFormat(issue.updated_at)} {renderLongDetailDateFormat(issue.updated_at)}
</div> </div>

View File

@ -163,18 +163,13 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
{issues?.map((issue) => { {issues?.map((issue) => {
const disableUserActions = !canEditProperties(issue.project); const disableUserActions = !canEditProperties(issue.project);
return ( return (
<div <div key={`${property}-${issue.id}`} className={`h-fit ${disableUserActions ? "" : "cursor-pointer"}`}>
key={`${property}-${issue.id}`}
className={`h-fit ${
disableUserActions ? "" : "cursor-pointer hover:bg-custom-background-80"
}`}
>
{property === "state" ? ( {property === "state" ? (
<SpreadsheetStateColumn <SpreadsheetStateColumn
disabled={disableUserActions} disabled={disableUserActions}
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
states={states} states={states}
/> />
) : property === "priority" ? ( ) : property === "priority" ? (
@ -182,14 +177,14 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
disabled={disableUserActions} disabled={disableUserActions}
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "estimate" ? ( ) : property === "estimate" ? (
<SpreadsheetEstimateColumn <SpreadsheetEstimateColumn
disabled={disableUserActions} disabled={disableUserActions}
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "assignee" ? ( ) : property === "assignee" ? (
<SpreadsheetAssigneeColumn <SpreadsheetAssigneeColumn
@ -197,7 +192,7 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
members={members} members={members}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "labels" ? ( ) : property === "labels" ? (
<SpreadsheetLabelColumn <SpreadsheetLabelColumn
@ -205,21 +200,21 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
labels={labels} labels={labels}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "start_date" ? ( ) : property === "start_date" ? (
<SpreadsheetStartDateColumn <SpreadsheetStartDateColumn
disabled={disableUserActions} disabled={disableUserActions}
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "due_date" ? ( ) : property === "due_date" ? (
<SpreadsheetDueDateColumn <SpreadsheetDueDateColumn
disabled={disableUserActions} disabled={disableUserActions}
expandedIssues={expandedIssues} expandedIssues={expandedIssues}
issue={issue} issue={issue}
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)} onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
/> />
) : property === "created_on" ? ( ) : property === "created_on" ? (
<SpreadsheetCreatedOnColumn expandedIssues={expandedIssues} issue={issue} /> <SpreadsheetCreatedOnColumn expandedIssues={expandedIssues} issue={issue} />

View File

@ -1,11 +1,11 @@
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import useSWR from "swr"; import useSWR, { mutate } from "swr";
// services // services
import { IssueService } from "services/issue"; import { IssueService } from "services/issue";
// types // types
import { ISubIssueResponse } from "types"; import { IIssue, ISubIssueResponse } from "types";
// fetch-keys // fetch-keys
import { SUB_ISSUES } from "constants/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 shouldFetch ? () => issueService.subIssues(workspaceSlug as string, projectId as string, issueId as string) : null
); );
const mutateSubIssues = (issue: IIssue, data: Partial<IIssue>) => {
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 { return {
subIssues: subIssuesResponse?.sub_issues ?? [], subIssues: subIssuesResponse?.sub_issues ?? [],
isLoading, isLoading,
mutateSubIssues,
}; };
}; };