fix: activity not coming for blocking/blocked, 'related to' and duplicate (#2189)

* fix: activity not coming for duplicate, relatesd to and for blocked/blocking

refactor: mutation logic to use relation id instead of issue id

* fix: mutation logic and changed keys to be aligned with api

* fix: build error
This commit is contained in:
Dakshesh Jain 2023-09-19 12:58:00 +05:30 committed by GitHub
parent 79bf7d4c0c
commit f6b92fc953
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 142 additions and 98 deletions

View File

@ -2,8 +2,9 @@ import { useRouter } from "next/router";
// icons
import { Icon, Tooltip } from "components/ui";
import { CopyPlus } from "lucide-react";
import { Squares2X2Icon } from "@heroicons/react/24/outline";
import { BlockedIcon, BlockerIcon } from "components/icons";
import { BlockedIcon, BlockerIcon, RelatedIcon } from "components/icons";
// helpers
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { capitalizeFirstLetter } from "helpers/string.helper";
@ -157,7 +158,7 @@ const activityDetails: {
},
icon: <BlockerIcon height="12" width="12" color="#6b7280" />,
},
blocks: {
blocked_by: {
message: (activity) => {
if (activity.old_value === "")
return (
@ -176,6 +177,44 @@ const activityDetails: {
},
icon: <BlockedIcon height="12" width="12" color="#6b7280" />,
},
duplicate: {
message: (activity) => {
if (activity.old_value === "")
return (
<>
marked this issue as duplicate of{" "}
<span className="font-medium text-custom-text-100">{activity.new_value}</span>.
</>
);
else
return (
<>
removed this issue as a duplicate of{" "}
<span className="font-medium text-custom-text-100">{activity.old_value}</span>.
</>
);
},
icon: <CopyPlus size={12} color="#6b7280" />,
},
relates_to: {
message: (activity) => {
if (activity.old_value === "")
return (
<>
marked that this issue relates to{" "}
<span className="font-medium text-custom-text-100">{activity.new_value}</span>.
</>
);
else
return (
<>
removed the relation from{" "}
<span className="font-medium text-custom-text-100">{activity.old_value}</span>.
</>
);
},
icon: <RelatedIcon height="12" width="12" color="#6b7280" />,
},
cycles: {
message: (activity, showIssue, workspaceSlug) => {
if (activity.verb === "created")

View File

@ -73,7 +73,7 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
...selectedIssues.map((issue) => ({
issue: issueId as string,
relation_type: "blocked_by" as const,
related_issue_detail: issue.blocked_issue_detail,
issue_detail: issue.blocked_issue_detail,
related_issue: issue.blocked_issue_detail.id,
})),
],
@ -111,17 +111,17 @@ export const SidebarBlockedSelect: React.FC<Props> = ({
{blockedByIssue && blockedByIssue.length > 0
? blockedByIssue.map((relation) => (
<div
key={relation.related_issue_detail?.id}
key={relation?.id}
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-1.5 py-0.5 text-xs text-red-500 duration-300 hover:border-red-500/20 hover:bg-red-500/20"
>
<a
href={`/${workspaceSlug}/projects/${relation.related_issue_detail?.project_detail.id}/issues/${relation.related_issue_detail?.id}`}
href={`/${workspaceSlug}/projects/${relation.issue_detail?.project_detail.id}/issues/${relation.issue_detail?.id}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1"
>
<BlockedIcon height={10} width={10} />
{`${relation.related_issue_detail?.project_detail.identifier}-${relation.related_issue_detail?.sequence_id}`}
{`${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`}
</a>
<button
type="button"

View File

@ -81,6 +81,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
related_issue_detail: issue.blocker_issue_detail,
})),
],
relation: "blocking",
})
.then((response) => {
submitChanges({
@ -89,7 +90,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
...(response ?? []).map((i: any) => ({
id: i.id,
relation_type: i.relation_type,
issue_detail: i.related_issue_detail,
issue_detail: i.issue_detail,
issue: i.related_issue,
})),
],
@ -118,7 +119,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
{blockerIssue && blockerIssue.length > 0
? blockerIssue.map((relation) => (
<div
key={relation.issue_detail?.id}
key={relation.id}
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-1.5 py-0.5 text-xs text-yellow-500 duration-300 hover:border-yellow-500/20 hover:bg-yellow-500/20"
>
<a
@ -134,9 +135,7 @@ export const SidebarBlockerSelect: React.FC<Props> = ({
type="button"
className="opacity-0 duration-300 group-hover:opacity-100"
onClick={() => {
const updatedBlockers = blockerIssue.filter(
(i) => i.issue_detail?.id !== relation.issue_detail?.id
);
const updatedBlockers = blockerIssue.filter((i) => i.id !== relation.id);
submitChanges({
issue_relations: updatedBlockers,

View File

@ -18,7 +18,7 @@ import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";
type Props = {
issueId?: string;
submitChanges: (formData: Partial<IIssue>) => void;
submitChanges: (formData?: Partial<IIssue>) => void;
watch: UseFormWatch<IIssue>;
disabled?: boolean;
};
@ -69,7 +69,7 @@ export const SidebarDuplicateSelect: React.FC<Props> = (props) => {
related_list: [
...selectedIssues.map((issue) => ({
issue: issueId as string,
related_issue_detail: issue.blocker_issue_detail,
issue_detail: issue.blocker_issue_detail,
related_issue: issue.blocker_issue_detail.id,
relation_type: "duplicate" as const,
})),
@ -90,7 +90,7 @@ export const SidebarDuplicateSelect: React.FC<Props> = (props) => {
?.filter((i) => i.relation_type === "duplicate")
.map((i) => ({
...i,
related_issue_detail: i.issue_detail,
issue_detail: i.issue_detail,
related_issue: i.issue_detail?.id,
})),
];
@ -114,39 +114,35 @@ export const SidebarDuplicateSelect: React.FC<Props> = (props) => {
{duplicateIssuesRelation && duplicateIssuesRelation.length > 0
? duplicateIssuesRelation.map((relation) => (
<div
key={relation.related_issue_detail?.id}
key={relation.issue_detail?.id}
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-1.5 py-0.5 text-xs text-yellow-500 duration-300 hover:border-yellow-500/20 hover:bg-yellow-500/20"
>
<a
href={`/${workspaceSlug}/projects/${relation.related_issue_detail?.project_detail.id}/issues/${relation.related_issue_detail?.id}`}
href={`/${workspaceSlug}/projects/${relation.issue_detail?.project_detail.id}/issues/${relation.issue_detail?.id}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1"
>
<BlockerIcon height={10} width={10} />
{`${relation.related_issue_detail?.project_detail.identifier}-${relation.related_issue_detail?.sequence_id}`}
{`${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`}
</a>
<button
type="button"
className="opacity-0 duration-300 group-hover:opacity-100"
onClick={() => {
const updatedBlockers = duplicateIssuesRelation.filter(
(i) => i.related_issue_detail?.id !== relation.related_issue_detail?.id
);
submitChanges({
related_issues: updatedBlockers,
});
if (!user) return;
issuesService.deleteIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
relation.id,
user
);
issuesService
.deleteIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
relation.id,
user
)
.then(() => {
submitChanges();
});
}}
>
<X className="h-2 w-2" />

View File

@ -18,7 +18,7 @@ import { BlockeIssueDetail, IIssue, ISearchIssueResponse } from "types";
type Props = {
issueId?: string;
submitChanges: (formData: Partial<IIssue>) => void;
submitChanges: (formData?: Partial<IIssue>) => void;
watch: UseFormWatch<IIssue>;
disabled?: boolean;
};
@ -69,7 +69,7 @@ export const SidebarRelatesSelect: React.FC<Props> = (props) => {
related_list: [
...selectedIssues.map((issue) => ({
issue: issueId as string,
related_issue_detail: issue.blocker_issue_detail,
issue_detail: issue.blocker_issue_detail,
related_issue: issue.blocker_issue_detail.id,
relation_type: "relates_to" as const,
})),
@ -90,7 +90,7 @@ export const SidebarRelatesSelect: React.FC<Props> = (props) => {
?.filter((i) => i.relation_type === "relates_to")
.map((i) => ({
...i,
related_issue_detail: i.issue_detail,
issue_detail: i.issue_detail,
related_issue: i.issue_detail?.id,
})),
];
@ -114,39 +114,35 @@ export const SidebarRelatesSelect: React.FC<Props> = (props) => {
{relatedToIssueRelation && relatedToIssueRelation.length > 0
? relatedToIssueRelation.map((relation) => (
<div
key={relation.related_issue_detail?.id}
key={relation.issue_detail?.id}
className="group flex cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-1.5 py-0.5 text-xs text-yellow-500 duration-300 hover:border-yellow-500/20 hover:bg-yellow-500/20"
>
<a
href={`/${workspaceSlug}/projects/${relation.related_issue_detail?.project_detail.id}/issues/${relation.related_issue_detail?.id}`}
href={`/${workspaceSlug}/projects/${relation.issue_detail?.project_detail.id}/issues/${relation.issue_detail?.id}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1"
>
<BlockerIcon height={10} width={10} />
{`${relation.related_issue_detail?.project_detail.identifier}-${relation.related_issue_detail?.sequence_id}`}
{`${relation.issue_detail?.project_detail.identifier}-${relation.issue_detail?.sequence_id}`}
</a>
<button
type="button"
className="opacity-0 duration-300 group-hover:opacity-100"
onClick={() => {
const updatedBlockers = relatedToIssueRelation.filter(
(i) => i.related_issue_detail?.id !== relation.related_issue_detail?.id
);
submitChanges({
related_issues: updatedBlockers,
});
if (!user) return;
issuesService.deleteIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
relation.id,
user
);
issuesService
.deleteIssueRelation(
workspaceSlug as string,
projectId as string,
issueId as string,
relation.id,
user
)
.then(() => {
submitChanges();
});
}}
>
<X className="h-2 w-2" />

View File

@ -509,17 +509,14 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
<SidebarDuplicateSelect
issueId={issueId as string}
submitChanges={(data: any) => {
mutate<IIssue>(
ISSUE_DETAILS(issueId as string),
(prevData) => {
if (!prevData) return prevData;
return {
...prevData,
...data,
};
},
false
);
if (!data) return mutate(ISSUE_DETAILS(issueId as string));
mutate<IIssue>(ISSUE_DETAILS(issueId as string), (prevData) => {
if (!prevData) return prevData;
return {
...prevData,
...data,
};
});
}}
watch={watchIssue}
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}
@ -529,17 +526,14 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
<SidebarRelatesSelect
issueId={issueId as string}
submitChanges={(data: any) => {
mutate<IIssue>(
ISSUE_DETAILS(issueId as string),
(prevData) => {
if (!prevData) return prevData;
return {
...prevData,
...data,
};
},
false
);
if (!data) return mutate(ISSUE_DETAILS(issueId as string));
mutate<IIssue>(ISSUE_DETAILS(issueId as string), (prevData) => {
if (!prevData) return prevData;
return {
...prevData,
...data,
};
});
}}
watch={watchIssue}
disabled={memberRole.isGuest || memberRole.isViewer || uneditable}

View File

@ -1,9 +1,10 @@
import { useRouter } from "next/router";
// icons
import { CopyPlus } from "lucide-react";
import { Icon, Tooltip } from "components/ui";
import { Squares2X2Icon } from "@heroicons/react/24/outline";
import { BlockedIcon, BlockerIcon } from "components/icons";
import { BlockedIcon, BlockerIcon, RelatedIcon } from "components/icons";
// helpers
import { renderShortDateWithYearFormat } from "helpers/date-time.helper";
import { capitalizeFirstLetter } from "helpers/string.helper";
@ -117,7 +118,7 @@ const activityDetails: {
icon: <BlockerIcon height="12" width="12" color="#6b7280" />,
},
blocks: {
blocked_by: {
message: (activity) => (
<>
{activity.old_value === ""
@ -132,6 +133,36 @@ const activityDetails: {
icon: <BlockedIcon height="12" width="12" color="#6b7280" />,
},
duplicate: {
message: (activity) => (
<>
{activity.old_value === ""
? "marked this issue as duplicate of "
: "removed this issue as a duplicate of "}
<span className="font-medium text-custom-text-100">
{activity.verb === "created" ? activity.new_value : activity.old_value}
</span>
.
</>
),
icon: <CopyPlus size={12} color="#6b7280" />,
},
relates_to: {
message: (activity) => (
<>
{activity.old_value === ""
? "marked that this issue relates to "
: "removed the relation from "}
<span className="font-medium text-custom-text-100">
{activity.old_value === "" ? activity.new_value : activity.old_value}
</span>
.
</>
),
icon: <RelatedIcon height="12" width="12" color="#6b7280" />,
},
cycles: {
message: (activity) => (
<>

View File

@ -351,25 +351,23 @@ export const IssuePropertiesDetail: React.FC<Props> = (props) => {
{blockedIssue &&
blockedIssue.map((issue) => (
<div
key={issue.related_issue_detail?.id}
key={issue.issue_detail?.id}
className="group inline-flex mr-1 cursor-pointer items-center gap-1 rounded-2xl border border-custom-border-200 px-1.5 py-0.5 text-xs text-red-500 duration-300 hover:border-red-500/20 hover:bg-red-500/20"
>
<a
href={`/${workspaceSlug}/projects/${issue.related_issue_detail?.project_detail.id}/issues/${issue.related_issue_detail?.id}`}
href={`/${workspaceSlug}/projects/${issue.issue_detail?.project_detail.id}/issues/${issue.issue_detail?.id}`}
target="_blank"
rel="noopener noreferrer"
className="flex items-center gap-1"
>
<BlockedIcon height={10} width={10} />
{`${issue?.related_issue_detail?.project_detail?.identifier}-${issue?.related_issue_detail?.sequence_id}`}
{`${issue?.issue_detail?.project_detail?.identifier}-${issue?.issue_detail?.sequence_id}`}
</a>
<button
type="button"
className="duration-300"
onClick={() => {
const updatedBlocked = blockedIssue.filter(
(i) => i.related_issue_detail?.id !== issue.related_issue_detail?.id
);
const updatedBlocked = blockedIssue.filter((i) => i?.id !== issue?.id);
if (!user) return;

View File

@ -154,6 +154,7 @@ class ProjectIssuesServices extends APIService {
relation_type: "duplicate" | "relates_to" | "blocked_by";
related_issue: string;
}>;
relation?: "blocking" | null;
}
) {
return this.post(

20
web/types/issues.d.ts vendored
View File

@ -76,8 +76,10 @@ export type IssueRelationType = "duplicate" | "relates_to" | "blocked_by";
export interface IssueRelation {
id: string;
issue: string;
related_issue: string;
issue_detail: BlockeIssueDetail;
relation_type: IssueRelationType;
related_issue: string;
relation: "blocking" | null;
}
export interface IIssue {
@ -87,20 +89,8 @@ export interface IIssue {
assignees_list: string[];
attachment_count: number;
attachments: any[];
issue_relations: {
id: string;
issue: string;
issue_detail: BlockeIssueDetail;
relation_type: IssueRelationType;
related_issue: string;
}[];
related_issues: {
id: string;
issue: string;
related_issue_detail: BlockeIssueDetail;
relation_type: IssueRelationType;
related_issue: string;
}[];
issue_relations: IssueRelation[];
related_issues: IssueRelation[];
bridge_id?: string | null;
completed_at: Date;
created_at: string;