From 2f138e8c810b9384070d2aed1f0eb03fd67607ba Mon Sep 17 00:00:00 2001 From: claygorman Date: Wed, 20 Dec 2023 15:43:53 -0800 Subject: [PATCH 1/3] Add linked issues feature to IssueModal Implemented a new feature to display linked issues in the IssueModal component. This is achieved by fetching additional data from the GraphQL server side, and restructuring the IssueLinkedIssues component to group issues by link type. The backend has also been adjusted to include linked issues data in the `issue` GraphQL query. --- backend/src/resolvers.js | 27 ++++- backend/src/resolvers/issue.js | 4 +- .../IssueModal/IssueLinkedIssues.tsx | 105 ++++++++++-------- .../components/IssueModal/IssueOverview.tsx | 5 +- frontend/gql/gql-queries-mutations.ts | 5 + 5 files changed, 96 insertions(+), 50 deletions(-) diff --git a/backend/src/resolvers.js b/backend/src/resolvers.js index 9a58bb3..aa93b15 100644 --- a/backend/src/resolvers.js +++ b/backend/src/resolvers.js @@ -515,7 +515,32 @@ const resolvers = { }); }, issue: (parent, { input: { id } }, { db }) => { - return db.sequelize.models.Issue.findByPk(id); + return db.sequelize.models.Issue.findByPk(id, { + include: [ + { + model: db.sequelize.models.Issue, + as: 'linkedToIssues', + through: { + attributes: [ + ['issue_id', 'issueId'], + ['linked_issue_id', 'linkedIssueId'], + ['link_type', 'linkType'], + ], + }, + }, + { + model: db.sequelize.models.Issue, + as: 'linkedByIssues', + through: { + attributes: [ + ['issue_id', 'issueId'], + ['linked_issue_id', 'linkedIssueId'], + ['link_type', 'linkType'], + ], + }, + }, + ], + }); }, }, }; diff --git a/backend/src/resolvers/issue.js b/backend/src/resolvers/issue.js index 367ba8c..e898f37 100644 --- a/backend/src/resolvers/issue.js +++ b/backend/src/resolvers/issue.js @@ -1,12 +1,12 @@ export const issueResolvers = { links: async (parent, args, { db }) => { return [ - ...parent.linkedToIssues.map((issue) => ({ + ...parent.linkedToIssues?.map((issue) => ({ ...issue.toJSON(), linkType: issue.IssueLinks.linkType, linkedIssueId: parent.id, })), - ...parent.linkedByIssues.map((issue) => ({ + ...parent.linkedByIssues?.map((issue) => ({ ...issue.toJSON(), linkType: issue.IssueLinks.linkTypeInverted, linkedIssueId: parent.id, diff --git a/frontend/components/IssueModal/IssueLinkedIssues.tsx b/frontend/components/IssueModal/IssueLinkedIssues.tsx index 2fef678..4b8fa0c 100644 --- a/frontend/components/IssueModal/IssueLinkedIssues.tsx +++ b/frontend/components/IssueModal/IssueLinkedIssues.tsx @@ -1,59 +1,72 @@ import React from 'react'; import { CheckIcon, XMarkIcon } from '@heroicons/react/20/solid'; import { priorityToIcon } from '@/components/Icons'; +import { GET_ISSUE_QUERY } from '@/gql/gql-queries-mutations'; +import { useQuery } from '@apollo/client'; +import { groupBy, lowerCase, startCase } from 'lodash'; +import { BsPlus } from 'react-icons/bs'; +import { Issue } from '@/gql/__generated__/graphql'; -const IssueLinkedIssues = ({ issueId }: { issueId?: string }) => { - // TODO: This is sample data we need to pull from backend - // TODO: Restructure data to group by link type and then map over each group - const blockedIssues = [ - { - id: 1, - key: 'ticket-1', - subject: 'PLACEHOLDER: blocked ticket subject', - priority: 3, - assignee: 'test', - status: 'in progress', - }, - { - id: 2, - key: 'ticket-2', - subject: 'PLACEHOLDER: next ticket name', - priority: 5, - assignee: 'test', - status: 'done', - }, - ]; +type Links = { + [key: string]: Issue[]; +}; + +const IssueLinkedIssues = ({ + issueId, + projectKey, +}: { + issueId?: string; + projectKey?: string; +}) => { + const { data, error } = useQuery(GET_ISSUE_QUERY, { + skip: !issueId, + variables: { input: { id: issueId } }, + }); + + const links: Links = data?.issue?.links + ? groupBy(data.issue.links, 'linkType') + : {}; return ( <> -
Linked Issues
- {blockedIssues.map(({ id, key, subject, priority, status }) => ( -
-
-
- -
-
- {key} -
-
-
-
- {subject} +
+
Linked Issues
+
+ +
+
+ {Object.keys(links).map((linkType) => ( +
+
+ {startCase(lowerCase(linkType))} +
+ {links[linkType].map(({ id, title, priority, status }) => ( +
+
+
+ +
+
+ {projectKey}-{id} +
+
+
+
{title}
+
+
+
{priorityToIcon(Number(priority))}
+
+ {status?.name} +
+
+
-
{priorityToIcon(priority)}
-
- {status} -
-
- -
-
+ ))}
))} diff --git a/frontend/components/IssueModal/IssueOverview.tsx b/frontend/components/IssueModal/IssueOverview.tsx index 4e42945..3e1eed2 100644 --- a/frontend/components/IssueModal/IssueOverview.tsx +++ b/frontend/components/IssueModal/IssueOverview.tsx @@ -44,7 +44,10 @@ const IssueOverview = ({
- +
diff --git a/frontend/gql/gql-queries-mutations.ts b/frontend/gql/gql-queries-mutations.ts index 33cee52..1132329 100644 --- a/frontend/gql/gql-queries-mutations.ts +++ b/frontend/gql/gql-queries-mutations.ts @@ -121,6 +121,11 @@ export const GET_ISSUE_QUERY = gql(/* GraphQL */ ` query GetIssue($input: QueryIssueInput) { issue(input: $input) { ...IssueFields + links { + ...IssueFields + linkType + linkedIssueId + } } } `); From cc6e373c81b88949c599cb60ba895e28ca2234a8 Mon Sep 17 00:00:00 2001 From: Clay Gorman Date: Wed, 20 Dec 2023 15:50:18 -0800 Subject: [PATCH 2/3] Update frontend/components/IssueModal/IssueLinkedIssues.tsx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- frontend/components/IssueModal/IssueLinkedIssues.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/components/IssueModal/IssueLinkedIssues.tsx b/frontend/components/IssueModal/IssueLinkedIssues.tsx index 4b8fa0c..ff664e5 100644 --- a/frontend/components/IssueModal/IssueLinkedIssues.tsx +++ b/frontend/components/IssueModal/IssueLinkedIssues.tsx @@ -23,6 +23,10 @@ const IssueLinkedIssues = ({ variables: { input: { id: issueId } }, }); + if (error) { + return
Error loading linked issues
; + } + const links: Links = data?.issue?.links ? groupBy(data.issue.links, 'linkType') : {}; From de998a2c49dbe3258aa5f98ed8ba1c5a275dd6ad Mon Sep 17 00:00:00 2001 From: Clay Gorman Date: Wed, 20 Dec 2023 15:50:27 -0800 Subject: [PATCH 3/3] Update frontend/components/IssueModal/IssueLinkedIssues.tsx Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- frontend/components/IssueModal/IssueLinkedIssues.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/components/IssueModal/IssueLinkedIssues.tsx b/frontend/components/IssueModal/IssueLinkedIssues.tsx index ff664e5..e4812d2 100644 --- a/frontend/components/IssueModal/IssueLinkedIssues.tsx +++ b/frontend/components/IssueModal/IssueLinkedIssues.tsx @@ -18,11 +18,15 @@ const IssueLinkedIssues = ({ issueId?: string; projectKey?: string; }) => { - const { data, error } = useQuery(GET_ISSUE_QUERY, { + const { data, error, loading } = useQuery(GET_ISSUE_QUERY, { skip: !issueId, variables: { input: { id: issueId } }, }); + if (loading) { + return
Loading...
; + } + if (error) { return
Error loading linked issues
; }