mirror of
https://github.com/sourcegraph/sourcegraph.git
synced 2026-02-06 15:51:43 +00:00
VS Code proxy exploration (#42802)
Co-authored-by: David Veszelovszki <veszelovszki@gmail.com>
This commit is contained in:
parent
12a67271ba
commit
6b33130ad7
@ -1,3 +1,5 @@
|
||||
import type { Response as NodeFetchResponse } from 'node-fetch'
|
||||
|
||||
import { isErrorLike } from '@sourcegraph/common'
|
||||
|
||||
const EHTTPSTATUS = 'HTTPStatusError'
|
||||
@ -6,7 +8,7 @@ export class HTTPStatusError extends Error {
|
||||
public readonly name = EHTTPSTATUS
|
||||
public readonly status: number
|
||||
|
||||
constructor(response: Response) {
|
||||
constructor(response: Response | NodeFetchResponse) {
|
||||
super(`Request to ${response.url} failed with ${response.status} ${response.statusText}`)
|
||||
this.status = response.status
|
||||
}
|
||||
@ -30,11 +32,11 @@ export const isHTTPAuthError = (error: unknown): boolean =>
|
||||
failedWithHTTPStatus(error, 401) || failedWithHTTPStatus(error, 403)
|
||||
|
||||
/**
|
||||
* Checks if a given fetch Response has a HTTP 2xx status code and throws an HTTPStatusError otherwise.
|
||||
* Checks if a given fetch Response has an HTTP 2xx status code and throws an HTTPStatusError otherwise.
|
||||
*/
|
||||
export function checkOk(response: Response): Response {
|
||||
export function checkOk(response: Response | NodeFetchResponse): Response {
|
||||
if (!response.ok) {
|
||||
throw new HTTPStatusError(response)
|
||||
}
|
||||
return response
|
||||
return response as Response
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ export function applyConfig(config: PluginConfig): void {
|
||||
customRequestHeaders = parseCustomRequestHeadersString(config.customRequestHeadersAsString)
|
||||
anonymousUserId = config.anonymousUserId || 'no-user-id'
|
||||
pluginVersion = config.pluginVersion
|
||||
polyfillEventSource({ ...(accessToken ? { Authorization: `token ${accessToken}` } : {}), ...customRequestHeaders })
|
||||
polyfillEventSource({ ...(accessToken ? { Authorization: `token ${accessToken}` } : {}), ...customRequestHeaders }, undefined)
|
||||
}
|
||||
|
||||
function parseCustomRequestHeadersString(headersString: string | null): Record<string, string> | null {
|
||||
|
||||
@ -11,8 +11,6 @@ import { hasProperty } from '@sourcegraph/common'
|
||||
import { TextDocumentDecoration } from '@sourcegraph/extension-api-types'
|
||||
|
||||
// LINE DECORATIONS
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore: This errors even though we removed config from TextDocumentDecorationType
|
||||
export const createDecorationType = (): TextDocumentDecorationType => ({ key: uniqueId('TextDocumentDecorationType') })
|
||||
|
||||
/**
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
function polyfillEventSource(headers: { [name: string]: string }): void
|
||||
function polyfillEventSource(headers: { [name: string]: string }, agent: any): void
|
||||
export default polyfillEventSource
|
||||
|
||||
@ -11,9 +11,11 @@ const https = require('https')
|
||||
const util = require('util')
|
||||
|
||||
let fixedHeaders = {}
|
||||
let proxyAgent = null
|
||||
|
||||
module.exports = function polyfillEventSource(headers) {
|
||||
module.exports = function polyfillEventSource(headers, agent) {
|
||||
fixedHeaders = { ...headers }
|
||||
proxyAgent = agent
|
||||
|
||||
global.EventSource = EventSource
|
||||
|
||||
@ -171,6 +173,10 @@ function EventSource(url, eventSourceInitDict) {
|
||||
options.withCredentials = eventSourceInitDict.withCredentials
|
||||
}
|
||||
|
||||
if (proxyAgent) {
|
||||
options.agent = proxyAgent(url)
|
||||
}
|
||||
|
||||
request = (isSecure ? https : http).request(options, res => {
|
||||
self.connectionInProgress = false
|
||||
// Handle HTTP errors
|
||||
|
||||
@ -124,11 +124,12 @@ client/vscode
|
||||
#### Desktop and Web Version
|
||||
|
||||
1. `git clone` the [Sourcegraph repository](https://github.com/sourcegraph/sourcegraph)
|
||||
1. Install dependencies via `yarn` for the Sourcegraph repository
|
||||
1. Run `yarn generate` at the root directory to generate the required schemas
|
||||
1. Make your changes to the files within the `client/vscode` directory with VS Code
|
||||
1. Run `yarn build-vsce` to build or `yarn watch-vsce` to build and watch the tasks from the `root` directory
|
||||
1. Select `Launch VS Code Extension` (`Launch VS Code Web Extension` for VS Code Web) from the dropdown menu in the `Run and Debug` sidebar view to see your changes
|
||||
2. Install dependencies via `yarn` for the Sourcegraph repository
|
||||
3. Run `yarn generate` at the root directory to generate the required schemas
|
||||
4. Make your changes to the files within the `client/vscode` directory with VS Code
|
||||
5. Run `yarn build-vsce` to build or `yarn watch-vsce` to build and watch the tasks from the `root` directory
|
||||
6. To see your changes, open the `Run and Debug` sidebar view in VS Code, and
|
||||
select `Launch VS Code Extension` (`Launch VS Code Web Extension` for VS Code Web) from the dropdown menu.
|
||||
|
||||
### Integration Tests
|
||||
|
||||
|
||||
@ -96,14 +96,18 @@ Alternatively you can use the `Extensions: Configure Recommended Extensions (Wor
|
||||
|
||||
This extension contributes the following settings:
|
||||
|
||||
| Setting | Description | Example |
|
||||
| --------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| sourcegraph.url | Specify your on-premises Sourcegraph instance here, if applicable. The extension is connected to Sourcegraph Cloud by default. | "https://your-sourcegraph.com" |
|
||||
| sourcegraph.accessToken | [Depreciated after 2.2.12] The access token to query the Sourcegraph API. Required to use this extension with private instances. Create a new access token at `${SOURCEGRAPH_URL}/users/<sourcegraph-username>/settings/tokens` | null |
|
||||
| sourcegraph.remoteUrlReplacements | Object, where each `key` is replaced by `value` in the remote url. | {"github": "gitlab", "master": "main"} |
|
||||
| sourcegraph.defaultBranch | String to set the name of the default branch. Always open files in the default branch. | "master" |
|
||||
| sourcegraph.requestHeaders | Takes object, where each value pair will be added to the request headers made to your instance. | {"Cache-Control": "no-cache", "Proxy-Authenticate": "Basic"} |
|
||||
| sourcegraph.basePath | The file path on the machine to the folder that is expected to contain all repositories. We will try to open search results using the basePath. | "/Users/USERNAME/Documents/" |
|
||||
| Setting | Description | Example |
|
||||
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| sourcegraph.url | Specify your on-premises Sourcegraph instance here, if applicable. The extension is connected to Sourcegraph Cloud by default. | "https://your-sourcegraph.com" |
|
||||
| sourcegraph.accessToken | [Depreciated after 2.2.12] The access token to query the Sourcegraph API. Required to use this extension with private instances. Create a new access token at `${SOURCEGRAPH_URL}/users/<sourcegraph-username>/settings/tokens` | null |
|
||||
| sourcegraph.remoteUrlReplacements | Object, where each `key` is replaced by `value` in the remote url. | {"github": "gitlab", "master": "main"} |
|
||||
| sourcegraph.defaultBranch | String to set the name of the default branch. Always open files in the default branch. | "master" |
|
||||
| sourcegraph.requestHeaders | Takes object, where each value pair will be added to the request headers made to your instance. | {"Cache-Control": "no-cache", "Proxy-Authenticate": "Basic"} |
|
||||
| sourcegraph.basePath | The file path on the machine to the folder that is expected to contain all repositories. We will try to open search results using the basePath. | "/Users/USERNAME/Documents/" |
|
||||
| sourcegraph.proxyProtocol | The protocol to use when proxying requests to the Sourcegraph instance. | "http", "https" |
|
||||
| sourcegraph.proxyHost | The host to use when proxying requests to the Sourcegraph instance. It shouldn't include a protocol (like "http://") or a port (like ":7080"). When this is set, port must be set as well. | "localhost" |
|
||||
| sourcegraph.proxyPort | The port to use when proxying requests to the Sourcegraph instance. When this is set, host must be set as well. | 80, 443, 7080, 9090 |
|
||||
| sourcegraph.proxyPath | The full path to a file when proxying requests to the Sourcegraph instance via a UNIX socket. | "/home/user/path/unix.socket" |
|
||||
|
||||
## Questions & Feedback
|
||||
|
||||
|
||||
@ -163,6 +163,43 @@
|
||||
"examples": [
|
||||
"/Users/USERNAME/Documents/"
|
||||
]
|
||||
},
|
||||
"sourcegraph.proxyProtocol": {
|
||||
"description": "The protocol to use when proxying requests to the Sourcegraph instance.",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"http",
|
||||
"https"
|
||||
]
|
||||
},
|
||||
"sourcegraph.proxyHost": {
|
||||
"description": "The host to use when proxying requests to the Sourcegraph instance. It shouldn't include a protocol (like \"http://\") or a port (like \":7080\"). When this is set, port must be set as well.",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"localhost",
|
||||
"1.2.3.4"
|
||||
]
|
||||
},
|
||||
"sourcegraph.proxyPort": {
|
||||
"description": "The port to use when proxying requests to the Sourcegraph instance. When this is set, host must be set as well.",
|
||||
"type": "number",
|
||||
"default": 0,
|
||||
"examples": [
|
||||
80,
|
||||
443,
|
||||
7080,
|
||||
9090
|
||||
]
|
||||
},
|
||||
"sourcegraph.proxyPath": {
|
||||
"description": "The full path to a file when proxying requests to the Sourcegraph instance via a UNIX domain socket.",
|
||||
"type": "string",
|
||||
"default": "",
|
||||
"examples": [
|
||||
"/home/user/path/unix.socket"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
72
client/vscode/src/backend/fetch.ts
Normal file
72
client/vscode/src/backend/fetch.ts
Normal file
@ -0,0 +1,72 @@
|
||||
import type net from 'net'
|
||||
|
||||
import { ClientRequest, RequestOptions } from 'agent-base'
|
||||
import HttpProxyAgent from 'http-proxy-agent'
|
||||
import HttpsProxyAgent from 'https-proxy-agent'
|
||||
import fetch, { Headers } from 'node-fetch'
|
||||
import vscode from 'vscode'
|
||||
|
||||
export { fetch, Headers }
|
||||
export type { BodyInit, Response, HeadersInit } from 'node-fetch'
|
||||
|
||||
interface HttpsProxyAgentInterface {
|
||||
callback(req: ClientRequest, opts: RequestOptions): Promise<net.Socket>
|
||||
}
|
||||
|
||||
type HttpsProxyAgentConstructor = new (
|
||||
options: string | { [key: string]: number | boolean | string | null }
|
||||
) => HttpsProxyAgentInterface
|
||||
|
||||
export function getProxyAgent(): ((url: URL | string) => HttpsProxyAgentInterface | undefined) | undefined {
|
||||
const proxyProtocol = vscode.workspace.getConfiguration('sourcegraph').get<string>('proxyProtocol')
|
||||
const proxyHost = vscode.workspace.getConfiguration('sourcegraph').get<string>('proxyHost')
|
||||
const proxyPort = vscode.workspace.getConfiguration('sourcegraph').get<number>('proxyPort')
|
||||
const proxyPath = vscode.workspace.getConfiguration('sourcegraph').get<string>('proxyPath')
|
||||
|
||||
// Quit if we're in the browser—we don't need proxying there.
|
||||
if (HttpsProxyAgent === null) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (proxyHost && !proxyPort) {
|
||||
console.error('proxyHost is set but proxyPort is not. These two settings must be set together.')
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (proxyPort && !proxyHost) {
|
||||
console.error('proxyPort is set but proxyHost is not. These two settings must be set together.')
|
||||
return undefined
|
||||
}
|
||||
|
||||
if (proxyHost || proxyPort || proxyPath) {
|
||||
return (url: URL | string) => {
|
||||
const protocol = getProtocol(url)
|
||||
if (protocol === undefined) {
|
||||
return undefined
|
||||
}
|
||||
const ProxyAgent = ((protocol === 'http'
|
||||
? HttpProxyAgent
|
||||
: HttpsProxyAgent) as unknown) as HttpsProxyAgentConstructor
|
||||
return new ProxyAgent({
|
||||
protocol: proxyProtocol === 'http' || proxyProtocol === 'https' ? proxyProtocol : 'https',
|
||||
...(proxyHost ? { host: proxyHost } : null),
|
||||
...(proxyPort ? { port: proxyPort } : null),
|
||||
...(proxyPath ? { path: proxyPath } : null),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
|
||||
function getProtocol(url: URL | string): string | undefined {
|
||||
if (typeof url === 'string') {
|
||||
return url.startsWith('http:') ? 'http' : 'https'
|
||||
}
|
||||
|
||||
if (url instanceof URL) {
|
||||
return url.protocol === 'http:' ? 'http' : 'https'
|
||||
}
|
||||
|
||||
return undefined
|
||||
}
|
||||
7
client/vscode/src/backend/node-fetch-fake-for-browser.ts
Normal file
7
client/vscode/src/backend/node-fetch-fake-for-browser.ts
Normal file
@ -0,0 +1,7 @@
|
||||
// This fake reuses the built-in "fetch" in browsers.
|
||||
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default fetch
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
export const Headers = globalThis.Headers
|
||||
@ -0,0 +1,6 @@
|
||||
// This is a fake that we use instead of the read http-proxy-agent and https-proxy-agent modules in the browser.
|
||||
// (We don't need proxying in the browser—browser settings will determine the proxying.)
|
||||
|
||||
// Disabling ESLint because we want to match the library interfaces
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default null
|
||||
@ -1,12 +1,15 @@
|
||||
import { authentication } from 'vscode'
|
||||
|
||||
import { asError } from '@sourcegraph/common'
|
||||
import { checkOk, GraphQLResult, GRAPHQL_URI, isHTTPAuthError } from '@sourcegraph/http-client'
|
||||
import { checkOk, GRAPHQL_URI, GraphQLResult, isHTTPAuthError } from '@sourcegraph/http-client'
|
||||
|
||||
import { handleAccessTokenError } from '../settings/accessTokenSetting'
|
||||
import { endpointSetting, endpointRequestHeadersSetting } from '../settings/endpointSetting'
|
||||
import { endpointRequestHeadersSetting, endpointSetting } from '../settings/endpointSetting'
|
||||
|
||||
import { fetch, getProxyAgent, Headers, HeadersInit } from './fetch'
|
||||
|
||||
let invalidated = false
|
||||
|
||||
/**
|
||||
* To be called when Sourcegraph URL changes.
|
||||
*/
|
||||
@ -43,19 +46,20 @@ export const requestGraphQLFromVSCode = async <R, V = object>(
|
||||
// Debt: intercepted requests in integration tests
|
||||
// have 0 status codes, so don't check in test environment.
|
||||
const checkFunction = process.env.IS_TEST ? <T>(value: T): T => value : checkOk
|
||||
const response = checkFunction(
|
||||
await fetch(url, {
|
||||
body: JSON.stringify({
|
||||
query: request,
|
||||
variables,
|
||||
}),
|
||||
method: 'POST',
|
||||
headers,
|
||||
})
|
||||
)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const options: any = {
|
||||
agent: getProxyAgent(),
|
||||
body: JSON.stringify({
|
||||
query: request,
|
||||
variables,
|
||||
}),
|
||||
method: 'POST',
|
||||
headers,
|
||||
}
|
||||
|
||||
const response = checkFunction(await fetch(url, options))
|
||||
// TODO request cancellation w/ VS Code cancellation tokens.
|
||||
// eslint-disable-next-line @typescript-eslint/return-await
|
||||
return response.json() as Promise<GraphQLResult<any>>
|
||||
return (await response.json()) as GraphQLResult<R>
|
||||
} catch (error) {
|
||||
// If `overrideAccessToken` is set, we're validating the token
|
||||
// and errors will be displayed in the UI.
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
import 'cross-fetch/polyfill'
|
||||
|
||||
import { of, ReplaySubject } from 'rxjs'
|
||||
import vscode from 'vscode'
|
||||
|
||||
@ -9,6 +7,7 @@ import { fetchStreamSuggestions } from '@sourcegraph/shared/src/search/suggestio
|
||||
|
||||
import { observeAuthenticatedUser } from './backend/authenticatedUser'
|
||||
import { logEvent } from './backend/eventLogger'
|
||||
import { getProxyAgent } from './backend/fetch'
|
||||
import { initializeInstanceVersionNumber } from './backend/instanceVersion'
|
||||
import { requestGraphQLFromVSCode } from './backend/requestGraphQl'
|
||||
import { initializeSearchContexts } from './backend/searchContexts'
|
||||
@ -26,7 +25,7 @@ import { invalidateContextOnSettingsChange } from './settings/invalidation'
|
||||
import { LocalStorageService, SELECTED_SEARCH_CONTEXT_SPEC_KEY } from './settings/LocalStorageService'
|
||||
import { watchUninstall } from './settings/uninstall'
|
||||
import { createVSCEStateMachine, VSCEQueryState } from './state'
|
||||
import { focusSearchPanel, openSourcegraphLinks, registerWebviews, copySourcegraphLinks } from './webview/commands'
|
||||
import { copySourcegraphLinks, focusSearchPanel, openSourcegraphLinks, registerWebviews } from './webview/commands'
|
||||
import { scretTokenKey, SourcegraphAuthActions, SourcegraphAuthProvider } from './webview/platform/AuthProvider'
|
||||
/**
|
||||
* See CONTRIBUTING docs for the Architecture Diagram
|
||||
@ -57,7 +56,11 @@ export async function activate(context: vscode.ExtensionContext): Promise<void>
|
||||
// Sets global `EventSource` for Node, which is required for streaming search.
|
||||
// Add custom headers to `EventSource` Authorization header when provided
|
||||
const customHeaders = endpointRequestHeadersSetting()
|
||||
polyfillEventSource(initialAccessToken ? { Authorization: `token ${initialAccessToken}`, ...customHeaders } : {})
|
||||
polyfillEventSource(
|
||||
initialAccessToken ? { Authorization: `token ${initialAccessToken}`, ...customHeaders } : {},
|
||||
getProxyAgent()
|
||||
)
|
||||
|
||||
// For search panel webview to signal that it is ready for messages.
|
||||
// Replay subject with large buffer size just in case panels are opened in quick succession.
|
||||
const initializedPanelIDs = new ReplaySubject<string>(7)
|
||||
|
||||
@ -4,6 +4,7 @@ import * as vscode from 'vscode'
|
||||
import polyfillEventSource from '@sourcegraph/shared/src/polyfills/vendor/eventSource'
|
||||
import { LATEST_VERSION } from '@sourcegraph/shared/src/search/stream'
|
||||
|
||||
import { getProxyAgent } from '../backend/fetch'
|
||||
import { initializeSourcegraphSettings } from '../backend/sourcegraphSettings'
|
||||
import { initializeCodeIntel } from '../code-intel/initialize'
|
||||
import { ExtensionCoreAPI } from '../contract'
|
||||
@ -65,7 +66,8 @@ export function registerWebviews({
|
||||
if (config.affectsConfiguration('sourcegraph.requestHeaders') && session) {
|
||||
const newCustomHeaders = endpointRequestHeadersSetting()
|
||||
polyfillEventSource(
|
||||
session.accessToken ? { Authorization: `token ${session.accessToken}`, ...newCustomHeaders } : {}
|
||||
session.accessToken ? { Authorization: `token ${session.accessToken}`, ...newCustomHeaders } : {},
|
||||
getProxyAgent()
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@ -13,6 +13,7 @@ import {
|
||||
|
||||
import polyfillEventSource from '@sourcegraph/shared/src/polyfills/vendor/eventSource'
|
||||
|
||||
import { getProxyAgent } from '../../backend/fetch'
|
||||
import { endpointRequestHeadersSetting, endpointSetting, setEndpoint } from '../../settings/endpointSetting'
|
||||
|
||||
export const scretTokenKey = 'SOURCEGRAPH_AUTH'
|
||||
@ -24,6 +25,7 @@ class SourcegraphAuthSession implements AuthenticationSession {
|
||||
}
|
||||
public readonly id = SourcegraphAuthProvider.id
|
||||
public readonly scopes = []
|
||||
|
||||
constructor(public readonly accessToken: string) {}
|
||||
}
|
||||
|
||||
@ -83,7 +85,10 @@ export class SourcegraphAuthProvider implements AuthenticationProvider, Disposab
|
||||
await this.cacheTokenFromStorage()
|
||||
// Update the polyfillEventSource on token changes
|
||||
polyfillEventSource(
|
||||
this.currentToken ? { Authorization: `token ${this.currentToken}`, ...endpointRequestHeadersSetting() } : {}
|
||||
this.currentToken
|
||||
? { Authorization: `token ${this.currentToken}`, ...endpointRequestHeadersSetting() }
|
||||
: {},
|
||||
getProxyAgent()
|
||||
)
|
||||
this._onDidChangeSessions.fire({ added, removed, changed })
|
||||
}
|
||||
|
||||
@ -62,6 +62,9 @@ function getExtensionCoreConfiguration(targetType) {
|
||||
alias:
|
||||
targetType === 'webworker'
|
||||
? {
|
||||
'http-proxy-agent': path.resolve(__dirname, 'src', 'backend', 'proxy-agent-fake-for-browser.ts'),
|
||||
'https-proxy-agent': path.resolve(__dirname, 'src', 'backend', 'proxy-agent-fake-for-browser.ts'),
|
||||
'node-fetch': path.resolve(__dirname, 'src', 'backend', 'node-fetch-fake-for-browser.ts'),
|
||||
path: require.resolve('path-browserify'),
|
||||
'./browserActionsNode': path.resolve(__dirname, 'src', 'commands', 'browserActionsWeb'),
|
||||
}
|
||||
|
||||
@ -25,7 +25,10 @@ const StanfordCommunitySearchContextPage = lazyComponent(
|
||||
)
|
||||
const CncfCommunitySearchContextPage = lazyComponent(() => import('./cncf'), 'CncfCommunitySearchContextPage')
|
||||
const JuliaCommunitySearchContextPage = lazyComponent(() => import('./Julia'), 'JuliaCommunitySearchContextPage')
|
||||
const BackstageCommunitySearchContextPage = lazyComponent(() => import('./Backstage'), 'BackstageCommunitySearchContextPage')
|
||||
const BackstageCommunitySearchContextPage = lazyComponent(
|
||||
() => import('./Backstage'),
|
||||
'BackstageCommunitySearchContextPage'
|
||||
)
|
||||
|
||||
// Hack! Hardcode these routes into cmd/frontend/internal/app/ui/router.go
|
||||
export const communitySearchContextsRoutes: readonly LayoutRouteProps<any>[] = [
|
||||
|
||||
@ -78,10 +78,7 @@ export const AddExternalServicePage: React.FunctionComponent<React.PropsWithChil
|
||||
}
|
||||
setIsCreating(true)
|
||||
try {
|
||||
const service = await addExternalService(
|
||||
{ input: { ...getExternalServiceInput() } },
|
||||
telemetryService
|
||||
)
|
||||
const service = await addExternalService({ input: { ...getExternalServiceInput() } }, telemetryService)
|
||||
setIsCreating(false)
|
||||
setCreatedExternalService(service)
|
||||
} catch (error) {
|
||||
|
||||
@ -77,7 +77,7 @@ export const BackendInsightView = forwardRef<HTMLElement, BackendInsightProps>((
|
||||
seriesDisplayOptions: {
|
||||
limit: parseSeriesLimit(debouncedFilters.seriesDisplayOptions.limit),
|
||||
sortOptions: debouncedFilters.seriesDisplayOptions.sortOptions,
|
||||
}
|
||||
},
|
||||
},
|
||||
onCompleted: data => {
|
||||
const parsedData = createBackendInsightData({ ...insight, filters }, data.insightViews.nodes[0])
|
||||
|
||||
@ -13,12 +13,8 @@ import sinon from 'sinon'
|
||||
import { MockedTestProvider } from '@sourcegraph/shared/src/testing/apollo'
|
||||
import { MockIntersectionObserver } from '@sourcegraph/shared/src/testing/MockIntersectionObserver'
|
||||
|
||||
import { ALL_INSIGHTS_DASHBOARD } from '../constants';
|
||||
import {
|
||||
CodeInsightsBackend,
|
||||
CodeInsightsBackendContext,
|
||||
FakeDefaultCodeInsightsBackend,
|
||||
} from '../core'
|
||||
import { ALL_INSIGHTS_DASHBOARD } from '../constants'
|
||||
import { CodeInsightsBackend, CodeInsightsBackendContext, FakeDefaultCodeInsightsBackend } from '../core'
|
||||
|
||||
import { CodeInsightsRootPage, CodeInsightsRootPageTab } from './CodeInsightsRootPage'
|
||||
|
||||
|
||||
@ -427,8 +427,10 @@
|
||||
"graphiql": "^1.8.0",
|
||||
"highlight.js": "^10.5.0",
|
||||
"highlightjs-graphql": "^1.0.2",
|
||||
"http-proxy-agent": "^5.0.0",
|
||||
"http-status-codes": "^2.1.4",
|
||||
"https-browserify": "^1.0.0",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"is-absolute-url": "^3.0.3",
|
||||
"iterare": "^1.2.1",
|
||||
"js-base64": "^3.7.2",
|
||||
|
||||
@ -20011,7 +20011,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"https-proxy-agent@npm:5, https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0":
|
||||
"https-proxy-agent@npm:5, https-proxy-agent@npm:5.0.1, https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1":
|
||||
version: 5.0.1
|
||||
resolution: "https-proxy-agent@npm:5.0.1"
|
||||
dependencies:
|
||||
@ -29449,9 +29449,11 @@ pvutils@latest:
|
||||
highlightjs-graphql: ^1.0.2
|
||||
html-webpack-harddisk-plugin: ^2.0.0
|
||||
html-webpack-plugin: ^5.3.2
|
||||
http-proxy-agent: ^5.0.0
|
||||
http-proxy-middleware: ^1.1.2
|
||||
http-status-codes: ^2.1.4
|
||||
https-browserify: ^1.0.0
|
||||
https-proxy-agent: ^5.0.1
|
||||
identity-obj-proxy: ^3.0.0
|
||||
is-absolute-url: ^3.0.3
|
||||
iterare: ^1.2.1
|
||||
|
||||
Loading…
Reference in New Issue
Block a user