Wildcard: <Alert /> migration (#29862)

This commit is contained in:
Tom Ross 2022-01-24 14:48:41 +00:00 committed by GitHub
parent 30424e6e83
commit 880433282b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
144 changed files with 713 additions and 802 deletions

View File

@ -3,7 +3,7 @@
exports[`ErrorAlert should add a prefix if given 1`] = `
<DocumentFragment>
<div
class="alert alert-danger"
class=""
>
<strong>
An error happened:
@ -21,7 +21,7 @@ exports[`ErrorAlert should add a prefix if given 1`] = `
exports[`ErrorAlert should omit the icon if icon={false} 1`] = `
<DocumentFragment>
<div
class="alert alert-danger"
class=""
>
<span
@ -36,7 +36,7 @@ exports[`ErrorAlert should omit the icon if icon={false} 1`] = `
exports[`ErrorAlert should render a Go multierror nicely 1`] = `
<DocumentFragment>
<div
class="alert alert-danger"
class=""
>
<span
@ -64,7 +64,7 @@ exports[`ErrorAlert should render a Go multierror nicely 1`] = `
exports[`ErrorAlert should render an Error object as an alert 1`] = `
<DocumentFragment>
<div
class="alert alert-danger"
class=""
>
<span

View File

@ -1,10 +1,10 @@
import classNames from 'classnames'
import { upperFirst } from 'lodash'
import React, { HTMLAttributes } from 'react'
import { asError } from '@sourcegraph/common'
import { Markdown } from '@sourcegraph/shared/src/components/Markdown'
import { renderMarkdown } from '@sourcegraph/shared/src/util/markdown'
import { Alert, AlertProps } from '@sourcegraph/wildcard'
export const renderError = (error: unknown): string =>
renderMarkdown(upperFirst((asError(error).message || 'Unknown Error').replace(/\t/g, '')), { breaks: true })
@ -36,10 +36,15 @@ export type ErrorAlertProps = {
className?: string
style?: React.CSSProperties
/**
* The Alert variant to display. Defaults to "danger"
*/
variant?: AlertProps['variant']
} & HTMLAttributes<HTMLDivElement>
/**
* Renders a given `Error` object in a Bootstrap danger alert.
* Renders a given `Error` object as a Wildcard alert.
*
* The error message is optimistically formatted as markdown to enrich links,
* bullet points, respect line breaks, code and bolded elements.
@ -50,12 +55,13 @@ export const ErrorAlert: React.FunctionComponent<ErrorAlertProps> = ({
className,
icon = true,
prefix,
variant = 'danger',
...rest
}) => {
prefix = prefix?.trim().replace(/:+$/, '')
return (
<div className={classNames('alert', 'alert-danger', className)} {...rest}>
<Alert className={className} variant={variant} {...rest}>
{prefix && <strong>{prefix}:</strong>} <ErrorMessage error={error} />
</div>
</Alert>
)
}

View File

@ -17,12 +17,14 @@ import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { property } from '@sourcegraph/shared/src/util/types'
import { parseRepoURI } from '@sourcegraph/shared/src/util/url'
import { LoadingSpinner } from '@sourcegraph/wildcard'
import { LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import styles from './FileLocations.module.scss'
export const FileLocationsError: React.FunctionComponent<{ error: ErrorLike }> = ({ error }) => (
<div className="alert alert-danger m-2">Error getting locations: {upperFirst(error.message)}</div>
<Alert className="m-2" variant="danger">
Error getting locations: {upperFirst(error.message)}
</Alert>
)
export const FileLocationsNotFound: React.FunctionComponent = () => (

View File

@ -14,7 +14,7 @@ import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/co
import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { parseRepoURI } from '@sourcegraph/shared/src/util/url'
import { LoadingSpinner } from '@sourcegraph/wildcard'
import { LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import { FileLocations, FileLocationsError, FileLocationsNotFound } from './FileLocations'
import styles from './HierarchicalLocationsView.module.scss'
@ -235,12 +235,12 @@ export class HierarchicalLocationsView extends React.PureComponent<HierarchicalL
return (
<div>
{this.state.locationsOrError.result.isTruncated && (
<div className="alert alert-warning py-1 px-3 m-2 text-nowrap text-center">
<Alert className="py-1 px-3 m-2 text-nowrap text-center" variant="warning">
<small>
<strong>Large result set</strong> - only showing the first {this.maxLocationResults}{' '}
results.
</small>
</div>
</Alert>
)}
<div
className={classNames(styles.referencesContainer, this.props.className)}

View File

@ -1,39 +0,0 @@
import { action } from '@storybook/addon-actions'
import { Story } from '@storybook/react'
import classNames from 'classnames'
import { flow } from 'lodash'
import React from 'react'
import { Button } from '@sourcegraph/wildcard'
import { SEMANTIC_COLORS } from './constants'
import { preventDefault } from './utils'
export const AlertsStory: Story = () => (
<>
<h1>Alerts</h1>
<p>
Provide contextual feedback messages for typical user actions with the handful of available and flexible
alert messages.
</p>
{SEMANTIC_COLORS.map(semantic => (
<div key={semantic} className={classNames('alert', `alert-${semantic}`)}>
<h4>A shiny {semantic} alert - check it out!</h4>
It can also contain{' '}
<a href="/" onClick={flow(preventDefault, action('alert link clicked'))}>
links like this
</a>
.
</div>
))}
<div className="alert alert-info d-flex align-items-center">
<div className="flex-grow-1">
<h4>A shiny info alert with a button - check it out!</h4>
It can also contain text without links.
</div>
<Button onClick={flow(preventDefault, action('alert button clicked'))} variant="info">
Call to action
</Button>
</div>
</>
)

View File

@ -17,7 +17,6 @@ import { BrandedStory } from '../../components/BrandedStory'
import { CodeSnippet } from '../../components/CodeSnippet'
import { Form } from '../../components/Form'
import { AlertsStory } from './AlertsStory'
import { ColorVariants } from './ColorVariants'
import { FormFieldVariants } from './FormFieldVariants'
import { TextStory } from './TextStory'
@ -229,25 +228,6 @@ export const Layout: Story = () => (
</>
)
export const Alerts = AlertsStory
Alerts.parameters = {
design: [
{
type: 'figma',
name: 'Figma Light',
url:
'https://www.figma.com/file/NIsN34NH7lPu04olBzddTw/Design-Refresh-Systemization-source-of-truth?node-id=1563%3A196',
},
{
type: 'figma',
name: 'Figma Dark',
url:
'https://www.figma.com/file/NIsN34NH7lPu04olBzddTw/Design-Refresh-Systemization-source-of-truth?node-id=1563%3A525',
},
],
}
export const ButtonGroups: Story = () => {
const [active, setActive] = useState<'Left' | 'Middle' | 'Right'>('Left')
return (

View File

@ -1,198 +0,0 @@
.alert {
position: relative;
margin-bottom: 1rem;
border-radius: var(--border-radius);
border: 1px solid transparent;
}
.alert-heading {
color: inherit;
}
.alert a:not(.btn) {
font-weight: 500;
&:hover {
text-decoration: underline;
}
}
.alert-primary,
.alert-secondary,
.alert-success,
.alert-danger,
.alert-warning,
.alert-info,
.alert-merged {
--alert-icon-block-width: 2.5rem;
--alert-content-padding: 0.5rem;
color: var(--body-color);
overflow: hidden;
border-color: var(--alert-border-color);
// Apply `background-color` and `padding` only to `.alert-#{$name}` because we also use `.alert` elements without variants.
background-color: var(--color-bg-1);
padding: var(--alert-content-padding) var(--alert-content-padding) var(--alert-content-padding)
calc(var(--alert-icon-block-width) + var(--alert-content-padding));
&::before,
&::after {
display: block;
content: '';
position: absolute;
top: 0;
left: 0;
width: var(--alert-icon-block-width);
height: 100%;
}
// Alert icon background.
&::before {
border: 2px solid var(--color-bg-1);
border-top-left-radius: var(--border-radius);
border-bottom-left-radius: var(--border-radius);
background-color: var(--alert-icon-background-color);
}
&::after {
mask-repeat: no-repeat;
mask-size: 1rem;
mask-position: 50% 50%;
// Applied as a fill color for SVG icon because of the mask-image.
background-color: var(--alert-icon-color);
}
}
.alert-info {
--alert-border-color: var(--info);
.theme-light & {
--alert-icon-color: var(--info-3);
--alert-icon-background-color: var(--info-4);
}
.theme-dark & {
--alert-icon-color: var(--info);
--alert-icon-background-color: var(--info-3);
}
}
.alert-primary {
--alert-border-color: var(--primary);
--alert-icon-background-color: var(--primary-4);
.theme-light & {
--alert-icon-color: var(--primary-3);
}
.theme-dark & {
--alert-icon-color: var(--primary);
}
}
.alert-secondary {
--alert-icon-background-color: var(--secondary-4);
.theme-light & {
--alert-border-color: var(--secondary-3);
--alert-icon-color: var(--gray-06);
}
.theme-dark & {
--alert-border-color: var(--secondary);
--alert-icon-color: var(--gray-05);
}
}
.alert-info,
.alert-primary,
.alert-secondary {
&::after {
// We cannot render SVG in HTML because then we will need to add it to every `.alert` element manually.
// We can use it as a `mask-image` to apply CSS variables as a fill color.
// Icon: mdi-react/Information
mask-image: url(escape-svg(
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 9h-2V7h2m0 10h-2v-6h2m-1-9A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10A10 10 0 0012 2z'/></svg>"
));
}
}
.alert-warning {
--alert-border-color: var(--warning);
--alert-icon-background-color: var(--warning-4);
.theme-light & {
--alert-icon-color: var(--warning-3);
}
.theme-dark & {
--alert-icon-color: var(--warning);
}
&::after {
// Icon: mdi-react/Alert
mask-image: url(escape-svg(
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 14h-2V9h2m0 9h-2v-2h2M1 21h22L12 2 1 21z'/></svg>"
));
}
}
.alert-danger {
--alert-border-color: var(--danger);
--alert-icon-background-color: var(--danger-4);
.theme-light & {
--alert-icon-color: var(--danger-3);
}
.theme-dark & {
--alert-icon-color: var(--danger);
}
&::after {
// Icon: mdi-react/AlertCircle
mask-image: url(escape-svg(
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M13 13h-2V7h2m0 10h-2v-2h2M12 2A10 10 0 002 12a10 10 0 0010 10 10 10 0 0010-10A10 10 0 0012 2z'/></svg>"
));
}
}
.alert-success {
--alert-border-color: var(--success);
--alert-icon-background-color: var(--success-4);
.theme-light & {
--alert-icon-color: var(--success-3);
}
.theme-dark & {
--alert-icon-color: var(--success);
}
&::after {
// Icon: mdi-react/CheckCircle
mask-image: url(escape-svg(
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z'/></svg>"
));
}
}
.alert-merged {
--alert-border-color: var(--merged);
--alert-icon-background-color: var(--merged-4);
.theme-light & {
--alert-icon-color: var(--merged-3);
}
.theme-dark & {
--alert-icon-color: var(--merged);
}
&::after {
// Icon: mdi-react/SourceMerge
mask-image: url(escape-svg(
"data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'><path d='M7 3a3 3 0 013 3c0 1.29-.81 2.39-1.96 2.81.54 5 5.04 5.96 7.15 6.15A2.985 2.985 0 0118 13a3 3 0 013 3 3 3 0 01-3 3c-1.31 0-2.43-.84-2.84-2-4.25-.2-5.72-1.81-7.16-3.61v1.78c1.17.41 2 1.52 2 2.83a3 3 0 01-3 3 3 3 0 01-3-3c0-1.31.83-2.42 2-2.83V8.83A2.99 2.99 0 014 6a3 3 0 013-3m0 2a1 1 0 00-1 1 1 1 0 001 1 1 1 0 001-1 1 1 0 00-1-1m0 12a1 1 0 00-1 1 1 1 0 001 1 1 1 0 001-1 1 1 0 00-1-1m11-2a1 1 0 00-1 1 1 1 0 001 1 1 1 0 001-1 1 1 0 00-1-1z'/></svg>"
));
}
}

View File

@ -128,7 +128,6 @@ $spacer: 1rem;
@import './code';
@import './buttons';
@import './button-group';
@import './alert';
@import './forms';
@import './highlight';
@import './tabs';

View File

