Update dependency @sourcegraph/eslint-config to ^0.19.3 (#11683)

Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Felix Becker <felix.b@outlook.com>
This commit is contained in:
renovate[bot] 2020-06-24 11:00:55 +02:00 committed by GitHub
parent 7926b6c5b0
commit 2c2dcb66ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
74 changed files with 235 additions and 274 deletions

View File

@ -26,4 +26,6 @@ shared/dev/**/*.js
client/contrib/GH2SG.bookmarklet.js
docker-images/grafana/jsonnet/*.json
docker-images/grafana/grafonnet-lib/
docker-images/grafana/config/provisioning/dashboards/sourcegraph/
storybook-static/
!/.storybook/**

View File

@ -2,9 +2,9 @@ export function assertEnvironment(environment: typeof window['EXTENSION_ENV']):
if (window.EXTENSION_ENV !== environment) {
throw new Error(
'Detected transitive import of an entrypoint! ' +
window.EXTENSION_ENV +
String(window.EXTENSION_ENV) +
' attempted to import a file that is only intended to be imported by ' +
environment +
String(environment) +
'.'
)
}

View File

@ -100,11 +100,8 @@ export const diffDOMFunctions: DOMFunctions = {
const diffSide = codeElement.closest('.diff-editor')!
return diffSide.previousElementSibling &&
// If the sibling to the left is the diff divider, it's in the HEAD.
diffSide.previousElementSibling.classList.contains('segment-connector-column')
? 'head'
: 'base'
// If the sibling to the left is the diff divider, it's in the HEAD.
return diffSide.previousElementSibling?.classList.contains('segment-connector-column') ? 'head' : 'base'
},
isFirstCharacterDiffIndicator: () => false,
}

View File

@ -404,7 +404,7 @@ export const githubCodeHost: CodeHost = {
// Go to blob URL
const fragment = target.position
? `#L${target.position.line}${target.position.character ? ':' + target.position.character : ''}`
? `#L${target.position.line}${target.position.character ? `:${target.position.character}` : ''}`
: ''
return `https://${target.rawRepoName}/blob/${revision}/${target.filePath}${fragment}`
},

View File

@ -22,7 +22,7 @@ const getTextContent = (element: HTMLElement): { textContent: string; adjust: nu
// For some reason, phabricator adds an invisible element to the beginning of lines containing the diff indicator
// followed by a space (ex: '+ '). We need to adjust the position accordingly.
if (element.firstElementChild && element.firstElementChild.classList.contains('aural-only')) {
if (element.firstElementChild?.classList.contains('aural-only')) {
const pre = element.firstElementChild.textContent || ''
// Codeintellify handles ignoring one character for diff indicators so we'll allow it to adjust for that.
adjust = pre.replace(/^(\+|-)/, '').length

View File

@ -226,8 +226,7 @@ export function testDOMFunctions(
it('should return correctly whether the first character is a diff indicator', () => {
// Default is false
const actualFirstCharacterIsDiffIndicator = Boolean(
domFunctions.isFirstCharacterDiffIndicator &&
domFunctions.isFirstCharacterDiffIndicator(codeElement)
domFunctions.isFirstCharacterDiffIndicator?.(codeElement)
)
expect(actualFirstCharacterIsDiffIndicator).toBe(Boolean(firstCharacterIsDiffIndicator))
if (actualFirstCharacterIsDiffIndicator) {

View File

@ -9,7 +9,7 @@ import { DEFAULT_SOURCEGRAPH_URL, getExtensionVersion, observeSourcegraphURL } f
const IS_EXTENSION = true
const isExtensionStackTrace = (stacktrace: Sentry.Stacktrace, extensionID: string): boolean =>
!!(stacktrace.frames && stacktrace.frames.some(({ filename }) => !!filename?.includes(extensionID)))
!!stacktrace.frames?.some(({ filename }) => !!filename?.includes(extensionID))
const callSentryInit = once((extensionID: string) => {
Sentry.init({
@ -18,7 +18,7 @@ const callSentryInit = once((extensionID: string) => {
// Filter out events if we can tell from the stack trace that
// they didn't originate from extension code.
let keep = true
if (event.exception && event.exception.values) {
if (event.exception?.values) {
keep = event.exception.values.some(
({ stacktrace }) => !!(stacktrace && isExtensionStackTrace(stacktrace, extensionID))
)

View File

@ -75,13 +75,14 @@
"@babel/runtime": "^7.10.2",
"@gql2ts/from-schema": "^1.10.1",
"@gql2ts/language-typescript": "^1.9.0",
"@gql2ts/types": "^1.9.0",
"@istanbuljs/nyc-config-typescript": "^1.0.1",
"@octokit/rest": "^16.36.0",
"@percy/puppeteer": "^1.1.0",
"@percy/storybook": "^3.3.0",
"@slack/web-api": "^5.8.1",
"@sourcegraph/babel-plugin-transform-react-hot-loader-wrapper": "^1.0.0",
"@sourcegraph/eslint-config": "^0.19.2",
"@sourcegraph/eslint-config": "^0.19.3",
"@sourcegraph/prettierrc": "^3.0.3",
"@sourcegraph/stylelint-config": "^1.1.9",
"@sourcegraph/tsconfig": "^4.0.1",

View File

@ -47,10 +47,10 @@ async function graphQLTypes() {
},
{
generateNamespace: (name, interfaces) => interfaces,
interfaceBuilder: (name, body) => 'export ' + DEFAULT_OPTIONS.interfaceBuilder(name, body),
interfaceBuilder: (name, body) => `export ${DEFAULT_OPTIONS.interfaceBuilder(name, body)}`,
enumTypeBuilder: (name, values) =>
'export ' + DEFAULT_OPTIONS.enumTypeBuilder(name, values).replace(/^const enum/, 'enum'),
typeBuilder: (name, body) => 'export ' + DEFAULT_OPTIONS.typeBuilder(name, body),
`export ${DEFAULT_OPTIONS.enumTypeBuilder(name, values).replace(/^const enum/, 'enum')}`,
typeBuilder: (name, body) => `export ${DEFAULT_OPTIONS.typeBuilder(name, body)}`,
wrapList: type => `${type}[]`,
postProcessor: code => format(code, { ...formatOptions, parser: 'typescript' }),
}

View File

@ -120,8 +120,8 @@ export class ActionItem extends React.PureComponent<ActionItemProps, State> {
public componentDidUpdate(previousProps: ActionItemProps, previousState: State): void {
// If the tooltip changes while it's visible, we need to force-update it to show the new value.
const previousTooltip = previousProps.action.actionItem && previousProps.action.actionItem.description
const tooltip = this.props.action.actionItem && this.props.action.actionItem.description
const previousTooltip = previousProps.action.actionItem?.description
const tooltip = this.props.action.actionItem?.description
const descriptionTooltipChanged = previousTooltip !== tooltip
const errorTooltipChanged =

View File

@ -97,6 +97,7 @@ function exec(node: ExpressionNode, context: ComputedContext): any {
case '>=':
return left >= right()
case '+':
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
return left + right()
case '-':
return left - right()

View File

@ -15,7 +15,7 @@ export function fromHoverMerged(values: (Badged<Hover | PlainHover> | null | und
let range: Range | undefined
for (const result of values) {
if (result) {
if (result.contents && result.contents.value) {
if (result.contents?.value) {
contents.push({
value: result.contents.value,
kind: result.contents.kind || MarkupKind.PlainText,

View File

@ -6,7 +6,7 @@ import MenuDownIcon from 'mdi-react/MenuDownIcon'
import MenuIcon from 'mdi-react/MenuIcon'
import MenuUpIcon from 'mdi-react/MenuUpIcon'
import React, { useCallback, useMemo, useState } from 'react'
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
import TooltipPopoverWrapper from 'reactstrap/lib/TooltipPopoverWrapper'
import { Subscription } from 'rxjs'

View File

@ -67,7 +67,7 @@ export class ActivationChecklist extends React.PureComponent<ActivationChecklist
key={step.id}
{...step}
history={this.props.history}
done={(this.props.completed && this.props.completed[step.id]) || false}
done={this.props.completed?.[step.id] || false}
className={this.props.buttonClassName}
/>
</AccordionButton>

View File

@ -18,7 +18,7 @@ export function getContributedActionItems(
}
const allItems: ActionItemAction[] = []
const menuItems = contributions.menus && contributions.menus[menu]
const menuItems = contributions.menus?.[menu]
if (menuItems) {
for (const { action: actionID, alt: altActionID } of sortBy(menuItems, MENU_ITEMS_PROP_SORT_ORDER)) {
const action = contributions.actions.find(a => a.id === actionID)

View File

@ -160,8 +160,8 @@ export class HoverOverlay<A extends string> extends React.PureComponent<HoverOve
? {
opacity: 1,
visibility: 'visible',
left: overlayPosition.left + 'px',
top: overlayPosition.top + 'px',
left: `${overlayPosition.left}px`,
top: `${overlayPosition.top}px`,
}
: {
opacity: 0,

View File

@ -115,7 +115,7 @@ export class NotificationItem extends React.PureComponent<Props, State> {
<div
className="sourcegraph-notification-item__progressbar progress-bar"
// eslint-disable-next-line react/forbid-dom-props
style={{ width: this.state.progress.percentage + '%' }}
style={{ width: `${this.state.progress.percentage}%` }}
/>
</div>
)}

View File

@ -78,7 +78,7 @@ export interface PlatformContext {
* @returns A promise that resolves after the update succeeds and {@link PlatformContext#settings} reflects the
* update.
*/
updateSettings(subject: GQL.ID, edit: SettingsEdit | string): Promise<void>
updateSettings: (subject: GQL.ID, edit: SettingsEdit | string) => Promise<void>
/**
* Sends a request to the Sourcegraph GraphQL API and returns the response.
@ -87,7 +87,7 @@ export interface PlatformContext {
* could leak private information such as repository names.
* @returns Observable that emits the result or an error if the HTTP request failed
*/
requestGraphQL<R extends GQL.IQuery | GQL.IMutation>(options: {
requestGraphQL: <R extends GQL.IQuery | GQL.IMutation>(options: {
/**
* The GraphQL request (query or mutation)
*/
@ -101,12 +101,12 @@ export interface PlatformContext {
* could leak private information such as repository names.
*/
mightContainPrivateInfo: boolean
}): Observable<GraphQLResult<R>>
}) => Observable<GraphQLResult<R>>
/**
* Forces the currently displayed tooltip, if any, to update its contents.
*/
forceUpdateTooltip(): void
forceUpdateTooltip: () => void
/**
* Spawns a new JavaScript execution context (such as a Web Worker or browser extension
@ -116,7 +116,7 @@ export interface PlatformContext {
* @returns An observable that emits at most once with the message transports for communicating
* with the execution context (using, e.g., postMessage/onmessage) when it is ready.
*/
createExtensionHost(): Observable<EndpointPair>
createExtensionHost: () => Observable<EndpointPair>
/**
* Returns the script URL suitable for passing to importScripts for an extension's bundle.
@ -129,7 +129,7 @@ export interface PlatformContext {
* @returns A script URL suitable for passing to importScripts, typically either the original
* https:// URL for the extension's bundle or a blob: URI for it.
*/
getScriptURLForExtension(bundleURL: string): string | Promise<string>
getScriptURLForExtension: (bundleURL: string) => string | Promise<string>
/**
* Constructs the URL (possibly relative or absolute) to the file with the specified options.
@ -138,7 +138,7 @@ export interface PlatformContext {
* @param context Contextual information about the context of this invocation.
* @returns The URL to the file with the specified options.
*/
urlToFile(
urlToFile: (
target: RepoSpec &
Partial<RawRepoSpec> &
RevisionSpec &
@ -146,7 +146,7 @@ export interface PlatformContext {
Partial<UIPositionSpec> &
Partial<ViewStateSpec>,
context: URLToFileContext
): string
) => string
/**
* The URL to the Sourcegraph site that the user's session is associated with. This refers to

View File

@ -1,4 +1,3 @@
// @ts-expect-error
import configure from 'core-js/configurator'
configure({

View File

@ -111,7 +111,7 @@ function findElementMatchingRegexps(tag: string, regexps: string[]): HTMLElement
// Ignore hidden elements
continue
}
if (element.textContent && element.textContent.match(regexp)) {
if (element.textContent?.match(regexp)) {
return element
}
}
@ -317,10 +317,10 @@ export class Driver {
await this.page.waitForSelector(`[data-e2e-external-service-card-link="${kind.toUpperCase()}"]`, {
visible: true,
})
await this.page.evaluate(selector => {
await this.page.evaluate((selector: string) => {
const element = document.querySelector<HTMLElement>(selector)
if (!element) {
throw new Error('Could not find element to click on for selector ' + selector)
throw new Error(`Could not find element to click on for selector ${selector}`)
}
element.click()
}, `[data-e2e-external-service-card-link="${kind.toUpperCase()}"]`)

View File

@ -0,0 +1 @@
export default function configure(config: { usePolyfill?: string[] }): void

View File

@ -272,7 +272,7 @@ export function toPositionOrRangeHash(context: {
* @param ctx 1-indexed partial position
*/
export function toPositionHashComponent(position: { line: number; character?: number }): string {
return position.line.toString() + (position.character ? ':' + position.character : '')
return position.line.toString() + (position.character ? `:${position.character}` : '')
}
/**
@ -515,7 +515,7 @@ export function toViewStateHashComponent(viewState: string | undefined): string
}
const positionString = (position: Position): string =>
position.line + '' + (position.character ? ',' + position.character : '')
position.line.toString() + (position.character ? `,${position.character}` : '')
/**
* The inverse of parseRepoURI, this generates a string from parsed values.

View File

@ -68,7 +68,7 @@ export function refreshAuthenticatedUser(): Observable<never> {
export const authRequired = authenticatedUser.pipe(map(user => user === null && !window.context?.sourcegraphDotComMode))
// Populate authenticatedUser.
if (window.context && window.context.isAuthenticatedUser) {
if (window.context?.isAuthenticatedUser) {
refreshAuthenticatedUser()
.toPromise()
.then(

View File

@ -220,7 +220,7 @@ class ConnectionNodes<C extends Connection<N>, N, NP = {}> extends React.PureCom
</small>
</p>
)
} else if (this.props.connection.pageInfo && this.props.connection.pageInfo.hasNextPage) {
} else if (this.props.connection.pageInfo?.hasNextPage) {
// No total count to show, but it will show a 'Show more' button.
} else if (totalCount === 0) {
summary = this.props.emptyElement || (

View File

@ -159,10 +159,9 @@ export class MonacoEditor extends React.PureComponent<Props, State> {
id={this.props.id}
className={classNames(this.props.className, this.props.border !== false && 'border')}
/>
{this.props.keyboardShortcutForFocus &&
this.props.keyboardShortcutForFocus.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.focusInput} />
))}
{this.props.keyboardShortcutForFocus?.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.focusInput} />
))}
</>
)
}

View File

@ -153,7 +153,7 @@ export class BarChart<T extends BarChartSeries> extends React.Component<Props<T>
.data(series.slice().reverse())
.enter()
.append('g')
.attr('transform', (data, index) => 'translate(0,' + index * 20 + ')')
.attr('transform', (data, index) => `translate(0,${index * 20})`)
legend
.append('rect')
.attr('x', width - 19)
@ -188,12 +188,7 @@ function wrapLabel(text: Selection<any, any, any, any>, width: number): void {
// currentLine holds the line as it grows, until it overflows.
let currentLine: string[] = []
// tspan holds the current <tspan> element as it grows, until it overflows.
let tspan = text
.text(null)
.append('tspan')
.attr('x', 0)
.attr('y', yAttribute)
.attr('dy', dyAttribute + 'em')
let tspan = text.text(null).append('tspan').attr('x', 0).attr('y', yAttribute).attr('dy', `${dyAttribute}em`)
while (words.length) {
currentWord = words.pop() || ''
@ -208,7 +203,7 @@ function wrapLabel(text: Selection<any, any, any, any>, width: number): void {
.append('tspan')
.attr('x', 0)
.attr('y', yAttribute)
.attr('dy', ++lineNumber * lineHeight + dyAttribute + 'em')
.attr('dy', `${++lineNumber * lineHeight + dyAttribute}em`)
.text(currentWord)
}
}

View File

@ -66,7 +66,7 @@ export class FileDiffNode extends React.PureComponent<FileDiffNodeProps, State>
let stat: React.ReactFragment
// If one of the files was binary, display file size change instead of DiffStat.
if ((node.oldFile && node.oldFile.binary) || (node.newFile && node.newFile.binary)) {
if (node.oldFile?.binary || node.newFile?.binary) {
const sizeChange = (node.newFile?.byteSize ?? 0) - (node.oldFile?.byteSize ?? 0)
const className = sizeChange >= 0 ? 'text-success' : 'text-danger'
stat = <strong className={classNames(className, 'mr-2 code')}>{prettyBytes(sizeChange)}</strong>
@ -117,7 +117,7 @@ export class FileDiffNode extends React.PureComponent<FileDiffNodeProps, State>
</div>
</div>
{this.state.expanded &&
((node.oldFile && node.oldFile.binary) || (node.newFile && node.newFile.binary) ? (
(node.oldFile?.binary || node.newFile?.binary ? (
<div className="text-muted m-2">Binary files can't be rendered.</div>
) : (
<FileDiffHunks

View File

@ -100,13 +100,13 @@ describe('e2e test suite', () => {
})
await driver.page.click('.e2e-settings-file .e2e-save-toolbar-save')
await driver.page.waitForSelector('.e2e-global-alert .notices .global-alerts__alert', { visible: true })
await driver.page.evaluate(message => {
await driver.page.evaluate((message: string) => {
const element = document.querySelector<HTMLElement>('.e2e-global-alert .notices .global-alerts__alert')
if (!element) {
throw new Error('No .e2e-global-alert .notices .global-alerts__alert element found')
}
if (!element.textContent?.includes(message)) {
throw new Error('Expected "' + message + '" message, but didn\'t find it')
throw new Error(`Expected "${message}" message, but didn't find it`)
}
}, message)
})
@ -115,7 +115,7 @@ describe('e2e test suite', () => {
await driver.page.goto(sourcegraphBaseUrl + '/users/test/settings/tokens/new')
await driver.page.waitForSelector('.e2e-create-access-token-description')
const name = 'E2E Test ' + new Date().toISOString() + ' ' + random(1, 1e7)
const name = `E2E Test ${new Date().toISOString()} ${random(1, 1e7)}`
await driver.replaceText({
selector: '.e2e-create-access-token-description',

View File

@ -126,7 +126,7 @@ export const CampaignStatus: React.FunctionComponent<CampaignStatusProps> = ({
<div className="progress mt-2 mb-1">
{/* we need to set the width to control the progress bar, so: */}
{/* eslint-disable-next-line react/forbid-dom-props */}
<div className="progress-bar" style={{ width: progress + '%' }}>
<div className="progress-bar" style={{ width: `${progress}%` }}>
&nbsp;
</div>
</div>

View File

@ -5,7 +5,7 @@ import { subMinutes } from 'date-fns'
describe('ChangesetLastSynced', () => {
for (const viewerCanAdminister of [false, true]) {
describe('ViewerCanAdminister: ' + viewerCanAdminister, () => {
describe(`ViewerCanAdminister: ${viewerCanAdminister}`, () => {
test('renders not scheduled', () => {
const result = renderer.create(
<ChangesetLastSynced

View File

@ -25,7 +25,7 @@ export const ProductSubscriptionLabel: React.FunctionComponent<{
{productSubscription.invoiceItem.plan[planField || 'nameWithBrand']} (
{formatUserCount(productSubscription.invoiceItem.userCount)})
</>
) : productSubscription.activeLicense && productSubscription.activeLicense.info ? (
) : productSubscription.activeLicense?.info ? (
<>
{productSubscription.activeLicense.info.productNameWithBrand} (
{formatUserCount(productSubscription.activeLicense.info.userCount)})

View File

@ -81,7 +81,7 @@ export class ExtensionsExploreSection extends React.PureComponent<Props, State>
<ExtensionsExploreSectionExtensionCard
key={extension.id}
extensionID={extension.extensionIDWithoutRegistry}
description={(extension.manifest && extension.manifest.description) || undefined}
description={extension.manifest?.description || undefined}
url={extension.url}
className="list-group-item list-group-item-action"
/>

View File

@ -87,7 +87,7 @@ export const RegistryNewExtensionPage = withAuthenticatedUser(
concat(
[{ publishersOrError: 'loading' }],
queryViewerRegistryPublishers().pipe(
map(result => ({ publishersOrError: result, publisher: result[0] && result[0].id })),
map(result => ({ publishersOrError: result, publisher: result[0]?.id })),
catchError(error => [{ publishersOrError: asError(error) }])
)
).subscribe(

View File

@ -96,7 +96,7 @@ export const SiteAdminProductSubscriptionNode: React.FunctionComponent<SiteAdmin
)}
</td>
<td className="w-100">
{node.activeLicense && node.activeLicense.info && node.activeLicense.info.tags.length > 0 ? (
{node.activeLicense?.info && node.activeLicense.info.tags.length > 0 ? (
<ProductLicenseTags tags={node.activeLicense.info.tags} />
) : (
<span className="text-muted font-italic">None</span>

View File

@ -81,28 +81,25 @@ export const UserSubscriptionsProductSubscriptionPage: React.FunctionComponent<P
) : (
<>
<h2>Subscription {productSubscription.name}</h2>
{(productSubscription.invoiceItem ||
(productSubscription.activeLicense && productSubscription.activeLicense.info)) && (
{(productSubscription.invoiceItem || productSubscription.activeLicense?.info) && (
<UserProductSubscriptionStatus
subscriptionName={productSubscription.name}
productNameWithBrand={
productSubscription.activeLicense && productSubscription.activeLicense.info
productSubscription.activeLicense?.info
? productSubscription.activeLicense.info.productNameWithBrand
: productSubscription.invoiceItem!.plan.nameWithBrand
}
userCount={
productSubscription.activeLicense && productSubscription.activeLicense.info
productSubscription.activeLicense?.info
? productSubscription.activeLicense.info.userCount
: productSubscription.invoiceItem!.userCount
}
expiresAt={
productSubscription.activeLicense && productSubscription.activeLicense.info
productSubscription.activeLicense?.info
? parseISO(productSubscription.activeLicense.info.expiresAt)
: parseISO(productSubscription.invoiceItem!.expiresAt)
}
licenseKey={
productSubscription.activeLicense && productSubscription.activeLicense.licenseKey
}
licenseKey={productSubscription.activeLicense?.licenseKey ?? null}
/>
)}
<div className="card mt-3">

View File

@ -65,10 +65,7 @@ export class ExtensionCard extends React.PureComponent<Props> {
<div className="text-truncate w-100">
<div className="d-flex align-items-center">
<h4 className="card-title extension-card__body-title mb-0 mr-1 text-truncate font-weight-normal flex-1">
<LinkOrSpan
to={node.registryExtension && node.registryExtension.url}
className="stretched-link"
>
<LinkOrSpan to={node.registryExtension?.url} className="stretched-link">
<Path
path={
node.registryExtension
@ -78,7 +75,7 @@ export class ExtensionCard extends React.PureComponent<Props> {
/>
</LinkOrSpan>
</h4>
{node.registryExtension && node.registryExtension.isWorkInProgress && (
{node.registryExtension?.isWorkInProgress && (
<WorkInProgressBadge
viewerCanAdminister={node.registryExtension.viewerCanAdminister}
/>

View File

@ -9,6 +9,7 @@ import { SettingsCascade, SettingsCascadeOrError, SettingsCascadeProps } from '.
import { ErrorLike, isErrorLike } from '../../../shared/src/util/errors'
import { eventLogger } from '../tracking/eventLogger'
import { isExtensionAdded } from './extension/extension'
import { property } from '../../../shared/src/util/types'
interface Props extends SettingsCascadeProps, PlatformContextProps<'updateSettings'> {
/** The extension that this element is for. */
@ -113,13 +114,14 @@ function confirmAddExtension(extensionID: string): boolean {
/** Converts a SettingsCascadeOrError to a SettingsCascade, returning the first error it finds. */
function extractErrors(settingsCascade: SettingsCascadeOrError): SettingsCascade | ErrorLike {
if (settingsCascade.subjects === null) {
return new Error('Subjects was ' + settingsCascade.subjects)
return new Error('Subjects was null')
}
if (settingsCascade.final === null || isErrorLike(settingsCascade.final)) {
return new Error('Merged was ' + settingsCascade.final)
return new Error(`Merged was ${String(settingsCascade.final)}`)
}
if (settingsCascade.subjects.find(isErrorLike)) {
return new Error('One of the subjects was ' + settingsCascade.subjects.find(isErrorLike))
const found = settingsCascade.subjects.find(property('settings', isErrorLike))
if (found) {
return new Error(`One of the subjects was ${found.settings.message}`)
}
return settingsCascade as SettingsCascade
}

View File

@ -39,7 +39,7 @@ export const ExtensionAreaHeader: React.FunctionComponent<ExtensionAreaHeaderPro
// noop
}
const isWorkInProgress = props.extension.registryExtension && props.extension.registryExtension.isWorkInProgress
const isWorkInProgress = props.extension.registryExtension?.isWorkInProgress
return (
<div className={`extension-area-header ${props.className || ''}`}>

View File

@ -72,7 +72,7 @@ function toContributionsGroups(manifest: ExtensionManifest): ContributionGroup[]
const settingsGroup: ContributionGroup = { title: 'Settings', columnHeaders: ['Name', 'Description'], rows: [] }
try {
if (manifest.contributes.configuration && manifest.contributes.configuration.properties) {
if (manifest.contributes.configuration?.properties) {
for (const [name, schema] of Object.entries(manifest.contributes.configuration.properties)) {
settingsGroup.rows.push([
// eslint-disable-next-line react/jsx-key

View File

@ -15,7 +15,7 @@ export const ExtensionNoManifestAlert: React.FunctionComponent<{
}> = ({ extension }) => (
<div className="alert alert-info">
This extension is not yet published.
{extension.registryExtension && extension.registryExtension.viewerCanAdminister && (
{extension.registryExtension?.viewerCanAdminister && (
<>
<br />
<Link className="mt-3 btn btn-primary" to={`${extension.registryExtension.url}/-/releases/new`}>
@ -76,15 +76,14 @@ export class RegistryExtensionManifestPage extends React.PureComponent<Props, St
{this.state.viewMode === ViewMode.Plain ? ViewMode.Rich : ViewMode.Plain} viewer
</button>
)}{' '}
{this.props.extension.registryExtension &&
this.props.extension.registryExtension.viewerCanAdminister && (
<Link
className="btn btn-primary"
to={`${this.props.extension.registryExtension.url}/-/releases/new`}
>
Publish new release
</Link>
)}
{this.props.extension.registryExtension?.viewerCanAdminister && (
<Link
className="btn btn-primary"
to={`${this.props.extension.registryExtension.url}/-/releases/new`}
>
Publish new release
</Link>
)}
</div>
</div>
<div className="mt-2">

View File

@ -101,47 +101,41 @@ export class RegistryExtensionOverviewPage extends React.PureComponent<Props> {
)}
<small className="text-muted">
<dl className="border-top pt-2">
{this.props.extension.registryExtension &&
this.props.extension.registryExtension.publisher && (
<>
<dt>Publisher</dt>
<dd>
{this.props.extension.registryExtension.publisher ? (
<Link to={this.props.extension.registryExtension.publisher.url}>
{extensionIDPrefix(
this.props.extension.registryExtension.publisher
)}
</Link>
) : (
'Unavailable'
)}
</dd>
</>
)}
{this.props.extension.registryExtension &&
this.props.extension.registryExtension.registryName && (
<>
<dt
className={
this.props.extension.registryExtension.publisher
? 'border-top pt-2'
: ''
{this.props.extension.registryExtension?.publisher && (
<>
<dt>Publisher</dt>
<dd>
{this.props.extension.registryExtension.publisher ? (
<Link to={this.props.extension.registryExtension.publisher.url}>
{extensionIDPrefix(this.props.extension.registryExtension.publisher)}
</Link>
) : (
'Unavailable'
)}
</dd>
</>
)}
{this.props.extension.registryExtension?.registryName && (
<>
<dt
className={
this.props.extension.registryExtension.publisher ? 'border-top pt-2' : ''
}
>
Published on
</dt>
<dd>
<LinkOrSpan
to={this.props.extension.registryExtension.remoteURL}
target={
this.props.extension.registryExtension.isLocal ? undefined : '_self'
}
>
Published on
</dt>
<dd>
<LinkOrSpan
to={this.props.extension.registryExtension.remoteURL}
target={
this.props.extension.registryExtension.isLocal ? undefined : '_self'
}
>
{this.props.extension.registryExtension.registryName}
</LinkOrSpan>
</dd>
</>
)}
{this.props.extension.registryExtension.registryName}
</LinkOrSpan>
</dd>
</>
)}
<dt className="border-top pt-2">Extension ID</dt>
<dd>{this.props.extension.id}</dd>
{this.props.extension.registryExtension &&

View File

@ -15,7 +15,7 @@ const PublishNewManifestAlert: React.FunctionComponent<{
}> = ({ extension, text, buttonLabel, alertClass }) => (
<div className={`alert ${alertClass}`}>
{text}
{extension.registryExtension && extension.registryExtension.viewerCanAdminister && (
{extension.registryExtension?.viewerCanAdminister && (
<>
<br />
<Link className="mt-3 btn btn-primary" to={`${extension.registryExtension.url}/-/releases/new`}>

View File

@ -17,13 +17,6 @@ import { GlobalAlert } from './GlobalAlert'
import { Notices } from './Notices'
import * as H from 'history'
// This module is not in @types/semver yet. We can't use the top-level semver module because it uses
// dynamic requires, which Webpack complains about.
//
// eslint-disable-next-line @typescript-eslint/ban-ts-ignore
// @ts-ignore
import semverParse from 'semver/functions/parse'
interface Props extends SettingsCascadeProps {
history: H.History
isSiteAdmin: boolean

View File

@ -150,10 +150,10 @@ export class GlobalNavbar extends React.PureComponent<Props, State> {
const branding = window.context ? window.context.branding : null
if (branding) {
if (this.props.isLightTheme) {
if (branding.light && branding.light.symbol) {
if (branding.light?.symbol) {
logoSource = branding.light.symbol
}
} else if (branding.dark && branding.dark.symbol) {
} else if (branding.dark?.symbol) {
logoSource = branding.dark.symbol
}
if (branding.disableSymbolSpin) {

View File

@ -29,7 +29,7 @@ interface State {
*/
export class UserNavItem extends React.PureComponent<Props, State> {
private supportsSystemTheme = Boolean(
window.matchMedia && window.matchMedia('not all and (prefers-color-scheme), (prefers-color-scheme)').matches
window.matchMedia?.('not all and (prefers-color-scheme), (prefers-color-scheme)').matches
)
public state: State = { isOpen: false }
@ -98,10 +98,9 @@ export class UserNavItem extends React.PureComponent<Props, State> {
</small>
</div>
)}
{this.props.keyboardShortcutForSwitchTheme &&
this.props.keyboardShortcutForSwitchTheme.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.onThemeCycle} />
))}
{this.props.keyboardShortcutForSwitchTheme?.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.onThemeCycle} />
))}
</div>
{this.props.authenticatedUser.organizations.nodes.length > 0 && (
<>
@ -130,7 +129,7 @@ export class UserNavItem extends React.PureComponent<Props, State> {
Help
</Link>
)}
{this.props.authenticatedUser.session && this.props.authenticatedUser.session.canSignOut && (
{this.props.authenticatedUser.session?.canSignOut && (
<a href="/-/sign-out" className="dropdown-item">
Sign out
</a>

View File

@ -44,7 +44,7 @@ export const OrgHeader: React.FunctionComponent<Props> = ({ org, navItems, match
)}
</ul>
<div className="flex-1" />
{org.viewerPendingInvitation && org.viewerPendingInvitation.respondURL && (
{org.viewerPendingInvitation?.respondURL && (
<div className="pb-1">
<small className="mr-2">Join organization:</small>
<Link to={org.viewerPendingInvitation.respondURL} className="btn btn-success btn-sm">

View File

@ -310,30 +310,27 @@ export class InviteForm extends React.PureComponent<Props, State> {
</Form>
</div>
</div>
{this.props.authenticatedUser &&
this.props.authenticatedUser.siteAdmin &&
!window.context.emailEnabled && (
<DismissibleAlert className="alert-info" partialStorageKey="org-invite-email-config">
<p className=" mb-0">
Set <code>email.smtp</code> in{' '}
<Link to="/site-admin/configuration">site configuration</Link> to send email
notfications about invitations.
</p>
</DismissibleAlert>
)}
{this.state.invited &&
this.state.invited.map(({ username, sentInvitationEmail, invitationURL }, index) => (
/* eslint-disable react/jsx-no-bind */
<InvitedNotification
key={index}
className="alert alert-success invite-form__alert"
username={username}
sentInvitationEmail={sentInvitationEmail}
invitationURL={invitationURL}
onDismiss={() => this.dismissNotification(index)}
/>
/* eslint-enable react/jsx-no-bind */
))}
{this.props.authenticatedUser?.siteAdmin && !window.context.emailEnabled && (
<DismissibleAlert className="alert-info" partialStorageKey="org-invite-email-config">
<p className=" mb-0">
Set <code>email.smtp</code> in{' '}
<Link to="/site-admin/configuration">site configuration</Link> to send email notfications
about invitations.
</p>
</DismissibleAlert>
)}
{this.state.invited?.map(({ username, sentInvitationEmail, invitationURL }, index) => (
/* eslint-disable react/jsx-no-bind */
<InvitedNotification
key={index}
className="alert alert-success invite-form__alert"
username={username}
sentInvitationEmail={sentInvitationEmail}
invitationURL={invitationURL}
onDismiss={() => this.dismissNotification(index)}
/>
/* eslint-enable react/jsx-no-bind */
))}
{this.state.error && (
<ErrorAlert className="invite-form__alert" error={this.state.error} history={this.props.history} />
)}

View File

@ -211,9 +211,7 @@ describe('Search regression test suite', () => {
if (results.length === 0) {
return false
}
const hasExcludedRepo = results.some(
element => element.textContent && element.textContent.includes('google')
)
const hasExcludedRepo = results.some(element => element.textContent?.includes('google'))
if (hasExcludedRepo) {
throw new Error('Results contain excluded repository')
}
@ -467,7 +465,7 @@ describe('Search regression test suite', () => {
this.timeout(2 * 1000)
const response = await search(gqlClient, 'router index:no timeout:1ns', 'V2', GQL.SearchPatternType.literal)
expect(response.results.matchCount).toBe(0)
expect(response.results.alert && response.results.alert.title).toBe('Timed out while searching')
expect(response.results.alert?.title).toBe('Timed out while searching')
})
test('Search repo group', async () => {

View File

@ -205,8 +205,8 @@ export async function getGlobalSettings(
}
return {
subjectID: globalSettingsSubject.id,
settingsID: globalSettingsSubject.latestSettings && globalSettingsSubject.latestSettings.id,
contents: (globalSettingsSubject.latestSettings && globalSettingsSubject.latestSettings.contents) || '',
settingsID: globalSettingsSubject.latestSettings?.id ?? null,
contents: globalSettingsSubject.latestSettings?.contents || '',
}
}

View File

@ -28,7 +28,7 @@ const Breadcrumb: React.FunctionComponent<Props> = props => {
)
if (index < parts.length - 1) {
spans.push(
<span key={'sep' + index} className="breadcrumb__separator">
<span key={`sep${index}`} className="breadcrumb__separator">
/
</span>
)

View File

@ -33,7 +33,7 @@ export const GitReferenceNode: React.FunctionComponent<GitReferenceNodeProps> =
(node.target.commit.committer && node.target.commit.committer.date > node.target.commit.author.date
? node.target.commit.committer
: node.target.commit.author)
const behindAhead = node.target.commit && node.target.commit.behindAhead
const behindAhead = node.target.commit?.behindAhead
url = url !== undefined ? url : node.url
return (

View File

@ -129,7 +129,7 @@ export class GoToCodeHostAction extends React.PureComponent<Props, State> {
if (this.props.range) {
url += `#L${this.props.range.start.line}-L${this.props.range.end.line}`
} else if (this.props.position) {
url += '#L' + this.props.position.line
url += `#L${this.props.position.line}`
}
}

View File

@ -95,11 +95,7 @@ const TextSearchIndexedReference: React.FunctionComponent<{
&nbsp;&mdash; indexed at{' '}
<code>
<LinkOrSpan
to={
indexedRef.indexedCommit && indexedRef.indexedCommit.commit
? indexedRef.indexedCommit.commit.url
: repo.url
}
to={indexedRef.indexedCommit?.commit ? indexedRef.indexedCommit.commit.url : repo.url}
>
{indexedRef.indexedCommit!.abbreviatedOID}
</LinkOrSpan>

View File

@ -157,7 +157,7 @@ export class SavedSearchForm extends React.Component<Props, State> {
<div className="alert alert-warning mb-3">
<strong>Warning:</strong> Sending emails is not currently configured on this Sourcegraph
server.{' '}
{this.props.authenticatedUser && this.props.authenticatedUser.siteAdmin
{this.props.authenticatedUser?.siteAdmin
? 'Use the email.smtp site configuration setting to enable sending emails.'
: 'Contact your server admin for more information.'}
</div>

View File

@ -118,7 +118,7 @@ describe('search/helpers', () => {
test('filters suggestions for filter aliases', () => {
const [{ value }] = filterStaticSuggestions({ query: 'l', cursorPosition: 1 }, searchFilterSuggestions)
expect(value).toBe(filterAliases.l + ':')
expect(value).toBe(`${filterAliases.l}:`)
})
test('does not throw for query ":"', () => {

View File

@ -426,10 +426,9 @@ export class QueryInput extends React.Component<Props, State> {
)
}}
</Downshift>
{this.props.keyboardShortcutForFocus &&
this.props.keyboardShortcutForFocus.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.focusInputAndPositionCursorAtEnd} />
))}
{this.props.keyboardShortcutForFocus?.keybindings.map((keybinding, index) => (
<Shortcut key={index} {...keybinding} onMatch={this.focusInputAndPositionCursorAtEnd} />
))}
</>
)
}

View File

@ -12,7 +12,7 @@ import { FilterType } from '../../../../shared/src/search/interactive/util'
import { SearchSuggestion } from '../../../../shared/src/search/suggestions'
import { appendSubtreeQueryParameter } from '../../../../shared/src/util/url'
export const filterAliases: Record<string, FilterSuggestionTypes | undefined> = {
export const filterAliases: Record<string, FilterSuggestionTypes> = {
r: FilterType.repo,
g: FilterType.repogroup,
f: FilterType.file,

View File

@ -202,10 +202,10 @@ export class InteractiveModeInput extends React.Component<InteractiveModeProps,
const { branding } = window.context
if (branding) {
if (this.props.isLightTheme) {
if (branding.light && branding.light.symbol) {
if (branding.light?.symbol) {
logoSource = branding.light.symbol
}
} else if (branding.dark && branding.dark.symbol) {
} else if (branding.dark?.symbol) {
logoSource = branding.dark.symbol
}
if (branding.disableSymbolSpin) {

View File

@ -48,10 +48,7 @@ export const Toggles: React.FunctionComponent<TogglesProps> = (props: TogglesPro
copyQueryButton,
} = props
const structuralSearchDisabled =
window.context &&
window.context.experimentalFeatures &&
window.context.experimentalFeatures.structuralSearch === 'disabled'
const structuralSearchDisabled = window.context?.experimentalFeatures?.structuralSearch === 'disabled'
const submitOnToggle = useCallback(
(args: { newPatternType: SearchPatternType } | { newCaseSensitivity: boolean }): void => {

View File

@ -173,7 +173,7 @@ export const CommitSearchResult: React.FunctionComponent<Props> = (props: Props)
lineClasses.push({ line: index + 1, className: 'hunk-header', url: toPrettyBlobURL(rhsContext) })
} else {
if (rhsContext.position && rhsContext.position.line) {
if (rhsContext.position?.line) {
if (!line.startsWith('+')) {
lhsContext.position.line++
}

View File

@ -154,11 +154,7 @@ export class SearchResults extends React.Component<SearchResultsProps, SearchRes
? { mode: this.props.interactiveSearchMode ? 'interactive' : 'plain' }
: {}),
})
if (
query_data.query &&
query_data.query.field_type &&
query_data.query.field_type.value_diff > 0
) {
if (query_data.query?.field_type && query_data.query.field_type.value_diff > 0) {
this.props.telemetryService.log('DiffSearchResultsQueried')
}
}),
@ -293,7 +289,7 @@ export class SearchResults extends React.Component<SearchResultsProps, SearchRes
public render(): JSX.Element | null {
const query = parseSearchURLQuery(this.props.location.search)
const filters = this.getFilters()
const extensionFilters = this.state.contributions && this.state.contributions.searchFilters
const extensionFilters = this.state.contributions?.searchFilters
const quickLinks =
(isSettingsValid<Settings>(this.props.settingsCascade) && this.props.settingsCascade.final.quicklinks) || []

View File

@ -52,7 +52,7 @@ export const SearchResultsFilterBars: React.FunctionComponent<{
<FilterChip
query={navbarSearchQuery}
onFilterChosen={onFilterClick}
key={filter.name + filter.value}
key={String(filter.name) + filter.value}
value={filter.value}
name={filter.name}
/>

View File

@ -43,9 +43,9 @@ export class SettingsPage extends React.PureComponent<Props, State> {
//
// If the settings update is for some other subject that is unrelated to the viewer, then this is not
// necessary.
const isSubjectInViewerSettingsCascade =
this.props.settingsCascade.subjects &&
this.props.settingsCascade.subjects.some(({ subject }) => subject.id === this.props.subject.id)
const isSubjectInViewerSettingsCascade = this.props.settingsCascade.subjects?.some(
({ subject }) => subject.id === this.props.subject.id
)
try {
if (isSubjectInViewerSettingsCascade) {

View File

@ -129,7 +129,7 @@ export class AccessTokenNode extends React.PureComponent<AccessTokenNodeProps, A
)}{' '}
<small className="text-muted">
{' '}
&mdash; <em>{this.props.node.scopes && this.props.node.scopes.join(', ')}</em>
&mdash; <em>{this.props.node.scopes?.join(', ')}</em>
<br />
{this.props.node.lastUsedAt ? (
<>

View File

@ -244,7 +244,7 @@ export class SiteAdminConfigurationPage extends React.Component<Props, State> {
.pipe(
tap(() => this.setState({ saving: true, error: undefined })),
concatMap(newContents => {
const lastConfiguration = this.state.site && this.state.site.configuration
const lastConfiguration = this.state.site?.configuration
const lastConfigurationID = lastConfiguration?.id || 0
return updateSiteConfiguration(lastConfigurationID, newContents).pipe(
@ -369,9 +369,7 @@ export class SiteAdminConfigurationPage extends React.Component<Props, State> {
)
}
if (
this.state.site &&
this.state.site.configuration &&
this.state.site.configuration.validationMessages &&
this.state.site?.configuration?.validationMessages &&
this.state.site.configuration.validationMessages.length > 0
) {
alerts.push(
@ -389,8 +387,7 @@ export class SiteAdminConfigurationPage extends React.Component<Props, State> {
}
// Avoid user confusion with values.yaml properties mixed in with site config properties.
const contents =
this.state.site && this.state.site.configuration && this.state.site.configuration.effectiveContents
const contents = this.state.site?.configuration?.effectiveContents
const legacyKubernetesConfigProps = [
'alertmanagerConfig',
'alertmanagerURL',
@ -445,7 +442,7 @@ export class SiteAdminConfigurationPage extends React.Component<Props, State> {
</p>
<div className="site-admin-configuration-page__alerts">{alerts}</div>
{this.state.loading && <LoadingSpinner className="icon-inline" />}
{this.state.site && this.state.site.configuration && (
{this.state.site?.configuration && (
<div>
<DynamicallyImportedMonacoSettingsEditor
value={contents || ''}

View File

@ -125,7 +125,7 @@ class UserSurveyResponseNode extends React.PureComponent<UserSurveyResponseNodeP
</strong>
</td>
<td>
{this.props.node.usageStatistics && this.props.node.usageStatistics.lastActiveTime ? (
{this.props.node.usageStatistics?.lastActiveTime ? (
<Timestamp date={this.props.node.usageStatistics.lastActiveTime} />
) : (
'?'

View File

@ -110,7 +110,7 @@ export class SiteAdminUpdatesPage extends React.Component<Props, State> {
<br />
<small>
<strong>Last update check:</strong>{' '}
{this.state.updateCheck && this.state.updateCheck.checkedAt
{this.state.updateCheck?.checkedAt
? formatDistance(parseISO(this.state.updateCheck.checkedAt), new Date(), {
addSuffix: true,
})

View File

@ -136,15 +136,14 @@ class UserUsageStatisticsNode extends React.PureComponent<UserUsageStatisticsNod
{this.props.node.usageStatistics ? this.props.node.usageStatistics.codeIntelligenceActions : 'n/a'}
</td>
<td className="site-admin-usage-statistics-page__date-column">
{this.props.node.usageStatistics && this.props.node.usageStatistics.lastActiveTime ? (
{this.props.node.usageStatistics?.lastActiveTime ? (
<Timestamp date={this.props.node.usageStatistics.lastActiveTime} />
) : (
'never'
)}
</td>
<td className="site-admin-usage-statistics-page__date-column">
{this.props.node.usageStatistics &&
this.props.node.usageStatistics.lastActiveCodeHostIntegrationTime ? (
{this.props.node.usageStatistics?.lastActiveCodeHostIntegrationTime ? (
<Timestamp date={this.props.node.usageStatistics.lastActiveCodeHostIntegrationTime} />
) : (
'never'

View File

@ -446,9 +446,7 @@ export function fetchAllConfigAndSettings(): Observable<AllConfig> {
const finalSettings = parseJSONC(data.viewerSettings.final)
return {
site:
data.site &&
data.site.configuration &&
data.site.configuration.effectiveContents &&
data.site?.configuration?.effectiveContents &&
parseJSONC(data.site.configuration.effectiveContents),
externalServices,
settings: {

View File

@ -38,7 +38,7 @@ export class EventLogger implements TelemetryService {
* Page titles should be specific and human-readable in pascal case, e.g. "SearchResults" or "Blob" or "NewOrg"
*/
public logViewEvent(pageTitle: string, logAsActiveUser = true): void {
if ((window.context && window.context.userAgentIsBot) || !pageTitle) {
if (window.context?.userAgentIsBot || !pageTitle) {
return
}
pageTitle = `View${pageTitle}`
@ -59,7 +59,7 @@ export class EventLogger implements TelemetryService {
* Event labels should be specific and follow a ${noun}${verb} structure in pascal case, e.g. "ButtonClicked" or "SignInInitiated"
*/
public log(eventLabel: string, eventProperties?: any): void {
if ((window.context && window.context.userAgentIsBot) || !eventLabel) {
if (window.context?.userAgentIsBot || !eventLabel) {
return
}
serverAdmin.trackAction(eventLabel, eventProperties)

View File

@ -213,7 +213,7 @@ export class TreeLayer extends React.Component<TreeLayerProps, TreeLayerState> {
this.componentUpdates.next(this.props)
const isDirectory = this.props.entryInfo && this.props.entryInfo.isDirectory
const isDirectory = this.props.entryInfo?.isDirectory
// When scrolling through the tree with the keyboard, if we hover a child tree node, prefetch its children.
if (this.node === this.props.selectedNode && isDirectory && this.props.onHover) {
this.props.onHover(this.node.path)

View File

@ -82,5 +82,5 @@ function gitTreeToTreeObject(entry: TreeEntryInfo): SingleChildGitTree {
/** Determines whether a Tree has single-child directories as children, in order to determine whether to render a SingleChildTreeLayer or TreeLayer */
export function hasSingleChild(tree: TreeEntryInfo[]): boolean {
return tree[0] && tree[0].isSingleChild
return tree[0]?.isSingleChild
}

View File

@ -161,21 +161,19 @@ export class UserSettingsProfilePage extends React.Component<Props, State> {
<PageTitle title="Profile" />
<h2>Profile</h2>
{this.props.activation &&
this.props.activation.completed &&
percentageDone(this.props.activation.completed) < 100 && (
<div className="card mb-3">
<div className="card-body">
<h3 className="mb-0">Almost there!</h3>
<p className="mb-0">Complete the steps below to finish onboarding to Sourcegraph.</p>
</div>
<ActivationChecklist
history={this.props.history}
steps={this.props.activation.steps}
completed={this.props.activation.completed}
/>
{this.props.activation?.completed && percentageDone(this.props.activation.completed) < 100 && (
<div className="card mb-3">
<div className="card-body">
<h3 className="mb-0">Almost there!</h3>
<p className="mb-0">Complete the steps below to finish onboarding to Sourcegraph.</p>
</div>
)}
<ActivationChecklist
history={this.props.history}
steps={this.props.activation.steps}
completed={this.props.activation.completed}
/>
</div>
)}
{isErrorLike(this.state.userOrError) && (
<ErrorAlert error={this.state.userOrError.message} history={this.props.history} />

View File

@ -1355,6 +1355,13 @@
"@gql2ts/util" "^1.9.0"
humps "^2.0.0"
"@gql2ts/types@^1.9.0":
version "1.9.0"
resolved "https://registry.npmjs.org/@gql2ts/types/-/types-1.9.0.tgz#f6725aa2beda33b6f1948e046be260e34d0b3405"
integrity sha512-1gtNzOMczIBS+ZnA3wizxOhLgy3lxfUVydQVMeGCe8kGRRI51BQzJKOza39OsIB9Fmwc6psHyamk/Z8RllTksA==
dependencies:
"@gql2ts/util" "^1.9.0"
"@gql2ts/util@^1.9.0":
version "1.9.0"
resolved "https://registry.npmjs.org/@gql2ts/util/-/util-1.9.0.tgz#d07a54832757d2f2d1fc9891e5b0e3e3b4886c6a"
@ -2155,14 +2162,14 @@
rxjs "^6.5.5"
ts-key-enum "^2.0.0"
"@sourcegraph/eslint-config@^0.19.2":
version "0.19.2"
resolved "https://registry.npmjs.org/@sourcegraph/eslint-config/-/eslint-config-0.19.2.tgz#d1950d5010f1993043fd1080f72a86cfb8ccc6a3"
integrity sha512-GedJzZd/cpnyS26Vn1bQIc5VdZjQeVE69uodYJODuwZDwP+xzFTvbURpK8phNWrC4UOdsK7tUGVe/WR7Mtsvrg==
"@sourcegraph/eslint-config@^0.19.3":
version "0.19.3"
resolved "https://registry.npmjs.org/@sourcegraph/eslint-config/-/eslint-config-0.19.3.tgz#5cbb6a8ebf355affae3f6d596cea20468076d762"
integrity sha512-1xtIEa4UXQ8gBcZkQ8MeHxstIM9M7IKJ4uAGnVJEKl6ytB7+12HUdmP0MNB7pZdrTDp/Q4x3cCqs1FeINRMRoQ==
dependencies:
"@sourcegraph/prettierrc" "^3.0.3"
"@typescript-eslint/eslint-plugin" "^2.34.0"
"@typescript-eslint/parser" "^2.34.0"
"@typescript-eslint/eslint-plugin" "^3.0.2"
"@typescript-eslint/parser" "^3.0.2"
eslint-config-prettier "^6.11.0"
eslint-plugin-ban "^1.4.0"
eslint-plugin-etc "^0.0.1-beta.25"
@ -2195,7 +2202,8 @@
integrity sha512-KWxkyphmlwam8kfYPSmoitKQRMGQCsr1ZRmNZgijT7ABKaVyk/+I5ezt2J213tM04Hi0vyg4L7iH1VCkNvm2Jw==
"@sourcegraph/extension-api-types@link:packages/@sourcegraph/extension-api-types":
version "2.1.0"
version "0.0.0"
uid ""
"@sourcegraph/prettierrc@^3.0.3":
version "3.0.3"
@ -3817,40 +3825,42 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/eslint-plugin@^2.34.0":
version "2.34.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.34.0.tgz#6f8ce8a46c7dea4a6f1d171d2bb8fbae6dac2be9"
integrity sha512-4zY3Z88rEE99+CNvTbXSyovv2z9PNOVffTWD2W8QF5s2prBQtwN2zadqERcrHpcR7O/+KMI3fcTAmUUhK/iQcQ==
"@typescript-eslint/eslint-plugin@^3.0.2":
version "3.4.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-3.4.0.tgz#8378062e6be8a1d049259bdbcf27ce5dfbeee62b"
integrity sha512-wfkpiqaEVhZIuQRmudDszc01jC/YR7gMSxa6ulhggAe/Hs0KVIuo9wzvFiDbG3JD5pRFQoqnf4m7REDsUvBnMQ==
dependencies:
"@typescript-eslint/experimental-utils" "2.34.0"
"@typescript-eslint/experimental-utils" "3.4.0"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.0.0"
semver "^7.3.2"
tsutils "^3.17.1"
"@typescript-eslint/experimental-utils@2.34.0":
version "2.34.0"
resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-2.34.0.tgz#d3524b644cdb40eebceca67f8cf3e4cc9c8f980f"
integrity sha512-eS6FTkq+wuMJ+sgtuNTtcqavWXqsflWcfBnlYhg/nS4aZ1leewkXGbvBhaapn1q6qf4M71bsR1tez5JTRMuqwA==
"@typescript-eslint/experimental-utils@3.4.0":
version "3.4.0"
resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-3.4.0.tgz#8a44dfc6fb7f1d071937b390fe27608ebda122b8"
integrity sha512-rHPOjL43lOH1Opte4+dhC0a/+ks+8gOBwxXnyrZ/K4OTAChpSjP76fbI8Cglj7V5GouwVAGaK+xVwzqTyE/TPw==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/typescript-estree" "2.34.0"
"@typescript-eslint/typescript-estree" "3.4.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/parser@^2.34.0":
version "2.34.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-2.34.0.tgz#50252630ca319685420e9a39ca05fe185a256bc8"
integrity sha512-03ilO0ucSD0EPTw2X4PntSIRFtDPWjrVq7C3/Z3VQHRC7+13YB55rcJI3Jt+YgeHbjUdJPcPa7b23rXCBokuyA==
"@typescript-eslint/parser@^3.0.2":
version "3.4.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-3.4.0.tgz#fe52b68c5cb3bba3f5d875bd17adb70420d49d8d"
integrity sha512-ZUGI/de44L5x87uX5zM14UYcbn79HSXUR+kzcqU42gH0AgpdB/TjuJy3m4ezI7Q/jk3wTQd755mxSDLhQP79KA==
dependencies:
"@types/eslint-visitor-keys" "^1.0.0"
"@typescript-eslint/experimental-utils" "2.34.0"
"@typescript-eslint/typescript-estree" "2.34.0"
"@typescript-eslint/experimental-utils" "3.4.0"
"@typescript-eslint/typescript-estree" "3.4.0"
eslint-visitor-keys "^1.1.0"
"@typescript-eslint/typescript-estree@2.34.0":
version "2.34.0"
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-2.34.0.tgz#14aeb6353b39ef0732cc7f1b8285294937cf37d5"
integrity sha512-OMAr+nJWKdlVM9LOqCqh3pQQPwxHAN7Du8DR6dmwCrAmxtiXQnhHJ6tBNtf+cggqfo51SG/FCwnKhXCIM7hnVg==
"@typescript-eslint/typescript-estree@3.4.0":
version "3.4.0"
resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-3.4.0.tgz#6a787eb70b48969e4cd1ea67b057083f96dfee29"
integrity sha512-zKwLiybtt4uJb4mkG5q2t6+W7BuYx2IISiDNV+IY68VfoGwErDx/RfVI7SWL4gnZ2t1A1ytQQwZ+YOJbHHJ2rw==
dependencies:
debug "^4.1.1"
eslint-visitor-keys "^1.1.0"
@ -19610,7 +19620,8 @@ source-map@^0.7.3:
integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
"sourcegraph@link:packages/sourcegraph-extension-api":
version "24.5.0"
version "0.0.0"
uid ""
space-separated-tokens@^1.0.0:
version "1.1.2"