mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:51:43 +00:00
clean up FilteredConnection filter types and code (#63590)
- Renames some types and fields for clarity:
- FilteredConnectionFilter -> Filter
- field name `values` -> `options`
- FilteredConnectionFilterValue -> FilterOption
- Avoids passing around unnecessary data
No behavior change. This makes it easier to use the FilterControl
component.
## Test plan
Use existing filtered connections with filters (see the diff for a list
of pages that contain this component).
This commit is contained in:
parent
121a01beb6
commit
a73b1b0964
@ -6,7 +6,41 @@ import { RadioButtons } from '../RadioButtons'
|
||||
|
||||
import styles from './FilterControl.module.scss'
|
||||
|
||||
export interface FilteredConnectionFilterValue {
|
||||
/**
|
||||
* A filter to display next to the search input field.
|
||||
*/
|
||||
export interface Filter {
|
||||
/** The UI label for the filter. */
|
||||
label: string
|
||||
|
||||
/** The UI form control to use when displaying this filter. */
|
||||
type: 'radio' | 'select'
|
||||
|
||||
/**
|
||||
* The URL query parameter name for this filter (conventionally the label, lowercased and
|
||||
* without spaces and punctuation).
|
||||
*/
|
||||
id: string
|
||||
|
||||
/** An optional tooltip to display for this filter. */
|
||||
tooltip?: string
|
||||
|
||||
/**
|
||||
* All of the possible values for this filter that the user can select.
|
||||
*/
|
||||
options: FilterOption[]
|
||||
}
|
||||
|
||||
/**
|
||||
* An option that the user can select for a filter ({@link Filter}).
|
||||
*/
|
||||
export interface FilterOption {
|
||||
/**
|
||||
* The value (corresponding to the key in {@link Filter.id}) if this option is chosen. For
|
||||
* example, if a filter has {@link Filter.id} of `sort` and the user selects a
|
||||
* {@link FilterOption} with {@link FilterOption.value} of `asc`, then the URL query string
|
||||
* would be `sort=asc`.
|
||||
*/
|
||||
value: string
|
||||
label: string
|
||||
tooltip?: string
|
||||
@ -14,34 +48,18 @@ export interface FilteredConnectionFilterValue {
|
||||
}
|
||||
|
||||
/**
|
||||
* A filter to display next to the search input field.
|
||||
* The values of all filters, keyed by the filter ID ({@link Filter.id}).
|
||||
*/
|
||||
export interface FilteredConnectionFilter {
|
||||
/** The UI label for the filter. */
|
||||
label: string
|
||||
|
||||
/** "radio" or "select" */
|
||||
type: string
|
||||
|
||||
/**
|
||||
* The URL string for this filter (conventionally the label, lowercased and without spaces and punctuation).
|
||||
*/
|
||||
id: string
|
||||
|
||||
/** An optional tooltip to display for this filter. */
|
||||
tooltip?: string
|
||||
|
||||
values: FilteredConnectionFilterValue[]
|
||||
}
|
||||
export interface FilterValues extends Record<string, FilterOption['value'] | null> {}
|
||||
|
||||
interface FilterControlProps {
|
||||
/** All filters. */
|
||||
filters: FilteredConnectionFilter[]
|
||||
filters: Filter[]
|
||||
|
||||
/** Called when a filter is selected. */
|
||||
onValueSelect: (filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue) => void
|
||||
onValueSelect: (filter: Filter, value: FilterOption['value']) => void
|
||||
|
||||
values: Map<string, FilteredConnectionFilterValue>
|
||||
values: FilterValues
|
||||
}
|
||||
|
||||
export const FilterControl: React.FunctionComponent<React.PropsWithChildren<FilterControlProps>> = ({
|
||||
@ -51,12 +69,12 @@ export const FilterControl: React.FunctionComponent<React.PropsWithChildren<Filt
|
||||
children,
|
||||
}) => {
|
||||
const onChange = useCallback(
|
||||
(filter: FilteredConnectionFilter, id: string) => {
|
||||
const value = filter.values.find(value => value.value === id)
|
||||
(filter: Filter, id: string) => {
|
||||
const value = filter.options.find(opt => opt.value === id)
|
||||
if (value === undefined) {
|
||||
return
|
||||
}
|
||||
onValueSelect(filter, value)
|
||||
onValueSelect(filter, value.value)
|
||||
},
|
||||
[onValueSelect]
|
||||
)
|
||||
@ -70,8 +88,8 @@ export const FilterControl: React.FunctionComponent<React.PropsWithChildren<Filt
|
||||
key={filter.id}
|
||||
name={filter.id}
|
||||
className="d-inline-flex flex-row"
|
||||
selected={values.get(filter.id)?.value}
|
||||
nodes={filter.values.map(({ value, label, tooltip }) => ({
|
||||
selected={values[filter.id] ?? undefined}
|
||||
nodes={filter.options.map(({ value, label, tooltip }) => ({
|
||||
tooltip,
|
||||
label,
|
||||
id: value,
|
||||
@ -94,12 +112,12 @@ export const FilterControl: React.FunctionComponent<React.PropsWithChildren<Filt
|
||||
id=""
|
||||
name={filter.id}
|
||||
onChange={event => onChange(filter, event.currentTarget.value)}
|
||||
value={values.get(filter.id)?.value}
|
||||
value={values[filter.id] ?? undefined}
|
||||
className="mb-0"
|
||||
isCustomStyle={true}
|
||||
>
|
||||
{filter.values.map(value => (
|
||||
<option key={value.value} value={value.value} label={value.label} />
|
||||
{filter.options.map(opt => (
|
||||
<option key={opt.value} value={opt.value} label={opt.label} />
|
||||
))}
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
@ -2,8 +2,8 @@ import * as React from 'react'
|
||||
|
||||
import type * as H from 'history'
|
||||
import { isEqual, uniq } from 'lodash'
|
||||
import { type NavigateFunction, useLocation, useNavigate } from 'react-router-dom'
|
||||
import { combineLatest, merge, type Observable, of, Subject, Subscription } from 'rxjs'
|
||||
import { useLocation, useNavigate, type NavigateFunction } from 'react-router-dom'
|
||||
import { combineLatest, merge, of, Subject, Subscription, type Observable } from 'rxjs'
|
||||
import {
|
||||
catchError,
|
||||
debounceTime,
|
||||
@ -20,7 +20,7 @@ import {
|
||||
tap,
|
||||
} from 'rxjs/operators'
|
||||
|
||||
import { asError, type ErrorLike, isErrorLike, logger } from '@sourcegraph/common'
|
||||
import { asError, isErrorLike, logger, type ErrorLike } from '@sourcegraph/common'
|
||||
|
||||
import {
|
||||
ConnectionNodes,
|
||||
@ -30,7 +30,7 @@ import {
|
||||
} from './ConnectionNodes'
|
||||
import type { Connection, ConnectionQueryArguments } from './ConnectionType'
|
||||
import { QUERY_KEY } from './constants'
|
||||
import type { FilteredConnectionFilter, FilteredConnectionFilterValue } from './FilterControl'
|
||||
import type { Filter, FilterOption, FilterValues } from './FilterControl'
|
||||
import { ConnectionContainer, ConnectionError, ConnectionForm, ConnectionLoading } from './ui'
|
||||
import type { ConnectionFormProps } from './ui/ConnectionForm'
|
||||
import { getFilterFromURL, getUrlQuery, hasID, parseQueryInt } from './utils'
|
||||
@ -101,7 +101,6 @@ interface FilteredConnectionDisplayProps extends ConnectionNodesDisplayProps, Co
|
||||
|
||||
/**
|
||||
* Props for the FilteredConnection component.
|
||||
*
|
||||
* @template C The GraphQL connection type, such as GQL.IRepositoryConnection.
|
||||
* @template N The node type of the GraphQL connection, such as GQL.IRepository (if C is GQL.IRepositoryConnection)
|
||||
* @template NP Props passed to `nodeComponent` in addition to `{ node: N }`
|
||||
@ -131,7 +130,7 @@ interface FilteredConnectionProps<C extends Connection<N>, N, NP = {}, HP = {}>
|
||||
export interface FilteredConnectionQueryArguments extends ConnectionQueryArguments {}
|
||||
|
||||
interface FilteredConnectionState<C extends Connection<N>, N> extends ConnectionNodesState {
|
||||
activeFilterValues: Map<string, FilteredConnectionFilterValue>
|
||||
activeFilterValues: FilterValues
|
||||
|
||||
/** The fetched connection data or an error (if an error occurred). */
|
||||
connectionOrError?: C | ErrorLike
|
||||
@ -161,7 +160,6 @@ interface FilteredConnectionState<C extends Connection<N>, N> extends Connection
|
||||
* Displays a collection of items with filtering and pagination. It is called
|
||||
* "connection" because it is intended for use with GraphQL, which calls it that
|
||||
* (see http://graphql.org/learn/pagination/).
|
||||
*
|
||||
* @template N The node type of the GraphQL connection, such as `GQL.IRepository` (if `C` is `GQL.IRepositoryConnection`)
|
||||
* @template NP Props passed to `nodeComponent` in addition to `{ node: N }`
|
||||
* @template HP Props passed to `headComponent` in addition to `{ nodes: N[]; totalCount?: number | null }`.
|
||||
@ -186,7 +184,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
}
|
||||
|
||||
private queryInputChanges = new Subject<string>()
|
||||
private activeFilterValuesChanges = new Subject<Map<string, FilteredConnectionFilterValue>>()
|
||||
private activeFilterValuesChanges = new Subject<FilterValues>()
|
||||
private showMoreClicks = new Subject<void>()
|
||||
private componentUpdates = new Subject<FilteredConnectionProps<C, N, NP, HP>>()
|
||||
private subscriptions = new Subscription()
|
||||
@ -214,8 +212,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
loading: true,
|
||||
query: (!this.props.hideSearch && this.props.useURLQuery && searchParameters.get(QUERY_KEY)) || '',
|
||||
activeFilterValues:
|
||||
(this.props.useURLQuery && getFilterFromURL(searchParameters, this.props.filters)) ||
|
||||
new Map<string, FilteredConnectionFilterValue>(),
|
||||
(this.props.useURLQuery && getFilterFromURL(searchParameters, this.props.filters)) || {},
|
||||
first: (this.props.useURLQuery && parseQueryInt(searchParameters, 'first')) || this.props.defaultFirst!,
|
||||
visible: (this.props.useURLQuery && parseQueryInt(searchParameters, 'visible')) || 0,
|
||||
}
|
||||
@ -248,7 +245,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
}
|
||||
for (const filter of this.props.filters) {
|
||||
if (this.props.onFilterSelect) {
|
||||
const value = values.get(filter.id)
|
||||
const value = values[filter.id]
|
||||
if (value === undefined) {
|
||||
continue
|
||||
}
|
||||
@ -264,7 +261,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
// Use this.activeFilterChanges not activeFilterChanges so that it doesn't trigger on the initial mount
|
||||
// (it doesn't need to).
|
||||
this.activeFilterValuesChanges.subscribe(values => {
|
||||
this.setState({ activeFilterValues: new Map(values) })
|
||||
this.setState({ activeFilterValues: values })
|
||||
})
|
||||
)
|
||||
|
||||
@ -277,10 +274,10 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
.pipe(
|
||||
// Track whether the query or the active order or filter changed
|
||||
scan<
|
||||
[string, Map<string, FilteredConnectionFilterValue> | undefined, { forceRefresh: boolean }],
|
||||
[string, FilterValues | undefined, { forceRefresh: boolean }],
|
||||
{
|
||||
query: string
|
||||
filterValues: Map<string, FilteredConnectionFilterValue> | undefined
|
||||
filterValues: FilterValues | undefined
|
||||
shouldRefresh: boolean
|
||||
queryCount: number
|
||||
}
|
||||
@ -311,7 +308,9 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
first: (queryCount === 1 && this.state.visible) || this.state.first,
|
||||
after: shouldRefresh ? undefined : this.state.after,
|
||||
query,
|
||||
...(filterValues ? this.buildArgs(filterValues) : {}),
|
||||
...(this.props.filters && filterValues
|
||||
? this.buildArgs(this.props.filters, filterValues)
|
||||
: {}),
|
||||
})
|
||||
.pipe(
|
||||
catchError(error => [asError(error)]),
|
||||
@ -406,7 +405,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
this.props.onUpdate(
|
||||
connectionOrError,
|
||||
this.state.query,
|
||||
this.buildArgs(this.state.activeFilterValues)
|
||||
this.buildArgs(this.props.filters ?? [], this.state.activeFilterValues)
|
||||
)
|
||||
}
|
||||
this.setState({ connectionOrError, ...rest })
|
||||
@ -511,7 +510,7 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
}: {
|
||||
first?: number
|
||||
query?: string
|
||||
filterValues?: Map<string, FilteredConnectionFilterValue>
|
||||
filterValues?: FilterValues
|
||||
visibleResultCount?: number
|
||||
}): string {
|
||||
if (!first) {
|
||||
@ -647,13 +646,11 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
this.queryInputChanges.next(event.currentTarget.value)
|
||||
}
|
||||
|
||||
private onDidSelectFilterValue = (filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue): void => {
|
||||
private onDidSelectFilterValue = (filter: Filter, value: FilterOption['value'] | null): void => {
|
||||
if (this.props.filters === undefined) {
|
||||
return
|
||||
}
|
||||
const values = new Map(this.state.activeFilterValues)
|
||||
values.set(filter.id, value)
|
||||
this.activeFilterValuesChanges.next(values)
|
||||
this.activeFilterValuesChanges.next({ ...this.state.activeFilterValues, [filter.id]: value })
|
||||
}
|
||||
|
||||
private onClickShowMore = (): void => {
|
||||
@ -663,21 +660,23 @@ class InnerFilteredConnection<N, NP = {}, HP = {}, C extends Connection<N> = Con
|
||||
private buildArgs = buildFilterArgs
|
||||
}
|
||||
|
||||
export const buildFilterArgs = (filterValues: Map<string, FilteredConnectionFilterValue>): FilteredConnectionArgs => {
|
||||
export const buildFilterArgs = (filters: Filter[], filterValues: FilterValues): FilteredConnectionArgs => {
|
||||
let args: FilteredConnectionArgs = {}
|
||||
for (const key of filterValues.keys()) {
|
||||
const value = filterValues.get(key)
|
||||
for (const [filterID, value] of Object.entries(filterValues)) {
|
||||
if (value === undefined) {
|
||||
continue
|
||||
}
|
||||
args = { ...args, ...value.args }
|
||||
const filter = filters.find(f => f.id === filterID)
|
||||
if (filter) {
|
||||
const valueArgs = filter.options.find(opt => opt.value === value)?.args
|
||||
args = { ...args, ...valueArgs }
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the `FilteredConnection` URL query string parameters to the defaults
|
||||
*
|
||||
* @param parameters the current URL search parameters
|
||||
*/
|
||||
export const resetFilteredConnectionURLQuery = (parameters: URLSearchParams): void => {
|
||||
|
||||
@ -3,9 +3,9 @@ import React, { useCallback, useRef } from 'react'
|
||||
import classNames from 'classnames'
|
||||
import { useMergeRefs } from 'use-callback-ref'
|
||||
|
||||
import { useAutoFocus, Input, Form } from '@sourcegraph/wildcard'
|
||||
import { Form, Input, useAutoFocus } from '@sourcegraph/wildcard'
|
||||
|
||||
import { FilterControl, type FilteredConnectionFilter, type FilteredConnectionFilterValue } from '../FilterControl'
|
||||
import { FilterControl, type Filter, type FilterOption, type FilterValues } from '../FilterControl'
|
||||
|
||||
import styles from './ConnectionForm.module.scss'
|
||||
|
||||
@ -42,14 +42,14 @@ export interface ConnectionFormProps {
|
||||
*
|
||||
* Filters are mutually exclusive.
|
||||
*/
|
||||
filters?: FilteredConnectionFilter[]
|
||||
filters?: Filter[]
|
||||
|
||||
onFilterSelect?: (filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue) => void
|
||||
onFilterSelect?: (filter: Filter, value: FilterOption['value'] | null) => void
|
||||
|
||||
/** An element rendered as a sibling of the filters. */
|
||||
additionalFilterElement?: React.ReactElement
|
||||
|
||||
filterValues?: Map<string, FilteredConnectionFilterValue>
|
||||
filterValues?: FilterValues
|
||||
|
||||
compact?: boolean
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import type { Scalars } from '@sourcegraph/shared/src/graphql-operations'
|
||||
|
||||
import type { Connection } from './ConnectionType'
|
||||
import { QUERY_KEY } from './constants'
|
||||
import type { FilteredConnectionFilter, FilteredConnectionFilterValue } from './FilterControl'
|
||||
import type { Filter, FilterValues } from './FilterControl'
|
||||
|
||||
/** Checks if the passed value satisfies the GraphQL Node interface */
|
||||
export const hasID = (value: unknown): value is { id: Scalars['ID'] } =>
|
||||
@ -19,26 +19,22 @@ export const hasDisplayName = (value: unknown): value is { displayName: Scalars[
|
||||
hasProperty('displayName')(value) &&
|
||||
typeof value.displayName === 'string'
|
||||
|
||||
export const getFilterFromURL = (
|
||||
searchParameters: URLSearchParams,
|
||||
filters: FilteredConnectionFilter[] | undefined
|
||||
): Map<string, FilteredConnectionFilterValue> => {
|
||||
const values: Map<string, FilteredConnectionFilterValue> = new Map<string, FilteredConnectionFilterValue>()
|
||||
|
||||
if (filters === undefined || filters.length === 0) {
|
||||
export const getFilterFromURL = (searchParameters: URLSearchParams, filters: Filter[] | undefined): FilterValues => {
|
||||
const values: FilterValues = {}
|
||||
if (filters === undefined) {
|
||||
return values
|
||||
}
|
||||
for (const filter of filters) {
|
||||
const urlValue = searchParameters.get(filter.id)
|
||||
if (urlValue !== null) {
|
||||
const value = filter.values.find(value => value.value === urlValue)
|
||||
const value = filter.options.find(opt => opt.value === urlValue)
|
||||
if (value !== undefined) {
|
||||
values.set(filter.id, value)
|
||||
values[filter.id] = value.value
|
||||
continue
|
||||
}
|
||||
}
|
||||
// couldn't find a value, add default
|
||||
values.set(filter.id, filter.values[0])
|
||||
values[filter.id] = filter.options[0].value
|
||||
}
|
||||
return values
|
||||
}
|
||||
@ -70,8 +66,8 @@ export interface GetUrlQueryParameters {
|
||||
default: number
|
||||
}
|
||||
query?: string
|
||||
filterValues?: Map<string, FilteredConnectionFilterValue>
|
||||
filters?: FilteredConnectionFilter[]
|
||||
filterValues?: FilterValues
|
||||
filters?: Filter[]
|
||||
visibleResultCount?: number
|
||||
search: Location['search']
|
||||
}
|
||||
@ -99,12 +95,12 @@ export const getUrlQuery = ({
|
||||
|
||||
if (filterValues && filters) {
|
||||
for (const filter of filters) {
|
||||
const value = filterValues.get(filter.id)
|
||||
if (value === undefined) {
|
||||
const value = filterValues[filter.id]
|
||||
if (value === undefined || value === null) {
|
||||
continue
|
||||
}
|
||||
if (value !== filter.values[0]) {
|
||||
searchParameters.set(filter.id, value.value)
|
||||
if (value !== filter.options[0].value) {
|
||||
searchParameters.set(filter.id, value)
|
||||
} else {
|
||||
searchParameters.delete(filter.id)
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { type FC, useEffect } from 'react'
|
||||
import { useEffect, type FC } from 'react'
|
||||
|
||||
import { mdiPlus } from '@mdi/js'
|
||||
import { Navigate, useLocation } from 'react-router-dom'
|
||||
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { Link, ButtonLink, Icon, PageHeader, Container } from '@sourcegraph/wildcard'
|
||||
import { ButtonLink, Container, Icon, Link, PageHeader } from '@sourcegraph/wildcard'
|
||||
|
||||
import {
|
||||
ConnectionContainer,
|
||||
|
||||
@ -167,7 +167,7 @@ export const CodeIntelConfigurationPage: FunctionComponent<CodeIntelConfiguratio
|
||||
id: 'filters',
|
||||
label: 'Show',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All policies',
|
||||
value: 'all',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { type FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useCallback, useEffect, useMemo, useState, type FunctionComponent } from 'react'
|
||||
|
||||
import { useApolloClient } from '@apollo/client'
|
||||
import { mdiChevronRight, mdiDelete, mdiMapSearch, mdiRedo } from '@mdi/js'
|
||||
@ -29,16 +29,16 @@ import {
|
||||
|
||||
import {
|
||||
FilteredConnection,
|
||||
type FilteredConnectionFilter,
|
||||
type Filter,
|
||||
type FilteredConnectionQueryArguments,
|
||||
} from '../../../../components/FilteredConnection'
|
||||
import { PageTitle } from '../../../../components/PageTitle'
|
||||
import {
|
||||
PreciseIndexState,
|
||||
type IndexerListResult,
|
||||
type IndexerListVariables,
|
||||
type PreciseIndexesVariables,
|
||||
type PreciseIndexFields,
|
||||
PreciseIndexState,
|
||||
type PreciseIndexesVariables,
|
||||
} from '../../../../graphql-operations'
|
||||
import { FlashMessage } from '../../configuration/components/FlashMessage'
|
||||
import { PreciseIndexLastUpdated } from '../components/CodeIntelLastUpdated'
|
||||
@ -71,11 +71,11 @@ export interface CodeIntelPreciseIndexesPageProps extends TelemetryProps, Teleme
|
||||
indexingEnabled?: boolean
|
||||
}
|
||||
|
||||
const STATE_FILTER: FilteredConnectionFilter = {
|
||||
const STATE_FILTER: Filter = {
|
||||
id: 'filters',
|
||||
label: 'State',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
@ -146,12 +146,12 @@ export const CodeIntelPreciseIndexesPage: FunctionComponent<CodeIntelPreciseInde
|
||||
|
||||
const { data: indexerData } = useQuery<IndexerListResult, IndexerListVariables>(INDEXER_LIST, {})
|
||||
|
||||
const filters = useMemo<FilteredConnectionFilter[]>(() => {
|
||||
const indexerFilter: FilteredConnectionFilter = {
|
||||
const filters = useMemo<Filter[]>(() => {
|
||||
const indexerFilter: Filter = {
|
||||
id: 'filters-indexer',
|
||||
label: 'Indexer',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
@ -163,7 +163,7 @@ export const CodeIntelPreciseIndexesPage: FunctionComponent<CodeIntelPreciseInde
|
||||
const keys = (indexerData?.indexerKeys || []).filter(key => Boolean(key))
|
||||
|
||||
for (const key of keys) {
|
||||
indexerFilter.values.push({
|
||||
indexerFilter.options.push({
|
||||
label: key,
|
||||
value: key,
|
||||
args: { indexerKey: key },
|
||||
|
||||
@ -5,11 +5,11 @@ import { mdiMapSearch } from '@mdi/js'
|
||||
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
|
||||
import { Container, Link, PageHeader, Icon, H3, Text } from '@sourcegraph/wildcard'
|
||||
import { Container, H3, Icon, Link, PageHeader, Text } from '@sourcegraph/wildcard'
|
||||
|
||||
import {
|
||||
FilteredConnection,
|
||||
type FilteredConnectionFilter,
|
||||
type Filter,
|
||||
type FilteredConnectionQueryArguments,
|
||||
} from '../../../components/FilteredConnection'
|
||||
import { PageTitle } from '../../../components/PageTitle'
|
||||
@ -18,12 +18,12 @@ import type { ExecutorFields } from '../../../graphql-operations'
|
||||
import { ExecutorNode } from './ExecutorNode'
|
||||
import { queryExecutors as defaultQueryExecutors } from './useExecutors'
|
||||
|
||||
const filters: FilteredConnectionFilter[] = [
|
||||
const filters: Filter[] = [
|
||||
{
|
||||
id: 'filters',
|
||||
label: 'State',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
|
||||
@ -17,8 +17,8 @@ import type { AuthenticatedUser } from '../../auth'
|
||||
import {
|
||||
FilteredConnection,
|
||||
type Connection,
|
||||
type FilteredConnectionFilter,
|
||||
type FilteredConnectionFilterValue,
|
||||
type Filter,
|
||||
type FilterOption,
|
||||
} from '../../components/FilteredConnection'
|
||||
|
||||
import { useDefaultContext } from './hooks/useDefaultContext'
|
||||
@ -64,7 +64,7 @@ export const SearchContextsList: React.FunctionComponent<SearchContextsListProps
|
||||
[authenticatedUser, fetchSearchContexts, getUserSearchContextNamespaces, platformContext]
|
||||
)
|
||||
|
||||
const ownerNamespaceFilterValues: FilteredConnectionFilterValue[] = useMemo(
|
||||
const ownerNamespaceFilterValues: FilterOption[] = useMemo(
|
||||
() =>
|
||||
authenticatedUser
|
||||
? [
|
||||
@ -87,14 +87,14 @@ export const SearchContextsList: React.FunctionComponent<SearchContextsListProps
|
||||
[authenticatedUser]
|
||||
)
|
||||
|
||||
const filters: FilteredConnectionFilter[] = useMemo(
|
||||
const filters = useMemo<Filter[]>(
|
||||
() => [
|
||||
{
|
||||
label: 'Sort',
|
||||
type: 'select',
|
||||
id: 'order',
|
||||
tooltip: 'Order search contexts',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
value: 'spec-asc',
|
||||
label: 'By name',
|
||||
@ -118,7 +118,7 @@ export const SearchContextsList: React.FunctionComponent<SearchContextsListProps
|
||||
type: 'select',
|
||||
id: 'owner',
|
||||
tooltip: 'Search context owner',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
value: 'all',
|
||||
label: 'All',
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
import { type FC, useCallback, useEffect } from 'react'
|
||||
import { useCallback, useEffect, type FC } from 'react'
|
||||
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { H2 } from '@sourcegraph/wildcard'
|
||||
|
||||
import { FilteredConnection, type FilteredConnectionFilter } from '../../components/FilteredConnection'
|
||||
import { FilteredConnection, type Filter } from '../../components/FilteredConnection'
|
||||
import type {
|
||||
ListNotebooksResult,
|
||||
ListNotebooksVariables,
|
||||
@ -20,7 +20,7 @@ import styles from './NotebooksList.module.scss'
|
||||
export interface NotebooksListProps extends TelemetryProps {
|
||||
title: string
|
||||
logEventName: NotebooksFilterEvents
|
||||
orderOptions: FilteredConnectionFilter[]
|
||||
orderOptions: Filter[]
|
||||
creatorUserID?: string
|
||||
starredByUserID?: string
|
||||
namespace?: string
|
||||
|
||||
@ -2,22 +2,22 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
|
||||
import { mdiBookOutline } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
import { type Location, Navigate, useNavigate, useLocation, type NavigateFunction } from 'react-router-dom'
|
||||
import { Navigate, useLocation, useNavigate, type Location, type NavigateFunction } from 'react-router-dom'
|
||||
import type { Observable } from 'rxjs'
|
||||
import { catchError, startWith, switchMap } from 'rxjs/operators'
|
||||
|
||||
import { asError, type ErrorLike, isErrorLike } from '@sourcegraph/common'
|
||||
import { asError, isErrorLike, type ErrorLike } from '@sourcegraph/common'
|
||||
import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting'
|
||||
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { PageHeader, Button, useEventObservable, Alert, ButtonLink } from '@sourcegraph/wildcard'
|
||||
import { Alert, Button, ButtonLink, PageHeader, useEventObservable } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { AuthenticatedUser } from '../../auth'
|
||||
import type { FilteredConnectionFilter } from '../../components/FilteredConnection'
|
||||
import type { Filter } from '../../components/FilteredConnection'
|
||||
import { Page } from '../../components/Page'
|
||||
import { type CreateNotebookVariables, NotebooksOrderBy } from '../../graphql-operations'
|
||||
import { NotebooksOrderBy, type CreateNotebookVariables } from '../../graphql-operations'
|
||||
import { PageRoutes } from '../../routes.constants'
|
||||
import { fetchNotebooks as _fetchNotebooks, createNotebook as _createNotebook } from '../backend'
|
||||
import { createNotebook as _createNotebook, fetchNotebooks as _fetchNotebooks } from '../backend'
|
||||
|
||||
import { NotebooksGettingStartedTab } from './NotebooksGettingStartedTab'
|
||||
import { NotebooksList, type NotebooksListProps } from './NotebooksList'
|
||||
@ -106,13 +106,13 @@ export const NotebooksListPage: React.FunctionComponent<React.PropsWithChildren<
|
||||
[navigate, location, setSelectedTab, telemetryService, telemetryRecorder]
|
||||
)
|
||||
|
||||
const orderOptions: FilteredConnectionFilter[] = [
|
||||
const orderOptions: Filter[] = [
|
||||
{
|
||||
label: 'Order by',
|
||||
type: 'select',
|
||||
id: 'order',
|
||||
tooltip: 'Order notebooks',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
value: 'updated-at-desc',
|
||||
label: 'Last update (descending)',
|
||||
|
||||
@ -2,19 +2,19 @@ import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
|
||||
import { mdiChevronRight } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
import { of, type Observable, forkJoin } from 'rxjs'
|
||||
import { forkJoin, of, type Observable } from 'rxjs'
|
||||
import { catchError, map, mergeMap } from 'rxjs/operators'
|
||||
|
||||
import { asError, type ErrorLike, isErrorLike, pluralize } from '@sourcegraph/common'
|
||||
import { aggregateStreamingSearch, type ContentMatch, LATEST_VERSION } from '@sourcegraph/shared/src/search/stream'
|
||||
import { asError, isErrorLike, pluralize, type ErrorLike } from '@sourcegraph/common'
|
||||
import { LATEST_VERSION, aggregateStreamingSearch, type ContentMatch } from '@sourcegraph/shared/src/search/stream'
|
||||
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import { Link, PageHeader, Container, Code, H3, Text, Icon, Tooltip, ButtonLink, Alert } from '@sourcegraph/wildcard'
|
||||
import { Alert, ButtonLink, Code, Container, H3, Icon, Link, PageHeader, Text, Tooltip } from '@sourcegraph/wildcard'
|
||||
|
||||
import { FilteredConnection, type FilteredConnectionFilter } from '../components/FilteredConnection'
|
||||
import { FilteredConnection, type Filter } from '../components/FilteredConnection'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
import { useFeatureFlag } from '../featureFlags/useFeatureFlag'
|
||||
import { type FeatureFlagFields, SearchPatternType } from '../graphql-operations'
|
||||
import { SearchPatternType, type FeatureFlagFields } from '../graphql-operations'
|
||||
|
||||
import { fetchFeatureFlags as defaultFetchFeatureFlags } from './backend'
|
||||
|
||||
@ -104,12 +104,12 @@ export function getFeatureFlagReferences(flagName: string, productGitVersion: st
|
||||
)
|
||||
}
|
||||
|
||||
const filters: FilteredConnectionFilter[] = [
|
||||
const filters: Filter[] = [
|
||||
{
|
||||
id: 'filters',
|
||||
label: 'Type',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
|
||||
@ -1,31 +1,31 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react'
|
||||
|
||||
import { mdiAlertCircle, mdiAlert, mdiArrowLeftBold, mdiArrowRightBold } from '@mdi/js'
|
||||
import { mdiAlert, mdiAlertCircle, mdiArrowLeftBold, mdiArrowRightBold } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
import { type Observable, of, timer } from 'rxjs'
|
||||
import { of, timer, type Observable } from 'rxjs'
|
||||
import { catchError, concatMap, map, repeat, takeWhile } from 'rxjs/operators'
|
||||
import { parse as _parseVersion, type SemVer } from 'semver'
|
||||
|
||||
import { Timestamp } from '@sourcegraph/branded/src/components/Timestamp'
|
||||
import { asError, type ErrorLike, isErrorLike } from '@sourcegraph/common'
|
||||
import { asError, isErrorLike, type ErrorLike } from '@sourcegraph/common'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import {
|
||||
LoadingSpinner,
|
||||
useObservable,
|
||||
Alert,
|
||||
Container,
|
||||
Icon,
|
||||
Code,
|
||||
Container,
|
||||
ErrorAlert,
|
||||
H3,
|
||||
Icon,
|
||||
LoadingSpinner,
|
||||
PageHeader,
|
||||
Text,
|
||||
Tooltip,
|
||||
PageHeader,
|
||||
ErrorAlert,
|
||||
useObservable,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import { Collapsible } from '../components/Collapsible'
|
||||
import { FilteredConnection, type FilteredConnectionFilter, type Connection } from '../components/FilteredConnection'
|
||||
import { FilteredConnection, type Connection, type Filter } from '../components/FilteredConnection'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
import type { OutOfBandMigrationFields } from '../graphql-operations'
|
||||
|
||||
@ -42,12 +42,12 @@ export interface SiteAdminMigrationsPageProps extends TelemetryProps, TelemetryV
|
||||
now?: () => Date
|
||||
}
|
||||
|
||||
const filters: FilteredConnectionFilter[] = [
|
||||
const filters: Filter[] = [
|
||||
{
|
||||
id: 'filters',
|
||||
label: 'Migration state',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { type ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useState, type ReactNode } from 'react'
|
||||
|
||||
import { mdiChevronDown } from '@mdi/js'
|
||||
import { VisuallyHidden } from '@reach/visually-hidden'
|
||||
@ -30,7 +30,7 @@ import {
|
||||
|
||||
import {
|
||||
FilteredConnection,
|
||||
type FilteredConnectionFilter,
|
||||
type Filter,
|
||||
type FilteredConnectionQueryArguments,
|
||||
} from '../components/FilteredConnection'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
@ -45,12 +45,12 @@ export interface SiteAdminOutboundRequestsPageProps extends TelemetryProps, Tele
|
||||
|
||||
export type OutboundRequest = OutboundRequestsResult['outboundRequests']['nodes'][0]
|
||||
|
||||
const filters: FilteredConnectionFilter[] = [
|
||||
const filters: Filter[] = [
|
||||
{
|
||||
id: 'filters',
|
||||
label: 'Filter',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
|
||||
@ -6,46 +6,47 @@ import { useLocation, useNavigate } from 'react-router-dom'
|
||||
|
||||
import { dataOrThrowErrors, useQuery } from '@sourcegraph/http-client'
|
||||
import { RepoLink } from '@sourcegraph/shared/src/components/RepoLink'
|
||||
import { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import type { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Code,
|
||||
Container,
|
||||
ErrorAlert,
|
||||
Icon,
|
||||
Input,
|
||||
Link,
|
||||
LoadingSpinner,
|
||||
PageHeader,
|
||||
Input,
|
||||
useDebounce,
|
||||
Button,
|
||||
Alert,
|
||||
Text,
|
||||
Code,
|
||||
Icon,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuList,
|
||||
MenuItem,
|
||||
MenuLink,
|
||||
MenuList,
|
||||
PageHeader,
|
||||
Position,
|
||||
Text,
|
||||
useDebounce,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import { externalRepoIcon } from '../components/externalServices/externalServices'
|
||||
import {
|
||||
buildFilterArgs,
|
||||
FilterControl,
|
||||
type FilteredConnectionFilter,
|
||||
type FilteredConnectionFilterValue,
|
||||
type Filter,
|
||||
type FilterOption,
|
||||
type FilterValues,
|
||||
} from '../components/FilteredConnection'
|
||||
import { useShowMorePagination } from '../components/FilteredConnection/hooks/useShowMorePagination'
|
||||
import { ConnectionSummary } from '../components/FilteredConnection/ui'
|
||||
import { getFilterFromURL, getUrlQuery } from '../components/FilteredConnection/utils'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
import type {
|
||||
ExternalServiceKindsResult,
|
||||
ExternalServiceKindsVariables,
|
||||
PackagesResult,
|
||||
PackagesVariables,
|
||||
SiteAdminPackageFields,
|
||||
ExternalServiceKindsVariables,
|
||||
ExternalServiceKindsResult,
|
||||
} from '../graphql-operations'
|
||||
|
||||
import { EXTERNAL_SERVICE_KINDS, PACKAGES_QUERY } from './backend'
|
||||
@ -179,7 +180,7 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
error: extSvcError,
|
||||
} = useQuery<ExternalServiceKindsResult, ExternalServiceKindsVariables>(EXTERNAL_SERVICE_KINDS, {})
|
||||
|
||||
const ecosystemFilterValues = useMemo<FilteredConnectionFilterValue[]>(() => {
|
||||
const ecosystemFilterValues = useMemo<FilterOption[]>(() => {
|
||||
const values = []
|
||||
|
||||
for (const extSvc of extSvcs?.externalServices.nodes ?? []) {
|
||||
@ -196,13 +197,13 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
return values
|
||||
}, [extSvcs?.externalServices.nodes])
|
||||
|
||||
const filters = useMemo<FilteredConnectionFilter[]>(
|
||||
const filters = useMemo<Filter[]>(
|
||||
() => [
|
||||
{
|
||||
id: 'ecosystem',
|
||||
label: 'Ecosystem',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
@ -215,7 +216,7 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
[ecosystemFilterValues]
|
||||
)
|
||||
|
||||
const [filterValues, setFilterValues] = useState<Map<string, FilteredConnectionFilterValue>>(() =>
|
||||
const [filterValues, setFilterValues] = useState<FilterValues>(() =>
|
||||
getFilterFromURL(new URLSearchParams(location.search), filters)
|
||||
)
|
||||
|
||||
@ -254,7 +255,7 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
}, [filterValues, filters, searchValue, location, navigate])
|
||||
|
||||
const variables = useMemo<PackagesVariables>(() => {
|
||||
const args = buildFilterArgs(filterValues)
|
||||
const args = buildFilterArgs(filters, filterValues)
|
||||
|
||||
return {
|
||||
name: query,
|
||||
@ -263,7 +264,7 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
first: DEFAULT_FIRST,
|
||||
...args,
|
||||
}
|
||||
}, [filterValues, query])
|
||||
}, [filters, filterValues, query])
|
||||
|
||||
const {
|
||||
connection,
|
||||
@ -343,12 +344,8 @@ export const SiteAdminPackagesPage: React.FunctionComponent<React.PropsWithChild
|
||||
<FilterControl
|
||||
filters={filters}
|
||||
values={filterValues}
|
||||
onValueSelect={(filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue) =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set(filter.id, value)
|
||||
return newValues
|
||||
})
|
||||
onValueSelect={(filter: Filter, value: FilterOption['value'] | null) =>
|
||||
setFilterValues(values => ({ ...values, [filter.id]: value }))
|
||||
}
|
||||
/>
|
||||
{connection && (
|
||||
|
||||
@ -10,8 +10,9 @@ import { EXTERNAL_SERVICE_IDS_AND_NAMES } from '../components/externalServices/b
|
||||
import {
|
||||
buildFilterArgs,
|
||||
FilterControl,
|
||||
type FilteredConnectionFilter,
|
||||
type FilteredConnectionFilterValue,
|
||||
type Filter,
|
||||
type FilterOption,
|
||||
type FilterValues,
|
||||
} from '../components/FilteredConnection'
|
||||
import { usePageSwitcherPagination } from '../components/FilteredConnection/hooks/usePageSwitcherPagination'
|
||||
import { getFilterFromURL, getUrlQuery } from '../components/FilteredConnection/utils'
|
||||
@ -32,7 +33,7 @@ import { RepositoryNode } from './RepositoryNode'
|
||||
|
||||
import styles from './SiteAdminRepositoriesContainer.module.scss'
|
||||
|
||||
const STATUS_FILTERS: { [label: string]: FilteredConnectionFilterValue } = {
|
||||
const STATUS_FILTERS: { [label: string]: FilterOption } = {
|
||||
All: {
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
@ -83,12 +84,12 @@ const STATUS_FILTERS: { [label: string]: FilteredConnectionFilterValue } = {
|
||||
},
|
||||
}
|
||||
|
||||
const FILTERS: FilteredConnectionFilter[] = [
|
||||
const FILTERS: Filter[] = [
|
||||
{
|
||||
id: 'order',
|
||||
label: 'Order',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'Name (A-Z)',
|
||||
value: 'name-asc',
|
||||
@ -131,7 +132,7 @@ const FILTERS: FilteredConnectionFilter[] = [
|
||||
id: 'status',
|
||||
label: 'Status',
|
||||
type: 'select',
|
||||
values: Object.values(STATUS_FILTERS),
|
||||
options: Object.values(STATUS_FILTERS),
|
||||
},
|
||||
]
|
||||
|
||||
@ -193,13 +194,13 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
id: 'codeHost',
|
||||
label: 'Code Host',
|
||||
type: 'select',
|
||||
values,
|
||||
options: values,
|
||||
})
|
||||
}
|
||||
return filtersWithExternalServices
|
||||
}, [extSvcs, location.pathname])
|
||||
|
||||
const [filterValues, setFilterValues] = useState<Map<string, FilteredConnectionFilterValue>>(() =>
|
||||
const [filterValues, setFilterValues] = useState<FilterValues>(() =>
|
||||
getFilterFromURL(new URLSearchParams(location.search), filters)
|
||||
)
|
||||
|
||||
@ -240,7 +241,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
}, [filters, filterValues, searchQuery, location, navigate])
|
||||
|
||||
const variables = useMemo<RepositoriesVariables>(() => {
|
||||
const args = buildFilterArgs(filterValues)
|
||||
const args = buildFilterArgs(filters, filterValues)
|
||||
|
||||
return {
|
||||
...args,
|
||||
@ -252,7 +253,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
cloneStatus: args.cloneStatus ?? null,
|
||||
externalService: args.externalService ?? null,
|
||||
} as RepositoriesVariables
|
||||
}, [searchQuery, filterValues])
|
||||
}, [filters, searchQuery, filterValues])
|
||||
|
||||
const debouncedVariables = useDebounce(variables, 300)
|
||||
|
||||
@ -295,12 +296,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
color: 'var(--body-color)',
|
||||
position: 'right',
|
||||
tooltip: 'The number of repositories that are queued to be cloned.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.NotCloned)
|
||||
return newValues
|
||||
}),
|
||||
onClick: () => setFilterValues(values => ({ ...values, status: STATUS_FILTERS.NotCloned.value })),
|
||||
},
|
||||
{
|
||||
value: data.repositoryStats.cloning,
|
||||
@ -308,12 +304,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
color: data.repositoryStats.cloning > 0 ? 'var(--primary)' : 'var(--body-color)',
|
||||
position: 'right',
|
||||
tooltip: 'The number of repositories that are currently being cloned.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.Cloning)
|
||||
return newValues
|
||||
}),
|
||||
onClick: () => setFilterValues(values => ({ ...values, status: STATUS_FILTERS.Cloning.value })),
|
||||
},
|
||||
{
|
||||
value: data.repositoryStats.cloned,
|
||||
@ -321,12 +312,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
color: 'var(--success)',
|
||||
position: 'right',
|
||||
tooltip: 'The number of repositories that have been cloned.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.Cloned)
|
||||
return newValues
|
||||
}),
|
||||
onClick: () => setFilterValues(values => ({ ...values, status: STATUS_FILTERS.Cloned.value })),
|
||||
},
|
||||
{
|
||||
value: data.repositoryStats.indexed,
|
||||
@ -334,12 +320,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
color: 'var(--body-color)',
|
||||
position: 'right',
|
||||
tooltip: 'The number of repositories that have been indexed for search.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.Indexed)
|
||||
return newValues
|
||||
}),
|
||||
onClick: () => setFilterValues(values => ({ ...values, status: STATUS_FILTERS.Indexed.value })),
|
||||
},
|
||||
{
|
||||
value: data.repositoryStats.failedFetch,
|
||||
@ -348,11 +329,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
position: 'right',
|
||||
tooltip: 'The number of repositories where the last syncing attempt produced an error.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.FailedFetchOrClone)
|
||||
return newValues
|
||||
}),
|
||||
setFilterValues(values => ({ ...values, status: STATUS_FILTERS.FailedFetchOrClone.value })),
|
||||
},
|
||||
]
|
||||
|
||||
@ -364,12 +341,7 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
position: 'right',
|
||||
tooltip:
|
||||
'The number of repositories where corruption has been detected. Reclone these repositories to get rid of corruption.',
|
||||
onClick: () =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set('status', STATUS_FILTERS.Corrupted)
|
||||
return newValues
|
||||
}),
|
||||
onClick: () => setFilterValues(values => ({ ...values, status: STATUS_FILTERS.Corrupted.value })),
|
||||
})
|
||||
}
|
||||
return items
|
||||
@ -387,12 +359,8 @@ export const SiteAdminRepositoriesContainer: React.FunctionComponent<{ alwaysPol
|
||||
<FilterControl
|
||||
filters={filters}
|
||||
values={filterValues}
|
||||
onValueSelect={(filter: FilteredConnectionFilter, value: FilteredConnectionFilterValue) =>
|
||||
setFilterValues(values => {
|
||||
const newValues = new Map(values)
|
||||
newValues.set(filter.id, value)
|
||||
return newValues
|
||||
})
|
||||
onValueSelect={(filter: Filter, value: FilterOption['value'] | null) =>
|
||||
setFilterValues(values => ({ ...values, [filter.id]: value }))
|
||||
}
|
||||
/>
|
||||
<Input
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import React, { type ReactNode, useCallback, useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useState, type ReactNode } from 'react'
|
||||
|
||||
import { mdiChevronDown, mdiContentCopy } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
@ -27,7 +27,7 @@ import {
|
||||
import { requestGraphQL } from '../backend/graphql'
|
||||
import {
|
||||
FilteredConnection,
|
||||
type FilteredConnectionFilter,
|
||||
type Filter,
|
||||
type FilteredConnectionQueryArguments,
|
||||
} from '../components/FilteredConnection'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
@ -41,12 +41,12 @@ export interface SiteAdminSlowRequestsPageProps extends TelemetryProps, Telemetr
|
||||
|
||||
type SlowRequest = SlowRequestsResult['slowRequests']['nodes'][0]
|
||||
|
||||
const filters: FilteredConnectionFilter[] = [
|
||||
const filters: Filter[] = [
|
||||
{
|
||||
id: 'filters',
|
||||
label: 'Filter',
|
||||
type: 'select',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All',
|
||||
value: 'all',
|
||||
|
||||
@ -8,28 +8,28 @@ import type { TelemetryV2Props } from '@sourcegraph/shared/src/telemetry'
|
||||
import { EVENT_LOGGER } from '@sourcegraph/shared/src/telemetry/web/eventLogger'
|
||||
import {
|
||||
Badge,
|
||||
type BADGE_VARIANTS,
|
||||
Button,
|
||||
useLocalStorage,
|
||||
Card,
|
||||
H2,
|
||||
H3,
|
||||
Link,
|
||||
Tab,
|
||||
TabList,
|
||||
TabPanel,
|
||||
TabPanels,
|
||||
Tabs,
|
||||
H2,
|
||||
H3,
|
||||
Text,
|
||||
Card,
|
||||
useLocalStorage,
|
||||
type BADGE_VARIANTS,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import { FilteredConnection, type FilteredConnectionFilter } from '../components/FilteredConnection'
|
||||
import { FilteredConnection, type Filter } from '../components/FilteredConnection'
|
||||
import { PageTitle } from '../components/PageTitle'
|
||||
import {
|
||||
UserActivePeriod,
|
||||
type SurveyResponseAggregateFields,
|
||||
type SurveyResponseFields,
|
||||
type UserWithSurveyResponseFields,
|
||||
UserActivePeriod,
|
||||
} from '../graphql-operations'
|
||||
import {
|
||||
fetchAllSurveyResponses,
|
||||
@ -43,12 +43,12 @@ import { ValueLegendItem } from './analytics/components/ValueLegendList'
|
||||
|
||||
import styles from './SiteAdminSurveyResponsesPage.module.scss'
|
||||
|
||||
const USER_ACTIVITY_FILTERS: FilteredConnectionFilter[] = [
|
||||
const USER_ACTIVITY_FILTERS: Filter[] = [
|
||||
{
|
||||
label: '',
|
||||
type: 'radio',
|
||||
id: 'user-activity-filters',
|
||||
values: [
|
||||
options: [
|
||||
{
|
||||
label: 'All users',
|
||||
value: 'all',
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { Modal, PageHeader } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../components/FilteredConnection'
|
||||
import type { FilterOption } from '../../components/FilteredConnection'
|
||||
|
||||
import {
|
||||
AddPackageFilterModalContent,
|
||||
@ -11,7 +11,7 @@ import styles from './PackagesModal.module.scss'
|
||||
|
||||
interface AddFilterModalProps extends AddPackageFilterModalContentProps {
|
||||
onDismiss: () => void
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
}
|
||||
|
||||
export const AddFilterModal: React.FunctionComponent<AddFilterModalProps> = props => (
|
||||
|
||||
@ -2,7 +2,7 @@ import { useState } from 'react'
|
||||
|
||||
import { Button, Modal, PageHeader } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../components/FilteredConnection'
|
||||
import type { FilterOption } from '../../components/FilteredConnection'
|
||||
import type { PackageRepoFilterFields } from '../../graphql-operations'
|
||||
|
||||
import { EditPackageFilterModalContent } from './modal-content/EditPackageFilterModalContent'
|
||||
@ -16,7 +16,7 @@ import styles from './PackagesModal.module.scss'
|
||||
interface ManageFiltersModalProps extends Omit<ManagePackageFiltersModalContentProps, 'setActiveFilter'> {
|
||||
onDismiss: () => void
|
||||
onAdd: () => void
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
}
|
||||
|
||||
export const ManageFiltersModal: React.FunctionComponent<ManageFiltersModalProps> = props => {
|
||||
|
||||
@ -5,20 +5,20 @@ import classNames from 'classnames'
|
||||
|
||||
import { RepoLink } from '@sourcegraph/shared/src/components/RepoLink'
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
ErrorAlert,
|
||||
Form,
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
Alert,
|
||||
LoadingSpinner,
|
||||
Select,
|
||||
Tooltip,
|
||||
useDebounce,
|
||||
LoadingSpinner,
|
||||
ErrorAlert,
|
||||
Select,
|
||||
Form,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../../components/FilteredConnection'
|
||||
import type { FilterOption } from '../../../components/FilteredConnection'
|
||||
import type { PackageRepoReferenceKind } from '../../../graphql-operations'
|
||||
import { prettyBytesBigint } from '../../../util/prettyBytesBigint'
|
||||
import { useMatchingPackages } from '../hooks/useMatchingPackages'
|
||||
@ -35,7 +35,7 @@ export interface MultiPackageState {
|
||||
|
||||
interface MultiPackageFormProps {
|
||||
initialState: MultiPackageState
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
setType: (type: BlockType) => void
|
||||
onDismiss: () => void
|
||||
onSave: (state: MultiPackageState) => Promise<unknown>
|
||||
|
||||
@ -1,26 +1,26 @@
|
||||
import { useState, useCallback } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
||||
import { mdiPlus } from '@mdi/js'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import { toRepoURL } from '@sourcegraph/shared/src/util/url'
|
||||
import {
|
||||
Badge,
|
||||
Button,
|
||||
ErrorAlert,
|
||||
Form,
|
||||
Icon,
|
||||
Input,
|
||||
Label,
|
||||
Tooltip,
|
||||
Select,
|
||||
LoadingSpinner,
|
||||
ErrorAlert,
|
||||
Badge,
|
||||
useDebounce,
|
||||
Form,
|
||||
Link,
|
||||
LoadingSpinner,
|
||||
Select,
|
||||
Tooltip,
|
||||
useDebounce,
|
||||
} from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../../components/FilteredConnection'
|
||||
import type { PackageRepoReferenceKind, PackageRepoMatchFields } from '../../../graphql-operations'
|
||||
import type { FilterOption } from '../../../components/FilteredConnection'
|
||||
import type { PackageRepoMatchFields, PackageRepoReferenceKind } from '../../../graphql-operations'
|
||||
import { useMatchingPackages } from '../hooks/useMatchingPackages'
|
||||
import { useMatchingVersions } from '../hooks/useMatchingVersions'
|
||||
import type { BlockType } from '../modal-content/AddPackageFilterModalContent'
|
||||
@ -37,7 +37,7 @@ export interface SinglePackageState {
|
||||
|
||||
interface SinglePackageFormProps {
|
||||
initialState: SinglePackageState
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
setType: (type: BlockType) => void
|
||||
onDismiss: () => void
|
||||
onSave: (state: SinglePackageState) => Promise<unknown>
|
||||
|
||||
@ -3,11 +3,11 @@ import { useState } from 'react'
|
||||
import { useMutation } from '@sourcegraph/http-client'
|
||||
import { ErrorAlert } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../../components/FilteredConnection'
|
||||
import type { FilterOption } from '../../../components/FilteredConnection'
|
||||
import {
|
||||
PackageMatchBehaviour,
|
||||
type AddPackageRepoFilterResult,
|
||||
type AddPackageRepoFilterVariables,
|
||||
PackageMatchBehaviour,
|
||||
type PackageRepoReferenceKind,
|
||||
type SiteAdminPackageFields,
|
||||
} from '../../../graphql-operations'
|
||||
@ -20,7 +20,7 @@ import styles from './AddPackageFilterModalContent.module.scss'
|
||||
|
||||
export interface AddPackageFilterModalContentProps {
|
||||
node?: SiteAdminPackageFields
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
onDismiss: () => void
|
||||
}
|
||||
|
||||
|
||||
@ -3,12 +3,12 @@ import { useState } from 'react'
|
||||
import { useMutation } from '@sourcegraph/http-client'
|
||||
import { ErrorAlert } from '@sourcegraph/wildcard'
|
||||
|
||||
import type { FilteredConnectionFilterValue } from '../../../components/FilteredConnection'
|
||||
import type { FilterOption } from '../../../components/FilteredConnection'
|
||||
import type {
|
||||
UpdatePackageRepoFilterVariables,
|
||||
PackageMatchBehaviour,
|
||||
PackageRepoFilterFields,
|
||||
UpdatePackageRepoFilterResult,
|
||||
UpdatePackageRepoFilterVariables,
|
||||
} from '../../../graphql-operations'
|
||||
import { updatePackageRepoFilterMutation } from '../backend'
|
||||
import { BehaviourSelect } from '../components/BehaviourSelect'
|
||||
@ -42,7 +42,7 @@ const getInitialState = (packageFilter: PackageRepoFilterFields): SinglePackageS
|
||||
|
||||
export interface EditPackageFilterModalContentProps {
|
||||
packageFilter: PackageRepoFilterFields
|
||||
filters: FilteredConnectionFilterValue[]
|
||||
filters: FilterOption[]
|
||||
onDismiss: () => void
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user