Skip to content

Commit 0b53912

Browse files
[WEB-3207] chore: add state_id, priority and assignee_ids to create issue relation response (#6448)
1 parent 586a320 commit 0b53912

File tree

5 files changed

+129
-83
lines changed

5 files changed

+129
-83
lines changed

apiserver/plane/app/serializers/issue.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,10 +283,26 @@ class IssueRelationSerializer(BaseSerializer):
283283
)
284284
name = serializers.CharField(source="related_issue.name", read_only=True)
285285
relation_type = serializers.CharField(read_only=True)
286+
state_id = serializers.UUIDField(source="related_issue.state.id", read_only=True)
287+
priority = serializers.CharField(source="related_issue.priority", read_only=True)
288+
assignee_ids = serializers.ListField(
289+
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
290+
write_only=True,
291+
required=False,
292+
)
286293

287294
class Meta:
288295
model = IssueRelation
289-
fields = ["id", "project_id", "sequence_id", "relation_type", "name"]
296+
fields = [
297+
"id",
298+
"project_id",
299+
"sequence_id",
300+
"relation_type",
301+
"name",
302+
"state_id",
303+
"priority",
304+
"assignee_ids",
305+
]
290306
read_only_fields = ["workspace", "project"]
291307

292308

@@ -298,10 +314,26 @@ class RelatedIssueSerializer(BaseSerializer):
298314
sequence_id = serializers.IntegerField(source="issue.sequence_id", read_only=True)
299315
name = serializers.CharField(source="issue.name", read_only=True)
300316
relation_type = serializers.CharField(read_only=True)
317+
state_id = serializers.UUIDField(source="issue.state.id", read_only=True)
318+
priority = serializers.CharField(source="issue.priority", read_only=True)
319+
assignee_ids = serializers.ListField(
320+
child=serializers.PrimaryKeyRelatedField(queryset=User.objects.all()),
321+
write_only=True,
322+
required=False,
323+
)
301324

302325
class Meta:
303326
model = IssueRelation
304-
fields = ["id", "project_id", "sequence_id", "relation_type", "name"]
327+
fields = [
328+
"id",
329+
"project_id",
330+
"sequence_id",
331+
"relation_type",
332+
"name",
333+
"state_id",
334+
"priority",
335+
"assignee_ids",
336+
]
305337
read_only_fields = ["workspace", "project"]
306338

307339