@ -34,7 +34,7 @@ import {
mapTo,
take,
} from 'rxjs/operators'
import { NotificationType, HoverAlert } from 'sourcegraph'
import { HoverAlert } from 'sourcegraph'
import {
ContextResolver,
@ -64,6 +64,7 @@ import { registerHighlightContributions } from '@sourcegraph/shared/src/highligh
import { getHoverActions, registerHoverContributions } from '@sourcegraph/shared/src/hover/actions'
import { HoverContext, HoverOverlay, HoverOverlayClassProps } from '@sourcegraph/shared/src/hover/HoverOverlay'
import { getModeFromPath } from '@sourcegraph/shared/src/languages'
import { UnbrandedNotificationItemStyleProps } from '@sourcegraph/shared/src/notifications/NotificationItem'
import { URLToFileContext } from '@sourcegraph/shared/src/platform/context'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
@ -271,7 +272,7 @@ export interface CodeHost extends ApplyLinkPreviewOptions {
context: URLToFileContext
) => string
notificationClassNames: Record<NotificationType, string>
notificationClassNames: UnbrandedNotificationItemStyleProps['notificationItemClassNames']
/**
* CSS classes for the command palette to customize styling

View File

@ -21,7 +21,7 @@ import {
createController as createExtensionsController,
ExtensionsControllerProps,
} from '@sourcegraph/shared/src/extensions/controller'
import { NotificationClassNameProps } from '@sourcegraph/shared/src/notifications/NotificationItem'
import { UnbrandedNotificationItemStyleProps } from '@sourcegraph/shared/src/notifications/NotificationItem'
import { Notifications } from '@sourcegraph/shared/src/notifications/Notifications'
import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
@ -55,15 +55,19 @@ interface InjectProps
render: typeof render
}
interface RenderCommandPaletteProps
extends TelemetryProps,
InjectProps,
Pick<CommandListPopoverButtonProps, 'inputClassName' | 'popoverClassName' | 'popoverInnerClassName'> {
notificationClassNames: UnbrandedNotificationItemStyleProps['notificationItemClassNames']
}
export const renderCommandPalette = ({
extensionsController,
history,
render,
...props
}: TelemetryProps &
InjectProps &
Pick<CommandListPopoverButtonProps, 'inputClassName' | 'popoverClassName' | 'popoverInnerClassName'> &
NotificationClassNameProps) => (mount: HTMLElement): void => {
}: RenderCommandPaletteProps) => (mount: HTMLElement): void => {
render(
<ShortcutProvider>
<CommandListPopoverButton
@ -76,7 +80,9 @@ export const renderCommandPalette = ({
/>
<Notifications
extensionsController={extensionsController}
notificationClassNames={props.notificationClassNames}
notificationItemStyleProps={{
notificationItemClassNames: props.notificationClassNames,
}}
/>
</ShortcutProvider>,
mount

View File

@ -4,6 +4,7 @@ import React, { useCallback, useState } from 'react'
import { DropdownItem, DropdownMenu, DropdownToggle, ButtonDropdown } from 'reactstrap'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { Alert } from '@sourcegraph/wildcard'
interface SearchHelpDropdownButtonProps extends TelemetryProps {
isSourcegraphDotCom?: boolean
@ -124,10 +125,10 @@ export const SearchHelpDropdownButton: React.FunctionComponent<SearchHelpDropdow
<ExternalLinkIcon className="icon-inline small" /> All search keywords
</a>
{isSourcegraphDotCom && (
<div className="alert alert-info small rounded-0 mb-0 mt-1">
<Alert className="small rounded-0 mb-0 mt-1" variant="info">
On Sourcegraph.com, use a <code>repo:</code> filter to narrow your search to &le;500
repositories.
</div>
</Alert>
)}
</DropdownMenu>
</ButtonDropdown>

View File

@ -3,7 +3,7 @@ import React from 'react'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { AggregateStreamingSearchResults } from '@sourcegraph/shared/src/search/stream'
import { LoadingSpinner } from '@sourcegraph/wildcard'
import { Alert, LoadingSpinner } from '@sourcegraph/wildcard'
import { StreamingProgressCount } from './progress/StreamingProgressCount'
import styles from './StreamingSearchResultsList.module.scss'
@ -29,23 +29,23 @@ export const StreamingSearchResultFooter: React.FunctionComponent<{
{results?.state === 'complete' && !results.alert && results?.results.length === 0 && (
<div className="pr-3 mt-3 align-self-stretch">
<div className="alert alert-info">
<Alert variant="info">
<p className="m-0">
<strong>No results matched your query</strong>
<br />
Use the tips below to improve your query.
</p>
</div>
</Alert>
</div>
)}
{results?.state === 'complete' && results.progress.skipped.some(skipped => skipped.reason.includes('-limit')) && (
<div className="alert alert-info d-flex m-3">
<Alert className="d-flex m-3" variant="info">
<p className="m-0">
<strong>Result limit hit.</strong> Modify your search with <code>count:</code> to return additional
items.
</p>
</div>
</Alert>
)}
{children}

View File

@ -3,7 +3,7 @@ import { from } from 'rxjs'
import { catchError, switchMap } from 'rxjs/operators'
import { asError, isErrorLike } from '@sourcegraph/common'
import { Button, LoadingSpinner, useObservable, Link, CardHeader, CardBody } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, useObservable, Link, CardHeader, CardBody, Alert } from '@sourcegraph/wildcard'
import { wrapRemoteObservable } from '../../api/client/api/common'
@ -39,7 +39,9 @@ export const ActiveExtensionsPanel: React.FunctionComponent<ExtensionsDevelopmen
<CardHeader>Active extensions (DEBUG)</CardHeader>
{extensionsOrError ? (
isErrorLike(extensionsOrError) ? (
<div className="alert alert-danger mb-0 rounded-0">{extensionsOrError.message}</div>
<Alert className="mb-0 rounded-0" variant="danger">
{extensionsOrError.message}
</Alert>
) : extensionsOrError.length > 0 ? (
<div className="list-group list-group-flush">
{extensionsOrError.map(({ id }, index) => (

View File

@ -12,7 +12,7 @@ import { ThemeProps } from '../theme'
import { sanitizeClass } from '../util/strings'
import hoverOverlayStyle from './HoverOverlay.module.scss'
import type { HoverContext, HoverOverlayBaseProps, GetAlertClassName } from './HoverOverlay.types'
import type { HoverContext, HoverOverlayBaseProps, GetAlertClassName, GetAlertVariant } from './HoverOverlay.types'
import { HoverOverlayAlerts, HoverOverlayAlertsProps } from './HoverOverlayAlerts'
import { HoverOverlayContents } from './HoverOverlayContents'
import style from './HoverOverlayContents.module.scss'
@ -35,7 +35,15 @@ export interface HoverOverlayClassProps {
contentClassName?: string
/**
* Allows providing any custom className to style the notifications as desired.
*/
getAlertClassName?: GetAlertClassName
/**
* Allows providing a specific variant style for use in branded Sourcegraph applications.
*/
getAlertVariant?: GetAlertVariant
}
export interface HoverOverlayProps
@ -85,6 +93,7 @@ export const HoverOverlay: React.FunctionComponent<HoverOverlayProps> = props =>
contentClassName,
getAlertClassName,
getAlertVariant,
onAlertDismissed,
useBrandedLogo,
@ -117,6 +126,7 @@ export const HoverOverlay: React.FunctionComponent<HoverOverlayProps> = props =>
iconClassName={iconClassName}
badgeClassName={badgeClassName}
errorAlertClassName={getAlertClassName?.(NotificationType.Error)}
errorAlertVariant={getAlertVariant?.(NotificationType.Error)}
contentClassName={contentClassName}
/>
</div>
@ -129,6 +139,7 @@ export const HoverOverlay: React.FunctionComponent<HoverOverlayProps> = props =>
hoverAlerts={hoverOrError.alerts}
iconClassName={iconClassName}
getAlertClassName={getAlertClassName}
getAlertVariant={getAlertVariant}
onAlertDismissed={onAlertDismissed}
/>
)}

View File

@ -1,6 +1,7 @@
import { NotificationType } from 'sourcegraph'
import { HoverOverlayProps as GenericHoverOverlayProps } from '@sourcegraph/codeintellify'
import { AlertProps } from '@sourcegraph/wildcard'
import { ActionItemAction } from '../actions/ActionItem'
import { HoverMerged } from '../api/client/types/hover'
@ -13,3 +14,7 @@ export interface HoverOverlayBaseProps extends GenericHoverOverlayProps<HoverCon
export type GetAlertClassName = (
kind: Exclude<NotificationType, NotificationType.Log | NotificationType.Success>
) => string | undefined
export type GetAlertVariant = (
kind: Exclude<NotificationType, NotificationType.Log | NotificationType.Success>
) => AlertProps['variant']

View File

