mirror of
https://github.com/harness/drone.git
synced 2025-05-10 00:11:43 +08:00
[CODE-1144] UI : Added author filter on PR page (#855)
This commit is contained in:
parent
0a4d370676
commit
d3fe654e23
@ -56,19 +56,18 @@ export default function PullRequests() {
|
||||
UserPreference.PULL_REQUESTS_FILTER_SELECTED_OPTIONS,
|
||||
PullRequestFilterOption.OPEN
|
||||
)
|
||||
const [authorFilter, setAuthorFilter] = useState<string>()
|
||||
const space = useGetSpaceParam()
|
||||
const { updateQueryParams } = useUpdateQueryParams()
|
||||
|
||||
const pageBrowser = useQueryParams<PageBrowserProps>()
|
||||
const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1
|
||||
const [page, setPage] = usePageIndex(pageInit)
|
||||
|
||||
useEffect(() => {
|
||||
if (page > 1) {
|
||||
updateQueryParams({ page: page.toString() })
|
||||
}
|
||||
}, [setPage]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const { repoMetadata, error, loading, refetch } = useGetRepositoryMetadata()
|
||||
const {
|
||||
data,
|
||||
@ -84,7 +83,8 @@ export default function PullRequests() {
|
||||
sort: filter == PullRequestFilterOption.MERGED ? 'merged' : 'number',
|
||||
order: 'desc',
|
||||
query: searchTerm,
|
||||
state: filter == PullRequestFilterOption.ALL ? '' : filter
|
||||
state: filter == PullRequestFilterOption.ALL ? '' : filter,
|
||||
...(authorFilter && { created_by: Number(authorFilter) })
|
||||
},
|
||||
debounce: 500,
|
||||
lazy: !repoMetadata
|
||||
@ -234,6 +234,11 @@ export default function PullRequests() {
|
||||
setSearchTerm(value)
|
||||
setPage(1)
|
||||
}}
|
||||
activePullRequestAuthorFilterOption={authorFilter}
|
||||
onPullRequestAuthorFilterChanged={_authorFilter => {
|
||||
setAuthorFilter(_authorFilter)
|
||||
setPage(1)
|
||||
}}
|
||||
/>
|
||||
<Container padding="xlarge">
|
||||
<Match expr={data?.length}>
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import React, { useMemo, useState } from 'react'
|
||||
import { Container, Layout, FlexExpander, DropDown, ButtonVariation, Button } from '@harnessio/uicore'
|
||||
import { Container, Layout, FlexExpander, DropDown, ButtonVariation, Button, SelectOption } from '@harnessio/uicore'
|
||||
import { sortBy } from 'lodash-es'
|
||||
import { getConfig, getUsingFetch } from 'services/config'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CodeIcon, GitInfoProps, makeDiffRefs, PullRequestFilterOption } from 'utils/GitUtils'
|
||||
import { UserPreference, useUserPreference } from 'hooks/useUserPreference'
|
||||
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
||||
import type { TypesPrincipalInfo } from 'services/code'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { SearchInputWithSpinner } from 'components/SearchInputWithSpinner/SearchInputWithSpinner'
|
||||
import { permissionProps } from 'utils/Utils'
|
||||
@ -29,15 +32,19 @@ import css from './PullRequestsContentHeader.module.scss'
|
||||
interface PullRequestsContentHeaderProps extends Pick<GitInfoProps, 'repoMetadata'> {
|
||||
loading?: boolean
|
||||
activePullRequestFilterOption?: string
|
||||
activePullRequestAuthorFilterOption?: string
|
||||
onPullRequestFilterChanged: (filter: string) => void
|
||||
onPullRequestAuthorFilterChanged: (authorFilter: string) => void
|
||||
onSearchTermChanged: (searchTerm: string) => void
|
||||
}
|
||||
|
||||
export function PullRequestsContentHeader({
|
||||
loading,
|
||||
onPullRequestFilterChanged,
|
||||
onPullRequestAuthorFilterChanged,
|
||||
onSearchTermChanged,
|
||||
activePullRequestFilterOption = PullRequestFilterOption.OPEN,
|
||||
activePullRequestAuthorFilterOption,
|
||||
repoMetadata
|
||||
}: PullRequestsContentHeaderProps) {
|
||||
const history = useHistory()
|
||||
@ -47,10 +54,13 @@ export function PullRequestsContentHeader({
|
||||
UserPreference.PULL_REQUESTS_FILTER_SELECTED_OPTIONS,
|
||||
activePullRequestFilterOption
|
||||
)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const space = useGetSpaceParam()
|
||||
|
||||
const { standalone } = useAppContext()
|
||||
const [authorFilterOption, setAuthorFilterOption] = useState(activePullRequestAuthorFilterOption)
|
||||
const [searchTerm, setSearchTerm] = useState('')
|
||||
const [query, setQuery] = useState<string>('')
|
||||
const [loadingAuthors, setLoadingAuthors] = useState<boolean>(false)
|
||||
const space = useGetSpaceParam()
|
||||
const { standalone, routingId } = useAppContext()
|
||||
const { hooks } = useAppContext()
|
||||
const permPushResult = hooks?.usePermissionTranslate?.(
|
||||
{
|
||||
@ -73,6 +83,40 @@ export function PullRequestsContentHeader({
|
||||
[getString]
|
||||
)
|
||||
|
||||
const getAuthorsPromise = (): Promise<SelectOption[]> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
setLoadingAuthors(true)
|
||||
try {
|
||||
getUsingFetch(getConfig('code/api/v1'), `/principals`, {
|
||||
queryParams: {
|
||||
query: query?.trim(),
|
||||
type: 'user',
|
||||
accountIdentifier: routingId
|
||||
}
|
||||
})
|
||||
.then((obj: TypesPrincipalInfo[]) => {
|
||||
const updatedAuthorsList = Array.isArray(obj)
|
||||
? ([
|
||||
...(obj || []).map(item => ({
|
||||
label: String(item?.display_name),
|
||||
value: String(item?.id)
|
||||
}))
|
||||
] as SelectOption[])
|
||||
: ([] as SelectOption[])
|
||||
setLoadingAuthors(false)
|
||||
resolve(sortBy(updatedAuthorsList, item => item.label.toLowerCase()))
|
||||
})
|
||||
.catch(error => {
|
||||
setLoadingAuthors(false)
|
||||
reject(error)
|
||||
})
|
||||
} catch (error) {
|
||||
setLoadingAuthors(false)
|
||||
reject(error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<Container className={css.main} padding="xlarge">
|
||||
<Layout.Horizontal spacing="medium">
|
||||
@ -86,6 +130,27 @@ export function PullRequestsContentHeader({
|
||||
}}
|
||||
/>
|
||||
<FlexExpander />
|
||||
<DropDown
|
||||
value={authorFilterOption}
|
||||
items={() => getAuthorsPromise()}
|
||||
disabled={loadingAuthors}
|
||||
onChange={({ value, label }) => {
|
||||
setAuthorFilterOption(label as string)
|
||||
onPullRequestAuthorFilterChanged(value as string)
|
||||
}}
|
||||
popoverClassName={css.branchDropdown}
|
||||
icon="nav-user-profile"
|
||||
iconProps={{ size: 16 }}
|
||||
placeholder="Select Authors"
|
||||
addClearBtn={true}
|
||||
resetOnClose
|
||||
resetOnSelect
|
||||
resetOnQuery
|
||||
query={query}
|
||||
onQueryChange={newQuery => {
|
||||
setQuery(newQuery)
|
||||
}}
|
||||
/>
|
||||
<DropDown
|
||||
value={filterOption}
|
||||
items={items}
|
||||
|
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import qs, { IStringifyOptions } from 'qs'
|
||||
|
||||
export const getConfig = (str: string): string => {
|
||||
// 'code/api/v1' -> 'api/v1' (standalone)
|
||||
// -> 'code/api/v1' (embedded inside Harness platform)
|
||||
@ -23,3 +25,66 @@ export const getConfig = (str: string): string => {
|
||||
|
||||
return window.apiUrl ? `${window.apiUrl}/${str}` : `${window.harnessNameSpace || ''}/${str}`
|
||||
}
|
||||
|
||||
export interface GetUsingFetchProps<
|
||||
_TData = any,
|
||||
_TError = any,
|
||||
TQueryParams = {
|
||||
[key: string]: any
|
||||
},
|
||||
TPathParams = {
|
||||
[key: string]: any
|
||||
}
|
||||
> {
|
||||
queryParams?: TQueryParams
|
||||
queryParamStringifyOptions?: IStringifyOptions
|
||||
pathParams?: TPathParams
|
||||
requestOptions?: RequestInit
|
||||
mock?: _TData
|
||||
}
|
||||
|
||||
export const getUsingFetch = <
|
||||
TData = any,
|
||||
_TError = any,
|
||||
TQueryParams = {
|
||||
[key: string]: any
|
||||
},
|
||||
TPathParams = {
|
||||
[key: string]: any
|
||||
}
|
||||
>(
|
||||
base: string,
|
||||
path: string,
|
||||
props: GetUsingFetchProps<TData, _TError, TQueryParams, TPathParams>,
|
||||
signal?: RequestInit['signal']
|
||||
): Promise<TData> => {
|
||||
if (props.mock) return Promise.resolve(props.mock)
|
||||
let url = base + path
|
||||
if (props.queryParams && Object.keys(props.queryParams).length) {
|
||||
url += `?${qs.stringify(props.queryParams, props.queryParamStringifyOptions)}`
|
||||
}
|
||||
return fetch(url, {
|
||||
signal,
|
||||
...(props.requestOptions || {})
|
||||
// headers: getHeaders(props.requestOptions?.headers)
|
||||
}).then(res => {
|
||||
// custom event to allow the app framework to handle api responses
|
||||
const responseEvent = new CustomEvent('PROMISE_API_RESPONSE', { detail: { response: res } })
|
||||
window.dispatchEvent(responseEvent) // this will be captured in App.tsx to handle 401 and token refresh
|
||||
|
||||
const contentType = res.headers.get('content-type') || ''
|
||||
|
||||
if (contentType.toLowerCase().indexOf('application/json') > -1) {
|
||||
if (res.status === 401) {
|
||||
return res.json().then(json => Promise.reject(json))
|
||||
}
|
||||
return res.json()
|
||||
}
|
||||
|
||||
if (res.status === 401) {
|
||||
return res.text().then(text => Promise.reject(text))
|
||||
}
|
||||
|
||||
return res.text()
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user