fix: [CODE-1577] include pr author in browser param in PR listing page (#2868)

* fix: [CODE-1577] remove redundant code
* refactor: [code-1577] address comments
* fix: [code-1577] lint
* fix: [CODE-1577] address comments
* fix: [code-1577] lint
* fix: [code-1577] lint
* fix: [code-1577] lint
* fix: [code-1577] lint
* feat: [code-1577] add author in URL
This commit is contained in:
Ritik Kapoor 2024-11-06 10:20:51 +00:00 committed by Harness
parent 1c43fbde25
commit 68db486133
6 changed files with 136 additions and 5 deletions

View File

@ -26,6 +26,10 @@ import (
"github.com/swaggest/openapi-go/openapi3" "github.com/swaggest/openapi-go/openapi3"
) )
type principalInfoRequest struct {
ID int64 `path:"id"`
}
var QueryParameterQueryPrincipals = openapi3.ParameterOrRef{ var QueryParameterQueryPrincipals = openapi3.ParameterOrRef{
Parameter: &openapi3.Parameter{ Parameter: &openapi3.Parameter{
Name: request.QueryParamQuery, Name: request.QueryParamQuery,
@ -74,4 +78,16 @@ func buildPrincipals(reflector *openapi3.Reflector) {
_ = reflector.SetJSONResponse(&opList, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&opList, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&opList, new(usererror.Error), http.StatusNotFound) _ = reflector.SetJSONResponse(&opList, new(usererror.Error), http.StatusNotFound)
_ = reflector.Spec.AddOperation(http.MethodGet, "/principals", opList) _ = reflector.Spec.AddOperation(http.MethodGet, "/principals", opList)
getPrincipal := openapi3.Operation{}
getPrincipal.WithTags("principals")
getPrincipal.WithMapOfAnything(map[string]interface{}{"operationId": "getPrincipal"})
_ = reflector.SetRequest(&getPrincipal, new(principalInfoRequest), http.MethodGet)
_ = reflector.SetJSONResponse(&getPrincipal, new(types.PrincipalInfo), http.StatusOK)
_ = reflector.SetJSONResponse(&getPrincipal, new(usererror.Error), http.StatusBadRequest)
_ = reflector.SetJSONResponse(&getPrincipal, new(usererror.Error), http.StatusInternalServerError)
_ = reflector.SetJSONResponse(&getPrincipal, new(usererror.Error), http.StatusUnauthorized)
_ = reflector.SetJSONResponse(&getPrincipal, new(usererror.Error), http.StatusForbidden)
_ = reflector.SetJSONResponse(&getPrincipal, new(usererror.Error), http.StatusNotFound)
_ = reflector.Spec.AddOperation(http.MethodGet, "/principals/{id}", getPrincipal)
} }

View File

@ -52,7 +52,12 @@ import { usePageIndex } from 'hooks/usePageIndex'
import { useGetSpaceParam } from 'hooks/useGetSpaceParam' import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams' import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams'
import { useQueryParams } from 'hooks/useQueryParams' import { useQueryParams } from 'hooks/useQueryParams'
import type { TypesPullReq, RepoRepositoryOutput, TypesLabelPullReqAssignmentInfo } from 'services/code' import type {
TypesPullReq,
RepoRepositoryOutput,
TypesLabelPullReqAssignmentInfo,
TypesPrincipalInfo
} from 'services/code'
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination' import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
import { NoResultCard } from 'components/NoResultCard/NoResultCard' import { NoResultCard } from 'components/NoResultCard/NoResultCard'
import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator' import { PipeSeparator } from 'components/PipeSeparator/PipeSeparator'
@ -62,6 +67,7 @@ import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
import useSpaceSSE from 'hooks/useSpaceSSE' import useSpaceSSE from 'hooks/useSpaceSSE'
import { TimePopoverWithLocal } from 'utils/timePopoverLocal/TimePopoverWithLocal' import { TimePopoverWithLocal } from 'utils/timePopoverLocal/TimePopoverWithLocal'
import { Label } from 'components/Label/Label' import { Label } from 'components/Label/Label'
import { getConfig } from 'services/config'
import { PullRequestsContentHeader } from './PullRequestsContentHeader/PullRequestsContentHeader' import { PullRequestsContentHeader } from './PullRequestsContentHeader/PullRequestsContentHeader'
import css from './PullRequests.module.scss' import css from './PullRequests.module.scss'
@ -70,20 +76,32 @@ const SSE_EVENTS = ['pullreq_updated']
export default function PullRequests() { export default function PullRequests() {
const { getString } = useStrings() const { getString } = useStrings()
const history = useHistory() const history = useHistory()
const { routes, hooks, standalone } = useAppContext() const { routes, hooks, standalone, routingId } = useAppContext()
const { CODE_PULLREQ_LABELS: isLabelEnabled } = hooks?.useFeatureFlags() const { CODE_PULLREQ_LABELS: isLabelEnabled } = hooks?.useFeatureFlags()
const [searchTerm, setSearchTerm] = useState<string | undefined>() const [searchTerm, setSearchTerm] = useState<string | undefined>()
const browserParams = useQueryParams<PageBrowserProps>() const browserParams = useQueryParams<PageBrowserProps>()
const [filter, setFilter] = useState(browserParams?.state || (PullRequestFilterOption.OPEN as string)) const [filter, setFilter] = useState(browserParams?.state || (PullRequestFilterOption.OPEN as string))
const [authorFilter, setAuthorFilter] = useState<string>() const [authorFilter, setAuthorFilter] = useState<string>(browserParams?.author ?? '')
const [labelFilter, setLabelFilter] = useState<LabelFilterObj[]>([]) const [labelFilter, setLabelFilter] = useState<LabelFilterObj[]>([])
const space = useGetSpaceParam() const space = useGetSpaceParam()
const { updateQueryParams, replaceQueryParams } = useUpdateQueryParams() const { updateQueryParams, replaceQueryParams } = useUpdateQueryParams()
const pageInit = browserParams.page ? parseInt(browserParams.page) : 1 const pageInit = browserParams.page ? parseInt(browserParams.page) : 1
const [page, setPage] = usePageIndex(pageInit) const [page, setPage] = usePageIndex(pageInit)
const { data: principal, refetch: refetchPrincipal } = useGet<TypesPrincipalInfo>({
base: getConfig('code/api/v1'),
path: `/principals/${browserParams.author}`,
queryParams: {
accountIdentifier: routingId
},
lazy: true,
debounce: 500
})
useEffect(() => { useEffect(() => {
const params = { const params = {
...browserParams, ...browserParams,
...(Boolean(authorFilter) && { author: authorFilter }),
...(page > 1 && { page: page.toString() }), ...(page > 1 && { page: page.toString() }),
...(filter && { state: filter }) ...(filter && { state: filter })
} }
@ -94,7 +112,18 @@ export default function PullRequests() {
delete updateParams.page delete updateParams.page
replaceQueryParams(updateParams, undefined, true) replaceQueryParams(updateParams, undefined, true)
} }
}, [page, filter]) // eslint-disable-line react-hooks/exhaustive-deps
if (!authorFilter && browserParams.author) {
const paramList = { ...params }
delete paramList.author
replaceQueryParams(paramList, undefined, true)
}
if (browserParams.author) {
refetchPrincipal()
}
}, [page, filter, authorFilter]) // eslint-disable-line react-hooks/exhaustive-deps
const { repoMetadata, error, loading, refetch } = useGetRepositoryMetadata() const { repoMetadata, error, loading, refetch } = useGetRepositoryMetadata()
const { const {
data, data,
@ -385,6 +414,7 @@ export default function PullRequests() {
setSearchTerm(value) setSearchTerm(value)
setPage(1) setPage(1)
}} }}
activePullRequestAuthorObj={principal}
activePullRequestAuthorFilterOption={authorFilter} activePullRequestAuthorFilterOption={authorFilter}
activePullRequestLabelFilterOption={labelFilter} activePullRequestLabelFilterOption={labelFilter}
onPullRequestAuthorFilterChanged={_authorFilter => { onPullRequestAuthorFilterChanged={_authorFilter => {

View File

@ -45,6 +45,7 @@ interface PullRequestsContentHeaderProps extends Pick<GitInfoProps, 'repoMetadat
loading?: boolean loading?: boolean
activePullRequestFilterOption?: string activePullRequestFilterOption?: string
activePullRequestAuthorFilterOption?: string activePullRequestAuthorFilterOption?: string
activePullRequestAuthorObj?: TypesPrincipalInfo | null
activePullRequestLabelFilterOption?: LabelFilterObj[] activePullRequestLabelFilterOption?: LabelFilterObj[]
onPullRequestFilterChanged: React.Dispatch<React.SetStateAction<string>> onPullRequestFilterChanged: React.Dispatch<React.SetStateAction<string>>
onPullRequestAuthorFilterChanged: (authorFilter: string) => void onPullRequestAuthorFilterChanged: (authorFilter: string) => void
@ -60,6 +61,7 @@ export function PullRequestsContentHeader({
onSearchTermChanged, onSearchTermChanged,
activePullRequestFilterOption = PullRequestFilterOption.OPEN, activePullRequestFilterOption = PullRequestFilterOption.OPEN,
activePullRequestAuthorFilterOption, activePullRequestAuthorFilterOption,
activePullRequestAuthorObj,
activePullRequestLabelFilterOption, activePullRequestLabelFilterOption,
repoMetadata repoMetadata
}: PullRequestsContentHeaderProps) { }: PullRequestsContentHeaderProps) {
@ -158,7 +160,11 @@ export function PullRequestsContentHeader({
} }
} }
) )
const authorsList = await moveCurrentUserToTop(fetchedAuthors, currentUser, query)
const authors = [...fetchedAuthors, ...(activePullRequestAuthorObj ? [activePullRequestAuthorObj] : [])]
const authorsList = await moveCurrentUserToTop(authors, currentUser, query)
const updatedAuthorsList = Array.isArray(authorsList) const updatedAuthorsList = Array.isArray(authorsList)
? ([ ? ([
...(authorsList || []).map(item => ({ ...(authorsList || []).map(item => ({

View File

@ -2580,6 +2580,36 @@ export const useListPrincipals = (props: UseListPrincipalsProps) =>
...props ...props
}) })
export interface GetPrincipalPathParams {
id: number
}
export type GetPrincipalProps = Omit<
GetProps<TypesPrincipalInfo, UsererrorError, void, GetPrincipalPathParams>,
'path'
> &
GetPrincipalPathParams
export const GetPrincipal = ({ id, ...props }: GetPrincipalProps) => (
<Get<TypesPrincipalInfo, UsererrorError, void, GetPrincipalPathParams>
path={`/principals/${id}`}
base={getConfig('code/api/v1')}
{...props}
/>
)
export type UseGetPrincipalProps = Omit<
UseGetProps<TypesPrincipalInfo, UsererrorError, void, GetPrincipalPathParams>,
'path'
> &
GetPrincipalPathParams
export const useGetPrincipal = ({ id, ...props }: UseGetPrincipalProps) =>
useGet<TypesPrincipalInfo, UsererrorError, void, GetPrincipalPathParams>(
(paramsInPath: GetPrincipalPathParams) => `/principals/${paramsInPath.id}`,
{ base: getConfig('code/api/v1'), pathParams: { id }, ...props }
)
export interface OnRegisterQueryParams { export interface OnRegisterQueryParams {
/** /**
* If set to true the token is also returned as a cookie. * If set to true the token is also returned as a cookie.

View File

@ -1042,6 +1042,54 @@ paths:
description: Internal Server Error description: Internal Server Error
tags: tags:
- principals - principals
/principals/{id}:
get:
operationId: getPrincipal
parameters:
- in: path
name: id
required: true
schema:
type: integer
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/TypesPrincipalInfo'
description: OK
'400':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Bad Request
'401':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Unauthorized
'403':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Forbidden
'404':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Not Found
'500':
content:
application/json:
schema:
$ref: '#/components/schemas/UsererrorError'
description: Internal Server Error
tags:
- principals
/register: /register:
post: post:
operationId: onRegister operationId: onRegister

View File

@ -99,6 +99,7 @@ export const getErrorMessage = (error: Unknown): string | undefined =>
error ? get(error, 'data.error', get(error, 'data.message', get(error, 'message', error))) : undefined error ? get(error, 'data.error', get(error, 'data.message', get(error, 'message', error))) : undefined
export interface PageBrowserProps { export interface PageBrowserProps {
author?: string
page?: string page?: string
state?: string state?: string
tab?: string tab?: string