From af3288dd9c373fbc4327f26543da8a4ea127c43e Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 12:43:51 +0100 Subject: [PATCH 1/8] chore: sort and filter for PR and issue tab working --- .../filter-dropdown/FilterDropdown.styles.ts | 16 ++- .../filter-dropdown/FilterDropdown.tsx | 4 +- .../pull-request/PullRequest.stories.tsx | 17 +++ .../pr-tab-header/PRTabHeader.tsx | 78 ++++++----- .../pull-request/PullRequest.data.tsx | 115 ++-------------- .../pull-request/PullRequest.type.ts | 1 + .../pull-request/PullRequest.view.tsx | 4 +- .../repo-issues/Issues/Issue.type.ts | 8 ++ .../components/repo-issues/Issues/Issues.tsx | 1 + .../repo-issues/Issues/Issues.view.tsx | 2 +- .../issue-tab-header/IssueTabHeader.tsx | 81 +++++------ .../src/components/sub-header/SubHeader.tsx | 2 + .../src/constants/data.ts | 24 ++++ .../src/constants/url.constants.ts | 62 ++++++++- .../src/context/RepoContext.tsx | 40 +++++- .../src/helpers/parseSortParams.ts | 12 ++ .../src/helpers/replaceSpaceWithPlus.ts | 7 + .../use-repository-issues.ts.ts | 54 -------- .../src/hooks/useIssuesPRs.tsx | 129 ++++++++++++++++++ .../src/routes/repo/repository-issues.tsx | 8 +- cra-rxjs-styled-components/src/types/types.ts | 11 +- 21 files changed, 425 insertions(+), 251 deletions(-) create mode 100644 cra-rxjs-styled-components/src/helpers/parseSortParams.ts create mode 100644 cra-rxjs-styled-components/src/helpers/replaceSpaceWithPlus.ts delete mode 100644 cra-rxjs-styled-components/src/hooks/repository-issues/use-repository-issues.ts.ts create mode 100644 cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx diff --git a/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.styles.ts b/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.styles.ts index 5bf564c02..edee9b34d 100644 --- a/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.styles.ts +++ b/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.styles.ts @@ -1,5 +1,5 @@ import colors from '../../constants/colors'; -import styled from 'styled-components'; +import styled, { css } from 'styled-components'; export const DropdownContainer = styled.div` display: flex; @@ -22,7 +22,7 @@ export const DropdownOptionsHeadingText = styled.span` font-weight: 700; `; -export const DropdownBtn = styled.button` +export const DropdownBtn = styled.button<{ flat?: boolean }>` display: flex; flex-grow: 1; border-radius: 8px; @@ -35,9 +35,19 @@ export const DropdownBtn = styled.button` min-width: 70px; outline: none; @media (min-width: 768px) { - gap: 8px; + ${(props) => + !props.flat && + css` + gap: 8px; + `} min-width: 80px; } + ${(props) => + props.flat && + css` + border: none; + gap: 2px; + `} `; export const DropdownOption = styled.li` diff --git a/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.tsx b/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.tsx index 5b3d68d39..3beaecf7f 100644 --- a/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.tsx +++ b/cra-rxjs-styled-components/src/components/filter-dropdown/FilterDropdown.tsx @@ -20,6 +20,7 @@ interface FilterDropdownProps { items?: string[]; selected?: string; itemsColors?: string[]; + flat?: boolean; selectOption?: (value: string) => void; } export default function FilterDropdown({ @@ -27,6 +28,7 @@ export default function FilterDropdown({ items, selected, itemsColors, + flat, selectOption, }: FilterDropdownProps) { const [showOptions, setShowOptions] = useState(false); @@ -62,7 +64,7 @@ export default function FilterDropdown({ }); return ( - + {name} diff --git a/cra-rxjs-styled-components/src/components/pull-request/PullRequest.stories.tsx b/cra-rxjs-styled-components/src/components/pull-request/PullRequest.stories.tsx index 48500da81..b361684f7 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/PullRequest.stories.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/PullRequest.stories.tsx @@ -1,10 +1,27 @@ import { ComponentStory, ComponentMeta } from '@storybook/react'; import { Routes, Route, MemoryRouter } from 'react-router-dom'; import PullRequest from './pull-request/PullRequest.view'; +import { RepoProvider } from '../../context/RepoContext'; export default { title: 'Repo/PullRequest', component: PullRequest, + decorators: [ + (Story) => ( + + + + ), + ], } as ComponentMeta; const Template: ComponentStory = (args) => ( diff --git a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx index 8c40d2934..ebd07b5f5 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx @@ -1,11 +1,12 @@ import { Container, StatusLabel, StatusTab } from './PRTabHeader.style'; -import { useCallback, useState } from 'react'; +import { useState } from 'react'; import CorrectIcon from '../../icons/CorrectIcon'; -import DetailsDropdown from '../../details-dropdown/DetailsDropdown'; -import type { DropdownTitle } from '../types'; import type { PRTabValues } from '../types'; import PullRequestIcon from '../../icons/PullRequestIcon'; +import { useRepo } from '../../../context/RepoContext'; +import { SORT_OPTIONS } from '../../../constants/data'; +import FilterDropdown from '../../../components/filter-dropdown/FilterDropdown'; interface Props { toggleTab: any; @@ -15,20 +16,31 @@ interface Props { export default function PullRequestTabHeader(props: Props) { const [activeTab, setActiveTab] = useState('open'); - const [openDropdown, setOpenDropdown] = useState(); const { toggleTab } = props; + const { + labels, + milestones, + label, + sortBy, + milestone, + setLabel, + setMilestone, + setSortBy, + } = useRepo(); + const changeTab = (value: PRTabValues) => { toggleTab(value); setActiveTab(value); }; - const toggleDropdown = useCallback( - (dropdownName: DropdownTitle) => { - setOpenDropdown(openDropdown === dropdownName ? undefined : dropdownName); - }, - [openDropdown] - ); + const sortOptions = Object.values(SORT_OPTIONS); + + const labelOptions = (labels || []).map((label) => label.name) || []; + const labelOptionsColors = (labels || []).map((label) => label.color) || []; + const milestoneOptions = + (milestones || []).map((milestone) => milestone.title) || []; + return ( @@ -51,28 +63,30 @@ export default function PullRequestTabHeader(props: Props) { - toggleDropdown('Label')} - isOpen={openDropdown === 'Label'} - > - WIP DO NOT MERGE - Enhancement - - toggleDropdown('Sort')} - isOpen={openDropdown === 'Sort'} - > - Newest - Oldest - Most Commented - Least Commented - Resently Updated - Least Resently Updated - + + + + + ); diff --git a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.data.tsx b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.data.tsx index cfe13bd4c..275717222 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.data.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.data.tsx @@ -1,124 +1,27 @@ -import { - Observable, - Subscription, - filter, - map, - switchMap, - tap, - zip, -} from 'rxjs'; -import React, { useEffect, useState } from 'react'; +import { useState } from 'react'; import type { PRTabValues } from '../types'; -import { - OPEN_PULLS_URL, - CLOSED_PULLS_URL, -} from '../../../constants/url.constants'; -import type { PullRequest, PullRequests } from './PullRequest.type'; import PullRequestView from './PullRequest.view'; -import { fromFetchWithAuth } from '../../../hooks/auth/from-fetch-with-auth'; -import { useParams } from 'react-router-dom'; +import useIssuesPRs from '../../../hooks/useIssuesPRs'; export default function PullRequestCtrl() { const [activeTab, setActiveTab] = useState('open'); - const [openPRPage, setOpenPRPage] = useState(1); - const [closedPRPage, setClosedPRPage] = useState(1); - const setPRPage = activeTab === 'open' ? setOpenPRPage : setClosedPRPage; - const [openPullRequests, setOpenPullRequests] = useState({ - total_count: 0, - items: [], - }); - const [closedPullRequests, setClosedPullRequests] = useState({ - total_count: 0, - items: [], + const { open, closed, setClosedPRPage, setOpenPRPage } = useIssuesPRs({ + searchType: 'pull-request', + type: 'pulls', }); + const setPRPage = activeTab === 'open' ? setOpenPRPage : setClosedPRPage; - const { username, repo } = useParams(); - - useEffect(() => { - if (username && repo) { - const openPRSubscription: Subscription = fromFetchWithAuth( - OPEN_PULLS_URL(username, repo, openPRPage), - { - selector: async (response: Response) => { - const res = await response.json(); - return res as any; - }, - } - ) - .pipe( - filter((pulls) => !!pulls.total_count), - switchMap((pulls: PullRequests) => { - const requests = pulls.items.map(createCommentCountRequest); - return zip(...requests).pipe( - map(mergePullRequestsWithCommentCount(pulls)) - ); - }), - tap(setOpenPullRequests) - ) - .subscribe(); - - const closedPRSubscription: Subscription = fromFetchWithAuth( - CLOSED_PULLS_URL(username, repo, closedPRPage), - { - selector: async (response: Response) => { - const res = await response.json(); - return res as any; - }, - } - ) - .pipe( - filter((pulls) => !!pulls.total_count), - switchMap((pulls: PullRequests) => { - const requests = pulls.items.map(createCommentCountRequest); - return zip(...requests).pipe( - map(mergePullRequestsWithCommentCount(pulls)) - ); - }), - tap(setClosedPullRequests) - ) - .subscribe(); - - return () => { - openPRSubscription.unsubscribe(); - closedPRSubscription.unsubscribe(); - }; - } - }, [username, repo, openPRPage, closedPRPage]); - - const PRS = - activeTab === 'open' ? openPullRequests.items : closedPullRequests.items; + const PRS = activeTab === 'open' ? open.items : closed.items; return ( ); } - -function createCommentCountRequest(pr: PullRequest): Observable { - const review_comments_url = `${pr.repository_url}/pulls/${pr.number}/comments`; - return fromFetchWithAuth(review_comments_url, { - selector: (response: Response) => { - return response.json(); - }, - }); -} - -function mergePullRequestsWithCommentCount(pulls: PullRequests) { - return (counts: number[]): PullRequests => { - const items = pulls.items.map((p: PullRequest, index: number) => ({ - ...p, - comments: counts[index], - })); - return { - total_count: pulls.total_count, - items, - }; - }; -} diff --git a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.type.ts b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.type.ts index 8a1fbdcbd..a8a01d629 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.type.ts +++ b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.type.ts @@ -15,5 +15,6 @@ export type PullRequest = { export type PullRequests = { total_count: number; + incomplete_results: boolean; items: PullRequest[]; }; diff --git a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx index 905c59455..4e913a273 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx @@ -43,14 +43,14 @@ export default function PullRequestView({ closedPRCount={closedPRCount} toggleTab={changeActiveTab} /> - {pullRequests.map((pr, index) => ( + {(pullRequests || []).map((pr, index) => ( ))} diff --git a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issue.type.ts b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issue.type.ts index 598bdfeff..f89d51303 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issue.type.ts +++ b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issue.type.ts @@ -18,3 +18,11 @@ export type Label = { export type User = { login: string; }; + +export interface MilestoneProps { + id: string; + closed: boolean; + description: string; + number: number; + title: string; +} diff --git a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.tsx b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.tsx index cf7ef5a76..01ec3926e 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.tsx +++ b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import IssueView from './Issues.view'; import type { IssueTabValues, IssueTypes } from '../../../types/types'; + type IssuesProps = { issues: IssueTypes; }; diff --git a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.view.tsx b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.view.tsx index e05d2bc70..9a43fb79a 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.view.tsx +++ b/cra-rxjs-styled-components/src/components/repo-issues/Issues/Issues.view.tsx @@ -26,7 +26,7 @@ export default function IssueView({ closedCount={closedCount} openCount={openCount} /> - {issues.map((issue, index) => ( + {(issues || []).map((issue, index) => ( ))} diff --git a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx b/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx index cf8c62fdc..65429ff97 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx +++ b/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx @@ -1,11 +1,12 @@ -import { useCallback, useState } from 'react'; -import DetailsDropdown from '../../details-dropdown/DetailsDropdown'; +import { useState } from 'react'; import CorrectIcon from '../../icons/CorrectIcon'; import OpenIssueIcon from '../../icons/OpenIssueIcon'; import type { IssueTabValues } from '../../../types/types'; import { Container, StatusLabel, StatusTab } from './IssueTabHeader.styles'; -import type { DropdownTitle } from '../../../types/types'; +import { useRepo } from '../../../context/RepoContext'; +import FilterDropdown from '../../../components/filter-dropdown/FilterDropdown'; +import { SORT_OPTIONS } from '../../../constants/data'; interface Props { toggleTab: any; @@ -14,8 +15,17 @@ interface Props { } export default function IssueTabHeader(props: Props) { + const { + labels, + milestones, + label, + sortBy, + milestone, + setLabel, + setMilestone, + setSortBy, + } = useRepo(); const [activeTab, setActiveTab] = useState('open'); - const [openDropdown, setOpenDropdown] = useState(); const { toggleTab, closedCount, openCount } = props; const changeTab = (value: IssueTabValues) => { @@ -23,12 +33,11 @@ export default function IssueTabHeader(props: Props) { setActiveTab(value); }; - const toggleDropdown = useCallback( - (dropdownName: DropdownTitle) => { - setOpenDropdown(openDropdown === dropdownName ? undefined : dropdownName); - }, - [openDropdown] - ); + const sortOptions = Object.values(SORT_OPTIONS); + + const labelOptions = (labels || []).map((label) => label.name) || []; + const labelOptionsColors = (labels || []).map((label) => label.color) || []; + const milestoneOptions = (milestones || []).map((milestone) => milestone.title) || []; return ( @@ -51,38 +60,30 @@ export default function IssueTabHeader(props: Props) { - toggleDropdown('Label')} - isOpen={openDropdown === 'Label'} - > - WIP DO NOT MERGE - Enhancement - + - toggleDropdown('Milestones')} - isOpen={openDropdown === 'Milestones'} - > - Issue With No Milestone - + - toggleDropdown('Sort')} - isOpen={openDropdown === 'Sort'} - > - Newest - Oldest - Most Commented - Least Commented - Resently Updated - Least Resently Updated - + ); diff --git a/cra-rxjs-styled-components/src/components/sub-header/SubHeader.tsx b/cra-rxjs-styled-components/src/components/sub-header/SubHeader.tsx index bb24115d7..a7f900ea1 100644 --- a/cra-rxjs-styled-components/src/components/sub-header/SubHeader.tsx +++ b/cra-rxjs-styled-components/src/components/sub-header/SubHeader.tsx @@ -30,6 +30,7 @@ import { useRepo } from '../../context/RepoContext'; export default function SubHeader() { const repo = useRepo(); + const { resetFilterValues } = repo; const pathname = window.location.pathname; const btnArr = [ @@ -105,6 +106,7 @@ export default function SubHeader() { key={index} to={`${repo.basePath}${tabInfo.to}`} className={isCurrentTab(tabInfo.to) ? 'active-tab' : ''} + onClick={resetFilterValues} > {tabInfo.icon} {tabInfo.label} diff --git a/cra-rxjs-styled-components/src/constants/data.ts b/cra-rxjs-styled-components/src/constants/data.ts index 081eb6037..9733b55d2 100644 --- a/cra-rxjs-styled-components/src/constants/data.ts +++ b/cra-rxjs-styled-components/src/constants/data.ts @@ -1,3 +1,27 @@ import { RepoIcon } from '../components/icons'; export const tabs = [{ title: 'Repositories', Icon: RepoIcon }]; + + +export const OrderField = { + /** Order issues by comment count */ + Comments: 'comments', + /** Order issues by creation time */ + CreatedAt: 'created', + /** Order issues by update time */ + UpdatedAt: 'updated', +}; + +export const OrderDirection = { + Asc: 'asc', + Desc: 'desc', +}; + +export const SORT_OPTIONS = { + [`${OrderField.CreatedAt}^${OrderDirection.Desc}`]: 'Newest', + [`${OrderField.CreatedAt}^${OrderDirection.Asc}`]: 'Oldest', + [`${OrderField.Comments}^${OrderDirection.Desc}`]: 'Most commented', + [`${OrderField.Comments}^${OrderDirection.Asc}`]: 'Least commented', + [`${OrderField.UpdatedAt}^${OrderDirection.Desc}`]: 'Recently updated', + [`${OrderField.UpdatedAt}^${OrderDirection.Asc}`]: 'Least recently updated', +}; diff --git a/cra-rxjs-styled-components/src/constants/url.constants.ts b/cra-rxjs-styled-components/src/constants/url.constants.ts index d2799c435..236eed3ac 100644 --- a/cra-rxjs-styled-components/src/constants/url.constants.ts +++ b/cra-rxjs-styled-components/src/constants/url.constants.ts @@ -1,3 +1,6 @@ +import replaceSpaceWithPlus, { + replaceEncodedSpaceWithPlus, +} from '../helpers/replaceSpaceWithPlus'; import convertObjectToQueryString from '../helpers/objectToQueryString'; import { IssueType, State } from '../types/types'; @@ -52,11 +55,49 @@ export const PULLS_URL = ( ) => `${GITHUB_URL_BASE}/search/issues?q=repo:${owner}/${repoName}&per_page=30&page=${page}`; -export const OPEN_PULLS_URL = (owner: string, repoName: string, page = 1) => - `${GITHUB_URL_BASE}/search/issues?q=repo:${owner}/${repoName}+is:open+is:pr&page=${page}&per_page=${PULLS_PER_PAGE}`; - -export const CLOSED_PULLS_URL = (owner: string, repoName: string, page = 1) => - `${GITHUB_URL_BASE}/search/issues?q=repo:${owner}/${repoName}+is:closed+is:pr&page=${page}&per_page=${PULLS_PER_PAGE}`; +export const ISSUES_PULLS_URL = ({ + user, + repo, + type, + state, + per_page, + page, + labels, + milestone, + sort, + direction, +}: { + user: string; + repo: string; + type: string; + state: State; + per_page: number; + page: number; + labels?: string; + milestone?: string | number; + sort?: string; + direction?: string; +}) => { + const params = { + per_page, + page, + sort, + order: direction, + }; + const queryStrings = convertObjectToQueryString(params); + const Q = `+is:${state}+is:${type}${ + labels ? `+label:"${replaceSpaceWithPlus(labels)}"` : '' + }${ + milestone + ? `+milestone:"${ + typeof milestone === 'string' + ? replaceEncodedSpaceWithPlus(encodeURIComponent(milestone)) + : milestone + }"` + : '' + }`; + return `${GITHUB_URL_BASE}/search/issues?q=repo:${user}/${repo}${Q}&${queryStrings}`; +}; export const ISSUE_PR_SEARCH = ( user: string, @@ -69,3 +110,14 @@ export const ISSUE_PR_SEARCH = ( `${GITHUB_URL_BASE}/search/issues?q=repo:${user}/${repo}%20is:${type}%20state:${state}&per_page=${per_page}&page=${page}`; export const ORG_INFO = (org: string) => `${GITHUB_URL_BASE}/orgs/${org}`; + +export const REPO_LABELS = ({ user, repo }: { user: string; repo: string }) => + `${GITHUB_URL_BASE}/repos/${user}/${repo}/labels`; + +export const REPO_MILESTONES = ({ + user, + repo, +}: { + user: string; + repo: string; +}) => `${GITHUB_URL_BASE}/repos/${user}/${repo}/milestones`; diff --git a/cra-rxjs-styled-components/src/context/RepoContext.tsx b/cra-rxjs-styled-components/src/context/RepoContext.tsx index c6e45aaab..1607a75dc 100644 --- a/cra-rxjs-styled-components/src/context/RepoContext.tsx +++ b/cra-rxjs-styled-components/src/context/RepoContext.tsx @@ -1,5 +1,9 @@ +import { + Label, + MilestoneProps, +} from '../components/repo-issues/Issues/Issue.type'; import type { ReactNode } from 'react'; -import { createContext, useContext } from 'react'; +import { createContext, useContext, useState } from 'react'; export interface RepoContextInterface { name: string; @@ -20,6 +24,17 @@ export interface RepoContextInterface { topics: string[]; isOrg: boolean; }; + label?: string; + milestone?: string; + setLabel?: (value: string) => void; + setMilestone?: (value: string) => void; + labels?: Label[]; + milestones?: MilestoneProps[]; + setLabels?: (value: Label[]) => void; + setMilestones?: (value: MilestoneProps[]) => void; + sortBy?: string; + setSortBy?: (value: string) => void; + resetFilterValues?: () => void; } interface RepoProviderProps { @@ -32,11 +47,34 @@ export const RepoContext = createContext( ); export function RepoProvider({ children, value }: RepoProviderProps) { + const [labels, setLabels] = useState([]); + const [milestones, setMilestones] = useState([]); + const [label, setLabel] = useState(''); + const [milestone, setMilestone] = useState(''); + const [sortBy, setSortBy] = useState(''); + + const resetFilterValues = () => { + setLabel(''); + setMilestone(''); + setSortBy(''); + }; + return ( {children} diff --git a/cra-rxjs-styled-components/src/helpers/parseSortParams.ts b/cra-rxjs-styled-components/src/helpers/parseSortParams.ts new file mode 100644 index 000000000..098e87fe7 --- /dev/null +++ b/cra-rxjs-styled-components/src/helpers/parseSortParams.ts @@ -0,0 +1,12 @@ +export const parseSortParams = ({ + options, + value, + position, +}: { + options: Record; + position: number; + value?: string; +}) => + Object.keys(options) + .find((key) => options[key] === value) + ?.split('^')[position]; diff --git a/cra-rxjs-styled-components/src/helpers/replaceSpaceWithPlus.ts b/cra-rxjs-styled-components/src/helpers/replaceSpaceWithPlus.ts new file mode 100644 index 000000000..06e55f5e0 --- /dev/null +++ b/cra-rxjs-styled-components/src/helpers/replaceSpaceWithPlus.ts @@ -0,0 +1,7 @@ +export default function replaceSpaceWithPlus(str: string) { + return str.split(' ').join('+'); +} + +export const replaceEncodedSpaceWithPlus = (str: string) => { + return str.split(encodeURIComponent(' ')).join('+'); +}; diff --git a/cra-rxjs-styled-components/src/hooks/repository-issues/use-repository-issues.ts.ts b/cra-rxjs-styled-components/src/hooks/repository-issues/use-repository-issues.ts.ts deleted file mode 100644 index f55899c4f..000000000 --- a/cra-rxjs-styled-components/src/hooks/repository-issues/use-repository-issues.ts.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { useEffect, useState } from 'react'; -import { forkJoin, tap } from 'rxjs'; -import { ISSUE_PR_SEARCH } from '../../constants/url.constants'; -import { IssueTypes, IssueType } from '../../types/types'; -import { fromFetchWithAuth } from '../auth/from-fetch-with-auth'; - -export function useRepositoryIssues( - username: string, - repo: string, - issueType: IssueType -): IssueTypes { - const [issues, setIssues] = useState({ - closed: { - total_count: 0, - incomplete_results: true, - items: [], - }, - open: { - total_count: 0, - incomplete_results: true, - items: [], - }, - }); - - const request = (url: string) => - fromFetchWithAuth(url, { - selector: (response: Response) => { - return response.json(); - }, - }); - - useEffect(() => { - const subscription = forkJoin([ - request(`${ISSUE_PR_SEARCH(username, repo, issueType, 'open', 20, 1)}`), - request(`${ISSUE_PR_SEARCH(username, repo, issueType, 'closed', 20, 1)}`), - ]) - .pipe( - tap((val) => { - if (val) { - setIssues({ - open: val[0], - closed: val[1], - }); - } - }) - ) - .subscribe(); - return () => { - subscription.unsubscribe(); - }; - }, [username, repo, issueType]); - - return issues; -} diff --git a/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx b/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx new file mode 100644 index 000000000..27d771c6e --- /dev/null +++ b/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx @@ -0,0 +1,129 @@ +import { + Label, + MilestoneProps, +} from '../components/repo-issues/Issues/Issue.type'; +import { SORT_OPTIONS } from '../constants/data'; +import { + ISSUES_PULLS_URL, + PULLS_PER_PAGE, + REPO_LABELS, + REPO_MILESTONES, +} from '../constants/url.constants'; +import { useRepo } from '../context/RepoContext'; +import { parseSortParams } from '../helpers/parseSortParams'; +import { useEffect, useState } from 'react'; +import { forkJoin, tap } from 'rxjs'; +import { fromFetchWithAuth } from './auth/from-fetch-with-auth'; + +export interface IUseIssuesPRs { + searchType: 'pull-request' | 'issue'; + type: 'pulls' | 'issues'; +} + +interface IResult { + total_count: number; + incomplete_results: boolean; + items: []; +} + +export default function useIssuesPRs({ searchType, type }: IUseIssuesPRs) { + const [openPRPage, setOpenPRPage] = useState(1); + const [closedPRPage, setClosedPRPage] = useState(1); + const [open, setOpen] = useState({ + total_count: 0, + incomplete_results: true, + items: [], + }); + const [closed, setClosed] = useState({ + total_count: 0, + incomplete_results: true, + items: [], + }); + + const { + owner, + name: repo, + label, + milestone, + sortBy, + setLabels, + setMilestones, + } = useRepo(); + + const request = (url: string) => + fromFetchWithAuth(url, { + selector: (response: Response) => { + return response.json(); + }, + }); + + useEffect(() => { + const sort = parseSortParams({ + options: SORT_OPTIONS, + value: sortBy, + position: 0, + }); + const direction = parseSortParams({ + options: SORT_OPTIONS, + value: sortBy, + position: 1, + }); + const subscription = forkJoin([ + request( + `${ISSUES_PULLS_URL({ + user: owner, + repo, + type: searchType, + state: 'open', + per_page: PULLS_PER_PAGE, + page: openPRPage, + labels: label, + milestone: milestone, + sort, + direction, + })}` + ), + request( + `${ISSUES_PULLS_URL({ + user: owner, + repo, + type: searchType, + state: 'closed', + per_page: PULLS_PER_PAGE, + page: closedPRPage, + labels: label, + milestone: milestone, + sort, + direction, + })}` + ), + request(`${REPO_LABELS({ user: owner, repo })}`), + request(`${REPO_MILESTONES({ user: owner, repo })}`), + ]) + .pipe( + tap((val) => { + if (val) { + const labels = val[2] as Label[]; + const milestones = val[3] as MilestoneProps[]; + setLabels?.(labels); + setMilestones?.(milestones); + setOpen(val[0]); + setClosed(val[1]); + } + }) + ) + .subscribe(); + return () => { + subscription.unsubscribe(); + }; + }, [owner, repo, openPRPage, closedPRPage, sortBy, label, milestone, type]); + + return { + openPRPage, + setOpenPRPage, + closedPRPage, + setClosedPRPage, + open, + closed, + }; +} diff --git a/cra-rxjs-styled-components/src/routes/repo/repository-issues.tsx b/cra-rxjs-styled-components/src/routes/repo/repository-issues.tsx index 8e23f0673..d4c2283e5 100644 --- a/cra-rxjs-styled-components/src/routes/repo/repository-issues.tsx +++ b/cra-rxjs-styled-components/src/routes/repo/repository-issues.tsx @@ -1,9 +1,7 @@ +import useIssuesPRs from '../../hooks/useIssuesPRs'; import IssueCtrl from '../../components/repo-issues/Issues/Issues'; -import { useRepo } from '../../context/RepoContext'; -import { useRepositoryIssues } from '../../hooks/repository-issues/use-repository-issues.ts'; export default function RepoIssues() { - const repo = useRepo(); - const issues = useRepositoryIssues(repo.owner, repo.name, 'issue'); - return ; + const { open, closed } = useIssuesPRs({ searchType: 'issue', type: 'issues' }); + return ; } diff --git a/cra-rxjs-styled-components/src/types/types.ts b/cra-rxjs-styled-components/src/types/types.ts index 3ccbda319..9f08eff3a 100644 --- a/cra-rxjs-styled-components/src/types/types.ts +++ b/cra-rxjs-styled-components/src/types/types.ts @@ -1,3 +1,7 @@ +// import { Issue } from "../components/issue/Issue/Issue.type"; +import { Issue } from '@/components/repo-issues/Issues/Issue.type'; +import { PullRequests } from '../components/pull-request/pull-request/PullRequest.type'; + export type IssueType = 'issue' | 'pr'; export type State = 'open' | 'closed'; export type IssueTabValues = 'open' | 'closed'; @@ -6,7 +10,7 @@ export type DropdownTitle = 'Label' | 'Sort' | 'Milestones'; export type IssueDetails = { total_count: number; incomplete_results: boolean; - items: any[]; + items: Issue[]; }; export type IssueTypes = { @@ -23,3 +27,8 @@ export type FileInfo = { files: FileItem[]; directories: FileItem[]; }; + +export type IssuePRTypes = { + closed: IssueDetails | PullRequests; + open: IssueDetails | PullRequests; +}; From b8ceb6786985d2febe512781f3450d0a65b4d61f Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 12:50:29 +0100 Subject: [PATCH 2/8] chore: lint fix --- .../src/components/pull-request/pr-tab-header/PRTabHeader.tsx | 1 - .../components/repo-issues/issue-tab-header/IssueTabHeader.tsx | 3 ++- cra-rxjs-styled-components/src/constants/data.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx index ebd07b5f5..ffb0948be 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx @@ -41,7 +41,6 @@ export default function PullRequestTabHeader(props: Props) { const milestoneOptions = (milestones || []).map((milestone) => milestone.title) || []; - return ( diff --git a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx b/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx index 65429ff97..73c9bd3f6 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx +++ b/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx @@ -37,7 +37,8 @@ export default function IssueTabHeader(props: Props) { const labelOptions = (labels || []).map((label) => label.name) || []; const labelOptionsColors = (labels || []).map((label) => label.color) || []; - const milestoneOptions = (milestones || []).map((milestone) => milestone.title) || []; + const milestoneOptions = + (milestones || []).map((milestone) => milestone.title) || []; return ( diff --git a/cra-rxjs-styled-components/src/constants/data.ts b/cra-rxjs-styled-components/src/constants/data.ts index 9733b55d2..9d3ab560f 100644 --- a/cra-rxjs-styled-components/src/constants/data.ts +++ b/cra-rxjs-styled-components/src/constants/data.ts @@ -2,7 +2,6 @@ import { RepoIcon } from '../components/icons'; export const tabs = [{ title: 'Repositories', Icon: RepoIcon }]; - export const OrderField = { /** Order issues by comment count */ Comments: 'comments', From b22e8237ad3cbcc042057fe402433c0696c5c7e5 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 12:53:24 +0100 Subject: [PATCH 3/8] chore: build fix --- .../src/hooks/useIssuesPRs.tsx | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx b/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx index 27d771c6e..437238e17 100644 --- a/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx +++ b/cra-rxjs-styled-components/src/hooks/useIssuesPRs.tsx @@ -116,7 +116,19 @@ export default function useIssuesPRs({ searchType, type }: IUseIssuesPRs) { return () => { subscription.unsubscribe(); }; - }, [owner, repo, openPRPage, closedPRPage, sortBy, label, milestone, type]); + }, [ + owner, + repo, + openPRPage, + closedPRPage, + sortBy, + label, + milestone, + type, + searchType, + setLabels, + setMilestones, + ]); return { openPRPage, From bf7aa9b1e08de8b728f293f9efa90f6a447a39a0 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 12:59:49 +0100 Subject: [PATCH 4/8] chore: sonar code smell fix --- .../src/constants/url.constants.ts | 14 +++++--------- cra-rxjs-styled-components/src/types/types.ts | 1 - 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/cra-rxjs-styled-components/src/constants/url.constants.ts b/cra-rxjs-styled-components/src/constants/url.constants.ts index 236eed3ac..3800011d6 100644 --- a/cra-rxjs-styled-components/src/constants/url.constants.ts +++ b/cra-rxjs-styled-components/src/constants/url.constants.ts @@ -85,17 +85,13 @@ export const ISSUES_PULLS_URL = ({ order: direction, }; const queryStrings = convertObjectToQueryString(params); + const milestone_check = + typeof milestone === 'string' + ? replaceEncodedSpaceWithPlus(encodeURIComponent(milestone)) + : milestone; const Q = `+is:${state}+is:${type}${ labels ? `+label:"${replaceSpaceWithPlus(labels)}"` : '' - }${ - milestone - ? `+milestone:"${ - typeof milestone === 'string' - ? replaceEncodedSpaceWithPlus(encodeURIComponent(milestone)) - : milestone - }"` - : '' - }`; + }${milestone ? `+milestone:"${milestone_check}"` : ''}`; return `${GITHUB_URL_BASE}/search/issues?q=repo:${user}/${repo}${Q}&${queryStrings}`; }; diff --git a/cra-rxjs-styled-components/src/types/types.ts b/cra-rxjs-styled-components/src/types/types.ts index 9f08eff3a..9895ebb1d 100644 --- a/cra-rxjs-styled-components/src/types/types.ts +++ b/cra-rxjs-styled-components/src/types/types.ts @@ -1,4 +1,3 @@ -// import { Issue } from "../components/issue/Issue/Issue.type"; import { Issue } from '@/components/repo-issues/Issues/Issue.type'; import { PullRequests } from '../components/pull-request/pull-request/PullRequest.type'; From c69817490bdd6bca1a2a79ab4187f12ddb9cec79 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 13:11:23 +0100 Subject: [PATCH 5/8] chore: sonar code smell fix --- cra-rxjs-styled-components/src/constants/url.constants.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cra-rxjs-styled-components/src/constants/url.constants.ts b/cra-rxjs-styled-components/src/constants/url.constants.ts index 3800011d6..a503c8cd2 100644 --- a/cra-rxjs-styled-components/src/constants/url.constants.ts +++ b/cra-rxjs-styled-components/src/constants/url.constants.ts @@ -85,13 +85,14 @@ export const ISSUES_PULLS_URL = ({ order: direction, }; const queryStrings = convertObjectToQueryString(params); - const milestone_check = + const milestone_check = `+milestone:"${ typeof milestone === 'string' ? replaceEncodedSpaceWithPlus(encodeURIComponent(milestone)) - : milestone; + : milestone + }"`; const Q = `+is:${state}+is:${type}${ labels ? `+label:"${replaceSpaceWithPlus(labels)}"` : '' - }${milestone ? `+milestone:"${milestone_check}"` : ''}`; + }${milestone ? milestone_check : ''}`; return `${GITHUB_URL_BASE}/search/issues?q=repo:${user}/${repo}${Q}&${queryStrings}`; }; From d07cc129e8e7f896680d1efe85d6158596affeac Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 14:34:16 +0100 Subject: [PATCH 6/8] chore: sonar code duplication --- .../src/components/issue/Issue.stories.tsx | 94 --------------- .../src/components/issue/Issue/Issue.data.tsx | 91 -------------- .../components/issue/Issue/Issue.style.tsx | 112 ------------------ .../src/components/issue/Issue/Issue.type.ts | 10 -- .../src/components/issue/Issue/Issue.view.tsx | 36 ------ .../issue/issue-card/IssueCard.style.tsx | 75 ------------ .../components/issue/issue-card/IssueCard.tsx | 55 --------- .../issue/issue-tab-header/IssueTabHeader.tsx | 85 ------------- .../src/components/issue/types.ts | 3 - .../IssuePRTabHeader.styles.tsx} | 4 +- .../IssuePRTabHeader.tsx} | 35 +++--- .../pull-request/PullRequest.view.tsx | 9 +- .../repo-issues/Issues/Issues.view.tsx | 5 +- .../IssueTabHeader.styles.tsx | 63 ---------- 14 files changed, 29 insertions(+), 648 deletions(-) delete mode 100644 cra-rxjs-styled-components/src/components/issue/Issue.stories.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/Issue/Issue.data.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/Issue/Issue.style.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/Issue/Issue.type.ts delete mode 100644 cra-rxjs-styled-components/src/components/issue/Issue/Issue.view.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.style.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.tsx delete mode 100644 cra-rxjs-styled-components/src/components/issue/types.ts rename cra-rxjs-styled-components/src/components/{issue/issue-tab-header/IssueTabHeader.style.tsx => pr-issue-tab/IssuePRTabHeader.styles.tsx} (92%) rename cra-rxjs-styled-components/src/components/{repo-issues/issue-tab-header/IssueTabHeader.tsx => pr-issue-tab/IssuePRTabHeader.tsx} (60%) delete mode 100644 cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.styles.tsx diff --git a/cra-rxjs-styled-components/src/components/issue/Issue.stories.tsx b/cra-rxjs-styled-components/src/components/issue/Issue.stories.tsx deleted file mode 100644 index 47cb0830b..000000000 --- a/cra-rxjs-styled-components/src/components/issue/Issue.stories.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { ComponentStory, ComponentMeta } from '@storybook/react'; -import { Routes, Route, MemoryRouter } from 'react-router-dom'; -import Issue from './Issue/Issue.view'; - -export default { - title: 'Repo/Issue', - component: Issue, -} as ComponentMeta; - -const Template: ComponentStory = (args) => ( - - - }> - - -); - -const openDate = new Date().toISOString(); - -export const OpenIssues = Template.bind({}); -OpenIssues.args = { - issues: [ - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 0, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 2, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 3, - }, - ], -}; - -export const ClosedIssues = Template.bind({}); -ClosedIssues.args = { - issues: [ - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: openDate, - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - ], -}; diff --git a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.data.tsx b/cra-rxjs-styled-components/src/components/issue/Issue/Issue.data.tsx deleted file mode 100644 index bca516511..000000000 --- a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.data.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import { useState } from 'react'; -import IssuesView from './Issue.view'; -import type { Issue } from './Issue.type'; -import type { IssueTabValues } from '../types'; - -export default function IssuesCtrl() { - const [activeTab, setActiveTab] = useState('open'); - const OPEN_PRS: Issue[] = [ - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 0, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 2, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'open', - messageCount: 3, - }, - ]; - const CLOSED_PRS: Issue[] = [ - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - { - title: 'Remix/Feature/125 individual repo page', - openedNum: '#134 opened', - openedDay: 'yesterday', - openedBy: 'by vyktoremario', - status: 'closed', - messageCount: 8, - }, - ]; - - return ( - - ); -} diff --git a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.style.tsx b/cra-rxjs-styled-components/src/components/issue/Issue/Issue.style.tsx deleted file mode 100644 index 154db99c2..000000000 --- a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.style.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import styled from 'styled-components'; -import colors from '../../../constants/colors'; - -export const Wrapper = styled.div` - margin-inline: auto; - margin-top: 16px; - max-width: 60rem; -`; - -export const Content = styled.div` - border: 1px solid ${colors.gray300}; - border-radius: 6px; -`; - -export const PaginationContainer = styled.div` - display: flex; - justify-content: center; - padding: 10px 0; - - & > span { - min-width: 32px; - padding: 5px 10px; - font-style: normal; - line-height: 20px; - color: ${colors.gray800}; - text-align: center; - white-space: nowrap; - vertical-align: middle; - cursor: pointer; - -webkit-user-select: none; - user-select: none; - border: 1px solid transparent; - border-radius: 6px; - transition: border-color 0.2s cubic-bezier(0.3, 0, 0.5, 1); - } - - & .disabled { - color: ${colors.gray400}; - cursor: default; - border-color: transparent; - } - - & > .prev { - position: relative; - &::before { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: text-bottom; - content: ''; - background-color: currentColor; - margin-right: 4px; - -webkit-clip-path: polygon( - 9.8px 12.8px, - 8.7px 12.8px, - 4.5px 8.5px, - 4.5px 7.5px, - 8.7px 3.2px, - 9.8px 4.3px, - 6.1px 8px, - 9.8px 11.7px, - 9.8px 12.8px - ); - clip-path: polygon( - 9.8px 12.8px, - 8.7px 12.8px, - 4.5px 8.5px, - 4.5px 7.5px, - 8.7px 3.2px, - 9.8px 4.3px, - 6.1px 8px, - 9.8px 11.7px, - 9.8px 12.8px - ); - } - } - - & > .next { - position: relative; - &::after { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: text-bottom; - content: ''; - background-color: currentColor; - margin-left: 4px; - -webkit-clip-path: polygon( - 6.2px 3.2px, - 7.3px 3.2px, - 11.5px 7.5px, - 11.5px 8.5px, - 7.3px 12.8px, - 6.2px 11.7px, - 9.9px 8px, - 6.2px 4.3px, - 6.2px 3.2px - ); - clip-path: polygon( - 6.2px 3.2px, - 7.3px 3.2px, - 11.5px 7.5px, - 11.5px 8.5px, - 7.3px 12.8px, - 6.2px 11.7px, - 9.9px 8px, - 6.2px 4.3px, - 6.2px 3.2px - ); - } - } -`; diff --git a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.type.ts b/cra-rxjs-styled-components/src/components/issue/Issue/Issue.type.ts deleted file mode 100644 index 12a0978b6..000000000 --- a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.type.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Status } from '../types'; - -export type Issue = { - title: string; - openedNum: string; - openedDay: string; - openedBy: string; - status: Status; - messageCount: number; -}; diff --git a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.view.tsx b/cra-rxjs-styled-components/src/components/issue/Issue/Issue.view.tsx deleted file mode 100644 index 2a724950c..000000000 --- a/cra-rxjs-styled-components/src/components/issue/Issue/Issue.view.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import IssueTabHeader from '../issue-tab-header/IssueTabHeader'; -import IssueCard from '../issue-card/IssueCard'; -import { PaginationContainer, Content, Wrapper } from './Issue.style'; -import type { Issue } from './Issue.type'; -import type { IssueTabValues } from '../types'; - -type IssueProps = { - issues: Issue[]; - changeActiveTab: (value: IssueTabValues) => void; -}; - -export default function IssuesView({ issues, changeActiveTab }: IssueProps) { - const changeTab = changeActiveTab || (() => {}); - return ( - - - - {issues.map((issue, index) => ( - - ))} - - - Previous - Next - - - ); -} diff --git a/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.style.tsx b/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.style.tsx deleted file mode 100644 index ec00b64a3..000000000 --- a/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.style.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import styled, { css } from 'styled-components'; -import colors from '../../../constants/colors'; - -const flex = css` - display: flex; - align-items: center; -`; -export const IssueCardWrapper = styled.div` - ${flex}; - padding: 15px 20px; - border-bottom: 1px solid ${colors.gray300}; - justify-content: space-between; - & > .left { - ${flex}; - & > .icon { - font-size: 1.1rem; - margin-right: 0.8rem; - align-self: start; - color: ${colors.green800}; - &.closed { - color: ${colors.purple500}; - } - } - & > .info { - ${flex}; - flex-direction: column; - align-items: start; - & > .heading { - font-weight: 600 !important - font-size: 16px !important; - vertical-align: middle !important; - color: ${colors.gray800}; - margin-bottom: 0.8rem; - &:hover { - color: ${colors.blue800}; - } - } - & > .sub_heading { - color: ${colors.gray600}; - font-size: 12px !important; - & > *:not(:last-child) { - margin-inline: 0.2rem; - } - } - } - } - - & > .right { - .message { - ${flex}; - & .icon { - font-size: 1.1rem; - } - flex-direction: column; - } - } - - a { - text-decoration: none; - color: ${colors.gray600}; - &:hover { - color: ${colors.blue800}; - } - } - svg { - color: ${colors.gray600}; - display: inline-block; - overflow: visible !important; - vertical-align: text-bottom; - fill: currentColor; - &:hover { - color: ${colors.blue800}; - } - } -`; diff --git a/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.tsx b/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.tsx deleted file mode 100644 index fa687c44b..000000000 --- a/cra-rxjs-styled-components/src/components/issue/issue-card/IssueCard.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import ClosedIssueIcon from '../../icons/ClosedIssueIcon'; -import MessageIcon from '../../icons/MessageIcon'; -import OpenIssueIcon from '../../icons/OpenIssueIcon'; -import PullRequestIssueInfo from '../../pull-request-issue-info/PullRequestIssueInfo'; -import { IssueCardWrapper } from './IssueCard.style'; -import type { Status } from '../types'; -import { Link } from 'react-router-dom'; - -interface Props { - status: Status; - title: string; - openedNum: string; - openedDay: string; - openedBy: string; - messageCount: number; -} - -export default function IssueCard({ - status, - title, - openedBy, - openedDay, - openedNum, - messageCount, -}: Props) { - const getPRIcon = (status: Status) => { - if (status === 'open') { - return ; - } else { - return ; - } - }; - return ( - -
- {getPRIcon(status)} - -
-
- {messageCount > 0 && ( - - - 8 - - )} -
-
- ); -} diff --git a/cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.tsx b/cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.tsx deleted file mode 100644 index c917ee135..000000000 --- a/cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import { useCallback, useState } from 'react'; -import DetailsDropdown from '../../details-dropdown/DetailsDropdown'; -import CorrectIcon from '../../icons/CorrectIcon'; -import IssueIcon from '../../icons/IssueIcon'; -import type { IssueTabValues, DropdownTitle } from '../types'; -import { Link } from 'react-router-dom'; -import { Container, StatusLabel, StatusTab } from './IssueTabHeader.style'; -interface Props { - toggleTab: (value: IssueTabValues) => void; -} - -export default function IssueTabHeader({ toggleTab }: Props) { - const [activeTab, setActiveTab] = useState('open'); - const [openDropdown, setOpenDropdown] = useState(); - - const changeTab = (value: IssueTabValues) => { - toggleTab(value); - setActiveTab(value); - }; - - const toggleDropdown = useCallback( - (dropdownName: DropdownTitle) => { - setOpenDropdown((prevValue) => - prevValue === dropdownName ? undefined : dropdownName - ); - }, - [openDropdown] - ); - - return ( - - - changeTab('open')} - active={activeTab === 'open'} - > - - 10 - Open - - changeTab('close')} - active={activeTab === 'close'} - > - - 14 - Close - - - - toggleDropdown('Milestones')} - isOpen={openDropdown === 'Milestones'} - > - Issues with no milestones - Serverless Migrations - - toggleDropdown('Label')} - isOpen={openDropdown === 'Label'} - > - WIP DO NOT MERGE - Enhancement - - toggleDropdown('Sort')} - isOpen={openDropdown === 'Sort'} - > - Newest - Oldest - Most Commented - Least Commented - Resently Updated - Least Resently Updated - - - - ); -} diff --git a/cra-rxjs-styled-components/src/components/issue/types.ts b/cra-rxjs-styled-components/src/components/issue/types.ts deleted file mode 100644 index 95b6fbaac..000000000 --- a/cra-rxjs-styled-components/src/components/issue/types.ts +++ /dev/null @@ -1,3 +0,0 @@ -export type IssueTabValues = 'open' | 'close'; -export type Status = 'closed' | 'open'; -export type DropdownTitle = 'Milestones' | 'Label' | 'Sort'; diff --git a/cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.style.tsx b/cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.styles.tsx similarity index 92% rename from cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.style.tsx rename to cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.styles.tsx index b26c3fce1..86ee35229 100644 --- a/cra-rxjs-styled-components/src/components/issue/issue-tab-header/IssueTabHeader.style.tsx +++ b/cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.styles.tsx @@ -1,5 +1,5 @@ import styled, { css } from 'styled-components'; -import colors from '../../../constants/colors'; +import colors from '../../constants/colors'; const flex = css` display: flex; @@ -50,7 +50,7 @@ export const StatusLabel = styled.span` } color: ${colors.gray600}; cursor: pointer; - ${(props: { active: Boolean }) => + ${(props: { active: boolean }) => props.active ? css` color: ${colors.gray800}; diff --git a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx b/cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.tsx similarity index 60% rename from cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx rename to cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.tsx index 73c9bd3f6..7b13de56c 100644 --- a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.tsx +++ b/cra-rxjs-styled-components/src/components/pr-issue-tab/IssuePRTabHeader.tsx @@ -1,20 +1,23 @@ import { useState } from 'react'; -import CorrectIcon from '../../icons/CorrectIcon'; -import OpenIssueIcon from '../../icons/OpenIssueIcon'; -import type { IssueTabValues } from '../../../types/types'; -import { Container, StatusLabel, StatusTab } from './IssueTabHeader.styles'; -import { useRepo } from '../../../context/RepoContext'; -import FilterDropdown from '../../../components/filter-dropdown/FilterDropdown'; -import { SORT_OPTIONS } from '../../../constants/data'; +import { Container, StatusLabel, StatusTab } from './IssuePRTabHeader.styles'; +import { useRepo } from '../../context/RepoContext'; +import FilterDropdown from '../filter-dropdown/FilterDropdown'; +import { CorrectIcon } from '../icons'; +import OpenIssueIcon from '../icons/OpenIssueIcon'; +import { SORT_OPTIONS } from '../../constants/data'; +import PullRequestIcon from '../icons/PullRequestIcon'; interface Props { toggleTab: any; closedCount: number; openCount: number; + type: 'issue' | 'pr'; } -export default function IssueTabHeader(props: Props) { +export type IssuePRTabValues = 'open' | 'close'; + +export default function IssuePRTabHeader(props: Props) { const { labels, milestones, @@ -25,10 +28,10 @@ export default function IssueTabHeader(props: Props) { setMilestone, setSortBy, } = useRepo(); - const [activeTab, setActiveTab] = useState('open'); - const { toggleTab, closedCount, openCount } = props; + const [activeTab, setActiveTab] = useState('open'); + const { toggleTab, closedCount, openCount, type } = props; - const changeTab = (value: IssueTabValues) => { + const changeTab = (value: IssuePRTabValues) => { toggleTab(value); setActiveTab(value); }; @@ -47,16 +50,16 @@ export default function IssueTabHeader(props: Props) { onClick={() => changeTab('open')} active={activeTab === 'open'} > - - {openCount} + {type === 'issue' ? : } + {openCount || 0} Open changeTab('closed')} - active={activeTab === 'closed'} + onClick={() => changeTab('close')} + active={activeTab === 'close'} > - {closedCount} + {closedCount || 0} Closed
diff --git a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx index 4e913a273..d94fc42e2 100644 --- a/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx +++ b/cra-rxjs-styled-components/src/components/pull-request/pull-request/PullRequest.view.tsx @@ -3,10 +3,10 @@ import { Content, PaginationContainer, Wrapper } from './PullRequest.style'; import type { PRTabValues } from '../types'; import type { PullRequest } from './PullRequest.type'; import PullRequestCard from '../pull-request-card/PullRequestCard'; -import PullRequestTabHeader from '../pr-tab-header/PRTabHeader'; import { getPullsState } from '../../../helpers/getPullsState'; import ReactPaginate from 'react-paginate'; import { PULLS_PER_PAGE } from '../../../constants/url.constants'; +import IssuePRTabHeader from '../../../components/pr-issue-tab/IssuePRTabHeader'; type PullRequestProps = { pullRequests: PullRequest[]; @@ -38,10 +38,11 @@ export default function PullRequestView({ return ( - {(pullRequests || []).map((pr, index) => ( - {(issues || []).map((issue, index) => ( diff --git a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.styles.tsx b/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.styles.tsx deleted file mode 100644 index b26c3fce1..000000000 --- a/cra-rxjs-styled-components/src/components/repo-issues/issue-tab-header/IssueTabHeader.styles.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import styled, { css } from 'styled-components'; -import colors from '../../../constants/colors'; - -const flex = css` - display: flex; - align-items: center; -`; - -export const Container = styled.div` - background-color: ${colors.gray100}; - border: 1px solid ${colors.gray300}; - border-left-width: 1px; - border-right-width: 1px; - border-top-left-radius: 6px; - border-top-right-radius: 6px; - padding: 16px; - margin: -1px -1px 0; - ${flex}; - justify-content: space-between; - - svg { - color: ${colors.gray600}; - display: inline-block; - overflow: visible !important; - vertical-align: text-bottom; - fill: currentColor; - } -`; - -export const StatusTab = styled.div` - ${flex}; - font-size: 1.1rem; - & > .statusLabel { - } -`; - -export const StatusLabel = styled.span` - ${flex}; - & > *:not(:last-child) { - margin-right: 0.4rem; - } - svg { - margin-right: 0.3rem; - } - span { - font-size: 14px; - } - &:not(:last-child) { - margin-right: 0.8rem; - } - color: ${colors.gray600}; - cursor: pointer; - ${(props: { active: Boolean }) => - props.active - ? css` - color: ${colors.gray800}; - font-weight: 600; - svg { - color: ${colors.gray800}; - } - ` - : ''} -`; From 73c967f0fb5f6f866ab147067a06fa708c7557af Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 14:39:36 +0100 Subject: [PATCH 7/8] chore: sonar duplication --- .../pr-tab-header/PRTabHeader.style.tsx | 63 ------------- .../pr-tab-header/PRTabHeader.tsx | 92 ------------------- 2 files changed, 155 deletions(-) delete mode 100644 cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.style.tsx delete mode 100644 cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx diff --git a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.style.tsx b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.style.tsx deleted file mode 100644 index b26c3fce1..000000000 --- a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.style.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import styled, { css } from 'styled-components'; -import colors from '../../../constants/colors'; - -const flex = css` - display: flex; - align-items: center; -`; - -export const Container = styled.div` - background-color: ${colors.gray100}; - border: 1px solid ${colors.gray300}; - border-left-width: 1px; - border-right-width: 1px; - border-top-left-radius: 6px; - border-top-right-radius: 6px; - padding: 16px; - margin: -1px -1px 0; - ${flex}; - justify-content: space-between; - - svg { - color: ${colors.gray600}; - display: inline-block; - overflow: visible !important; - vertical-align: text-bottom; - fill: currentColor; - } -`; - -export const StatusTab = styled.div` - ${flex}; - font-size: 1.1rem; - & > .statusLabel { - } -`; - -export const StatusLabel = styled.span` - ${flex}; - & > *:not(:last-child) { - margin-right: 0.4rem; - } - svg { - margin-right: 0.3rem; - } - span { - font-size: 14px; - } - &:not(:last-child) { - margin-right: 0.8rem; - } - color: ${colors.gray600}; - cursor: pointer; - ${(props: { active: Boolean }) => - props.active - ? css` - color: ${colors.gray800}; - font-weight: 600; - svg { - color: ${colors.gray800}; - } - ` - : ''} -`; diff --git a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx b/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx deleted file mode 100644 index ffb0948be..000000000 --- a/cra-rxjs-styled-components/src/components/pull-request/pr-tab-header/PRTabHeader.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Container, StatusLabel, StatusTab } from './PRTabHeader.style'; -import { useState } from 'react'; - -import CorrectIcon from '../../icons/CorrectIcon'; -import type { PRTabValues } from '../types'; -import PullRequestIcon from '../../icons/PullRequestIcon'; -import { useRepo } from '../../../context/RepoContext'; -import { SORT_OPTIONS } from '../../../constants/data'; -import FilterDropdown from '../../../components/filter-dropdown/FilterDropdown'; - -interface Props { - toggleTab: any; - openPRCount: number; - closedPRCount: number; -} - -export default function PullRequestTabHeader(props: Props) { - const [activeTab, setActiveTab] = useState('open'); - const { toggleTab } = props; - - const { - labels, - milestones, - label, - sortBy, - milestone, - setLabel, - setMilestone, - setSortBy, - } = useRepo(); - - const changeTab = (value: PRTabValues) => { - toggleTab(value); - setActiveTab(value); - }; - - const sortOptions = Object.values(SORT_OPTIONS); - - const labelOptions = (labels || []).map((label) => label.name) || []; - const labelOptionsColors = (labels || []).map((label) => label.color) || []; - const milestoneOptions = - (milestones || []).map((milestone) => milestone.title) || []; - - return ( - - - changeTab('open')} - active={activeTab === 'open'} - > - - {props.openPRCount} - Open - - changeTab('close')} - active={activeTab === 'close'} - > - - {props.closedPRCount} - Close - - - - - - - - - - - ); -} From c2934d9eb0ba105055bc7d733157c1dbaff5a5d8 Mon Sep 17 00:00:00 2001 From: Jerry Hogan Date: Thu, 17 Aug 2023 14:44:09 +0100 Subject: [PATCH 8/8] chore: sonar duplication --- cra-rxjs-styled-components/src/constants/data.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cra-rxjs-styled-components/src/constants/data.ts b/cra-rxjs-styled-components/src/constants/data.ts index 9d3ab560f..87ed473d3 100644 --- a/cra-rxjs-styled-components/src/constants/data.ts +++ b/cra-rxjs-styled-components/src/constants/data.ts @@ -2,7 +2,7 @@ import { RepoIcon } from '../components/icons'; export const tabs = [{ title: 'Repositories', Icon: RepoIcon }]; -export const OrderField = { +const OrderField = { /** Order issues by comment count */ Comments: 'comments', /** Order issues by creation time */ @@ -11,7 +11,7 @@ export const OrderField = { UpdatedAt: 'updated', }; -export const OrderDirection = { +const OrderDirection = { Asc: 'asc', Desc: 'desc', };