@ -2,10 +2,12 @@ import classNames from 'classnames'
import React from 'react'
import { HoverAlert } from 'sourcegraph'
import { Alert } from '@sourcegraph/wildcard'
import { NotificationType } from '../../api/extension/extensionHostApi'
import { renderMarkdown } from '../../util/markdown'
import hoverOverlayStyle from '../HoverOverlay.module.scss'
import { GetAlertClassName } from '../HoverOverlay.types'
import { GetAlertClassName, GetAlertVariant } from '../HoverOverlay.types'
import contentStyles from '../HoverOverlayContents/HoverOverlayContent/HoverOverlayContent.module.scss'
import styles from './HoverOverlayAlerts.module.scss'
@ -16,6 +18,7 @@ export interface HoverOverlayAlertsProps {
/** Called when an alert is dismissed, with the type of the dismissed alert. */
onAlertDismissed?: (alertType: string) => void
getAlertClassName?: GetAlertClassName
getAlertVariant?: GetAlertVariant
className?: string
}
@ -26,7 +29,7 @@ const iconKindToNotificationType: Record<Required<HoverAlert>['iconKind'], Param
}
export const HoverOverlayAlerts: React.FunctionComponent<HoverOverlayAlertsProps> = props => {
const { hoverAlerts, onAlertDismissed, getAlertClassName = () => undefined } = props
const { hoverAlerts, onAlertDismissed, getAlertClassName, getAlertVariant } = props
const createAlertDismissedHandler = (alertType: string) => (event: React.MouseEvent<HTMLAnchorElement>) => {
event.preventDefault()
@ -39,11 +42,12 @@ export const HoverOverlayAlerts: React.FunctionComponent<HoverOverlayAlertsProps
return (
<div className={classNames(styles.hoverOverlayAlerts, props.className)}>
{hoverAlerts.map(({ summary, iconKind, type }, index) => (
<div
<Alert
key={index}
variant={getAlertVariant?.(iconKind ? iconKindToNotificationType[iconKind] : NotificationType.Info)}
className={classNames(
hoverOverlayStyle.alert,
getAlertClassName(iconKind ? iconKindToNotificationType[iconKind] : NotificationType.Info)
getAlertClassName?.(iconKind ? iconKindToNotificationType[iconKind] : NotificationType.Info)
)}
>
{summary.kind === 'plaintext' ? (
@ -78,7 +82,7 @@ export const HoverOverlayAlerts: React.FunctionComponent<HoverOverlayAlertsProps
</a>
</div>
)}
</div>
</Alert>
))}
</div>
)

View File

@ -3,7 +3,7 @@ import { upperFirst } from 'lodash'
import React from 'react'
import { asError } from '@sourcegraph/common'
import { Badge } from '@sourcegraph/wildcard'
import { Alert, AlertProps, Badge } from '@sourcegraph/wildcard'
import { HoverMerged } from '../../../api/client/types/hover'
import { renderMarkdown } from '../../../util/markdown'
@ -22,6 +22,7 @@ interface HoverOverlayContentProps {
*/
badgeClassName?: string
errorAlertClassName?: string
errorAlertVariant?: AlertProps['variant']
contentClassName?: string
}
@ -34,7 +35,7 @@ function tryMarkdownRender(content: string): string | Error {
}
export const HoverOverlayContent: React.FunctionComponent<HoverOverlayContentProps> = props => {
const { content, aggregatedBadges = [], index, errorAlertClassName, badgeClassName } = props
const { content, aggregatedBadges = [], index, errorAlertClassName, errorAlertVariant, badgeClassName } = props
if (content.kind !== 'markdown') {
return (
@ -51,9 +52,12 @@ export const HoverOverlayContent: React.FunctionComponent<HoverOverlayContentPro
if (markdownOrError instanceof Error) {
return (
<div className={classNames(hoverOverlayStyle.hoverError, errorAlertClassName)}>
<Alert
className={classNames(hoverOverlayStyle.hoverError, errorAlertClassName)}
variant={errorAlertVariant}
>
{upperFirst(markdownOrError.message)}
</div>
</Alert>
)
}

View File

@ -3,7 +3,7 @@ import { upperFirst } from 'lodash'
import React from 'react'
import { isErrorLike } from '@sourcegraph/common'
import { LoadingSpinner } from '@sourcegraph/wildcard'
import { Alert, AlertProps, LoadingSpinner } from '@sourcegraph/wildcard'
import hoverOverlayStyle from '../HoverOverlay.module.scss'
import { HoverOverlayBaseProps } from '../HoverOverlay.types'
@ -14,11 +14,19 @@ interface HoverOverlayContentsProps extends Pick<HoverOverlayBaseProps, 'hoverOr
iconClassName?: string
badgeClassName?: string
errorAlertClassName?: string
errorAlertVariant?: AlertProps['variant']
contentClassName?: string
}
export const HoverOverlayContents: React.FunctionComponent<HoverOverlayContentsProps> = props => {
const { hoverOrError, iconClassName, errorAlertClassName, badgeClassName, contentClassName } = props
const {
hoverOrError,
iconClassName,
errorAlertClassName,
errorAlertVariant,
badgeClassName,
contentClassName,
} = props
if (hoverOrError === 'loading') {
return (
@ -30,9 +38,12 @@ export const HoverOverlayContents: React.FunctionComponent<HoverOverlayContentsP
if (isErrorLike(hoverOrError)) {
return (
<div className={classNames(errorAlertClassName, hoverOverlayStyle.hoverError)}>
<Alert
className={classNames(errorAlertClassName, hoverOverlayStyle.hoverError)}
variant={errorAlertVariant}
>
{upperFirst(hoverOrError.message)}
</div>
</Alert>
)
}
@ -56,6 +67,7 @@ export const HoverOverlayContents: React.FunctionComponent<HoverOverlayContentsP
content={content}
aggregatedBadges={hoverOrError.aggregatedBadges}
errorAlertClassName={errorAlertClassName}
errorAlertVariant={errorAlertVariant}
badgeClassName={badgeClassName}
contentClassName={contentClassName}
/>

View File

@ -11,11 +11,11 @@ import webStyles from '@sourcegraph/web/src/SourcegraphWebApp.scss'
import { NotificationItem } from './NotificationItem'
const notificationClassNames = {
[NotificationType.Log]: 'alert alert-secondary',
[NotificationType.Success]: 'alert alert-success',
[NotificationType.Info]: 'alert alert-info',
[NotificationType.Warning]: 'alert alert-warning',
[NotificationType.Error]: 'alert alert-danger',
[NotificationType.Log]: 'bg-secondary',
[NotificationType.Success]: 'bg-success',
[NotificationType.Info]: 'bg-info',
[NotificationType.Warning]: 'bg-warning',
[NotificationType.Error]: 'bg-danger',
}
const onDismiss = action('onDismiss')
@ -43,7 +43,7 @@ export const WithoutProgress: Story = () => {
return (
<NotificationItem
notification={{ message, type, source }}
notificationClassNames={notificationClassNames}
notificationItemStyleProps={{ notificationItemClassNames: notificationClassNames }}
onDismiss={onDismiss}
/>
)
@ -70,7 +70,7 @@ export const WithProgress: Story = () => {
percentage: progressPercentage,
}),
}}
notificationClassNames={notificationClassNames}
notificationItemStyleProps={{ notificationItemClassNames: notificationClassNames }}
onDismiss={onDismiss}
/>
)

View File

@ -4,32 +4,45 @@ import { from, Subject, Subscription } from 'rxjs'
import { catchError, distinctUntilChanged, map, scan, switchMap } from 'rxjs/operators'
import * as sourcegraph from 'sourcegraph'
import { Alert, AlertProps } from '@sourcegraph/wildcard'
import { renderMarkdown } from '../util/markdown'
import { Notification } from './notification'
import styles from './NotificationItem.module.scss'
export interface NotificationClassNameProps {
notificationClassNames: Record<sourcegraph.NotificationType, string>
export interface UnbrandedNotificationItemStyleProps {
notificationItemClassNames: Record<sourcegraph.NotificationType, string>
}
interface Props extends NotificationClassNameProps {
export interface BrandedNotificationItemStyleProps {
notificationItemVariants: Record<sourcegraph.NotificationType, AlertProps['variant']>
}
/**
* Note, we do not export this type because it is not intended to be used directly.
* Consumers should use either `UnbrandedNotificationItemStyleProps` or `BrandedNotificationItemStyleProps` when configuring this component.
*/
type NotificationItemStyleProps = UnbrandedNotificationItemStyleProps | BrandedNotificationItemStyleProps
export interface NotificationItemProps {
notification: Notification
onDismiss: (notification: Notification) => void
className?: string
notificationItemStyleProps: NotificationItemStyleProps
}
interface State {
interface NotificationItemState {
progress?: Required<sourcegraph.Progress>
}
/**
* A notification message displayed in a {@link module:./Notifications.Notifications} component.
*/
export class NotificationItem extends React.PureComponent<Props, State> {
private componentUpdates = new Subject<Props>()
export class NotificationItem extends React.PureComponent<NotificationItemProps, NotificationItemState> {
private componentUpdates = new Subject<NotificationItemProps>()
private subscription = new Subscription()
constructor(props: Props) {
constructor(props: NotificationItemProps) {
super(props)
this.state = {
progress: props.notification.progress && {
@ -75,14 +88,24 @@ export class NotificationItem extends React.PureComponent<Props, State> {
this.subscription.unsubscribe()
}
public render(): JSX.Element | null {
const baseAlertClassName = classNames(styles.sourcegraphNotificationItem, this.props.className)
const { notificationItemStyleProps } = this.props
const alertProps =
'notificationItemVariants' in notificationItemStyleProps
? {
variant: notificationItemStyleProps.notificationItemVariants[this.props.notification.type],
className: baseAlertClassName,
}
: {
className: classNames(
baseAlertClassName,
notificationItemStyleProps.notificationItemClassNames[this.props.notification.type]
),
}
return (
<div
className={classNames(
styles.sourcegraphNotificationItem,
this.props.className,
this.props.notificationClassNames[this.props.notification.type]
)}
>
<Alert {...alertProps}>
<div className={styles.bodyContainer}>
<div className={styles.body}>
<div
@ -122,7 +145,7 @@ export class NotificationItem extends React.PureComponent<Props, State> {
/>
</div>
)}
</div>
</Alert>
)
}

View File

@ -10,12 +10,14 @@ import { NotificationType } from '../api/extension/extensionHostApi'
import { ExtensionsControllerProps } from '../extensions/controller'
import { Notification } from './notification'
import { NotificationItem, NotificationClassNameProps } from './NotificationItem'
import { NotificationItem, NotificationItemProps } from './NotificationItem'
import styles from './Notifications.module.scss'
interface Props extends ExtensionsControllerProps, NotificationClassNameProps {}
export interface NotificationsProps
extends ExtensionsControllerProps,
Pick<NotificationItemProps, 'notificationItemStyleProps'> {}
interface State {
interface NotificationsState {
// TODO(tj): use remote progress observable type
notifications: (Notification & { id: string })[]
}
@ -23,14 +25,14 @@ interface State {
/**
* A notifications center that displays global, non-modal messages.
*/
export class Notifications extends React.PureComponent<Props, State> {
export class Notifications extends React.PureComponent<NotificationsProps, NotificationsState> {
/**
* The maximum number of notifications at a time. Older notifications are truncated when the length exceeds
* this number.
*/
private static MAX_RETAIN = 7
public state: State = {
public state: NotificationsState = {
notifications: [],
}
@ -138,7 +140,7 @@ export class Notifications extends React.PureComponent<Props, State> {
notification={notification}
onDismiss={this.onDismiss}
className="sourcegraph-notifications__notification m-2"
notificationClassNames={this.props.notificationClassNames}
notificationItemStyleProps={this.props.notificationItemStyleProps}
/>
))}
</div>

View File

@ -35,6 +35,7 @@ import {
} from '@sourcegraph/shared/src/extensions/controller'
import { KeyboardShortcutsProps } from '@sourcegraph/shared/src/keyboardShortcuts/keyboardShortcuts'
import { getModeFromPath } from '@sourcegraph/shared/src/languages'
import { BrandedNotificationItemStyleProps } from '@sourcegraph/shared/src/notifications/NotificationItem'
import { Notifications } from '@sourcegraph/shared/src/notifications/Notifications'
import { PlatformContext } from '@sourcegraph/shared/src/platform/context'
import { FilterType } from '@sourcegraph/shared/src/search/query/filters'
@ -168,12 +169,14 @@ interface SourcegraphWebAppState extends SettingsCascadeProps {
featureFlags: FlagSet
}
const notificationClassNames = {
[NotificationType.Log]: 'alert alert-secondary',
[NotificationType.Success]: 'alert alert-success',
[NotificationType.Info]: 'alert alert-info',
[NotificationType.Warning]: 'alert alert-warning',
[NotificationType.Error]: 'alert alert-danger',
const notificationStyles: BrandedNotificationItemStyleProps = {
notificationItemVariants: {
[NotificationType.Log]: 'secondary',
[NotificationType.Success]: 'success',
[NotificationType.Info]: 'info',
[NotificationType.Warning]: 'warning',
[NotificationType.Error]: 'danger',
},
}
const LAST_SEARCH_CONTEXT_KEY = 'sg-last-search-context'
@ -477,7 +480,7 @@ export class SourcegraphWebApp extends React.Component<SourcegraphWebAppProps, S
<Notifications
key={2}
extensionsController={this.extensionsController}
notificationClassNames={notificationClassNames}
notificationItemStyleProps={notificationStyles}
/>
<UserSessionStores />
</SearchQueryStateStoreProvider>

View File

@ -6,7 +6,7 @@ import { catchError, debounceTime } from 'rxjs/operators'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { LoadingSpinner, Button, Link } from '@sourcegraph/wildcard'
import { LoadingSpinner, Button, Alert, Link } from '@sourcegraph/wildcard'
import { PageTitle } from '../components/PageTitle'
import { eventLogger } from '../tracking/eventLogger'
@ -176,11 +176,11 @@ export class ApiConsole extends React.PureComponent<Props, State> {
<Button to="/help/api/graphql" variant="link" as={Link}>
Docs
</Button>
<div className="alert alert-warning py-1 mb-0 ml-2 text-nowrap">
<Alert variant="warning" className="py-1 mb-0 ml-2 text-nowrap">
<small>
The API console uses <strong>real production data.</strong>
</small>
</div>
</Alert>
</div>
</GraphiQL.Toolbar>
</GraphiQL>

View File

@ -8,7 +8,7 @@ import { TelemetryService } from '@sourcegraph/shared/src/telemetry/telemetrySer
import { BrandLogo } from '@sourcegraph/web/src/components/branding/BrandLogo'
import { HeroPage } from '@sourcegraph/web/src/components/HeroPage'
import { PageRoutes } from '@sourcegraph/web/src/routes.constants'
import { Link } from '@sourcegraph/wildcard'
import { Alert, Link } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../auth'
import { PageTitle } from '../components/PageTitle'
@ -133,10 +133,10 @@ export const PostSignUpPage: FunctionComponent<PostSignUpPage> = ({
<div className="pb-1 d-flex flex-column align-items-center w-100">
<div className={styles.container}>
{hasErrors && (
<div className="alert alert-danger mb-4" role="alert">
<Alert className="mb-4" role="alert" variant="danger">
Sorry, something went wrong. Try refreshing the page or{' '}
<Link to={PageRoutes.Search}>skip to code search</Link>.
</div>
</Alert>
)}
<h2>Get started with Sourcegraph</h2>
<p className="text-muted pb-3">

View File

@ -6,7 +6,7 @@ import { RouteComponentProps } from 'react-router-dom'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { Form } from '@sourcegraph/branded/src/components/Form'
import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { Button, Link, LoadingSpinner } from '@sourcegraph/wildcard'
import { Button, Link, LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../auth'
import { HeroPage } from '../components/HeroPage'
@ -170,9 +170,9 @@ class ResetPasswordCodeForm extends React.PureComponent<ResetPasswordCodeFormPro
public render(): JSX.Element | null {
if (this.state.submitOrError === null) {
return (
<div className="alert alert-success">
<Alert variant="success">
Your password was reset. <Link to="/sign-in">Sign in with your new password</Link> to continue.
</div>
</Alert>
)
}
@ -265,7 +265,7 @@ export class ResetPasswordPage extends React.PureComponent<ResetPasswordPageProp
public render(): JSX.Element | null {
let body: JSX.Element
if (this.props.authenticatedUser) {
body = <div className="alert alert-danger">Authenticated users may not perform password reset.</div>
body = <Alert variant="danger">Authenticated users may not perform password reset.</Alert>
} else if (window.context.resetPasswordEnabled) {
const searchParameters = new URLSearchParams(this.props.location.search)
if (searchParameters.has('code') || searchParameters.has('userID')) {
@ -274,16 +274,16 @@ export class ResetPasswordPage extends React.PureComponent<ResetPasswordPageProp
if (code && !isNaN(userID)) {
body = <ResetPasswordCodeForm code={code} userID={userID} history={this.props.history} />
} else {
body = <div className="alert alert-danger">The password reset link you followed is invalid.</div>
body = <Alert variant="danger">The password reset link you followed is invalid.</Alert>
}
} else {
body = <ResetPasswordInitForm history={this.props.history} />
}
} else {
body = (
<div className="alert alert-warning">
<Alert variant="warning">
Password reset is disabled. Ask a site administrator to manually reset your password.
</div>
</Alert>
)
}

View File

@ -6,7 +6,7 @@ import React, { useEffect, useState } from 'react'
import { Redirect } from 'react-router-dom'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { Button, Link } from '@sourcegraph/wildcard'
import { Button, Link, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../auth'
import { HeroPage } from '../components/HeroPage'
@ -47,9 +47,9 @@ export const SignInPage: React.FunctionComponent<SignInPageProps> = props => {
const body =
!builtInAuthProvider && thirdPartyAuthProviders.length === 0 ? (
<div className="alert alert-info mt-3">
<Alert className="mt-3" variant="info">
No authentication providers are available. Contact a site administrator for help.
</div>
</Alert>
) : (
<div className={classNames('mb-4 pb-5', signInSignUpCommonStyles.signinPageContainer)}>
{error && <ErrorAlert className="mt-4 mb-0 text-left" error={error} icon={false} />}

View File

@ -1,6 +1,8 @@
import { gql, useMutation } from '@apollo/client'
import React, { useCallback, useState } from 'react'
import { Alert } from '@sourcegraph/wildcard'
import { LoaderButton } from '../components/LoaderButton'
import { SourcegraphIcon } from './icons'
@ -76,7 +78,9 @@ export const TosConsentModal: React.FunctionComponent<{ afterTosAccepted: () =>
account deleted.
</p>
{error && (
<div className="alert alert-danger mt-4">Error accepting Terms of Service: {error.message}</div>
<Alert className="mt-4" variant="danger">
Error accepting Terms of Service: {error.message}
</Alert>
)}
</div>
</div>

View File

@ -4,7 +4,7 @@ import React, { useEffect, useState } from 'react'
import { ErrorLike, isErrorLike } from '@sourcegraph/common'
import { CopyableText } from '@sourcegraph/web/src/components/CopyableText'
import { PageRoutes } from '@sourcegraph/web/src/routes.constants'
import { Link } from '@sourcegraph/wildcard'
import { Link, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../auth'
import { eventLogger } from '../../tracking/eventLogger'
@ -225,7 +225,7 @@ export const StartSearching: React.FunctionComponent<StartSearching> = ({
</Terminal>
</div>
{showAlert && (
<div className="alert alert-warning mt-4">
<Alert className="mt-4" variant="warning">
Cloning your repositories is taking a long time. You can wait for cloning to finish, or{' '}
<Link to={PageRoutes.Search} onClick={trackBannerClick}>
continue to Sourcegraph now
@ -236,7 +236,7 @@ export const StartSearching: React.FunctionComponent<StartSearching> = ({
Settings Repositories
</Link>
.
</div>
</Alert>
)}
</div>
</div>

View File

@ -8,7 +8,7 @@ import { DismissibleAlert } from './DismissibleAlert'
const { add } = storiesOf('web/DismissibleAlert', module).addDecorator(story => <WebStory>{() => story()}</WebStory>)
add('One-line alert', () => (
<DismissibleAlert className="alert-info" partialStorageKey="dismissible-alert-one-line">
<DismissibleAlert variant="info" partialStorageKey="dismissible-alert-one-line">
<span>
1 bulk operation has recently failed running. Click the <a href="?">bulk operations tab</a> to view.
</span>
@ -16,7 +16,7 @@ add('One-line alert', () => (
))
add('Multiline alert', () => (
<DismissibleAlert className="alert-info" partialStorageKey="dismissible-alert-multiline">
<DismissibleAlert variant="info" partialStorageKey="dismissible-alert-multiline">
WebAssembly (sometimes abbreviated Wasm) is an open standard that defines a portable binary-code format for
executable programs, and a corresponding textual assembly language, as well as interfaces for facilitating
interactions between such programs and their host environment. The main goal of WebAssembly is to enable

View File

@ -2,20 +2,17 @@ import classNames from 'classnames'
import CloseIcon from 'mdi-react/CloseIcon'
import * as React from 'react'
import { Button } from '@sourcegraph/wildcard'
import { Button, Alert, AlertProps } from '@sourcegraph/wildcard'
import styles from './DismissibleAlert.module.scss'
interface Props {
export interface DismissibleAlertProps extends AlertProps {
/**
* If provided, used to build the key that represents the alert in local storage. An
* alert with a storage key will be permanently dismissed once the user dismisses it.
*/
partialStorageKey?: string
/** class name to be applied to the alert */
className: string
testId?: string
}
@ -24,11 +21,12 @@ interface Props {
* alert will never be shown again after it is dismissed. Otherwise, it will be shown
* whenever unmounted and remounted.
*/
export const DismissibleAlert: React.FunctionComponent<Props> = ({
export const DismissibleAlert: React.FunctionComponent<DismissibleAlertProps> = ({
partialStorageKey,
className,
testId,
children,
variant,
}) => {
const [dismissed, setDismissed] = React.useState<boolean>(
partialStorageKey ? isAlertDismissed(partialStorageKey) : false
@ -46,12 +44,12 @@ export const DismissibleAlert: React.FunctionComponent<Props> = ({
}
return (
<div data-testid={testId} className={classNames('alert', styles.container, className)}>
<Alert data-testid={testId} className={classNames(styles.container, className)} variant={variant}>
<div className={styles.content}>{children}</div>
<Button aria-label="Close alert" className={classNames('btn-icon', styles.closeButton)} onClick={onDismiss}>
<CloseIcon className="icon-inline" />
</Button>
</div>
</Alert>
)
}

View File

@ -2,6 +2,7 @@ import classNames from 'classnames'
import React from 'react'
import { ErrorMessage } from '@sourcegraph/branded/src/components/alerts'
import { Alert } from '@sourcegraph/wildcard'
import styles from './ConnectionError.module.scss'
@ -14,11 +15,11 @@ interface ConnectionErrorProps {
* Renders FilteredConnection styled errors
*/
export const ConnectionError: React.FunctionComponent<ConnectionErrorProps> = ({ errors, compact }) => (
<div className={classNames('alert alert-danger', compact && styles.compact)}>
<Alert className={classNames(compact && styles.compact)} variant="danger">
{errors.map((error, index) => (
<React.Fragment key={index}>
<ErrorMessage error={error} />
</React.Fragment>
))}
</div>
</Alert>
)

View File

@ -6,20 +6,19 @@ import { isErrorLike } from '@sourcegraph/common'
import { urlForClientCommandOpen } from '@sourcegraph/shared/src/actions/ActionItem'
import { NotificationType } from '@sourcegraph/shared/src/api/extension/extensionHostApi'
import { HoverOverlay, HoverOverlayProps } from '@sourcegraph/shared/src/hover/HoverOverlay'
import { useLocalStorage } from '@sourcegraph/wildcard'
import { useLocalStorage, AlertProps } from '@sourcegraph/wildcard'
import { HoverThresholdProps } from '../../repo/RepoContainer'
import styles from './WebHoverOverlay.module.scss'
const iconKindToAlertKind = {
const iconKindToAlertVariant: Record<number, AlertProps['variant']> = {
[NotificationType.Info]: 'secondary',
[NotificationType.Error]: 'danger',
[NotificationType.Warning]: 'warning',
}
const getAlertClassName: HoverOverlayProps['getAlertClassName'] = iconKind =>
`alert alert-${iconKindToAlertKind[iconKind]}`
const getAlertVariant: HoverOverlayProps['getAlertVariant'] = iconKind => iconKindToAlertVariant[iconKind]
export const WebHoverOverlay: React.FunctionComponent<
HoverOverlayProps & HoverThresholdProps & { hoveredTokenElement?: HTMLElement; nav?: (url: string) => void }
@ -105,7 +104,7 @@ export const WebHoverOverlay: React.FunctionComponent<
className={styles.webHoverOverlay}
actionItemClassName="btn btn-sm btn-secondary border-0"
onAlertDismissed={onAlertDismissed}
getAlertClassName={getAlertClassName}
getAlertVariant={getAlertVariant}
/>
)
}

View File

@ -6,6 +6,7 @@ import { Markdown } from '@sourcegraph/shared/src/components/Markdown'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { renderMarkdown } from '@sourcegraph/shared/src/util/markdown'
import { Alert } from '@sourcegraph/wildcard'
import { ExternalServiceFields, Scalars, AddExternalServiceInput } from '../../graphql-operations'
import { refreshSiteFlags } from '../../site/backend'
@ -110,10 +111,10 @@ export const AddExternalServicePage: React.FunctionComponent<Props> = ({
to={`${routingPrefix}/external-services/${createdExternalService.id}`}
/>
</div>
<div className="alert alert-warning">
<Alert variant="warning">
<h4>Warning</h4>
<Markdown dangerousInnerHTML={renderMarkdown(createdExternalService.warning)} />
</div>
</Alert>
</div>
) : (
<div>

View File

@ -3,7 +3,7 @@ import React from 'react'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { useLocalStorage, Button } from '@sourcegraph/wildcard'
import { useLocalStorage, Button, Alert } from '@sourcegraph/wildcard'
import { Scalars } from '../../graphql-operations'
import { PageTitle } from '../PageTitle'
@ -82,7 +82,7 @@ export const AddExternalServicesPage: React.FunctionComponent<AddExternalService
</div>
<p className="mt-2">Add repositories from one of these code hosts.</p>
{!hasDismissedPrivacyWarning && (
<div className="alert alert-info">
<Alert variant="info">
{!userID && (
<p>
This Sourcegraph installation will never send your code, repository names, file names, or
@ -126,7 +126,7 @@ export const AddExternalServicesPage: React.FunctionComponent<AddExternalService
Do not show this again
</Button>
</div>
</div>
</Alert>
)}
{Object.entries(codeHostExternalServices).map(([id, externalService]) => (
<div className={styles.addExternalServicesPageCard} key={id}>

View File

@ -7,7 +7,7 @@ import { Form } from '@sourcegraph/branded/src/components/Form'
import { ErrorLike } from '@sourcegraph/common'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { Button, LoadingSpinner } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import { AddExternalServiceInput } from '../../graphql-operations'
import { DynamicallyImportedMonacoSettingsEditor } from '../../settings/DynamicallyImportedMonacoSettingsEditor'
@ -65,10 +65,10 @@ export const ExternalServiceForm: React.FunctionComponent<Props> = ({
<Form className="external-service-form" onSubmit={onSubmit}>
{error && <ErrorAlert error={error} />}
{warning && (
<div className="alert alert-warning">
<Alert variant="warning">
<h4>Warning</h4>
<ErrorMessage error={warning} />
</div>
</Alert>
)}
{hideDisplayNameField || (
<div className="form-group">

View File

@ -1,5 +1,7 @@
import React from 'react'
import { Alert } from '@sourcegraph/wildcard'
import { ExternalServiceFields, ExternalServiceKind } from '../../graphql-operations'
import { CopyableText } from '../CopyableText'
@ -51,7 +53,7 @@ export const ExternalServiceWebhook: React.FunctionComponent<Props> = ({ externa
}
return (
<div className="alert alert-info">
<Alert variant="info">
<h3>Batch changes webhooks</h3>
{description}
<CopyableText className="mb-2" text={webhookURL} size={webhookURL.length} />
@ -66,7 +68,7 @@ export const ExternalServiceWebhook: React.FunctionComponent<Props> = ({ externa
</a>
.
</p>
</div>
</Alert>
)
}

View File

@ -4,7 +4,7 @@ import React, { useCallback, useState } from 'react'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { isErrorLike, asError } from '@sourcegraph/common'
import { pluralize } from '@sourcegraph/shared/src/util/strings'
import { Button, AlertLink, LoadingSpinner, CardBody, Card } from '@sourcegraph/wildcard'
import { Button, AlertLink, LoadingSpinner, CardBody, Card, Alert } from '@sourcegraph/wildcard'
import { Scalars } from '../../../graphql-operations'
@ -86,13 +86,13 @@ export const BatchChangeCloseAlert: React.FunctionComponent<BatchChangeCloseAler
</>
)}
{!viewerCanAdminister && (
<div className="alert alert-warning">
<Alert variant="warning">
You don't have permission to close this batch change. See{' '}
<AlertLink to="https://docs.sourcegraph.com/batch_changes/explanations/permissions_in_batch_changes">
Permissions in batch changes
</AlertLink>{' '}
for more information about the batch changes permission model.
</div>
</Alert>
)}
<div className="d-flex justify-content-end">
<Button

View File

@ -7,7 +7,7 @@ import { useQuery } from '@sourcegraph/http-client'
import { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import { Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { PageHeader, LoadingSpinner } from '@sourcegraph/wildcard'
import { PageHeader, LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import { BatchChangesIcon } from '../../../batches/icons'
import { HeroPage } from '../../../components/HeroPage'
@ -99,9 +99,9 @@ export const BatchChangeDetailsPage: React.FunctionComponent<BatchChangeDetailsP
{/* If we received an error after we already had data, we keep the
data on the page but also surface the error with an alert. */}
{error && (
<div className="alert alert-danger">
<Alert variant="danger">
<ErrorMessage error={error.message} />
</div>
</Alert>
)}
<PageHeader
path={[

View File

@ -39,10 +39,7 @@ export const BulkOperationsAlerts: React.FunctionComponent<BulkOperationsAlertsP
if (latestProcessingNode && !isAlertDismissed(`bulkOperation-processing-${latestProcessingNode.id}`)) {
const processingCount = bulkOperations.nodes.filter(node => node.state === BulkOperationState.PROCESSING).length
return (
<DismissibleAlert
className="alert-info"
partialStorageKey={`bulkOperation-processing-${latestProcessingNode.id}`}
>
<DismissibleAlert variant="info" partialStorageKey={`bulkOperation-processing-${latestProcessingNode.id}`}>
<span>
{processingCount} bulk {pluralize('operation', processingCount)}{' '}
{pluralize('is', processingCount, 'are')} currently running. Click the{' '}
@ -56,7 +53,7 @@ export const BulkOperationsAlerts: React.FunctionComponent<BulkOperationsAlertsP
if (latestFailedNode && !isAlertDismissed(`bulkOperation-failed-${latestFailedNode.id}`)) {
const failedCount = bulkOperations.nodes.filter(node => node.state === BulkOperationState.FAILED).length
return (
<DismissibleAlert className="alert-info" partialStorageKey={`bulkOperation-failed-${latestFailedNode.id}`}>
<DismissibleAlert variant="info" partialStorageKey={`bulkOperation-failed-${latestFailedNode.id}`}>
<span>
{failedCount} bulk {pluralize('operation', failedCount)} {pluralize('has', failedCount, 'have')}{' '}
recently failed running. Click the <Link to="?tab=bulkoperations">bulk operations tab</Link> to
@ -69,10 +66,7 @@ export const BulkOperationsAlerts: React.FunctionComponent<BulkOperationsAlertsP
if (latestCompleteNode && !isAlertDismissed(`bulkOperation-completed-${latestCompleteNode.id}`)) {
const completeCount = bulkOperations.nodes.filter(node => node.state === BulkOperationState.COMPLETED).length
return (
<DismissibleAlert
className="alert-info"
partialStorageKey={`bulkOperation-completed-${latestCompleteNode.id}`}
>
<DismissibleAlert variant="info" partialStorageKey={`bulkOperation-completed-${latestCompleteNode.id}`}>
<span>
{completeCount} bulk {pluralize('operation', completeCount)}{' '}
{pluralize('has', completeCount, 'have')} recently finished running. Click the{' '}

View File

@ -40,7 +40,7 @@ export const ChangesetsArchivedNotice: React.FunctionComponent<ChangesetsArchive
}
return (
<DismissibleAlert className="alert-info" partialStorageKey={`changesets-archived-by-${archivedBy}`}>
<DismissibleAlert variant="info" partialStorageKey={`changesets-archived-by-${archivedBy}`}>
<div className="d-flex align-items-center">
<div className="d-none d-md-block">
<ArchiveIcon className="icon icon-inline mr-2" />

View File

@ -1,6 +1,7 @@
import classNames from 'classnames'
import React from 'react'
import { Alert } from '@sourcegraph/wildcard'
import { BatchChangeFields } from '../../../graphql-operations'
interface ClosedNoticeProps {
@ -14,9 +15,9 @@ export const ClosedNotice: React.FunctionComponent<ClosedNoticeProps> = ({ close
}
return (
<div className={classNames('alert alert-info', className)}>
<Alert className={className} variant="info">
Information on this page may be out of date because changesets that only exist in closed batch changes are
not synced with the code host.
</div>
</Alert>
)
}

View File

@ -23,10 +23,7 @@ export const SupersedingBatchSpecAlert: React.FunctionComponent<SupersedingBatch
}
return (
<DismissibleAlert
className="alert-info"
partialStorageKey={`superseding-spec-${parseISO(spec.createdAt).getTime()}`}
>
<DismissibleAlert variant="info" partialStorageKey={`superseding-spec-${parseISO(spec.createdAt).getTime()}`}>
<div className="d-flex align-items-center">
<div className="flex-grow-1">
A <Link to={applyURL}>modified batch spec</Link> is ready but not applied since{' '}

View File

@ -1,8 +1,7 @@
import classNames from 'classnames'
import React from 'react'
import { pluralize } from '@sourcegraph/shared/src/util/strings'
import { AlertLink } from '@sourcegraph/wildcard'
import { AlertLink, Alert } from '@sourcegraph/wildcard'
interface UnpublishedNoticeProps {
unpublished: number
@ -19,7 +18,7 @@ export const UnpublishedNotice: React.FunctionComponent<UnpublishedNoticeProps>
return <></>
}
return (
<div className={classNames('alert alert-secondary', className)}>
<Alert className={className} variant="secondary">
{unpublished} unpublished {pluralize('changeset', unpublished, 'changesets')}. Select changeset(s) and
choose the 'Publish changesets' action to publish them, or{' '}
<AlertLink
@ -30,6 +29,6 @@ export const UnpublishedNotice: React.FunctionComponent<UnpublishedNoticeProps>
read more about publishing changesets
</AlertLink>
.
</div>
</Alert>
)
}

View File

@ -50,7 +50,7 @@ export const WebhookAlert: React.FunctionComponent<Props> = ({
const SITE_ADMIN_CONFIG_DOC_URL = 'https://docs.sourcegraph.com/batch_changes/how-tos/site_admin_configuration'
return (
<DismissibleAlert className="alert-warning" partialStorageKey={id}>
<DismissibleAlert variant="warning" partialStorageKey={id}>
<div>
<h4>Changeset information may not be up to date</h4>
<p className={styles.blurb}>

View File

@ -10,7 +10,7 @@ import React from 'react'
import { ErrorMessage } from '@sourcegraph/branded/src/components/alerts'
import { BulkOperationState, BulkOperationType } from '@sourcegraph/shared/src/graphql-operations'
import { pluralize } from '@sourcegraph/shared/src/util/strings'
import { Badge, AlertLink, Link } from '@sourcegraph/wildcard'
import { Badge, AlertLink, Link, Alert } from '@sourcegraph/wildcard'
import { Collapsible } from '../../../../components/Collapsible'
import { Timestamp } from '../../../../components/time/Timestamp'
@ -100,7 +100,7 @@ export const BulkOperationNode: React.FunctionComponent<BulkOperationNodeProps>
title={<h4 className="mb-0">The following errors occured while running this task:</h4>}
>
{node.errors.map((error, index) => (
<div className="mt-2 alert alert-danger" key={index}>
<Alert className="mt-2" key={index} variant="danger">
<p>
{error.changeset.__typename === 'HiddenExternalChangeset' ? (
<span className="text-muted">On hidden repository</span>
@ -118,7 +118,7 @@ export const BulkOperationNode: React.FunctionComponent<BulkOperationNodeProps>
)}
</p>
{error.error && <ErrorMessage error={'```\n' + error.error + '\n```'} />}
</div>
</Alert>
))}
</Collapsible>
</div>

View File

@ -8,6 +8,7 @@ import { HoverMerged } from '@sourcegraph/shared/src/api/client/types/hover'
import { ExtensionsControllerProps } from '@sourcegraph/shared/src/extensions/controller'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { RepoSpec, RevisionSpec, FileSpec, ResolvedRevisionSpec } from '@sourcegraph/shared/src/util/url'
import { Alert } from '@sourcegraph/wildcard'
import { FileDiffConnection } from '../../../../components/diff/FileDiffConnection'
import { FileDiffNode } from '../../../../components/diff/FileDiffNode'
@ -146,7 +147,7 @@ function commitOIDForGitRevision(revision: GitRefSpecFields): string {
}
const DiffRenderingNotSupportedAlert: React.FunctionComponent<{}> = () => (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
Diffs for processing, merged, closed and deleted changesets are currently only available on the code host.
</div>
</Alert>
)

View File

@ -15,7 +15,7 @@ import { ChangesetState } from '@sourcegraph/shared/src/graphql-operations'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { RepoSpec, RevisionSpec, FileSpec, ResolvedRevisionSpec } from '@sourcegraph/shared/src/util/url'
import { InputTooltip } from '@sourcegraph/web/src/components/InputTooltip'
import { Button } from '@sourcegraph/wildcard'
import { Button, Alert } from '@sourcegraph/wildcard'
import { DiffStatStack } from '../../../../components/diff/DiffStat'
import { ChangesetSpecType, ExternalChangesetFields } from '../../../../graphql-operations'
@ -222,7 +222,7 @@ export const ExternalChangesetNode: React.FunctionComponent<ExternalChangesetNod
}
const SyncerError: React.FunctionComponent<{ syncerError: string }> = ({ syncerError }) => (
<div className="alert alert-danger" role="alert">
<Alert role="alert" variant="danger">
<h4 className={classNames(styles.alertHeading)}>
Encountered error during last attempt to sync changeset data from code host
</h4>
@ -231,7 +231,7 @@ const SyncerError: React.FunctionComponent<{ syncerError: string }> = ({ syncerE
<p className="mb-0">
<small>This might be an ephemeral error that resolves itself at the next sync.</small>
</p>
</div>
</Alert>
)
const ChangesetError: React.FunctionComponent<{
@ -242,10 +242,10 @@ const ChangesetError: React.FunctionComponent<{
}
return (
<div className="alert alert-danger" role="alert">
<Alert role="alert" variant="danger">
<h4 className={classNames(styles.alertHeading)}>Failed to run operations on changeset</h4>
<ErrorMessage error={node.error} />
</div>
</Alert>
)
}

View File

@ -6,7 +6,7 @@ import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { isErrorLike } from '@sourcegraph/common'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ButtonTooltip } from '@sourcegraph/web/src/components/ButtonTooltip'
import { Link } from '@sourcegraph/wildcard'
import { Alert, Link } from '@sourcegraph/wildcard'
import { BatchSpecFields } from '../../../graphql-operations'
import { MultiSelectContext } from '../MultiSelectContext'
@ -81,7 +81,7 @@ export const CreateUpdateBatchChangeAlert: React.FunctionComponent<CreateUpdateB
return (
<>
<div className="alert alert-info mb-3 d-block d-md-flex align-items-center body-lead">
<Alert className="mb-3 d-block d-md-flex align-items-center body-lead" variant="info">
<div className={classNames(styles.createUpdateBatchChangeAlertCopy, 'flex-grow-1 mr-3')}>
{batchChange ? (
<>
@ -110,7 +110,7 @@ export const CreateUpdateBatchChangeAlert: React.FunctionComponent<CreateUpdateB
Apply
</ButtonTooltip>
</div>
</div>
</Alert>
{isErrorLike(isLoading) && <ErrorAlert error={isLoading} />}
</>
)

View File

@ -1,7 +1,7 @@
import React from 'react'
import { pluralize } from '@sourcegraph/shared/src/util/strings'
import { Link } from '@sourcegraph/wildcard'
import { Alert, Link } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../auth'
import { ViewerBatchChangesCodeHostsFields } from '../../../graphql-operations'
@ -20,7 +20,7 @@ export const MissingCredentialsAlert: React.FunctionComponent<MissingCredentials
return <></>
}
return (
<div className="alert alert-warning">
<Alert variant="warning">
<p>
<strong>
You don't have credentials configured for{' '}
@ -39,6 +39,6 @@ export const MissingCredentialsAlert: React.FunctionComponent<MissingCredentials
</Link>{' '}
to apply this spec.
</p>
</div>
</Alert>
)
}

View File

@ -185,7 +185,7 @@ const PublicationStatesUpdateAlerts: React.FunctionComponent<{}> = () => {
return (
<div className="mt-2">
{recalculationUpdates.map(timestamp => (
<DismissibleAlert className="alert-success" key={timestamp}>
<DismissibleAlert variant="success" key={timestamp}>
Publication state actions were recalculated.
</DismissibleAlert>
))}

View File

@ -11,7 +11,7 @@ import React, { useCallback, useMemo, useState } from 'react'
import { Maybe } from '@sourcegraph/shared/src/graphql-operations'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { InputTooltip } from '@sourcegraph/web/src/components/InputTooltip'
import { Button, Link } from '@sourcegraph/wildcard'
import { Button, Link, Alert } from '@sourcegraph/wildcard'
import { DiffStatStack } from '../../../../components/diff/DiffStat'
import { ChangesetState, VisibleChangesetApplyPreviewFields } from '../../../../graphql-operations'
@ -275,18 +275,18 @@ const ExpandedSection: React.FunctionComponent<
}, [])
if (node.targets.__typename === 'VisibleApplyPreviewTargetsDetach') {
return (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
When run, the changeset <strong>{node.targets.changeset.title}</strong> in repo{' '}
<strong>{node.targets.changeset.repository.name}</strong> will be removed from this batch change.
</div>
</Alert>
)
}
if (node.targets.changesetSpec.description.__typename === 'ExistingChangesetReference') {
return (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
When run, the changeset with ID <strong>{node.targets.changesetSpec.description.externalID}</strong>{' '}
will be imported from <strong>{node.targets.changesetSpec.description.baseRepository.name}</strong>.
</div>
</Alert>
)
}
return (
@ -381,10 +381,10 @@ const ExpandedSection: React.FunctionComponent<
{selectedTab === 'diff' && (
<>
{node.delta.diffChanged && (
<div className="alert alert-warning">
<Alert variant="warning">
The files in this changeset have been altered from the previous version. These changes will
be pushed to the target branch.
</div>
</Alert>
)}
<ChangesetSpecFileDiffConnection
history={history}

View File

@ -1,7 +1,7 @@
import React from 'react'
import { RouteComponentProps } from 'react-router'
import { PageHeader } from '@sourcegraph/wildcard'
import { PageHeader, Alert } from '@sourcegraph/wildcard'
import { PageTitle } from '../../../components/PageTitle'
@ -21,10 +21,10 @@ export const BatchChangesSiteConfigSettingsArea: React.FunctionComponent<BatchCh
headerLine={
<>
<p>Add access tokens to enable Batch Changes changeset creation for all users.</p>
<div className="alert alert-info">
<Alert variant="info">
You are configuring <strong>global credentials</strong> for Batch Changes. The credentials on
this page can be used by all users of this Sourcegraph instance to create and sync changesets.
</div>
</Alert>
</>
}
userID={null}

View File

@ -3,7 +3,7 @@ import CloseIcon from 'mdi-react/CloseIcon'
import React from 'react'
import { useTemporarySetting } from '@sourcegraph/shared/src/settings/temporary/useTemporarySetting'
import { Button } from '@sourcegraph/wildcard'
import { Button, Alert } from '@sourcegraph/wildcard'
import styles from './CodeMonitorInfo.module.scss'
@ -15,7 +15,7 @@ export const CodeMonitorInfo: React.FunctionComponent<{ className?: string }> =
}
return (
<div className={classNames('alert alert-info alert-dismissable d-flex align-items-start', className)}>
<Alert className={classNames('d-flex align-items-start', className)} variant="info">
<p className="mb-0">
We currently recommend code monitors on repositories that dont have a high commit traffic and for
non-critical use cases.
@ -31,6 +31,6 @@ export const CodeMonitorInfo: React.FunctionComponent<{ className?: string }> =
>
<CloseIcon className="icon-inline" />
</Button>
</div>
</Alert>
)
})

View File

@ -5,7 +5,7 @@ import { switchMap, catchError, startWith, takeUntil, tap, delay, mergeMap } fro
import { Toggle } from '@sourcegraph/branded/src/components/Toggle'
import { ErrorLike, isErrorLike, asError } from '@sourcegraph/common'
import { Button, LoadingSpinner, useEventObservable, Link } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, useEventObservable, Link, Alert } from '@sourcegraph/wildcard'
import { CodeMonitorFields, ToggleCodeMonitorEnabledResult } from '../../graphql-operations'
@ -119,7 +119,7 @@ export const CodeMonitorNode: React.FunctionComponent<CodeMonitorNodeProps> = ({
</div>
</div>
{isErrorLike(toggleMonitorOrError) && (
<div className="alert alert-danger">Failed to toggle monitor: {toggleMonitorOrError.message}</div>
<Alert variant="danger">Failed to toggle monitor: {toggleMonitorOrError.message}</Alert>
)}
</div>
)

View File

@ -8,7 +8,7 @@ import { mergeMap, startWith, catchError, tap, filter } from 'rxjs/operators'
import { Form } from '@sourcegraph/branded/src/components/Form'
import { Toggle } from '@sourcegraph/branded/src/components/Toggle'
import { asError, isErrorLike } from '@sourcegraph/common'
import { Container, Button, useEventObservable } from '@sourcegraph/wildcard'
import { Container, Button, useEventObservable, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../auth'
import { CodeMonitorFields } from '../../../graphql-operations'
@ -276,7 +276,7 @@ export const CodeMonitorForm: React.FunctionComponent<CodeMonitorFormProps> = ({
)}
</div>
{isErrorLike(codeMonitorOrError) && (
<div className="alert alert-danger">Failed to create monitor: {codeMonitorOrError.message}</div>
<Alert variant="danger">Failed to create monitor: {codeMonitorOrError.message}</Alert>
)}
</div>
</Form>

View File

@ -3,7 +3,7 @@ import { Observable, throwError } from 'rxjs'
import { mergeMap, startWith, tap, catchError } from 'rxjs/operators'
import { asError, isErrorLike } from '@sourcegraph/common'
import { Button, LoadingSpinner, useEventObservable, Modal } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, useEventObservable, Modal, Alert } from '@sourcegraph/wildcard'
import { CodeMonitorFormProps } from './CodeMonitorForm'
@ -71,7 +71,7 @@ export const DeleteMonitorModal: React.FunctionComponent<DeleteModalProps> = ({
Yes, delete code monitor
</Button>
{isErrorLike(deleteCompletedOrError) && (
<div className="alert-danger">Error deleting monitor: {deleteCompletedOrError.message}</div>
<Alert variant="danger">Error deleting monitor: {deleteCompletedOrError.message}</Alert>
)}
</div>
)}

View File

@ -1,6 +1,7 @@
import classNames from 'classnames'
import React from 'react'
import { Alert } from '@sourcegraph/wildcard'
interface FlashMessageProps {
state: string
message: string
@ -8,7 +9,7 @@ interface FlashMessageProps {
}
export const FlashMessage: React.FunctionComponent<FlashMessageProps> = ({ state, message, className }) => (
<div className={classNames('alert', className, state === 'SUCCESS' ? 'alert-success' : 'alert-warning')}>
<Alert variant={state === 'SUCCESS' ? 'success' : 'warning'} className={className}>
{message}
</div>
</Alert>
)

View File

@ -1,6 +1,7 @@
import React, { FunctionComponent } from 'react'
import { Toggle } from '@sourcegraph/branded/src/components/Toggle'
import { Alert } from '@sourcegraph/wildcard'
import { RadioButtons } from '../../../../components/RadioButtons'
import { CodeIntelligenceConfigurationPolicyFields, GitObjectType } from '../../../../graphql-operations'
@ -65,10 +66,10 @@ export const IndexingSettings: FunctionComponent<IndexingSettingsProps> = ({
repo === undefined &&
(policy.repositoryPatterns || []).length === 0 &&
policy.indexingEnabled && (
<div className="alert alert-danger">
<Alert variant="danger">
This Sourcegraph instance has disabled global policies for auto-indexing. Create a more
constrained policy targeting an explicit set of repositories to enable this policy.
</div>
</Alert>
)}
<label className="ml-4" htmlFor="index-commit-max-age">

View File

@ -2,7 +2,7 @@ import classNames from 'classnames'
import React, { FunctionComponent } from 'react'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { LoadingSpinner } from '@sourcegraph/wildcard'
import { LoadingSpinner, Alert } from '@sourcegraph/wildcard'
import { usePreviewRepositoryFilter } from '../hooks/usePreviewRepositoryFilter'
@ -62,12 +62,12 @@ export const RepositoryPreview: FunctionComponent<RepositoryPreviewProps> = ({ p
</div>
{preview.totalMatches > preview.totalCount && (
<div className="alert alert-danger">
<Alert variant="danger">
Each policy pattern can match a maximum of {preview.limit} repositories. There are{' '}
{preview.totalMatches - preview.totalCount} additional repositories that match the
filter not covered by this policy. Create a more constrained policy or increase the
system limit.
</div>
</Alert>
)}
</>
)

View File

@ -9,7 +9,7 @@ import { GitObjectType } from '@sourcegraph/shared/src/graphql-operations'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { PageTitle } from '@sourcegraph/web/src/components/PageTitle'
import { Button, Container, LoadingSpinner, PageHeader } from '@sourcegraph/wildcard'
import { Button, Container, LoadingSpinner, PageHeader, Alert } from '@sourcegraph/wildcard'
import { CodeIntelligenceConfigurationPolicyFields } from '../../../../graphql-operations'
import { BranchTargetSettings } from '../components/BranchTargetSettings'
@ -128,10 +128,10 @@ export const CodeIntelConfigurationPolicyPage: FunctionComponent<CodeIntelConfig
)}
{policy.protected ? (
<div className="alert alert-info">
<Alert variant="info">
This configuration policy is protected. Protected configuration policies may not be deleted and only
the retention duration and indexing options are editable.
</div>
</Alert>
) : (
policy.id !== '' && (
<Container className="mb-3">

View File

@ -2,7 +2,7 @@ import React, { FunctionComponent, useCallback, useState } from 'react'
import { Subject } from 'rxjs'
import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { Button } from '@sourcegraph/wildcard'
import { Button, Alert } from '@sourcegraph/wildcard'
import { useEnqueueIndexJob } from '../hooks/useEnqueueIndexJob'
@ -75,7 +75,9 @@ export const EnqueueForm: FunctionComponent<EnqueueFormProps> = ({ repoId, query
</div>
{state === State.Queued && queueResult !== undefined && (
<div className="alert alert-success mt-3 mb-0">{queueResult} index jobs enqueued.</div>
<Alert className="mt-3 mb-0" variant="success">
{queueResult} index jobs enqueued.
</Alert>
)}
</>
)

View File

@ -12,7 +12,7 @@ import { Container, PageHeader, LoadingSpinner, useObservable } from '@sourcegra
import { AuthenticatedUser } from '../../../../auth'
import { PageTitle } from '../../../../components/PageTitle'
import { LsifIndexFields } from '../../../../graphql-operations'
import { CodeIntelStateBanner } from '../../shared/components/CodeIntelStateBanner'
import { CodeIntelStateBanner, CodeIntelStateBannerProps } from '../../shared/components/CodeIntelStateBanner'
import { CodeIntelAssociatedUpload } from '../components/CodeIntelAssociatedUpload'
import { CodeIntelDeleteIndex } from '../components/CodeIntelDeleteIndex'
import { CodeIntelIndexMeta } from '../components/CodeIntelIndexMeta'
@ -26,9 +26,9 @@ export interface CodeIntelIndexPageProps extends RouteComponentProps<{ id: strin
now?: () => Date
}
const classNamesByState = new Map([
[LSIFIndexState.COMPLETED, 'alert-success'],
[LSIFIndexState.ERRORED, 'alert-danger'],
const variantByState = new Map<LSIFIndexState, CodeIntelStateBannerProps['variant']>([
[LSIFIndexState.COMPLETED, 'success'],
[LSIFIndexState.ERRORED, 'danger'],
])
export const CodeIntelIndexPage: FunctionComponent<CodeIntelIndexPageProps> = ({
@ -134,7 +134,7 @@ export const CodeIntelIndexPage: FunctionComponent<CodeIntelIndexPageProps> = ({
failure={indexOrError.failure}
typeName="index"
pluralTypeName="indexes"
className={classNamesByState.get(indexOrError.state)}
variant={variantByState.get(indexOrError.state)}
/>
</Container>

View File

@ -1,6 +1,7 @@
import classNames from 'classnames'
import React, { FunctionComponent } from 'react'
import { Alert, AlertProps } from '@sourcegraph/wildcard'
import { LSIFIndexState, LSIFUploadState } from '../../../../graphql-operations'
import { CodeIntelStateDescription } from './CodeIntelStateDescription'
@ -11,7 +12,7 @@ export interface CodeIntelStateBannerProps {
state: LSIFUploadState | LSIFIndexState
placeInQueue?: number | null
failure?: string | null
className?: string
variant?: AlertProps['variant']
}
export const CodeIntelStateBanner: FunctionComponent<CodeIntelStateBannerProps> = ({
@ -20,9 +21,9 @@ export const CodeIntelStateBanner: FunctionComponent<CodeIntelStateBannerProps>
state,
placeInQueue,
failure,
className = 'alert-primary',
variant = 'primary',
}) => (
<div className={classNames('alert', className)}>
<Alert variant={variant}>
<span>
<CodeIntelStateDescription
state={state}
@ -32,5 +33,5 @@ export const CodeIntelStateBanner: FunctionComponent<CodeIntelStateBannerProps>
pluralTypeName={pluralTypeName}
/>
</span>
</div>
</Alert>
)

View File

@ -1,7 +1,7 @@
import classNames from 'classnames'
import React, { FunctionComponent } from 'react'
import { Timestamp } from '@sourcegraph/web/src/components/time/Timestamp'
import { Alert } from '@sourcegraph/wildcard'
export interface CommitGraphMetadataProps {
stale: boolean
@ -17,10 +17,10 @@ export const CommitGraphMetadata: FunctionComponent<CommitGraphMetadataProps> =
now,
}) => (
<>
<div className={classNames('alert', stale ? 'alert-primary' : 'alert-success', className)}>
<Alert variant={stale ? 'primary' : 'success'} className={className}>
{stale ? <StaleRepository /> : <FreshRepository />}{' '}
{updatedAt && <LastUpdated updatedAt={updatedAt} now={now} />}
</div>
</Alert>
</>
)

View File

@ -20,7 +20,7 @@ import { AuthenticatedUser } from '../../../../auth'
import { Collapsible } from '../../../../components/Collapsible'
import { PageTitle } from '../../../../components/PageTitle'
import { LsifUploadFields, LsifUploadConnectionFields } from '../../../../graphql-operations'
import { CodeIntelStateBanner } from '../../shared/components/CodeIntelStateBanner'
import { CodeIntelStateBanner, CodeIntelStateBannerProps } from '../../shared/components/CodeIntelStateBanner'
import { CodeIntelAssociatedIndex } from '../components/CodeIntelAssociatedIndex'
import { CodeIntelDeleteUpload } from '../components/CodeIntelDeleteUpload'
import { CodeIntelUploadMeta } from '../components/CodeIntelUploadMeta'
@ -41,9 +41,9 @@ export interface CodeIntelUploadPageProps extends RouteComponentProps<{ id: stri
now?: () => Date
}
const classNamesByState = new Map([
[LSIFUploadState.COMPLETED, 'alert-success'],
[LSIFUploadState.ERRORED, 'alert-danger'],
const variantByState = new Map<LSIFUploadState, CodeIntelStateBannerProps['variant']>([
[LSIFUploadState.COMPLETED, 'success'],
[LSIFUploadState.ERRORED, 'danger'],
])
enum DependencyGraphState {
@ -182,7 +182,7 @@ export const CodeIntelUploadPage: FunctionComponent<CodeIntelUploadPageProps> =
failure={uploadOrError.failure}
typeName="upload"
pluralTypeName="uploads"
className={classNamesByState.get(uploadOrError.state)}
variant={variantByState.get(uploadOrError.state)}
/>
{uploadOrError.isLatestForRepo && (
<div>

View File

@ -4,6 +4,7 @@ import format from 'date-fns/format'
import React from 'react'
import * as GQL from '@sourcegraph/shared/src/schema'
import { Alert } from '@sourcegraph/wildcard'
import { formatRelativeExpirationDate, isProductLicenseExpired } from '../../../productSubscription/helpers'
@ -16,16 +17,25 @@ export const ProductLicenseValidity: React.FunctionComponent<{
className?: string
}> = ({ licenseInfo: { expiresAt }, primary, className = '' }) => {
const isExpired = isProductLicenseExpired(expiresAt)
const tooltip = format(parseISO(expiresAt), 'PPpp')
const validityClass = isExpired ? 'danger' : 'success'
if (primary) {
return (
<Alert
className={classNames(className, 'py-1 px-2')}
variant={isExpired ? 'danger' : 'success'}
data-tooltip={tooltip}
>
<strong>{isExpired ? 'Expired' : 'Valid'}</strong> ({formatRelativeExpirationDate(expiresAt)})
</Alert>
)
}
return (
<div
className={classNames(className, primary && `alert alert-${validityClass} py-1 px-2`)}
data-tooltip={format(parseISO(expiresAt), 'PPpp')}
>
<strong className={classNames(!primary && `text-${validityClass}`)}>
{isExpired ? 'Expired' : 'Valid'}
</strong>{' '}
({formatRelativeExpirationDate(expiresAt)})
<div className={className} data-tooltip={tooltip}>
<strong className={`text-${validityClass}`}>{isExpired ? 'Expired' : 'Valid'}</strong> (
{formatRelativeExpirationDate(expiresAt)})
</div>
)
}

View File

@ -11,7 +11,7 @@ import { Form } from '@sourcegraph/branded/src/components/Form'
import { asError, createAggregateError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import * as GQL from '@sourcegraph/shared/src/schema'
import { Button, LoadingSpinner, Link, CardHeader, CardBody, Card } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, Link, CardHeader, CardBody, Card, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../auth'
import { withAuthenticatedUser } from '../../../auth/withAuthenticatedUser'
@ -169,12 +169,12 @@ export const RegistryExtensionManagePage = withAuthenticatedUser(
{extensionID &&
this.state.name &&
this.state.name !== this.props.extension.registryExtension.name && (
<div className="alert alert-primary">
<Alert variant="primary">
Extension will be renamed. New extension ID:{' '}
<code id="registry-extension__extensionID">
<strong>{extensionID}</strong>
</code>
</div>
</Alert>
)}
<Button type="submit" disabled={this.state.updateOrError === 'loading'} variant="primary">
{this.state.updateOrError === 'loading' ? <LoadingSpinner /> : 'Update extension'}

View File

@ -5,7 +5,7 @@ import { useMergeRefs } from 'use-callback-ref'
import { asError, isErrorLike } from '@sourcegraph/common'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { useDebounce } from '@sourcegraph/wildcard'
import { useDebounce, Alert } from '@sourcegraph/wildcard'
import * as View from '../../../../../../views'
import { LineChartSettingsContext } from '../../../../../../views'
@ -172,7 +172,9 @@ export const BackendInsightView: React.FunctionComponent<BackendInsightProps> =
) : isErrorLike(error) ? (
<View.ErrorContent error={error} title={insight.id}>
{error instanceof InsightInProcessError ? (
<div className="alert alert-info m-0">{error.message}</div>
<Alert className="m-0" variant="info">
{error.message}
</Alert>
) : null}
</View.ErrorContent>
) : (

View File

@ -3,7 +3,7 @@ import React, { FunctionComponent, useCallback, useState } from 'react'
import { Form } from '@sourcegraph/branded/src/components/Form'
import { gql, useLazyQuery, useMutation } from '@sourcegraph/http-client'
import { IFeatureFlagOverride } from '@sourcegraph/shared/src/schema'
import { Input } from '@sourcegraph/wildcard'
import { Input, Alert } from '@sourcegraph/wildcard'
import { LoaderButton } from '../../components/LoaderButton'
import { Maybe, OrganizationVariables } from '../../graphql-operations'
@ -123,9 +123,15 @@ export const EarlyAccessOrgsCodeForm: FunctionComponent<any> = () => {
/>
</div>
{error && <div className="mt-3 alert alert-danger">{error.message}</div>}
{error && (
<Alert className="mt-3" variant="danger">
{error.message}
</Alert>
)}
{data?.createFeatureFlagOverride && (
<div className="mt-3 mb-0 alert alert-success">Feature flag override created.</div>
<Alert className="mt-3 mb-0" variant="success">
Feature flag override created.
</Alert>
)}
</Form>
)

View File

@ -1,6 +1,7 @@
import classNames from 'classnames'
import React from 'react'
import { Alert } from '@sourcegraph/wildcard'
/**
* Displays a warning in debug mode (which is on for local dev) that generated license keys aren't
* actually valid. Local dev (with `sg start`) uses a test private key that does NOT correspond to
@ -12,10 +13,10 @@ import React from 'react'
*/
export const LicenseGenerationKeyWarning: React.FunctionComponent<{ className?: string }> = ({ className = '' }) =>
window.context?.debug ? (
<div className={classNames('alert alert-warning', className)}>
<Alert className={className} variant="warning">
License keys generated in dev mode are <strong>NOT VALID</strong>.{' '}
<a href="https://sourcegraph.com/site-admin/dotcom/product/subscriptions">
Use Sourcegraph.com to generate valid license keys.
</a>
</div>
</Alert>
) : null

View File

@ -1,7 +1,7 @@
import * as H from 'history'
import React, { useEffect, useMemo } from 'react'
import { Container, PageHeader, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { Container, PageHeader, LoadingSpinner, useObservable, Alert } from '@sourcegraph/wildcard'
import { PageTitle } from '../../../components/PageTitle'
import { Timestamp } from '../../../components/time/Timestamp'
@ -50,14 +50,14 @@ export const RepoSettingsPermissionsPage: React.FunctionComponent<RepoSettingsPe
/>
<Container className="repo-settings-permissions-page">
{!repo.isPrivate ? (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
Access to this repository is not restricted, all Sourcegraph users have access.
</div>
</Alert>
) : !permissionsInfo ? (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
This repository is queued to sync permissions, only site admins will have access to it until
syncing is finished.
</div>
</Alert>
) : (
<div>
<table className="table">

View File

@ -6,7 +6,7 @@ import { catchError } from 'rxjs/operators'
import { Form } from '@sourcegraph/branded/src/components/Form'
import { asError, isErrorLike, ErrorLike } from '@sourcegraph/common'
import { Badge, Button, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { Badge, Button, LoadingSpinner, useObservable, Alert } from '@sourcegraph/wildcard'
import { querySearchResultsStats } from './backend'
import { SearchStatsLanguages } from './SearchStatsLanguages'
@ -86,12 +86,12 @@ export const SearchStatsPage: React.FunctionComponent<Props> = ({
{stats === undefined ? (
<LoadingSpinner />
) : isErrorLike(stats) ? (
<div className="alert alert-danger">{stats.message}</div>
<Alert variant="danger">{stats.message}</Alert>
) : stats.limitHit ? (
<div className="alert alert-warning">
<Alert variant="warning">
Limit hit. Add <code>count:{DEFAULT_COUNT * 5}</code> (or an even larger number) to your query to
retry with a higher limit.
</div>
</Alert>
) : (
<SearchStatsLanguages query={query} stats={stats} />
)}

View File

@ -53,7 +53,7 @@ exports[`SearchStatsPage limitHit 1`] = `
class="my-3"
/>
<div
class="alert alert-warning"
class=""
>
Limit hit. Add
<code>

View File

@ -8,7 +8,7 @@ import { SearchContextProps } from '@sourcegraph/search'
import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
import { ISearchContext } from '@sourcegraph/shared/src/schema'
import { ALLOW_NAVIGATION } from '@sourcegraph/web/src/components/AwayPrompt'
import { Button, LoadingSpinner, useEventObservable, Modal } from '@sourcegraph/wildcard'
import { Button, LoadingSpinner, useEventObservable, Modal, Alert } from '@sourcegraph/wildcard'
interface DeleteSearchContextModalProps
extends Pick<SearchContextProps, 'deleteSearchContext'>,
@ -71,9 +71,7 @@ export const DeleteSearchContextModal: React.FunctionComponent<DeleteSearchConte
Yes, delete search context
</Button>
{isErrorLike(deleteCompletedOrError) && (
<div className="alert-danger">
Error deleting search context: {deleteCompletedOrError.message}
</div>
<Alert variant="danger">Error deleting search context: {deleteCompletedOrError.message}</Alert>
)}
</div>
)}

View File

@ -17,7 +17,7 @@ import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryServi
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { Page } from '@sourcegraph/web/src/components/Page'
import { PageTitle } from '@sourcegraph/web/src/components/PageTitle'
import { PageHeader, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { PageHeader, LoadingSpinner, useObservable, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../auth'
import { withAuthenticatedUser } from '../../auth/withAuthenticatedUser'
@ -99,9 +99,9 @@ export const AuthenticatedEditSearchContextPage: React.FunctionComponent<EditSea
<SearchContextForm {...props} searchContext={searchContextOrError} onSubmit={onSubmit} />
)}
{isErrorLike(searchContextOrError) && (
<div data-testid="search-contexts-alert-danger" className="alert alert-danger">
<Alert data-testid="search-contexts-alert-danger" variant="danger">
Error while loading the search context: <strong>{searchContextOrError.message}</strong>
</div>
</Alert>
)}
</div>
</Page>

View File

@ -19,7 +19,7 @@ import { ISearchContext, ISearchContextRepositoryRevisionsInput } from '@sourceg
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { ALLOW_NAVIGATION, AwayPrompt } from '@sourcegraph/web/src/components/AwayPrompt'
import { Container, Button, RadioButton, TextArea, useEventObservable } from '@sourcegraph/wildcard'
import { Container, Button, RadioButton, TextArea, useEventObservable, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../auth'
import { getExperimentalFeatures } from '../../stores'
@ -459,9 +459,9 @@ export const SearchContextForm: React.FunctionComponent<SearchContextFormProps>
)}
</div>
{isErrorLike(searchContextOrError) && (
<div className="alert alert-danger mt-2">
<Alert className="mt-2" variant="danger">
Failed to create search context: {searchContextOrError.message}
</div>
</Alert>
)}
<AwayPrompt
header="Discard unsaved changes?"

View File

@ -19,7 +19,7 @@ import { buildSearchURLQuery } from '@sourcegraph/shared/src/util/url'
import { Page } from '@sourcegraph/web/src/components/Page'
import { PageTitle } from '@sourcegraph/web/src/components/PageTitle'
import { Timestamp } from '@sourcegraph/web/src/components/time/Timestamp'
import { Badge, Container, PageHeader, LoadingSpinner, useObservable, Button, Link } from '@sourcegraph/wildcard'
import { Badge, Container, PageHeader, LoadingSpinner, useObservable, Button, Link, Alert } from '@sourcegraph/wildcard'
import styles from './SearchContextPage.module.scss'
@ -234,9 +234,9 @@ export const SearchContextPage: React.FunctionComponent<SearchContextPageProps>
</>
)}
{isErrorLike(searchContextOrError) && (
<div className="alert alert-danger">
<Alert variant="danger">
Error while loading the search context: <strong>{searchContextOrError.message}</strong>
</div>
</Alert>
)}
</div>
</Page>

View File

@ -9,7 +9,7 @@ import { delay, mergeMap, startWith, tap } from 'rxjs/operators'
import { ISearchContextRepositoryRevisions } from '@sourcegraph/shared/src/schema'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { Button, useEventObservable } from '@sourcegraph/wildcard'
import { Button, useEventObservable, Alert } from '@sourcegraph/wildcard'
import { DynamicallyImportedMonacoSettingsEditor } from '../../settings/DynamicallyImportedMonacoSettingsEditor'
@ -147,14 +147,14 @@ export const SearchContextRepositoriesFormArea: React.FunctionComponent<SearchCo
blockNavigationIfDirty={false}
/>
{triggerTestConfigErrors && triggerTestConfigErrors !== LOADING && triggerTestConfigErrors.length > 0 && (
<div className="alert alert-danger my-2">
<Alert className="my-2" variant="danger">
<strong>The following problems were found:</strong>
<ul className="mt-2">
{triggerTestConfigErrors.map(error => (
<li key={error.message}>{error.message}</li>
))}
</ul>
</div>
</Alert>
)}
<Button
className="mt-3"

View File

@ -9,7 +9,7 @@ import { Form } from '@sourcegraph/branded/src/components/Form'
import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { dataOrThrowErrors, gql } from '@sourcegraph/http-client'
import * as GQL from '@sourcegraph/shared/src/schema'
import { Button, useEventObservable, Link } from '@sourcegraph/wildcard'
import { Button, useEventObservable, Link, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../../auth'
import { mutateGraphQL, queryGraphQL } from '../../../../backend/graphql'
@ -99,16 +99,12 @@ const UserCreateSubscriptionNode: React.FunctionComponent<UserCreateSubscription
</Form>
</div>
</div>
{isErrorLike(createdSubscription) && (
<div className="alert alert-danger">{createdSubscription.message}</div>
)}
{isErrorLike(createdSubscription) && <Alert variant="danger">{createdSubscription.message}</Alert>}
{createdSubscription &&
createdSubscription !== 'saving' &&
!isErrorLike(createdSubscription) &&
!createdSubscription.urlForSiteAdmin && (
<div className="alert alert-danger">
No subscription URL available (only accessible to site admins)
</div>
<Alert variant="danger">No subscription URL available (only accessible to site admins)</Alert>
)}
</li>
</>

View File

@ -10,7 +10,7 @@ import { asError, createAggregateError, isErrorLike } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import * as GQL from '@sourcegraph/shared/src/schema'
import { Button, useEventObservable } from '@sourcegraph/wildcard'
import { Alert, Button, useEventObservable } from '@sourcegraph/wildcard'
import { mutateGraphQL } from '../../../../backend/graphql'
import { ExpirationDate } from '../../../productSubscription/ExpirationDate'
@ -125,12 +125,15 @@ export const SiteAdminGenerateProductLicenseForSubscriptionForm: React.FunctionC
<div className="site-admin-generate-product-license-for-subscription-form">
{creation && !isErrorLike(creation) && creation !== LOADING ? (
<div className="border rounded border-success mb-5">
<div className="border-top-0 border-left-0 border-right-0 rounded-0 alert alert-success mb-0 d-flex align-items-center justify-content-between px-3 py-2">
<Alert
variant="success"
className="border-top-0 border-left-0 border-right-0 rounded-0 mb-0 d-flex align-items-center justify-content-between px-3 py-2"
>
<span>Generated product license.</span>
<Button onClick={dismissAlert} autoFocus={true} variant="primary">
Dismiss
</Button>
</div>
</Alert>
</div>
) : (
<Form onSubmit={onSubmit}>

View File

@ -8,7 +8,7 @@ import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { gql, dataOrThrowErrors } from '@sourcegraph/http-client'
import * as GQL from '@sourcegraph/shared/src/schema'
import { numberWithCommas } from '@sourcegraph/shared/src/util/strings'
import { LoadingSpinner, useObservable, Button, Link, CardFooter } from '@sourcegraph/wildcard'
import { LoadingSpinner, useObservable, Button, Link, CardFooter, Alert } from '@sourcegraph/wildcard'
import { queryGraphQL } from '../../../backend/graphql'
import { formatUserCount } from '../../../productSubscription/helpers'
@ -165,7 +165,7 @@ export const ProductSubscriptionStatus: React.FunctionComponent<Props> = ({ clas
/>
) : (
license.userCount - actualUserCount < 0 && (
<div className="alert alert-warning">
<Alert variant="warning">
You have exceeded your licensed users.{' '}
<Link to="/site-admin/license">View your license details</Link> or{' '}
{/* eslint-disable-next-line react/jsx-no-target-blank */}
@ -173,7 +173,7 @@ export const ProductSubscriptionStatus: React.FunctionComponent<Props> = ({ clas
upgrade your license
</a>{' '}
to true up and prevent a retroactive charge.
</div>
</Alert>
)
))}
</div>

View File

@ -11,7 +11,7 @@ import { gql } from '@sourcegraph/http-client'
import { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import * as GQL from '@sourcegraph/shared/src/schema'
import { numberWithCommas } from '@sourcegraph/shared/src/util/strings'
import { LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { LoadingSpinner, useObservable, Alert } from '@sourcegraph/wildcard'
import { queryGraphQL } from '../../../backend/graphql'
import { formatUserCount, mailtoSales } from '../../../productSubscription/helpers'
@ -117,7 +117,7 @@ export const NewProductSubscriptionPaymentSection: React.FunctionComponent<Props
className="mb-2"
/>
{previewInvoice.isDowngradeRequiringManualIntervention ? (
<div className="alert alert-danger mb-2">
<Alert className="mb-2" variant="danger">
Self-service downgrades are not yet supported.{' '}
<a
href={mailtoSales({
@ -127,7 +127,7 @@ export const NewProductSubscriptionPaymentSection: React.FunctionComponent<Props
Contact sales
</a>{' '}
for help.
</div>
</Alert>
) : (
!isEqual(previewInvoice.beforeInvoiceItem, previewInvoice.afterInvoiceItem) && (
<div className="mb-2">Amount due: ${numberWithCommas(previewInvoice.price / 100)}</div>

View File

@ -27,7 +27,7 @@ exports[`NewProductSubscriptionPaymentSection downgrade to existing subscription
</li>
</ul>
<div
class="alert alert-danger mb-2"
class="mb-2"
>
Self-service downgrades are not yet supported.
<a

View File

@ -1,7 +1,7 @@
import * as H from 'history'
import React, { useEffect, useMemo } from 'react'
import { Container, PageHeader, LoadingSpinner, useObservable } from '@sourcegraph/wildcard'
import { Container, PageHeader, LoadingSpinner, useObservable, Alert } from '@sourcegraph/wildcard'
import { PageTitle } from '../../../../components/PageTitle'
import { Timestamp } from '../../../../components/time/Timestamp'
@ -45,14 +45,14 @@ export const UserSettingsPermissionsPage: React.FunctionComponent<{
/>
<Container className="mb-3">
{user.siteAdmin && !window.context.site['authz.enforceForSiteAdmins'] ? (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
Site admin can access all repositories in the Sourcegraph instance.
</div>
</Alert>
) : !permissionsInfo ? (
<div className="alert alert-info mb-0">
<Alert className="mb-0" variant="info">
This user is queued to sync permissions, it can only access non-private repositories until
syncing is finished.
</div>
</Alert>
) : (
<>
<table className="table">

View File

@ -14,7 +14,7 @@ import {
import { SettingsCascadeProps, SettingsSubject } from '@sourcegraph/shared/src/settings/settings'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { isEncodedImage } from '@sourcegraph/shared/src/util/icon'
import { useTimeoutManager, Link, CardBody, Card } from '@sourcegraph/wildcard'
import { useTimeoutManager, Link, CardBody, Card, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../auth'
@ -288,9 +288,9 @@ export const ExtensionCard = memo<Props>(function ExtensionCard({
{/* Visual feedback: alert when optimistic update fails */}
{optimisticFailure && (
<div className={classNames('alert alert-danger px-2 py-1', styles.alert)}>
<Alert className={classNames('px-2 py-1', styles.alert)} variant="danger">
<span className="font-weight-medium">Error:</span> {actionableErrorMessage(optimisticFailure.error)}
</div>
</Alert>
)}
</Card>
)

View File

@ -11,7 +11,7 @@ import { PlatformContextProps } from '@sourcegraph/shared/src/platform/context'
import { ExtensionCategory, EXTENSION_CATEGORIES } from '@sourcegraph/shared/src/schema/extensionSchema'
import { Settings, SettingsCascadeProps, SettingsCascadeOrError } from '@sourcegraph/shared/src/settings/settings'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { AlertLink, useLocalStorage, useEventObservable } from '@sourcegraph/wildcard'
import { AlertLink, useLocalStorage, useEventObservable, Alert } from '@sourcegraph/wildcard'
import { PageTitle } from '../components/PageTitle'
import {
@ -356,10 +356,10 @@ export const ExtensionRegistry: React.FunctionComponent<Props> = props => {
</div>
</Form>
{!authenticatedUser && (
<div className="alert alert-info my-4">
<Alert className="my-4" variant="info">
<span>An account is required to create, enable and disable extensions. </span>
<AlertLink to="/sign-up?returnTo=/extensions">Register now!</AlertLink>
</div>
</Alert>
)}
<ExtensionsList
{...props}

View File

@ -6,7 +6,7 @@ import { NavLink, RouteComponentProps } from 'react-router-dom'
import { isErrorLike } from '@sourcegraph/common'
import { isExtensionEnabled, splitExtensionID } from '@sourcegraph/shared/src/extensions/extension'
import { ExtensionManifest } from '@sourcegraph/shared/src/schema/extensionSchema'
import { PageHeader, AlertLink, useTimeoutManager } from '@sourcegraph/wildcard'
import { PageHeader, AlertLink, useTimeoutManager, Alert } from '@sourcegraph/wildcard'
import { NavItemWithIconDescriptor } from '../../util/contributions'
import { ExtensionToggle } from '../ExtensionToggle'
@ -102,20 +102,18 @@ export const ExtensionAreaHeader: React.FunctionComponent<ExtensionAreaHeaderPro
actions={
<div className={classNames('position-relative', styles.actions)}>
{change && (
<div
className={classNames(classNames('alert px-2 py-1 mb-0', styles.alert), {
'alert-secondary': change === 'disabled',
'alert-success': change === 'enabled',
})}
<Alert
variant={change === 'enabled' ? 'success' : 'secondary'}
className={classNames('px-2 py-1 mb-0', styles.alert)}
>
<span className="font-weight-medium">{name}</span> is {change}
</div>
</Alert>
)}
{showCta && (
<div className={classNames('alert alert-info mb-0 py-1', styles.alert)}>
<Alert className={classNames('mb-0 py-1', styles.alert)} variant="info">
An account is required to create and configure extensions.{' '}
<AlertLink to="/sign-up">Register now!</AlertLink>
</div>
</Alert>
)}
{/* If site admin, render user toggle and site toggle (both small) */}
{props.authenticatedUser?.siteAdmin && siteSubject?.subject ? (

View File

@ -7,7 +7,7 @@ import { RouteComponentProps } from 'react-router'
import { ConfiguredRegistryExtension } from '@sourcegraph/shared/src/extensions/extension'
import extensionSchemaJSON from '@sourcegraph/shared/src/schema/extension.schema.json'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { Button, Link } from '@sourcegraph/wildcard'
import { Button, Link, Alert } from '@sourcegraph/wildcard'
import { PageTitle } from '../../components/PageTitle'
import { DynamicallyImportedMonacoSettingsEditor } from '../../settings/DynamicallyImportedMonacoSettingsEditor'
@ -19,7 +19,7 @@ import styles from './RegistryExtensionManifestPage.module.scss'
export const ExtensionNoManifestAlert: React.FunctionComponent<{
extension: ConfiguredRegistryExtension
}> = ({ extension }) => (
<div className="alert alert-info">
<Alert variant="info">
This extension is not yet published.
{extension.registryExtension?.viewerCanAdminister && (
<>
@ -34,7 +34,7 @@ export const ExtensionNoManifestAlert: React.FunctionComponent<{
</Button>
</>
)}
</div>
</Alert>
)
interface Props extends ExtensionAreaRouteContext, RouteComponentProps<{}>, ThemeProps {}

View File

@ -1,11 +1,10 @@
import classNames from 'classnames'
import * as React from 'react'
import { isErrorLike } from '@sourcegraph/common'
import { Markdown } from '@sourcegraph/shared/src/components/Markdown'
import { ConfiguredRegistryExtension } from '@sourcegraph/shared/src/extensions/extension'
import { renderMarkdown } from '@sourcegraph/shared/src/util/markdown'
import { Button, Link } from '@sourcegraph/wildcard'
import { Button, Link, Alert } from '@sourcegraph/wildcard'
import { ExtensionNoManifestAlert } from './RegistryExtensionManifestPage'
@ -13,9 +12,9 @@ const PublishNewManifestAlert: React.FunctionComponent<{
extension: ConfiguredRegistryExtension
text: string
buttonLabel: string
alertClass: 'alert-info' | 'alert-danger'
}> = ({ extension, text, buttonLabel, alertClass }) => (
<div className={classNames('alert', alertClass)}>
alertVariant: 'info' | 'danger'
}> = ({ extension, text, buttonLabel, alertVariant }) => (
<Alert variant={alertVariant}>
{text}
{extension.registryExtension?.viewerCanAdminister && (
<>
@ -30,7 +29,7 @@ const PublishNewManifestAlert: React.FunctionComponent<{
</Button>
</>
)}
</div>
</Alert>
)
export const ExtensionReadme: React.FunctionComponent<{
@ -45,7 +44,7 @@ export const ExtensionReadme: React.FunctionComponent<{
return (
<PublishNewManifestAlert
extension={extension}
alertClass="alert-danger"
alertVariant="danger"
text={`This extension's manifest is invalid: ${
manifest?.message ? manifest.message : 'JSON parse error'
}`}
@ -58,7 +57,7 @@ export const ExtensionReadme: React.FunctionComponent<{
return (
<PublishNewManifestAlert
extension={extension}
alertClass="alert-info"
alertVariant="info"
text="This extension has no README."
buttonLabel="Add README and publish new release"
/>
@ -72,7 +71,7 @@ export const ExtensionReadme: React.FunctionComponent<{
return (
<PublishNewManifestAlert
extension={extension}
alertClass="alert-danger"
alertVariant="danger"
text="This extension's Markdown README is invalid."
buttonLabel="Fix README and publish new release"
/>

View File

@ -5,7 +5,7 @@ import { AlertType } from '@sourcegraph/shared/src/graphql-operations'
import * as GQL from '@sourcegraph/shared/src/schema'
import { renderMarkdown } from '@sourcegraph/shared/src/util/markdown'
import { DismissibleAlert } from '../components/DismissibleAlert'
import { DismissibleAlert, DismissibleAlertProps } from '../components/DismissibleAlert'
/**
* A global alert that is shown at the top of the viewport.
@ -15,10 +15,14 @@ export const GlobalAlert: React.FunctionComponent<{
className: string
}> = ({ alert, className: commonClassName }) => {
const content = <Markdown dangerousInnerHTML={renderMarkdown(alert.message)} />
const className = `${commonClassName} alert alert-${alertClassForType(alert.type)} d-flex`
const className = `${commonClassName} alert d-flex`
if (alert.isDismissibleWithKey) {
return (
<DismissibleAlert partialStorageKey={`alert.${alert.isDismissibleWithKey}`} className={className}>
<DismissibleAlert
partialStorageKey={`alert.${alert.isDismissibleWithKey}`}
className={className}
variant={alertVariantForType(alert.type)}
>
{content}
</DismissibleAlert>
)
@ -26,7 +30,7 @@ export const GlobalAlert: React.FunctionComponent<{
return <div className={className}>{content}</div>
}
function alertClassForType(type: AlertType): string {
function alertVariantForType(type: AlertType): DismissibleAlertProps['variant'] {
switch (type) {
case AlertType.INFO:
return 'info'

View File

@ -98,7 +98,8 @@ export class GlobalAlerts extends React.PureComponent<Props, State> {
<DismissibleAlert
key={motd}
partialStorageKey={`motd.${motd}`}
className={classNames('alert-info', styles.alert)}
variant="info"
className={styles.alert}
>
<Markdown dangerousInnerHTML={renderMarkdown(motd)} />
</DismissibleAlert>
@ -107,7 +108,8 @@ export class GlobalAlerts extends React.PureComponent<Props, State> {
<DismissibleAlert
key="dev-web-server-alert"
partialStorageKey="dev-web-server-alert"
className={classNames('alert-danger', styles.alert)}
variant="danger"
className={styles.alert}
>
<div>
<strong>Warning!</strong> This build uses data from the proxied API:{' '}

View File

@ -5,31 +5,36 @@ import { Markdown } from '@sourcegraph/shared/src/components/Markdown'
import { Notice, Settings } from '@sourcegraph/shared/src/schema/settings.schema'
import { isSettingsValid, SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { renderMarkdown } from '@sourcegraph/shared/src/util/markdown'
import { Alert, AlertProps } from '@sourcegraph/wildcard'
import { DismissibleAlert } from '../components/DismissibleAlert'
import styles from './Notices.module.scss'
const NoticeAlert: React.FunctionComponent<{ notice: Notice; className?: string; testId?: string }> = ({
notice,
className = '',
testId,
}) => {
const getAlertVariant = (location: Notice['location']): AlertProps['variant'] =>
location === 'top' ? 'info' : undefined
interface NoticeAlertProps {
notice: Notice
className?: string
testId?: string
}
const NoticeAlert: React.FunctionComponent<NoticeAlertProps> = ({ notice, className = '', testId }) => {
const content = <Markdown dangerousInnerHTML={renderMarkdown(notice.message)} />
const baseClassName = notice.location === 'top' ? 'alert-info' : 'bg-transparent border'
const sharedProps = {
'data-testid': testId,
variant: getAlertVariant(notice.location),
className: classNames(notice.location !== 'top' && 'bg transparent border', className),
}
return notice.dismissible ? (
<DismissibleAlert
data-testid={testId}
className={classNames(baseClassName, className)}
partialStorageKey={`notice.${notice.message}`}
>
<DismissibleAlert {...sharedProps} partialStorageKey={`notice.${notice.message}`}>
{content}
</DismissibleAlert>
) : (
<div data-testid={testId} className={classNames('alert', baseClassName, className)}>
{content}
</div>
<Alert {...sharedProps}>{content}</Alert>
)
}

View File

@ -8,7 +8,7 @@ exports[`Notices shows notices for location 1`] = `
class="notices"
>
<div
class="alert bg-transparent border"
class="bg transparent border"
data-testid="notice-alert"
>
<div
@ -22,7 +22,7 @@ exports[`Notices shows notices for location 1`] = `
</div>
</div>
<div
class="alert container bg-transparent border"
class="container bg transparent border"
>
<div
class="content"

View File

@ -9,7 +9,7 @@ import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { dataOrThrowErrors, gql } from '@sourcegraph/http-client'
import { OrganizationInvitationResponseType } from '@sourcegraph/shared/src/graphql-operations'
import * as GQL from '@sourcegraph/shared/src/schema'
import { LoadingSpinner, Button, Link } from '@sourcegraph/wildcard'
import { LoadingSpinner, Button, Link, Alert } from '@sourcegraph/wildcard'
import { orgURL } from '..'
import { refreshAuthenticatedUser, AuthenticatedUser } from '../../auth'
@ -172,9 +172,9 @@ export const OrgInvitationPage = withAuthenticatedUser(
</Form>
</ModalPage>
) : (
<div className="alert alert-danger align-self-start mt-4 mx-auto">
<Alert className="align-self-start mt-4 mx-auto" variant="danger">
No pending invitation found.
</div>
</Alert>
)}
</>
)

View File

@ -10,7 +10,7 @@ import { Form } from '@sourcegraph/branded/src/components/Form'
import { asError, createAggregateError, isErrorLike } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import { Scalars } from '@sourcegraph/shared/src/graphql-operations'
import { LoadingSpinner, Button, Link } from '@sourcegraph/wildcard'
import { LoadingSpinner, Button, Link, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../auth'
import { requestGraphQL } from '../../../backend/graphql'
@ -166,7 +166,7 @@ export const InviteForm: React.FunctionComponent<Props> = ({
</Form>
</div>
{authenticatedUser?.siteAdmin && !emailInvitesEnabled && (
<DismissibleAlert className="alert-info" partialStorageKey="org-invite-email-config">
<DismissibleAlert variant="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 notifications about invitations.
@ -177,7 +177,7 @@ export const InviteForm: React.FunctionComponent<Props> = ({
<InvitedNotification
key={invited.username}
{...invited}
className={classNames('alert alert-success', styles.alert)}
className={styles.alert}
onDismiss={dismissNotification}
/>
)}
@ -262,7 +262,7 @@ const InvitedNotification: React.FunctionComponent<InvitedNotificationProps> = (
invitationURL,
onDismiss,
}) => (
<div className={classNames(styles.invitedNotification, className)}>
<Alert variant="success" className={classNames(styles.invitedNotification, className)}>
<div className={styles.message}>
{sentInvitationEmail ? (
<>
@ -276,5 +276,5 @@ const InvitedNotification: React.FunctionComponent<InvitedNotificationProps> = (
<Button className="btn-icon" title="Dismiss" onClick={onDismiss}>
<CloseIcon className="icon-inline" />
</Button>
</div>
</Alert>
)

View File

@ -9,7 +9,7 @@ import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts'
import { asError, createAggregateError, ErrorLike, isErrorLike } from '@sourcegraph/common'
import { gql } from '@sourcegraph/http-client'
import * as GQL from '@sourcegraph/shared/src/schema'
import { Container, PageHeader, Button, Link } from '@sourcegraph/wildcard'
import { Container, PageHeader, Button, Link, Alert } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../../auth'
import { queryGraphQL } from '../../../backend/graphql'
@ -225,7 +225,7 @@ export class OrgSettingsMembersPage extends React.PureComponent<Props, State> {
<PageHeader path={[{ text: 'Organization members' }]} headingElement="h2" className="mb-3" />
<Container>
{this.state.onlyMemberRemovalAttempted && (
<div className="alert alert-warning">You cant remove the only member of an organization</div>
<Alert variant="warning">You cant remove the only member of an organization</Alert>
)}
{this.state.viewerCanAdminister && (
<InviteForm

View File

@ -1,18 +1,17 @@
import classNames from 'classnames'
import * as React from 'react'
import { Link } from '@sourcegraph/wildcard'
import { Link, Alert } from '@sourcegraph/wildcard'
export const DirectImportRepoAlert: React.FunctionComponent<{ className?: string }> = ({ className = '' }) => (
<>
{['dev', 'docker-container'].includes(window.context.deployType) && (
<div className={classNames('alert alert-info', className)}>
<Alert className={className} variant="info">
Very large repository? See{' '}
<Link to="/help/admin/repo/pre_load_from_local_disk#add-repositories-already-cloned-to-disk">
how to reuse an existing local clone
</Link>{' '}
to speed this up.
</div>
</Alert>
)}
</>
)

View File

@ -1,7 +1,7 @@
import CloseIcon from 'mdi-react/CloseIcon'
import React from 'react'
import { Button, AlertLink } from '@sourcegraph/wildcard'
import { Button, AlertLink, Alert } from '@sourcegraph/wildcard'
import { ExternalLinkFields, ExternalServiceKind } from '../../graphql-operations'
import { eventLogger } from '../../tracking/eventLogger'
@ -47,9 +47,10 @@ export const InstallBrowserExtensionAlert: React.FunctionComponent<Props> = ({
}
return (
<div
className="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
<Alert
className="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
variant="info"
>
<div className="d-flex align-items-center">
<p className="my-0 mr-3">
@ -115,7 +116,7 @@ export const InstallBrowserExtensionAlert: React.FunctionComponent<Props> = ({
<Button onClick={onAlertDismissed} aria-label="Close alert" className="btn-icon test-close-alert">
<CloseIcon className="icon-inline" />
</Button>
</div>
</Alert>
)
}
@ -132,7 +133,7 @@ export function isFirefoxCampaignActive(currentMs: number): boolean {
}
export const FirefoxAddonAlert: React.FunctionComponent<FirefoxAlertProps> = ({ onAlertDismissed, displayName }) => (
<div className="alert alert-info m-3 d-flex justify-content-between flex-shrink-0 percy-hide">
<Alert className="m-3 d-flex justify-content-between flex-shrink-0 percy-hide" variant="info">
<div>
<p className="font-weight-medium my-0 mr-3">
Sourcegraph is back at{' '}
@ -162,7 +163,7 @@ export const FirefoxAddonAlert: React.FunctionComponent<FirefoxAlertProps> = ({
<Button onClick={onAlertDismissed} aria-label="Close alert" className="btn-icon test-close-alert">
<CloseIcon className="icon-inline" />
</Button>
</div>
</Alert>
)
const onInstallLinkClick = (): void => {

View File

@ -3,7 +3,7 @@
exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -47,7 +47,7 @@ exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (native integration) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -100,7 +100,7 @@ exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (native integration) 1`] =
exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (non-Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -144,7 +144,7 @@ exports[`InstallBrowserExtensionAlert BITBUCKETSERVER (non-Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert GITHUB (Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -188,7 +188,7 @@ exports[`InstallBrowserExtensionAlert GITHUB (Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert GITHUB (native integration) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -241,7 +241,7 @@ exports[`InstallBrowserExtensionAlert GITHUB (native integration) 1`] = `
exports[`InstallBrowserExtensionAlert GITHUB (non-Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -285,7 +285,7 @@ exports[`InstallBrowserExtensionAlert GITHUB (non-Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert GITLAB (Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -329,7 +329,7 @@ exports[`InstallBrowserExtensionAlert GITLAB (Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert GITLAB (native integration) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -382,7 +382,7 @@ exports[`InstallBrowserExtensionAlert GITLAB (native integration) 1`] = `
exports[`InstallBrowserExtensionAlert GITLAB (non-Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -426,7 +426,7 @@ exports[`InstallBrowserExtensionAlert GITLAB (non-Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert PHABRICATOR (Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -470,7 +470,7 @@ exports[`InstallBrowserExtensionAlert PHABRICATOR (Chrome) 1`] = `
exports[`InstallBrowserExtensionAlert PHABRICATOR (native integration) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div
@ -523,7 +523,7 @@ exports[`InstallBrowserExtensionAlert PHABRICATOR (native integration) 1`] = `
exports[`InstallBrowserExtensionAlert PHABRICATOR (non-Chrome) 1`] = `
<DocumentFragment>
<div
class="alert alert-info m-3 d-flex justify-content-between flex-shrink-0"
class="m-3 d-flex justify-content-between flex-shrink-0"
data-testid="install-browser-extension-alert"
>
<div

View File

@ -18,7 +18,7 @@ import { SettingsCascadeProps } from '@sourcegraph/shared/src/settings/settings'
import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService'
import { ThemeProps } from '@sourcegraph/shared/src/theme'
import { AbsoluteRepoFile, ModeSpec, parseQueryAndHash } from '@sourcegraph/shared/src/util/url'
import { Button, LoadingSpinner, useEventObservable } from '@sourcegraph/wildcard'
import { Alert, Button, LoadingSpinner, useEventObservable } from '@sourcegraph/wildcard'
import { AuthenticatedUser } from '../../auth'
import { BreadcrumbSetters } from '../../components/Breadcrumbs'
@ -334,12 +334,12 @@ export const BlobPage: React.FunctionComponent<Props> = props => {
)}
{!blobInfoOrError.richHTML && blobInfoOrError.aborted && (
<div>
<div className="alert alert-info">
<Alert variant="info">
Syntax-highlighting this file took too long. &nbsp;
<Button onClick={onExtendTimeoutClick} variant="primary" size="sm">
Try again
</Button>
</div>
</Alert>
</div>
)}
{/* Render the (unhighlighted) blob also in the case highlighting timed out */}

Some files were not shown because too many files have changed in this diff Show More