mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
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:
parent
4bb99d5fbf
commit
9d0056cfee
@ -10,7 +10,7 @@ import { IIssue, IUserLite } from "types";
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
members: IUserLite[] | undefined;
|
||||
onChange: (data: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, data: Partial<IIssue>) => void;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
};
|
||||
@ -18,7 +18,7 @@ type Props = {
|
||||
export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ 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<Props> = ({ 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
|
||||
|
@ -18,7 +18,7 @@ export const SpreadsheetAttachmentColumn: React.FC<Props> = (props) => {
|
||||
|
||||
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"}
|
||||
</div>
|
||||
|
||||
|
@ -19,7 +19,7 @@ export const SpreadsheetCreatedOnColumn: React.FC<Props> = ({ issue, expandedIss
|
||||
|
||||
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)}
|
||||
</div>
|
||||
|
||||
|
@ -9,7 +9,7 @@ import { IIssue } from "types";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
onChange: (data: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, data: Partial<IIssue>) => void;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
};
|
||||
@ -17,14 +17,19 @@ type Props = {
|
||||
export const SpreadsheetDueDateColumn: React.FC<Props> = ({ 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 (
|
||||
<>
|
||||
<ViewDueDateSelect
|
||||
issue={issue}
|
||||
onChange={(val) => 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}
|
||||
/>
|
||||
|
@ -7,7 +7,7 @@ import { IIssue } from "types";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
onChange: (formData: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
};
|
||||
@ -17,15 +17,20 @@ export const SpreadsheetEstimateColumn: React.FC<Props> = (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 (
|
||||
<>
|
||||
<IssuePropertyEstimates
|
||||
projectId={issue.project_detail?.id ?? null}
|
||||
value={issue.estimate_point}
|
||||
onChange={(data) => 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}
|
||||
|
@ -9,7 +9,7 @@ import { IIssue, IIssueLabel } from "types";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
onChange: (formData: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
|
||||
labels: IIssueLabel[] | undefined;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
@ -20,7 +20,7 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (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> = (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}
|
||||
|
@ -18,7 +18,7 @@ export const SpreadsheetLinkColumn: React.FC<Props> = (props) => {
|
||||
|
||||
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"}
|
||||
</div>
|
||||
|
||||
|
@ -9,7 +9,7 @@ import { IIssue } from "types";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
onChange: (data: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, data: Partial<IIssue>) => void;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
};
|
||||
@ -17,14 +17,19 @@ type Props = {
|
||||
export const SpreadsheetPriorityColumn: React.FC<Props> = ({ 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 (
|
||||
<>
|
||||
<PrioritySelect
|
||||
value={issue.priority}
|
||||
onChange={(data) => 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}
|
||||
|
@ -9,7 +9,7 @@ import { IIssue } from "types";
|
||||
|
||||
type Props = {
|
||||
issue: IIssue;
|
||||
onChange: (formData: Partial<IIssue>) => void;
|
||||
onChange: (issue: IIssue, formData: Partial<IIssue>) => void;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
};
|
||||
@ -17,14 +17,19 @@ type Props = {
|
||||
export const SpreadsheetStartDateColumn: React.FC<Props> = ({ 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 (
|
||||
<>
|
||||
<ViewStartDateSelect
|
||||
issue={issue}
|
||||
onChange={(val) => 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}
|
||||
/>
|
||||
|
@ -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<IIssue>) => void;
|
||||
onChange: (issue: IIssue, data: Partial<IIssue>) => void;
|
||||
states: IState[] | undefined;
|
||||
expandedIssues: string[];
|
||||
disabled: boolean;
|
||||
@ -20,7 +22,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = (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> = (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
|
||||
|
@ -18,7 +18,7 @@ export const SpreadsheetSubIssueColumn: React.FC<Props> = (props) => {
|
||||
|
||||
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"}
|
||||
</div>
|
||||
|
||||
|
@ -21,7 +21,7 @@ export const SpreadsheetUpdatedOnColumn: React.FC<Props> = (props) => {
|
||||
|
||||
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)}
|
||||
</div>
|
||||
|
||||
|
@ -163,18 +163,13 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
||||
{issues?.map((issue) => {
|
||||
const disableUserActions = !canEditProperties(issue.project);
|
||||
return (
|
||||
<div
|
||||
key={`${property}-${issue.id}`}
|
||||
className={`h-fit ${
|
||||
disableUserActions ? "" : "cursor-pointer hover:bg-custom-background-80"
|
||||
}`}
|
||||
>
|
||||
<div key={`${property}-${issue.id}`} className={`h-fit ${disableUserActions ? "" : "cursor-pointer"}`}>
|
||||
{property === "state" ? (
|
||||
<SpreadsheetStateColumn
|
||||
disabled={disableUserActions}
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
states={states}
|
||||
/>
|
||||
) : property === "priority" ? (
|
||||
@ -182,14 +177,14 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
||||
disabled={disableUserActions}
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "estimate" ? (
|
||||
<SpreadsheetEstimateColumn
|
||||
disabled={disableUserActions}
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "assignee" ? (
|
||||
<SpreadsheetAssigneeColumn
|
||||
@ -197,7 +192,7 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
members={members}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "labels" ? (
|
||||
<SpreadsheetLabelColumn
|
||||
@ -205,21 +200,21 @@ export const SpreadsheetColumn: React.FC<Props> = (props) => {
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
labels={labels}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "start_date" ? (
|
||||
<SpreadsheetStartDateColumn
|
||||
disabled={disableUserActions}
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "due_date" ? (
|
||||
<SpreadsheetDueDateColumn
|
||||
disabled={disableUserActions}
|
||||
expandedIssues={expandedIssues}
|
||||
issue={issue}
|
||||
onChange={(data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
onChange={(issue: IIssue, data: Partial<IIssue>) => handleUpdateIssue(issue, data)}
|
||||
/>
|
||||
) : property === "created_on" ? (
|
||||
<SpreadsheetCreatedOnColumn expandedIssues={expandedIssues} issue={issue} />
|
||||
|
@ -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<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 {
|
||||
subIssues: subIssuesResponse?.sub_issues ?? [],
|
||||
isLoading,
|
||||
mutateSubIssues,
|
||||
};
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user