Skip to content

Commit e4e83a9

Browse files
[WEB-2479] fix: merge default and archived issue details endpoint. (#5882)
1 parent 2ecc379 commit e4e83a9

File tree

11 files changed

+86
-48
lines changed

11 files changed

+86
-48
lines changed

apiserver/plane/app/views/issue/base.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,44 @@ def retrieve(self, request, slug, project_id, pk=None):
478478
project = Project.objects.get(pk=project_id, workspace__slug=slug)
479479

480480
issue = (
481-
self.get_queryset()
481+
Issue.objects.filter(
482+
project_id=self.kwargs.get("project_id")
483+
)
484+
.filter(workspace__slug=self.kwargs.get("slug"))
485+
.select_related("workspace", "project", "state", "parent")
486+
.prefetch_related("assignees", "labels", "issue_module__module")
487+
.annotate(
488+
cycle_id=Case(
489+
When(
490+
issue_cycle__cycle__deleted_at__isnull=True,
491+
then=F("issue_cycle__cycle_id"),
492+
),
493+
default=None,
494+
)
495+
)
496+
.annotate(
497+
link_count=IssueLink.objects.filter(issue=OuterRef("id"))
498+
.order_by()
499+
.annotate(count=Func(F("id"), function="Count"))
500+
.values("count")
501+
)
502+
.annotate(
503+
attachment_count=FileAsset.objects.filter(
504+
issue_id=OuterRef("id"),
505+
entity_type=FileAsset.EntityTypeContext.ISSUE_ATTACHMENT,
506+
)
507+
.order_by()
508+
.annotate(count=Func(F("id"), function="Count"))
509+
.values("count")
510+
)
511+
.annotate(
512+
sub_issues_count=Issue.issue_objects.filter(
513+
parent=OuterRef("id")
514+
)
515+
.order_by()
516+
.annotate(count=Func(F("id"), function="Count"))
517+
.values("count")
518+
)
482519
.filter(pk=pk)
483520
.annotate(
484521
label_ids=Coalesce(

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/issues/(detail)/[archivedIssueId]/page.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const ArchivedIssueDetailsPage = observer(() => {
2929
? `ARCHIVED_ISSUE_DETAIL_${workspaceSlug}_${projectId}_${archivedIssueId}`
3030
: null,
3131
workspaceSlug && projectId && archivedIssueId
32-
? () => fetchIssue(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString(), "ARCHIVED")
32+
? () => fetchIssue(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString())
3333
: null
3434
);
3535

web/app/[workspaceSlug]/(projects)/projects/(detail)/[projectId]/archives/issues/(detail)/header.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import { ISSUE_DETAILS } from "@/constants/fetch-keys";
1313
// hooks
1414
import { useProject } from "@/hooks/store";
1515
// services
16-
import { IssueArchiveService } from "@/services/issue";
16+
import { IssueService } from "@/services/issue";
1717

18-
const issueArchiveService = new IssueArchiveService();
18+
const issueService = new IssueService();
1919

2020
export const ProjectArchivedIssueDetailsHeader = observer(() => {
2121
// router
@@ -24,14 +24,9 @@ export const ProjectArchivedIssueDetailsHeader = observer(() => {
2424
const { currentProjectDetails, loader } = useProject();
2525

2626
const { data: issueDetails } = useSWR(
27-
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId as string) : null,
27+
workspaceSlug && projectId && archivedIssueId ? ISSUE_DETAILS(archivedIssueId.toString()) : null,
2828
workspaceSlug && projectId && archivedIssueId
29-
? () =>
30-
issueArchiveService.retrieveArchivedIssue(
31-
workspaceSlug as string,
32-
projectId as string,
33-
archivedIssueId as string
34-
)
29+
? () => issueService.retrieve(workspaceSlug.toString(), projectId.toString(), archivedIssueId.toString())
3530
: null
3631
);
3732

web/core/components/cycles/active-cycle/cycle-stats.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,12 @@ export const ActiveCycleStats: FC<ActiveCycleStatsProps> = observer((props) => {
172172
className="group flex cursor-pointer items-center justify-between gap-2 rounded-md hover:bg-custom-background-90 p-1"
173173
onClick={() => {
174174
if (issue.id) {
175-
setPeekIssue({ workspaceSlug, projectId, issueId: issue.id });
175+
setPeekIssue({
176+
workspaceSlug,
177+
projectId,
178+
issueId: issue.id,
179+
isArchived: !!issue.archived_at,
180+
});
176181
handleFiltersUpdate("priority", ["urgent", "high"], true);
177182
}
178183
}}

web/core/components/issues/issue-layouts/list/block.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,13 @@ export const IssueBlock = observer((props: IssueBlockProps) => {
7777
issue.project_id &&
7878
issue.id &&
7979
!getIsIssuePeeked(issue.id) &&
80-
setPeekIssue({ workspaceSlug, projectId: issue.project_id, issueId: issue.id, nestingLevel: nestingLevel });
80+
setPeekIssue({
81+
workspaceSlug,
82+
projectId: issue.project_id,
83+
issueId: issue.id,
84+
nestingLevel: nestingLevel,
85+
isArchived: !!issue.archived_at,
86+
});
8187

8288
const issue = issuesMap[issueId];
8389
const subIssuesCount = issue?.sub_issues_count ?? 0;

web/core/components/issues/issue-layouts/roots/archived-issue-layout-root.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const ArchivedIssueLayoutRoot: React.FC = observer(() => {
3434
<div className="relative h-full w-full overflow-auto">
3535
<ArchivedIssueListLayout />
3636
</div>
37-
<IssuePeekOverview is_archived />
37+
<IssuePeekOverview />
3838
</Fragment>
3939
</IssuesStoreContext.Provider>
4040
);

web/core/components/issues/peek-overview/root.tsx

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"use client";
22

3-
import { FC, useEffect, useState, useMemo } from "react";
3+
import { FC, useEffect, useState, useMemo, useCallback } from "react";
44
import { observer } from "mobx-react";
55
import { usePathname } from "next/navigation";
66
// plane types
@@ -21,12 +21,11 @@ import { EUserPermissions, EUserPermissionsLevel } from "@/plane-web/constants/u
2121
interface IIssuePeekOverview {
2222
embedIssue?: boolean;
2323
embedRemoveCurrentNotification?: () => void;
24-
is_archived?: boolean;
2524
is_draft?: boolean;
2625
}
2726

2827
export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
29-
const { embedIssue = false, embedRemoveCurrentNotification, is_archived = false, is_draft = false } = props;
28+
const { embedIssue = false, embedRemoveCurrentNotification, is_draft = false } = props;
3029
// router
3130
const pathname = usePathname();
3231
// store hook
@@ -47,26 +46,20 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
4746
// state
4847
const [error, setError] = useState(false);
4948

50-
const removeRoutePeekId = () => {
49+
const removeRoutePeekId = useCallback(() => {
5150
setPeekIssue(undefined);
5251
if (embedIssue) embedRemoveCurrentNotification?.();
53-
};
52+
}, [embedIssue, embedRemoveCurrentNotification, setPeekIssue]);
5453

5554
const issueOperations: TIssueOperations = useMemo(
5655
() => ({
5756
fetch: async (workspaceSlug: string, projectId: string, issueId: string) => {
5857
try {
5958
setError(false);
60-
await fetchIssue(
61-
workspaceSlug,
62-
projectId,
63-
issueId,
64-
is_archived ? "ARCHIVED" : is_draft ? "DRAFT" : "DEFAULT"
65-
);
66-
setError(false);
59+
await fetchIssue(workspaceSlug, projectId, issueId, is_draft ? "DRAFT" : "DEFAULT");
6760
} catch (error) {
6861
setError(true);
69-
console.error("Error fetching the parent issue");
62+
console.error("Error fetching the parent issue", error);
7063
}
7164
},
7265
update: async (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => {
@@ -109,7 +102,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
109102
});
110103
removeRoutePeekId();
111104
});
112-
} catch (error) {
105+
} catch {
113106
setToast({
114107
title: "Error!",
115108
type: TOAST_TYPE.ERROR,
@@ -124,13 +117,14 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
124117
},
125118
archive: async (workspaceSlug: string, projectId: string, issueId: string) => {
126119
try {
127-
issues?.archiveIssue && (await issues.archiveIssue(workspaceSlug, projectId, issueId));
120+
if (!issues?.archiveIssue) return;
121+
await issues.archiveIssue(workspaceSlug, projectId, issueId);
128122
captureIssueEvent({
129123
eventName: ISSUE_ARCHIVED,
130124
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
131125
path: pathname,
132126
});
133-
} catch (error) {
127+
} catch {
134128
captureIssueEvent({
135129
eventName: ISSUE_ARCHIVED,
136130
payload: { id: issueId, state: "FAILED", element: "Issue peek-overview" },
@@ -151,7 +145,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
151145
payload: { id: issueId, state: "SUCCESS", element: "Issue peek-overview" },
152146
path: pathname,
153147
});
154-
} catch (error) {
148+
} catch {
155149
setToast({
156150
type: TOAST_TYPE.ERROR,
157151
title: "Error!",
@@ -177,7 +171,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
177171
},
178172
path: pathname,
179173
});
180-
} catch (error) {
174+
} catch {
181175
setToast({
182176
type: TOAST_TYPE.ERROR,
183177
title: "Error!",
@@ -206,7 +200,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
206200
},
207201
path: pathname,
208202
});
209-
} catch (error) {
203+
} catch {
210204
setToast({
211205
type: TOAST_TYPE.ERROR,
212206
title: "Error!",
@@ -248,7 +242,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
248242
},
249243
path: pathname,
250244
});
251-
} catch (error) {
245+
} catch {
252246
captureIssueEvent({
253247
eventName: ISSUE_UPDATED,
254248
payload: { state: "FAILED", element: "Issue peek-overview" },
@@ -311,7 +305,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
311305
},
312306
path: pathname,
313307
});
314-
} catch (error) {
308+
} catch {
315309
captureIssueEvent({
316310
eventName: ISSUE_UPDATED,
317311
payload: { id: issueId, state: "FAILED", element: "Issue peek-overview" },
@@ -324,7 +318,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
324318
}
325319
},
326320
}),
327-
[is_archived, is_draft, fetchIssue, issues, restoreIssue, captureIssueEvent, pathname]
321+
[fetchIssue, is_draft, issues, fetchActivities, captureIssueEvent, pathname, removeRoutePeekId, restoreIssue]
328322
);
329323

330324
useEffect(() => {
@@ -350,7 +344,7 @@ export const IssuePeekOverview: FC<IIssuePeekOverview> = observer((props) => {
350344
issueId={peekIssue.issueId}
351345
isLoading={getIsFetchingIssueDetails(peekIssue.issueId)}
352346
isError={error}
353-
is_archived={is_archived}
347+
is_archived={!!peekIssue.isArchived}
354348
disabled={!isEditable}
355349
embedIssue={embedIssue}
356350
embedRemoveCurrentNotification={embedRemoveCurrentNotification}

web/core/components/issues/peek-overview/view.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ export const IssueView: FC<IIssueView> = observer((props) => {
6666
// remove peek id
6767
const removeRoutePeekId = () => {
6868
setPeekIssue(undefined);
69-
if (embedIssue) embedRemoveCurrentNotification && embedRemoveCurrentNotification();
69+
if (embedIssue && embedRemoveCurrentNotification) embedRemoveCurrentNotification();
7070
};
7171

7272
const isLocalDBIssueDescription = getIsLocalDBIssueDescription(issueId);

web/core/hooks/use-issue-peek-overview-redirection.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@ const useIssuePeekOverviewRedirection = () => {
2222
if (workspaceSlug && project_id && id && !getIsIssuePeeked(id) && !tempId) {
2323
const issuePath = `/${workspaceSlug}/projects/${project_id}/${archived_at ? "archives/" : ""}issues/${id}`;
2424

25-
isMobile
26-
? router.push(issuePath)
27-
: setPeekIssue({ workspaceSlug, projectId: project_id, issueId: id, nestingLevel });
25+
if (isMobile) {
26+
router.push(issuePath);
27+
} else {
28+
setPeekIssue({ workspaceSlug, projectId: project_id, issueId: id, nestingLevel, isArchived: !!archived_at });
29+
}
2830
}
2931
};
3032

web/core/store/issue/issue-details/issue.store.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface IIssueStoreActions {
1515
workspaceSlug: string,
1616
projectId: string,
1717
issueId: string,
18-
issueType?: "DEFAULT" | "DRAFT" | "ARCHIVED"
18+
issueStatus?: "DEFAULT" | "DRAFT",
1919
) => Promise<TIssue>;
2020
updateIssue: (workspaceSlug: string, projectId: string, issueId: string, data: Partial<TIssue>) => Promise<void>;
2121
removeIssue: (workspaceSlug: string, projectId: string, issueId: string) => Promise<void>;
@@ -82,7 +82,7 @@ export class IssueStore implements IIssueStore {
8282
});
8383

8484
// actions
85-
fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, issueType = "DEFAULT") => {
85+
fetchIssue = async (workspaceSlug: string, projectId: string, issueId: string, issueStatus = "DEFAULT") => {
8686
const query = {
8787
expand: "issue_reactions,issue_attachments,issue_link,parent",
8888
};
@@ -99,9 +99,7 @@ export class IssueStore implements IIssueStore {
9999
this.localDBIssueDescription = issueId;
100100
}
101101

102-
if (issueType === "ARCHIVED")
103-
issue = await this.issueArchiveService.retrieveArchivedIssue(workspaceSlug, projectId, issueId, query);
104-
else if (issueType === "DRAFT")
102+
if (issueStatus === "DRAFT")
105103
issue = await this.issueDraftService.getDraftIssueById(workspaceSlug, projectId, issueId, query);
106104
else issue = await this.issueService.retrieve(workspaceSlug, projectId, issueId, query);
107105

0 commit comments

Comments
 (0)