web/core/components/issues/issue-detail-widgets/relations/content.tsx

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"use client";
22
import { FC, useState } from "react";
33
import { observer } from "mobx-react";
4+
// plane imports
45
import { EIssueServiceType } from "@plane/constants";
5-
import { TIssue, TIssueRelationIdMap, TIssueServiceType } from "@plane/types";
6+
import { TIssue, TIssueServiceType } from "@plane/types";
67
import { Collapsible } from "@plane/ui";
78
// components
89
import { RelationIssueList } from "@/components/issues";
@@ -11,6 +12,7 @@ import { CreateUpdateIssueModal } from "@/components/issues/issue-modal";
1112
// hooks
1213
import { useIssueDetail } from "@/hooks/store";
1314
// Plane-web
15+
import { CreateUpdateEpicModal } from "@/plane-web/components/epics";
1416
import { useTimeLineRelationOptions } from "@/plane-web/components/relations";
1517
import { TIssueRelationTypes } from "@/plane-web/types";
1618
// helper
@@ -62,6 +64,7 @@ export const RelationsCollapsibleContent: FC<Props> = observer((props) => {
6264

6365
// helper
6466
const issueOperations = useRelationOperations();
67+
const epicOperations = useRelationOperations(EIssueServiceType.EPICS);
6568

6669
// derived values
6770
const relations = getRelationsByIssueId(issueId);
@@ -129,7 +132,6 @@ export const RelationsCollapsibleContent: FC<Props> = observer((props) => {
129132
relationKey={relation.relationKey}
130133
issueIds={relation.issueIds}
131134
disabled={disabled}
132-
issueOperations={issueOperations}
133135
handleIssueCrudState={handleIssueCrudState}
134136
issueServiceType={issueServiceType}
135137
/>
@@ -146,24 +148,44 @@ export const RelationsCollapsibleContent: FC<Props> = observer((props) => {
146148
toggleDeleteIssueModal(null);
147149
}}
148150
data={issueCrudState?.delete?.issue as TIssue}
149-
onSubmit={async () =>
150-
await issueOperations.remove(workspaceSlug, projectId, issueCrudState?.delete?.issue?.id as string)
151-
}
151+
onSubmit={async () => {
152+
const deleteOperation = !!issueCrudState.delete.issue?.is_epic
153+
? epicOperations.remove
154+
: issueOperations.remove;
155+
await deleteOperation(workspaceSlug, projectId, issueCrudState?.delete?.issue?.id as string);
156+
}}
157+
isEpic={!!issueCrudState.delete.issue?.is_epic}
152158
/>
153159
)}
154160

155161
{shouldRenderIssueUpdateModal && (
156-
<CreateUpdateIssueModal
157-
isOpen={issueCrudState?.update?.toggle}
158-
onClose={() => {
159-
handleIssueCrudState("update", null, null);
160-
toggleCreateIssueModal(false);
161-
}}
162-
data={issueCrudState?.update?.issue ?? undefined}
163-
onSubmit={async (_issue: TIssue) => {
164-
await issueOperations.update(workspaceSlug, projectId, _issue.id, _issue);
165-
}}
166-
/>
162+
<>
163+
{!!issueCrudState?.update?.issue?.is_epic ? (
164+
<CreateUpdateEpicModal
165+
isOpen={issueCrudState?.update?.toggle}
166+
onClose={() => {
167+
handleIssueCrudState("update", null, null);
168+
toggleCreateIssueModal(false);
169+
}}
170+
data={issueCrudState?.update?.issue ?? undefined}
171+
onSubmit={async (_issue: TIssue) => {
172+
await epicOperations.update(workspaceSlug, projectId, _issue.id, _issue);
173+
}}
174+
/>
175+
) : (
176+
<CreateUpdateIssueModal
177+
isOpen={issueCrudState?.update?.toggle}
178+
onClose={() => {
179+
handleIssueCrudState("update", null, null);
180+
toggleCreateIssueModal(false);
181+
}}
182+
data={issueCrudState?.update?.issue ?? undefined}
183+
onSubmit={async (_issue: TIssue) => {
184+
await issueOperations.update(workspaceSlug, projectId, _issue.id, _issue);
185+
}}
186+
/>
187+
)}
188+
</>
167189
)}
168190
</>
169191
);

web/core/components/issues/issue-detail-widgets/relations/helper.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ export const useRelationOperations = (
2323
const { updateIssue, removeIssue } = useIssueDetail(issueServiceType);
2424
const { captureIssueEvent } = useEventTracker();
2525
const pathname = usePathname();
26+
// derived values
27+
const entityName = issueServiceType === EIssueServiceType.ISSUES ? "Issue" : "Epic";
2628

2729
const issueOperations: TRelationIssueOperations = useMemo(
2830
() => ({
@@ -32,7 +34,7 @@ export const useRelationOperations = (
3234
setToast({
3335
type: TOAST_TYPE.SUCCESS,
3436
title: "Link Copied!",
35-
message: "Issue link copied to clipboard.",
37+
message: `${entityName} link copied to clipboard.`,
3638
});
3739
});
3840
},
@@ -51,7 +53,7 @@ export const useRelationOperations = (
5153
setToast({
5254
title: "Success!",
5355
type: TOAST_TYPE.SUCCESS,
54-
message: "Issue updated successfully",
56+
message: `${entityName} updated successfully`,
5557
});
5658
} catch (error) {
5759
captureIssueEvent({
@@ -66,7 +68,7 @@ export const useRelationOperations = (
6668
setToast({
6769
title: "Error!",
6870
type: TOAST_TYPE.ERROR,
69-
message: "Issue update failed",
71+
message: `${entityName} update failed`,
7072
});
7173
}
7274
},

web/core/components/issues/relations/issue-list-item.tsx

Lines changed: 52 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import { usePlatformOS } from "@/hooks/use-platform-os";
1616
// plane web components
1717
import { IssueIdentifier } from "@/plane-web/components/issues";
1818
import { TIssueRelationTypes } from "@/plane-web/types";
19-
//
20-
import { TRelationIssueOperations } from "../issue-detail-widgets/relations/helper";
19+
// local imports
20+
import { useRelationOperations } from "../issue-detail-widgets/relations/helper";
2121

2222
type Props = {
2323
workspaceSlug: string;
@@ -26,7 +26,6 @@ type Props = {
2626
relationKey: TIssueRelationTypes;
2727
relationIssueId: string;
2828
disabled: boolean;
29-
issueOperations: TRelationIssueOperations;
3029
handleIssueCrudState: (key: "update" | "delete", issueId: string, issue?: TIssue | null) => void;
3130
issueServiceType?: TIssueServiceType;
3231
};
@@ -39,7 +38,6 @@ export const RelationIssueListItem: FC<Props> = observer((props) => {
3938
relationKey,
4039
relationIssueId,
4140
disabled = false,
42-
issueOperations,
4341
handleIssueCrudState,
4442
issueServiceType = EIssueServiceType.ISSUES,
4543
} = props;
@@ -57,6 +55,7 @@ export const RelationIssueListItem: FC<Props> = observer((props) => {
5755
// derived values
5856
const issue = getIssueById(relationIssueId);
5957
const { handleRedirection } = useIssuePeekOverviewRedirection(!!issue?.is_epic);
58+
const issueOperations = useRelationOperations(!!issue?.is_epic ? EIssueServiceType.EPICS : EIssueServiceType.ISSUES);
6059
const projectDetail = (issue && issue.project_id && project.getProjectById(issue.project_id)) || undefined;
6160
const currentIssueStateDetail =
6261
(issue?.project_id && getProjectStates(issue?.project_id)?.find((state) => issue?.state_id == state.id)) ||
@@ -134,62 +133,58 @@ export const RelationIssueListItem: FC<Props> = observer((props) => {
134133
<span className="w-full truncate text-sm text-custom-text-100">{issue.name}</span>
135134
</Tooltip>
136135
</div>
137-
{!issue.is_epic && (
138-
<>
139-
<div
140-
className="flex-shrink-0 text-sm"
141-
onClick={(e) => {
142-
e.preventDefault();
143-
e.stopPropagation();
144-
}}
145-
>
146-
<RelationIssueProperty
147-
workspaceSlug={workspaceSlug}
148-
issueId={relationIssueId}
149-
disabled={disabled}
150-
issueOperations={issueOperations}
151-
issueServiceType={issueServiceType}
152-
/>
153-
</div>
154-
<div className="flex-shrink-0 text-sm">
155-
<CustomMenu placement="bottom-end" ellipsis>
156-
{!disabled && (
157-
<CustomMenu.MenuItem onClick={handleEditIssue}>
158-
<div className="flex items-center gap-2">
159-
<Pencil className="h-3.5 w-3.5" strokeWidth={2} />
160-
<span>Edit issue</span>
161-
</div>
162-
</CustomMenu.MenuItem>
163-
)}
136+
<div
137+
className="flex-shrink-0 text-sm"
138+
onClick={(e) => {
139+
e.preventDefault();
140+
e.stopPropagation();
141+
}}
142+
>
143+
<RelationIssueProperty
144+
workspaceSlug={workspaceSlug}
145+
issueId={relationIssueId}
146+
disabled={disabled}
147+
issueOperations={issueOperations}
148+
issueServiceType={issueServiceType}
149+
/>
150+
</div>
151+
<div className="flex-shrink-0 text-sm">
152+
<CustomMenu placement="bottom-end" ellipsis>
153+
{!disabled && (
154+
<CustomMenu.MenuItem onClick={handleEditIssue}>
155+
<div className="flex items-center gap-2">
156+
<Pencil className="h-3.5 w-3.5" strokeWidth={2} />
157+
<span>Edit</span>
158+
</div>
159+
</CustomMenu.MenuItem>
160+
)}
164161

165-
<CustomMenu.MenuItem onClick={handleCopyIssueLink}>
166-
<div className="flex items-center gap-2">
167-
<LinkIcon className="h-3.5 w-3.5" strokeWidth={2} />
168-
<span>Copy issue link</span>
169-
</div>
170-
</CustomMenu.MenuItem>
162+
<CustomMenu.MenuItem onClick={handleCopyIssueLink}>
163+
<div className="flex items-center gap-2">
164+
<LinkIcon className="h-3.5 w-3.5" strokeWidth={2} />
165+
<span>Copy link</span>
166+
</div>
167+
</CustomMenu.MenuItem>
171168

172-
{!disabled && (
173-
<CustomMenu.MenuItem onClick={handleRemoveRelation}>
174-
<div className="flex items-center gap-2">
175-
<X className="h-3.5 w-3.5" strokeWidth={2} />
176-
<span>Remove relation</span>
177-
</div>
178-
</CustomMenu.MenuItem>
179-
)}
169+
{!disabled && (
170+
<CustomMenu.MenuItem onClick={handleRemoveRelation}>
171+
<div className="flex items-center gap-2">
172+
<X className="h-3.5 w-3.5" strokeWidth={2} />
173+
<span>Remove relation</span>
174+
</div>
175+
</CustomMenu.MenuItem>
176+
)}
180177

181-
{!disabled && (
182-
<CustomMenu.MenuItem onClick={handleDeleteIssue}>
183-
<div className="flex items-center gap-2">
184-
<Trash className="h-3.5 w-3.5" strokeWidth={2} />
185-
<span>Delete issue</span>
186-
</div>
187-
</CustomMenu.MenuItem>
188-
)}
189-
</CustomMenu>
190-
</div>
191-
</>
192-
)}
178+
{!disabled && (
179+
<CustomMenu.MenuItem onClick={handleDeleteIssue}>
180+
<div className="flex items-center gap-2">
181+
<Trash className="h-3.5 w-3.5" strokeWidth={2} />
182+
<span>Delete</span>
183+
</div>
184+
</CustomMenu.MenuItem>
185+
)}
186+
</CustomMenu>
187+
</div>
193188
</div>
194189
)}
195190
</ControlLink>

web/core/components/issues/relations/issue-list.tsx

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,13 @@ import { TIssue, TIssueServiceType } from "@plane/types";
88
import { RelationIssueListItem } from "@/components/issues/relations";
99
// Plane-web
1010
import { TIssueRelationTypes } from "@/plane-web/types";
11-
//
12-
import { TRelationIssueOperations } from "../issue-detail-widgets/relations/helper";
1311

1412
type Props = {
1513
workspaceSlug: string;
1614
projectId: string;
1715
issueId: string;
1816
issueIds: string[];
1917
relationKey: TIssueRelationTypes;
20-
issueOperations: TRelationIssueOperations;
2118
handleIssueCrudState: (key: "update" | "delete", issueId: string, issue?: TIssue | null) => void;
2219
disabled?: boolean;
2320
issueServiceType?: TIssueServiceType;
@@ -31,7 +28,6 @@ export const RelationIssueList: FC<Props> = observer((props) => {
3128
issueIds,
3229
relationKey,
3330
disabled = false,
34-
issueOperations,
3531
handleIssueCrudState,
3632
issueServiceType = EIssueServiceType.ISSUES,
3733
} = props;
@@ -50,7 +46,6 @@ export const RelationIssueList: FC<Props> = observer((props) => {
5046
relationIssueId={relationIssueId}
5147
disabled={disabled}
5248
handleIssueCrudState={handleIssueCrudState}
53-
issueOperations={issueOperations}
5449
issueServiceType={issueServiceType}
5550
/>
5651
))}

0 commit comments

Comments
 (0)