+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { keyframes } from '@emotion/react';
-import styled from '@emotion/styled';
-import React, { DetailedHTMLProps, HTMLAttributes } from 'react';
-import { useIntl } from 'react-intl';
-import tw from 'twin.macro';
-import { themeColor } from '../helpers/theme';
-
-interface Props {
- ariaLabel?: string;
- children?: React.ReactNode;
- className?: string;
- customSpinner?: JSX.Element;
- loading?: boolean;
- placeholder?: boolean;
- timeout?: number;
-}
-
-interface State {
- showSpinner: boolean;
-}
-
-const DEFAULT_TIMEOUT = 100;
-
-export class DeferredSpinner extends React.PureComponent<Props, State> {
- timer?: number;
- static displayName = 'DeferredSpinner';
- state: State = { showSpinner: false };
-
- componentDidMount() {
- if (this.props.loading == null || this.props.loading) {
- this.startTimer();
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.loading === false && this.props.loading === true) {
- this.stopTimer();
- this.startTimer();
- }
- if (prevProps.loading === true && this.props.loading === false) {
- this.stopTimer();
- this.setState({ showSpinner: false });
- }
- }
-
- componentWillUnmount() {
- this.stopTimer();
- }
-
- startTimer = () => {
- this.timer = window.setTimeout(() => {
- this.setState({ showSpinner: true });
- }, this.props.timeout ?? DEFAULT_TIMEOUT);
- };
-
- stopTimer = () => {
- window.clearTimeout(this.timer);
- };
-
- render() {
- const { showSpinner } = this.state;
- const { customSpinner, className, children, placeholder, ariaLabel } = this.props;
- if (showSpinner) {
- if (customSpinner) {
- return customSpinner;
- }
- // Overwrite aria-label only if defined
- return <Spinner {...(ariaLabel ? { 'aria-label': ariaLabel } : {})} className={className} />;
- }
- if (children) {
- return children;
- }
- if (placeholder) {
- return <Placeholder className={className} />;
- }
- return null;
- }
-}
-
-const spinAnimation = keyframes`
- from {
- transform: rotate(0deg);
- }
-
- to {
- transform: rotate(-360deg);
- }
-`;
-
-/* Exported to allow styles to be overridden */
-export const StyledSpinner = styled.div`
- border: 2px solid transparent;
- background: linear-gradient(0deg, ${themeColor('primary')} 50%, transparent 50% 100%) border-box,
- linear-gradient(90deg, ${themeColor('primary')} 25%, transparent 75% 100%) border-box;
- mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
- -webkit-mask-composite: xor;
- mask-composite: exclude;
- animation: ${spinAnimation} 1s infinite linear;
-
- ${tw`sw-h-4 sw-w-4`};
- ${tw`sw-inline-block`};
- ${tw`sw-box-border`};
- ${tw`sw-rounded-pill`}
-`;
-
-export function Spinner(props: DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>) {
- const intl = useIntl();
-
- return (
- <StyledSpinner aria-label={intl.formatMessage({ id: 'loading' })} role="status" {...props} />
- );
-}
-
-const Placeholder = styled.div`
- position: relative;
- visibility: hidden;
-
- ${tw`sw-inline-flex sw-items-center sw-justify-center`};
- ${tw`sw-h-4 sw-w-4`};
-`;
import tw from 'twin.macro';
import { themeColor } from '../helpers';
import { Badge } from './Badge';
-import { DeferredSpinner } from './DeferredSpinner';
import { DestructiveIcon } from './InteractiveIcon';
+import { Spinner } from './Spinner';
import Tooltip from './Tooltip';
import { BareButton } from './buttons';
import { OpenCloseIndicator } from './icons';
<HeaderTitle disabled={disabled}>{name}</HeaderTitle>
</ChevronAndTitle>
- {<DeferredSpinner loading={loading} />}
+ {<Spinner loading={loading} />}
{counter > 0 && (
<BadgeAndIcons>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { keyframes } from '@emotion/react';
+import styled from '@emotion/styled';
+import classNames from 'classnames';
+import * as React from 'react';
+import { useIntl } from 'react-intl';
+import tw from 'twin.macro';
+import { themeColor } from '../helpers/theme';
+
+interface Props {
+ ariaLabel?: string;
+ className?: string;
+ customSpinner?: JSX.Element;
+ loading?: boolean;
+ placeholder?: boolean;
+}
+
+export function Spinner(props: React.PropsWithChildren<Props>) {
+ const intl = useIntl();
+ const {
+ customSpinner,
+ className,
+ children,
+ placeholder,
+ ariaLabel = intl.formatMessage({ id: 'loading' }),
+ loading = true,
+ } = props;
+
+ if (customSpinner) {
+ return <>{loading ? customSpinner : children}</>;
+ }
+
+ return (
+ <>
+ <div className="sw-overflow-hidden">
+ <StyledSpinner
+ aria-live="polite"
+ className={classNames(className, { 'a11y-hidden': !loading })}
+ role="status"
+ >
+ {loading && <span className="a11y-hidden">{ariaLabel}</span>}
+ </StyledSpinner>
+ </div>
+ {!loading && (children ?? (placeholder && <Placeholder className={className} />) ?? null)}
+ </>
+ );
+}
+
+const spinAnimation = keyframes`
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(-360deg);
+ }
+`;
+
+export const StyledSpinner = styled.div`
+ border: 2px solid transparent;
+ background: linear-gradient(0deg, ${themeColor('primary')} 50%, transparent 50% 100%) border-box,
+ linear-gradient(90deg, ${themeColor('primary')} 25%, transparent 75% 100%) border-box;
+ mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ animation: ${spinAnimation} 1s infinite linear;
+
+ ${tw`sw-h-4 sw-w-4`};
+ ${tw`sw-inline-block`};
+ ${tw`sw-box-border`};
+ ${tw`sw-rounded-pill`}
+`;
+
+const Placeholder = styled.div`
+ position: relative;
+ visibility: hidden;
+
+ ${tw`sw-inline-flex sw-items-center sw-justify-center`};
+ ${tw`sw-h-4 sw-w-4`};
+`;
*/
import { screen } from '@testing-library/react';
-import { render } from '../../helpers/testUtils';
+import { renderWithContext } from '../../helpers/testUtils';
import { FCProps } from '../../types/misc';
import { ColorsLegend } from '../ColorsLegend';
});
function renderColorLegend(props: Partial<FCProps<typeof ColorsLegend>> = {}) {
- return render(<ColorsLegend colors={colors} onColorClick={jest.fn()} {...props} />);
+ return renderWithContext(<ColorsLegend colors={colors} onColorClick={jest.fn()} {...props} />);
}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { render, screen } from '@testing-library/react';
-import { IntlWrapper } from '../../helpers/testUtils';
-import { DeferredSpinner } from '../DeferredSpinner';
-
-beforeEach(() => {
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('renders children before timeout', () => {
- renderDeferredSpinner({ children: <a href="#">foo</a> });
- expect(screen.getByRole('link')).toBeInTheDocument();
- jest.runAllTimers();
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
-});
-
-it('renders spinner after timeout', () => {
- renderDeferredSpinner();
- expect(screen.queryByLabelText('loading')).not.toBeInTheDocument();
- jest.runAllTimers();
- expect(screen.getByLabelText('loading')).toBeInTheDocument();
-});
-
-it('allows setting a custom class name', () => {
- renderDeferredSpinner({ className: 'foo' });
- jest.runAllTimers();
- expect(screen.getByLabelText('loading')).toHaveClass('foo');
-});
-
-it('can be controlled by the loading prop', () => {
- const { rerender } = renderDeferredSpinner({ loading: true });
- jest.runAllTimers();
- expect(screen.getByLabelText('loading')).toBeInTheDocument();
-
- rerender(prepareDeferredSpinner({ loading: false }));
- expect(screen.queryByLabelText('loading')).not.toBeInTheDocument();
-});
-
-function renderDeferredSpinner(props: Partial<DeferredSpinner['props']> = {}) {
- // We don't use our renderComponent() helper here, as we have some tests that
- // require changes in props.
- return render(prepareDeferredSpinner(props));
-}
-
-function prepareDeferredSpinner(props: Partial<DeferredSpinner['props']> = {}) {
- return (
- <IntlWrapper>
- <DeferredSpinner {...props} />
- </IntlWrapper>
- );
-}
import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { render } from '../../helpers/testUtils';
+import { renderWithContext } from '../../helpers/testUtils';
import { FacetBox, FacetBoxProps } from '../FacetBox';
it('should render an empty disabled facet box', async () => {
});
function renderComponent({ children, ...props }: Partial<FacetBoxProps> = {}) {
- return render(
+ return renderWithContext(
<FacetBox name="Test FacetBox" {...props}>
{children}
</FacetBox>
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { render, screen } from '@testing-library/react';
+import { IntlWrapper } from '../../helpers/testUtils';
+import { Spinner } from '../Spinner';
+
+it('allows setting a custom class name', () => {
+ renderSpinner({ className: 'foo' });
+ expect(screen.getByRole('status')).toHaveClass('foo');
+});
+
+it('can be controlled by the loading prop', () => {
+ const { rerender } = renderSpinner({ loading: true });
+ expect(screen.getByText('loading')).toBeInTheDocument();
+
+ rerender(prepareSpinner({ loading: false }));
+ expect(screen.queryByText('loading')).not.toBeInTheDocument();
+});
+
+function renderSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
+ // We don't use our renderComponent() helper here, as we have some tests that
+ // require changes in props.
+ return render(prepareSpinner(props));
+}
+
+function prepareSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
+ return (
+ <IntlWrapper>
+ <Spinner {...props} />
+ </IntlWrapper>
+ );
+}
/* eslint-disable import/no-extraneous-dependencies */
-import { render, screen } from '@testing-library/react';
+import { screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { useState } from 'react';
+import { renderWithContext } from '../../helpers/testUtils';
import { FCProps } from '../../types/misc';
import { Tags } from '../Tags';
import { TagsSelector } from '../TagsSelector';
});
function renderTags(overrides: Partial<FCProps<typeof Tags>> = {}) {
- render(<Wrapper {...overrides} />);
+ renderWithContext(<Wrapper {...overrides} />);
}
function Wrapper(overrides: Partial<FCProps<typeof Tags>> = {}) {
export * from './CodeSyntaxHighlighter';
export * from './ColorsLegend';
export * from './CoverageIndicator';
-export { DeferredSpinner, Spinner } from './DeferredSpinner';
export { ActionsDropdown, Dropdown } from './Dropdown';
export * from './DropdownMenu';
export { DropdownToggler } from './DropdownToggler';
export * from './SizeIndicator';
export * from './SonarCodeColorizer';
export * from './SonarQubeLogo';
+export { Spinner } from './Spinner';
export * from './Table';
export * from './Tags';
export * from './TagsSelector';
*/
import styled from '@emotion/styled';
+import { Spinner } from 'design-system/src/components/Spinner';
import React from 'react';
import tw from 'twin.macro';
import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
-import { DeferredSpinner } from '../DeferredSpinner';
import { CheckIcon } from '../icons/CheckIcon';
import { CustomIcon } from '../icons/Icon';
onFocus={onFocus}
type="checkbox"
/>
- <DeferredSpinner loading={loading}>
+ {!loading && (
<StyledCheckbox aria-hidden data-clickable="true" title={title}>
<CheckboxIcon checked={checked} thirdState={thirdState} />
</StyledCheckbox>
- </DeferredSpinner>
+ )}
+ <Spinner loading={loading} />
{!right && children}
</CheckboxContainer>
);
</CustomIcon>
);
} else if (checked) {
- return <CheckIcon fill="currentColor" />;
+ return <CheckIcon fill="buttonSecondary" />;
}
return null;
}
import { themeBorder, themeColor, themeContrast } from '../../helpers/theme';
import { isDefined } from '../../helpers/types';
import { InputSizeKeys } from '../../types/theme';
-import { DeferredSpinner, StyledSpinner } from '../DeferredSpinner';
import { InteractiveIcon } from '../InteractiveIcon';
+import { Spinner, StyledSpinner } from '../Spinner';
import { CloseIcon } from '../icons/CloseIcon';
import { SearchIcon } from '../icons/SearchIcon';
value={value}
/>
)}
- <DeferredSpinner className="sw-z-normal" loading={loading ?? false}>
+ <Spinner className="sw-z-normal" loading={loading ?? false}>
<StyledSearchIcon />
- </DeferredSpinner>
+ </Spinner>
{value && (
<StyledInteractiveIcon
Icon={CloseIcon}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { screen, waitFor } from '@testing-library/react';
-import { render } from '../../../helpers/testUtils';
+import { renderWithContext } from '../../../helpers/testUtils';
import { FCProps } from '../../../types/misc';
import { InputSearch } from '../InputSearch';
});
function setupWithProps(props: Partial<FCProps<typeof InputSearch>> = {}) {
- return render(
+ return renderWithContext(
<InputSearch
clearIconAriaLabel=""
maxLength={150}
import styled from '@emotion/styled';
import tw from 'twin.macro';
-import { DeferredSpinner } from '../DeferredSpinner';
+import { Spinner } from '../Spinner';
interface Props {
loading?: boolean;
export function ModalFooter({ loading = false, primaryButton, secondaryButton }: Props) {
return (
<StyledFooter>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{primaryButton}
{secondaryButton}
</StyledFooter>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { render } from '../../../helpers/testUtils';
+import { renderWithContext } from '../../../helpers/testUtils';
import { FCProps } from '../../../types/misc';
import { ModalFooter } from '../ModalFooter';
});
function setupWithProps(props: Partial<FCProps<typeof ModalFooter>> = {}) {
- return render(<ModalFooter secondaryButton={<div />} {...props} />);
+ return renderWithContext(<ModalFooter secondaryButton={<div />} {...props} />);
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render with primary and secondary buttons 1`] = `
+@keyframes animation-0 {
+ from {
+ -webkit-transform: rotate(0deg);
+ -moz-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+
+ to {
+ -webkit-transform: rotate(-360deg);
+ -moz-transform: rotate(-360deg);
+ -ms-transform: rotate(-360deg);
+ transform: rotate(-360deg);
+ }
+}
+
.emotion-0 {
display: -webkit-box;
display: -webkit-flex;
gap: 0.75rem;
}
+.emotion-2 {
+ border: 2px solid transparent;
+ background: linear-gradient(0deg, rgb(93,108,208) 50%, transparent 50% 100%) border-box,linear-gradient(90deg, rgb(93,108,208) 25%, transparent 75% 100%) border-box;
+ -webkit-mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ -webkit-mask-composite: exclude;
+ mask-composite: exclude;
+ -webkit-animation: animation-0 1s infinite linear;
+ animation: animation-0 1s infinite linear;
+ height: 1rem;
+ width: 1rem;
+ display: inline-block;
+ box-sizing: border-box;
+ border-radius: 625rem;
+}
+
<div>
<div
class="emotion-0 emotion-1"
>
+ <div
+ class="sw-overflow-hidden"
+ >
+ <div
+ aria-live="polite"
+ class="a11y-hidden emotion-2 emotion-3"
+ role="status"
+ />
+ </div>
<button
type="button"
>
`;
exports[`should render with secondary button 1`] = `
+@keyframes animation-0 {
+ from {
+ -webkit-transform: rotate(0deg);
+ -moz-transform: rotate(0deg);
+ -ms-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+
+ to {
+ -webkit-transform: rotate(-360deg);
+ -moz-transform: rotate(-360deg);
+ -ms-transform: rotate(-360deg);
+ transform: rotate(-360deg);
+ }
+}
+
.emotion-0 {
display: -webkit-box;
display: -webkit-flex;
gap: 0.75rem;
}
+.emotion-2 {
+ border: 2px solid transparent;
+ background: linear-gradient(0deg, rgb(93,108,208) 50%, transparent 50% 100%) border-box,linear-gradient(90deg, rgb(93,108,208) 25%, transparent 75% 100%) border-box;
+ -webkit-mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) padding-box,linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ -webkit-mask-composite: exclude;
+ mask-composite: exclude;
+ -webkit-animation: animation-0 1s infinite linear;
+ animation: animation-0 1s infinite linear;
+ height: 1rem;
+ width: 1rem;
+ display: inline-block;
+ box-sizing: border-box;
+ border-radius: 625rem;
+}
+
<div>
<div
class="emotion-0 emotion-1"
>
+ <div
+ class="sw-overflow-hidden"
+ >
+ <div
+ aria-live="polite"
+ class="a11y-hidden emotion-2 emotion-3"
+ role="status"
+ />
+ </div>
<button
type="button"
>
{
code: `function MyCompontent({ loading }) {
return <>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
</>
}`,
},
{
code: `function MyCompontent({ loading }) {
return <>
- {loading && <DeferredSpinner />}
+ {loading && <Spinner />}
</>
}`,
errors: [{ messageId: 'noConditionalRenderingOfDeferredSpinner' }],
{
code: `function MyComponent({ loading }) {
return <>
- {loading ? <DeferredSpinner /> : <div />}
+ {loading ? <Spinner /> : <div />}
</>
}`,
errors: [{ messageId: 'noConditionalRenderingOfDeferredSpinner' }],
{
code: `function MyCompontent({ loaded }) {
return <>
- {loaded ? <div /> : <DeferredSpinner />}
+ {loaded ? <div /> : <Spinner />}
</>
}`,
errors: [{ messageId: 'noConditionalRenderingOfDeferredSpinner' }],
meta: {
messages: {
noConditionalRenderingOfDeferredSpinner:
- 'For accessibility reasons, you should not conditionally render a <DeferredSpinner />. Always render it, and pass a loading prop instead.',
+ 'For accessibility reasons, you should not conditionally render a <Spinner />. Always render it, and pass a loading prop instead.',
},
},
create(context) {
return (
element.type === 'JSXElement' &&
element.openingElement &&
- element.openingElement.name.name === 'DeferredSpinner'
+ element.openingElement.name.name === 'Spinner'
);
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import classNames from 'classnames';
-import { DeferredSpinner, ItemButton } from 'design-system';
+import { ItemButton, Spinner } from 'design-system';
import * as React from 'react';
import { translate } from '../../../helpers/l10n';
this.handleMouseEnter(qualifier);
}}
>
- <DeferredSpinner loading={loadingMore === qualifier}>
- {translate('show_more')}
- </DeferredSpinner>
+ <Spinner loading={loadingMore === qualifier}>{translate('show_more')}</Spinner>
</ItemButton>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, FlagMessage, Link } from 'design-system';
+import { FlagMessage, Link, Spinner } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import { useBranchWarrningQuery } from '../../../../queries/branch';
if (isInProgress || isPending) {
return (
<div className="sw-flex sw-items-center">
- <DeferredSpinner timeout={0} />
+ <Spinner />
<span className="sw-ml-1">
{isInProgress
? translate('project_navigation.analysis_status.in_progress')
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import {
- DangerButtonSecondary,
- DeferredSpinner,
- FlagMessage,
- HtmlFormatter,
- Modal,
-} from 'design-system';
+import { DangerButtonSecondary, FlagMessage, HtmlFormatter, Modal, Spinner } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import { sanitizeStringRestricted } from '../../../../helpers/sanitize';
{translate('dismiss_permanently')}
</DangerButtonSecondary>
- <DeferredSpinner
- className="sw-ml-2"
- loading={isLoading && variables?.key === key}
- />
+ <Spinner className="sw-ml-2" loading={isLoading && variables?.key === key} />
</div>
)}
</div>
.a11y-hidden {
position: absolute !important;
left: -10000px !important;
- top: auto !important;
+ top: 0 !important;
width: 1px !important;
height: 1px !important;
overflow: hidden !important;
renderAccountApp(mockLoggedInUser(), notificationsPagePath);
await user.click(
- screen.getByRole('button', { name: 'my_profile.per_project_notifications.add' })
+ await screen.findByRole('button', { name: 'my_profile.per_project_notifications.add' })
);
expect(screen.getByLabelText('search.placeholder', { selector: 'input' })).toBeInTheDocument();
await user.keyboard('sonarqube');
WithNotificationsProps,
} from '../../../components/hoc/withNotifications';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import GlobalNotifications from './GlobalNotifications';
import Projects from './Projects';
<div className="account-body account-container">
<Helmet defer={false} title={translate('my_account.notifications')} />
<Alert variant="info">{translate('notification.dispatcher.information')}</Alert>
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{notifications && (
<>
<GlobalNotifications
/>
</>
)}
- </DeferredSpinner>
+ </Spinner>
</div>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import {
- DangerButtonSecondary,
- DeferredSpinner,
- FlagMessage,
- HtmlFormatter,
- Modal,
-} from 'design-system';
+import { DangerButtonSecondary, FlagMessage, HtmlFormatter, Modal, Spinner } from 'design-system';
import * as React from 'react';
import { dismissAnalysisWarning, getTask } from '../../../api/ce';
import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
const header = translate('warnings');
const body = (
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{warnings.map(({ dismissable, key, message }) => (
<React.Fragment key={key}>
<div className="sw-flex sw-items-center sw-mt-2">
{translate('dismiss_permanently')}
</DangerButtonSecondary>
- <DeferredSpinner className="sw-ml-2" loading={dismissedWarning === key} />
+ <Spinner className="sw-ml-2" loading={dismissedWarning === key} />
</div>
)}
</div>
</React.Fragment>
))}
- </DeferredSpinner>
+ </Spinner>
);
return (
import ListFooter from '../../../components/controls/ListFooter';
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { toShortISO8601String } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import { parseAsDate } from '../../../helpers/query';
return (
<div className="page page-limited">
<Helmet defer={false} title={translate('background_tasks.page')} />
- <DeferredSpinner loading />
+ <Spinner />
</div>
);
}
*/
import {
Card,
- DeferredSpinner,
FlagMessage,
HelperHintIcon,
KeyboardHint,
LargeCenteredLayout,
LightLabel,
+ Spinner,
} from 'design-system';
import { intersection } from 'lodash';
import * as React from 'react';
{(showComponentList || showSearch) && (
<Card className="sw-mt-2">
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{showComponentList && (
<Components
baseComponent={baseComponent}
selected={highlighted}
/>
)}
- </DeferredSpinner>
+ </Spinner>
</Card>
)}
import * as React from 'react';
import { getTree } from '../../../api/components';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { KeyboardKeys } from '../../../helpers/keycodes';
import { translate } from '../../../helpers/l10n';
size="large"
value={this.state.query}
/>
- <DeferredSpinner className="sw-ml-2" loading={loading} />
+ <Spinner className="sw-ml-2" loading={loading} />
</div>
);
}
import ConfirmButton from '../../../components/controls/ConfirmButton';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import { Button } from '../../../components/controls/buttons';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Dict, RuleActivation, RuleDetails as TypeRuleDetails } from '../../../types/types';
import { Activation, Query } from '../query';
return (
<div className="coding-rule-details">
- <DeferredSpinner loading={this.state.loading}>
+ <Spinner loading={this.state.loading}>
<RuleDetailsMeta
canWrite={canWrite}
onFilterChange={this.props.onFilterChange}
{!ruleDetails.isTemplate && ruleDetails.type !== 'SECURITY_HOTSPOT' && (
<RuleDetailsIssues ruleDetails={ruleDetails} />
)}
- </DeferredSpinner>
+ </Spinner>
</div>
);
}
import ConfirmButton from '../../../components/controls/ConfirmButton';
import { Button } from '../../../components/controls/buttons';
import SeverityHelper from '../../../components/shared/SeverityHelper';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getRuleUrl } from '../../../helpers/urls';
import { Rule, RuleDetails } from '../../../types/types';
</CustomRuleButton>
)}
- <DeferredSpinner className="spacer-left" loading={loading}>
+ <Spinner className="spacer-left" loading={loading}>
{rules.length > 0 && (
<table className="coding-rules-detail-list" id="coding-rules-detail-custom-rules">
<tbody>{sortBy(rules, (rule) => rule.name).map(this.renderRule)}</tbody>
</table>
)}
- </DeferredSpinner>
+ </Spinner>
</div>
</div>
);
} from '../../../app/components/available-features/withAvailableFeatures';
import Link from '../../../components/common/Link';
import Tooltip from '../../../components/controls/Tooltip';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
import { getIssuesUrl } from '../../../helpers/urls';
return (
<div className="js-rule-issues coding-rule-section">
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<h2 className="coding-rules-detail-title">
{translate('coding_rules.issues')}
{this.renderTotal()}
{translate('coding_rules.no_issue_detected_for_projects')}
</div>
)}
- </DeferredSpinner>
+ </Spinner>
</div>
);
}
import ListStyleFacet from '../../../components/facet/ListStyleFacet';
import ListStyleFacetFooter from '../../../components/facet/ListStyleFacetFooter';
import MultipleSelectionHint from '../../../components/facet/MultipleSelectionHint';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { highlightTerm } from '../../../helpers/search';
import {
const values = this.props[valuesProp];
if (!stats) {
- return <DeferredSpinner className="sw-ml-4" />;
+ return <Spinner className="sw-ml-4" />;
}
const categories = sortBy(Object.keys(stats), (key) => -stats[key]);
const values = this.props.sonarsourceSecurity;
if (!stats) {
- return <DeferredSpinner className="sw-ml-4" />;
+ return <Spinner className="sw-ml-4" />;
}
const sortedItems = sortBy(
import { withTheme } from '@emotion/react';
import styled from '@emotion/styled';
import {
- DeferredSpinner,
LargeCenteredLayout,
Note,
PageContentFontWrapper,
+ Spinner,
themeBorder,
themeColor,
} from 'design-system';
<Suggestions suggestions="component_measures" />
<Helmet defer={false} title={translate('layout.measures')} />
<PageContentFontWrapper>
- <DeferredSpinner
- className="my-10 sw-flex sw-content-center"
- loading={this.state.loading}
- />
+ <Spinner className="my-10 sw-flex sw-content-center" loading={this.state.loading} />
{measures.length > 0 ? (
<div className="sw-grid sw-grid-cols-12 sw-w-full">
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner } from 'design-system';
+import { Spinner } from 'design-system';
import * as React from 'react';
import { getComponentLeaves } from '../../../api/components';
import SourceViewer from '../../../components/SourceViewer/SourceViewer';
/>
<div className="sw-p-6">
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{!loading && this.renderContent(isFileComponent)}
</div>
</div>
*/
import {
ButtonPrimary,
- DeferredSpinner,
+ Spinner,
FlagErrorIcon,
FlagMessage,
FormField,
} = usePersonalAccessToken(almSetting, resetPat, onPersonalAccessTokenCreate);
if (checkingPat) {
- return <DeferredSpinner className="sw-ml-2" loading />;
+ return <Spinner className="sw-ml-2" loading />;
}
const isInvalid = (validationFailed && !touched) || (touched && !password);
<ButtonPrimary type="submit" disabled={isInvalid || submitting || !touched}>
{translate('save')}
</ButtonPrimary>
- <DeferredSpinner className="sw-ml-2" loading={submitting} />
+ <Spinner className="sw-ml-2" loading={submitting} />
</div>
</form>
);
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { Accordion, DeferredSpinner, FlagMessage, Link, SearchHighlighter } from 'design-system';
+import { Accordion, Spinner, FlagMessage, Link, SearchHighlighter } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import ListFooter from '../../../../components/controls/ListFooter';
>
{/* eslint-disable-next-line local-rules/no-conditional-rendering-of-deferredspinner*/}
{open && (
- <DeferredSpinner loading={loading}>
- {/* The extra loading guard is to prevent the flash of the Alert */}
- {!loading && repositories.length === 0 ? (
+ <Spinner loading={loading}>
+ {repositories.length === 0 ? (
<FlagMessage variant="warning">
<span>
<FormattedMessage
/>
</>
)}
- </DeferredSpinner>
+ </Spinner>
)}
</Accordion>
);
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import {
- DeferredSpinner,
FlagMessage,
InputSearch,
LightPrimary,
Link,
PageContentFontWrapper,
+ Spinner,
Title,
} from 'design-system';
import * as React from 'react';
onChangeConfig={props.onSelectedAlmInstanceChange}
/>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{showUrlError && (
<FlagMessage variant="error" className="sw-mb-2">
size="full"
/>
</div>
- <DeferredSpinner loading={Boolean(searching)}>
+ <Spinner loading={Boolean(searching)}>
<AzureProjectsList
loadingRepositories={loadingRepositories}
onOpenProject={props.onOpenProject}
searchResults={searchResults}
searchQuery={searchQuery}
/>
- </DeferredSpinner>
+ </Spinner>
</>
))}
</PageContentFontWrapper>
import {
ButtonPrimary,
- DeferredSpinner,
FlagErrorIcon,
FlagMessage,
FormField,
InputField,
LightPrimary,
Link,
+ Spinner,
} from 'design-system';
import React from 'react';
import { FormattedMessage } from 'react-intl';
} = usePersonalAccessToken(almSetting, resetPat, onPersonalAccessTokenCreated);
if (checkingPat) {
- return <DeferredSpinner className="sw-ml-2" loading />;
+ return <Spinner className="sw-ml-2" loading />;
}
const isInvalid = validationFailed && !touched;
<ButtonPrimary type="submit" disabled={submitButtonDiabled} className="sw-mb-6">
{translate('save')}
</ButtonPrimary>
- <DeferredSpinner className="sw-ml-2" loading={submitting} />
+ <Spinner className="sw-ml-2" loading={submitting} />
</form>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, LightPrimary, Title } from 'design-system';
+import { LightPrimary, Spinner, Title } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import { BitbucketCloudRepository } from '../../../../types/alm-integration';
onChangeConfig={props.onSelectedAlmInstanceChange}
/>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{!loading && !selectedAlmInstance && (
<WrongBindingCountAlert alm={AlmKeys.BitbucketCloud} canAdmin={!!canAdmin} />
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, LightPrimary, PageContentFontWrapper, Title } from 'design-system';
+import { LightPrimary, PageContentFontWrapper, Spinner, Title } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import {
onChangeConfig={props.onSelectedAlmInstanceChange}
/>
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{!loading && !selectedAlmInstance && (
<WrongBindingCountAlert alm={AlmKeys.BitbucketServer} canAdmin={!!canAdmin} />
)}
onImportRepository={props.onImportRepository}
/>
))}
- </DeferredSpinner>
+ </Spinner>
</PageContentFontWrapper>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, FlagMessage } from 'design-system';
+import { FlagMessage, Spinner } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import { BitbucketProject, BitbucketRepository } from '../../../../types/alm-integration';
);
return (
- <DeferredSpinner loading={searching}>
+ <Spinner loading={searching}>
{filteredSearchResults.length > 0 && (
<BitbucketProjectAccordion
onImportRepository={props.onImportRepository}
/>
);
})}
- </DeferredSpinner>
+ </Spinner>
);
}
import {
ButtonPrimary,
- DeferredSpinner,
FlagErrorIcon,
FlagMessage,
FormField,
InputField,
LightPrimary,
Link,
+ Spinner,
} from 'design-system';
import React from 'react';
import { FormattedMessage } from 'react-intl';
} = usePersonalAccessToken(almSetting, resetPat, onPersonalAccessTokenCreated);
if (checkingPat) {
- return <DeferredSpinner className="sw-ml-2" loading />;
+ return <Spinner className="sw-ml-2" loading />;
}
const { url } = almSetting;
<ButtonPrimary type="submit" disabled={submitButtonDiabled} className="sw-mb-6">
{translate('save')}
</ButtonPrimary>
- <DeferredSpinner className="sw-ml-2" loading={submitting} />
+ <Spinner className="sw-ml-2" loading={submitting} />
</form>
);
}
/* eslint-disable react/no-unused-prop-types */
import {
ButtonSecondary,
- DeferredSpinner,
GreyCard,
HelperHintIcon,
LightPrimary,
+ Spinner,
StandoutLink,
TextMuted,
Title,
)}
</div>
- <DeferredSpinner loading={loadingBindings}>
+ <Spinner loading={loadingBindings}>
{!hasConfig &&
(canAdmin ? (
<ButtonSecondary onClick={() => props.onConfigMode(configMode)}>
<HelperHintIcon aria-label="help-tooltip" />
</HelpTooltip>
))}
- </DeferredSpinner>
+ </Spinner>
</GreyCard>
);
}
import {
DarkLabel,
- DeferredSpinner,
FlagMessage,
InputSearch,
InputSelect,
LightPrimary,
Link,
+ Spinner,
Title,
} from 'design-system';
import * as React from 'react';
} = props;
if (loadingBindings) {
- return <DeferredSpinner />;
+ return <Spinner />;
}
return (
</FlagMessage>
)}
- <DeferredSpinner loading={loadingOrganizations && !error}>
+ <Spinner loading={loadingOrganizations && !error}>
{!error && (
<div className="sw-flex sw-flex-col">
<DarkLabel htmlFor="github-choose-organization" className="sw-mb-2">
)}
</div>
)}
- </DeferredSpinner>
+ </Spinner>
{renderRepositoryList(props)}
</>
import {
ButtonPrimary,
- DeferredSpinner,
FlagErrorIcon,
FlagMessage,
FormField,
InputField,
LightPrimary,
Link,
+ Spinner,
} from 'design-system';
import React from 'react';
import { FormattedMessage } from 'react-intl';
} = usePersonalAccessToken(almSetting, resetPat, onPersonalAccessTokenCreated);
if (checkingPat) {
- return <DeferredSpinner className="sw-ml-2" loading />;
+ return <Spinner className="sw-ml-2" loading />;
}
const isInvalid = validationFailed && !touched;
<ButtonPrimary type="submit" disabled={submitButtonDiabled} className="sw-mb-6">
{translate('save')}
</ButtonPrimary>
- <DeferredSpinner className="sw-ml-2" loading={submitting} />
+ <Spinner className="sw-ml-2" loading={submitting} />
</form>
);
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, LightPrimary, Title } from 'design-system';
+import { LightPrimary, Spinner, Title } from 'design-system';
import * as React from 'react';
import { translate } from '../../../../helpers/l10n';
import { GitlabProject } from '../../../../types/alm-integration';
onChangeConfig={props.onSelectedAlmInstanceChange}
/>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{!loading && !selectedAlmInstance && (
<WrongBindingCountAlert alm={AlmKeys.GitLab} canAdmin={!!canAdmin} />
await selectEvent.select(ui.instanceSelector.get(), [/conf-github-1/]);
expect(window.location.replace).toHaveBeenCalled();
- expect(
- screen.getByText('onboarding.create_project.github.choose_organization')
- ).toBeInTheDocument();
});
it('should not redirect to github when url is malformated', async () => {
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { ButtonPrimary, DeferredSpinner, Link, Title } from 'design-system';
+import { ButtonPrimary, Link, Spinner, Title } from 'design-system';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import { Router } from '../../../../components/hoc/withRouter';
type="submit"
>
{translate('onboarding.create_project.new_code_definition.create_project')}
- <DeferredSpinner className="sw-ml-2" loading={submitting} />
+ <Spinner className="sw-ml-2" loading={submitting} />
</ButtonPrimary>
</div>
</div>
import * as React from 'react';
import { useCallback } from 'react';
import { deleteGroup } from '../../../api/user_groups';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import SimpleModal from '../../../components/controls/SimpleModal';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Group } from '../../../types/types';
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton className="button-red" disabled={submitting}>
{translate('delete')}
</SubmitButton>
import * as React from 'react';
import { useCallback, useEffect, useState } from 'react';
import { createGroup, updateGroup } from '../../../api/user_groups';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import SimpleModal from '../../../components/controls/SimpleModal';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { omitNil } from '../../../helpers/request';
import { Group } from '../../../types/types';
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton disabled={submitting}>
{create ? translate('create') : translate('update_verb')}
</SubmitButton>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner } from 'design-system/lib';
+import { Spinner } from 'design-system/lib';
import * as React from 'react';
import { getUsersInGroup } from '../../../api/user_groups';
import ListFooter from '../../../components/controls/ListFooter';
value={query}
/>
<div className="select-list-list-container spacer-top">
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<ul className="menu">
{users.map((user) => (
<li key={user.login} className="display-flex-center">
</li>
))}
</ul>
- </DeferredSpinner>
+ </Spinner>
</div>
{total !== undefined && (
<ListFooter count={users.length} loadMore={() => setPage((p) => p + 1)} total={total} />
expect(screen.getByRole('button', { name: 'issues.bulk_change_X_issues.10' })).toHaveFocus();
await user.click(screen.getByRole('checkbox', { name: 'issues.select_all_issues' }));
- // Check that we bulk change the selected issue
- const issueBoxFixThat = within(screen.getByRole('region', { name: 'Fix that' }));
-
expect(
- issueBoxFixThat.getByLabelText('issue.type.type_x_click_to_change.issue.type.CODE_SMELL')
+ within(screen.getByRole('region', { name: 'Fix that' })).getByLabelText(
+ 'issue.type.type_x_click_to_change.issue.type.CODE_SMELL'
+ )
).toBeInTheDocument();
await user.click(
await user.click(screen.getByRole('button', { name: 'apply' }));
expect(
- issueBoxFixThat.getByLabelText('issue.type.type_x_click_to_change.issue.type.BUG')
+ await within(screen.getByRole('region', { name: 'Fix that' })).findByLabelText(
+ 'issue.type.type_x_click_to_change.issue.type.BUG'
+ )
).toBeInTheDocument();
});
});
import {
ButtonPrimary,
Checkbox,
- DeferredSpinner,
FlagMessage,
FormField,
HelperHintIcon,
LightLabel,
Modal,
RadioButton,
+ Spinner,
} from 'design-system';
import { pickBy, sortBy } from 'lodash';
import * as React from 'react';
const limitReached = paging && paging.total > MAX_PAGE_SIZE;
return (
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<form id="bulk-change-form" onSubmit={this.handleSubmit}>
{limitReached && (
<FlagMessage className="sw-mb-4" variant="warning">
<FlagMessage variant="warning">{translate('issue_bulk_change.no_match')}</FlagMessage>
)}
</form>
- </DeferredSpinner>
+ </Spinner>
);
};
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import IssueTabViewer from '../../../components/rules/IssueTabViewer';
import '../../../components/search-navigator.css';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { fillBranchLike, getBranchLikeQuery, isSameBranchLike } from '../../../helpers/branch-like';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
import { parseIssueFromResponse } from '../../../helpers/issues';
>
{this.renderHeader({ openIssue, paging, selectedIndex })}
- <DeferredSpinner loading={loadingRule}>
+ <Spinner loading={loadingRule}>
{/* eslint-disable-next-line local-rules/no-conditional-rendering-of-deferredspinner */}
{openIssue && openRuleDetails ? (
<IssueTabViewer
className="sw-px-6 sw-pb-6"
style={{ marginTop: `-${PSEUDO_SHADOW_HEIGHT}px` }}
>
- <DeferredSpinner
+ <Spinner
ariaLabel={translate('issues.loading_issues')}
className="sw-mt-4"
loading={loading}
)}
{this.renderList()}
- </DeferredSpinner>
+ </Spinner>
</div>
)}
- </DeferredSpinner>
+ </Spinner>
</div>
)}
</ScreenPositionHelper>
issuesByComponentAndLine,
} from '../../../components/SourceViewer/helpers/indexing';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { WorkspaceContext } from '../../../components/workspace/context';
import { getBranchLikeQuery } from '../../../helpers/branch-like';
import { throwGlobalError } from '../../../helpers/error';
if (loading) {
return (
<div>
- <DeferredSpinner ariaLabel={translate('code_viewer.loading')} />
+ <Spinner ariaLabel={translate('code_viewer.loading')} />
</div>
);
}
import {
ChevronRightIcon,
CopyIcon,
- DeferredSpinner,
HoverLink,
InteractiveIcon,
LightLabel,
Link,
+ Spinner,
ThemeProp,
UnfoldIcon,
themeColor,
</div>
)}
- <DeferredSpinner className="sw-mr-1" loading={loading} />
+ <Spinner className="sw-mr-1" loading={loading} />
{expandable && !loading && (
<div className="sw-ml-4">
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import styled from '@emotion/styled';
-import { DeferredSpinner, SubnavigationHeading, themeBorder } from 'design-system';
+import { Spinner, SubnavigationHeading, themeBorder } from 'design-system';
import * as React from 'react';
import { Paging } from '../../../types/types';
import IssuesCounter from '../components/IssuesCounter';
return (
<StyledHeader>
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{paging && <IssuesCounter current={selectedIndex} total={paging.total} />}
- </DeferredSpinner>
+ </Spinner>
</StyledHeader>
);
}
import Suggestions from '../../components/embed-docs-modal/Suggestions';
import { Location, Router, withRouter } from '../../components/hoc/withRouter';
import { Alert } from '../../components/ui/Alert';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import Spinner from '../../components/ui/Spinner';
import { translate } from '../../helpers/l10n';
import { EditionKey } from '../../types/editions';
import { PendingPluginResult, Plugin, RiskConsent } from '../../types/plugins';
updateCenterActive={this.props.updateCenterActive}
updateQuery={this.updateQuery}
/>
- <DeferredSpinner loading={loadingPlugins}>
+ <Spinner loading={loadingPlugins}>
{filteredPlugins.length === 0 &&
translate('marketplace.plugin_list.no_plugins', query.filter)}
{filteredPlugins.length > 0 && (
<Footer total={filteredPlugins.length} />
</>
)}
- </DeferredSpinner>
+ </Spinner>
</main>
);
}
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { BasicSeparator, Card, DeferredSpinner, PageTitle } from 'design-system';
+import { BasicSeparator, Card, PageTitle, Spinner } from 'design-system';
import * as React from 'react';
import GraphsHeader from '../../../components/activity-graph/GraphsHeader';
import GraphsHistory from '../../../components/activity-graph/GraphsHistory';
</div>
</Card>
<Card className="sw-mt-4" data-test="overview__activity-analyses">
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{filteredAnalyses.length === 0 ? (
<p>{translate('no_results')}</p>
) : (
</div>
))
)}
- </DeferredSpinner>
+ </Spinner>
</Card>
</div>
);
import {
Card,
CoverageIndicator,
- DeferredSpinner,
DuplicationsIndicator,
FlagMessage,
LightLabel,
PageTitle,
+ Spinner,
ToggleButton,
} from 'design-system';
import * as React from 'react';
{loading ? (
<div>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
</div>
) : (
<>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { BasicSeparator, Card, DeferredSpinner } from 'design-system';
+import { BasicSeparator, Card, Spinner } from 'design-system';
import { flatMap } from 'lodash';
import * as React from 'react';
import { ComponentQualifier, isApplication } from '../../../types/component';
<div>
{loading ? (
<div className="sw-p-6">
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
</div>
) : (
<>
.length > 0;
if (isLoading) {
- return <Spinner />;
+ return <Spinner loading />;
}
if (component.qualifier === ComponentQualifier.Application) {
<PageContentFontWrapper>
<FlagMessage variant="warning">
{translate('provisioning.permission_synch_in_progress')}
- <Spinner className="sw-ml-8 sw-hidden" aria-hidden />
+ <Spinner className="sw-ml-8 sw-hidden" aria-hidden loading />
</FlagMessage>
</PageContentFontWrapper>
</LargeCenteredLayout>
BasicSeparator,
Card,
CoverageIndicator,
- DeferredSpinner,
DuplicationsIndicator,
HelperHintIcon,
LargeCenteredLayout,
Link,
PageTitle,
+ Spinner,
TextMuted,
} from 'design-system';
import { uniq } from 'lodash';
return (
<LargeCenteredLayout>
<div className="sw-p-6">
- <DeferredSpinner loading />
+ <Spinner loading />
</div>
</LargeCenteredLayout>
);
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import SimpleModal from '../../../components/controls/SimpleModal';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { PermissionTemplate } from '../../../types/types';
</div>
<div className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton className="button-red" disabled={submitting}>
{translate('delete')}
</SubmitButton>
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import SimpleModal from '../../../components/controls/SimpleModal';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
interface Props {
</div>
<div className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton disabled={submitting} id="permission-template-submit">
{this.props.confirmButtonText}
</SubmitButton>
import { Button } from '../../../components/controls/buttons';
import { Router, withRouter } from '../../../components/hoc/withRouter';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { throwGlobalError } from '../../../helpers/error';
import { translate } from '../../../helpers/l10n';
import { useGithubProvisioningEnabledQuery } from '../../../queries/identity-provider';
<header className="page-header" id="project-permissions-header">
<h1 className="page-title">{translate('permission_templates.page')}</h1>
- <DeferredSpinner loading={!ready} />
+ <Spinner loading={!ready} />
<div className="page-actions">
<Button onClick={() => setCreateModal(true)}>{translate('create')}</Button>
*/
import * as React from 'react';
import Link from '../../../components/common/Link';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { PermissionTemplate } from '../../../types/types';
import { PERMISSION_TEMPLATES_PATH } from '../utils';
<h1 className="page-title">{template.name}</h1>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
<div className="pull-right">
<ActionsCell
*/
import * as React from 'react';
import { applyTemplateToProject, getPermissionTemplates } from '../../../../api/permissions';
-import { ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
import Select from '../../../../components/controls/Select';
import SimpleModal from '../../../../components/controls/SimpleModal';
+import { ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../../helpers/l10n';
import { PermissionTemplate } from '../../../../types/types';
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
{!this.state.done && (
<SubmitButton disabled={submitting || !this.state.permissionTemplate}>
{translate('apply')}
import GitHubSynchronisationWarning from '../../../../app/components/GitHubSynchronisationWarning';
import { Button } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
+import Spinner from '../../../../components/ui/Spinner';
import { translate } from '../../../../helpers/l10n';
import { getBaseUrl } from '../../../../helpers/system';
import { useGithubProvisioningEnabledQuery } from '../../../../queries/identity-provider';
)}
</h1>
- <DeferredSpinner className="spacer-left" loading={loading} />
+ <Spinner className="spacer-left" loading={loading} />
{canApplyPermissionTemplate && (
<div className="page-actions">
import styled from '@emotion/styled';
import classNames from 'classnames';
import { isEqual } from 'date-fns';
-import { Badge, DeferredSpinner, LightLabel, themeColor } from 'design-system';
+import { Badge, LightLabel, Spinner, themeColor } from 'design-system';
import * as React from 'react';
import Tooltip from '../../../components/controls/Tooltip';
import DateFormatter from '../../../components/intl/DateFormatter';
<div>
{this.props.initializing ? (
<div className="sw-p-4 sw-body-sm">
- <DeferredSpinner />
+ <Spinner />
</div>
) : (
<div className="sw-p-4 sw-body-sm">
})}
{this.props.analysesLoading && (
<li className="sw-text-center">
- <DeferredSpinner />
+ <Spinner />
</li>
)}
</ul>
import Tooltip from '../../../components/controls/Tooltip';
import DateFormatter, { longFormatterOption } from '../../../components/intl/DateFormatter';
import TimeFormatter from '../../../components/intl/TimeFormatter';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { parseDate, toShortISO8601String } from '../../../helpers/dates';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { ParsedAnalysis } from '../../../types/project-activity';
</div>
<div className="branch-analysis-list-wrapper">
<div className="bordered branch-analysis-list" onScroll={props.handleScroll}>
- <DeferredSpinner className="big-spacer-top" loading={loading} />
+ <Spinner className="big-spacer-top" loading={loading} />
{!loading && !hasFilteredData ? (
<div className="big-spacer-top big-spacer-bottom strong">
import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { toISO8601WithOffsetString } from '../../../helpers/dates';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getNumberOfDaysDefaultValue } from '../../../helpers/new-code-definition';
)}
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={saving} />
+ <Spinner className="spacer-right" loading={saving} />
<SubmitButton disabled={!isChanged || saving || !isValid}>
{translate('save')}
</SubmitButton>
*/
import * as React from 'react';
import { listBranchesNewCodePeriod, resetNewCodePeriod } from '../../../api/newCodePeriod';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { isBranch, sortBranches } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import { DEFAULT_NEW_CODE_DEFINITION_TYPE } from '../../../helpers/new-code-definition';
}
if (loading) {
- return <DeferredSpinner />;
+ return <Spinner />;
}
return (
import withComponentContext from '../../../app/components/componentContext/withComponentContext';
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import AlertSuccessIcon from '../../../components/icons/AlertSuccessIcon';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { isBranch, sortBranches } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import {
<Helmet defer={false} title={translate('project_baseline.page')} />
<div className="page page-limited">
<AppHeader canAdmin={!!appState.canAdmin} />
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
{!loading && (
<div className="panel-white project-baseline">
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { isNewCodeDefinitionCompliant } from '../../../helpers/new-code-definition';
import { Branch } from '../../../types/branch-like';
<Alert variant="info" className="spacer-bottom">
{translate('baseline.next_analysis_notice')}
</Alert>
- <DeferredSpinner className="spacer-right" loading={saving} />
+ <Spinner className="spacer-right" loading={saving} />
<SubmitButton disabled={saving || !isValid || !isChanged}>{translate('save')}</SubmitButton>
<ResetButtonLink className="spacer-left" onClick={props.onCancel}>
{translate('cancel')}
import { useEffect } from 'react';
import HelpTooltip from '../../../components/controls/HelpTooltip';
import Toggle from '../../../components/controls/Toggle';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { isMainBranch } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
import { useExcludeFromPurgeMutation } from '../../../queries/branch';
<>
<Toggle disabled={disabled} onChange={handleOnChange} value={branch.excludedFromPurge} />
<span className="spacer-left">
- <DeferredSpinner loading={isLoading} />
+ <Spinner loading={isLoading} />
</span>
{isTheMainBranch && (
<HelpTooltip
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import Link from '../../../components/common/Link';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
const { branchAndPullRequestLifeTimeInDays, canAdmin, loading } = props;
return (
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{branchAndPullRequestLifeTimeInDays && (
<p className="page-description">
<FormattedMessage
)}
</p>
)}
- </DeferredSpinner>
+ </Spinner>
);
}
BasicSeparator,
ButtonSecondary,
CodeSnippet,
- DeferredSpinner,
FlagMessage,
FormField,
IllustratedSelectionCard,
InputSelect,
+ Spinner,
SubTitle,
ToggleButton,
} from 'design-system';
<SubTitle>{translate('overview.badges.get_badge')}</SubTitle>
<p className="big-spacer-bottom">{translate('overview.badges.description', qualifier)}</p>
- <DeferredSpinner loading={isLoading || isEmpty(token)}>
+ <Spinner loading={isLoading || isEmpty(token)}>
<div className="sw-flex sw-space-x-4 sw-mb-4">
<IllustratedSelectionCard
className="sw-w-abs-300 it__badge-button"
)}
/>
</div>
- </DeferredSpinner>
+ </Spinner>
{BadgeType.measure === selectedType && (
<FormField htmlFor="badge-param-customize" label={translate('overview.badges.metric')}>
</div>
</FormField>
- <DeferredSpinner className="spacer-top spacer-bottom" loading={isFetchingToken || isRenewing}>
+ <Spinner className="spacer-top spacer-bottom" loading={isFetchingToken || isRenewing}>
{!isLoading && (
<CodeSnippet
language="plaintext"
wrap
/>
)}
- </DeferredSpinner>
+ </Spinner>
<FlagMessage className="sw-w-full" variant="warning">
<p>
WithNotificationsProps,
withNotifications,
} from '../../../components/hoc/withNotifications';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { hasMessage, translate, translateWithParameters } from '../../../helpers/l10n';
import { NotificationProjectType } from '../../../types/notifications';
import { Component } from '../../../types/types';
{translate('notification.dispatcher.information')}
</FlagMessage>
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<h3 id="notifications-update-title" className="sw-mt-6">
{translate('project_information.project_notifications.title')}
</h3>
</li>
))}
</ul>
- </DeferredSpinner>
+ </Spinner>
</form>
);
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { ResetButtonLink, SubmitButton } from '../../components/controls/buttons';
import SimpleModal from '../../components/controls/SimpleModal';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import { ResetButtonLink, SubmitButton } from '../../components/controls/buttons';
import MandatoryFieldMarker from '../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../components/ui/Spinner';
import { translate } from '../../helpers/l10n';
interface Props {
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton disabled={submitting} id="create-link-confirm">
{translate('create')}
</SubmitButton>
import { Helmet } from 'react-helmet-async';
import { createLink, deleteLink, getProjectLinks } from '../../api/projectLinks';
import withComponentContext from '../../app/components/componentContext/withComponentContext';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import Spinner from '../../components/ui/Spinner';
import { translate } from '../../helpers/l10n';
import { Component, ProjectLink } from '../../types/types';
import Header from './Header';
<div className="page page-limited">
<Helmet defer={false} title={translate('project_links.page')} />
<Header onCreate={this.handleCreateLink} />
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
{links && <Table links={links} onDelete={this.handleDeleteLink} />}
- </DeferredSpinner>
+ </Spinner>
</div>
);
}
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
import '../../../components/search-navigator.css';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
import { translate } from '../../../helpers/l10n';
import { addSideBarClass, removeSideBarClass } from '../../../helpers/pages';
renderMain = () => {
if (this.state.loading && this.state.projects === undefined) {
- return <DeferredSpinner />;
+ return <Spinner />;
}
return (
import { getComponentNavigation } from '../../api/navigation';
import { Project } from '../../api/project-management';
import ActionsDropdown, { ActionsDropdownItem } from '../../components/controls/ActionsDropdown';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import Spinner from '../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { getComponentPermissionsUrl } from '../../helpers/urls';
import { useGithubProvisioningEnabledQuery } from '../../queries/identity-provider';
>
{loading ? (
<ActionsDropdownItem>
- <DeferredSpinner />
+ <Spinner />
</ActionsDropdownItem>
) : (
<>
import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
import Suggestions from '../../../components/embed-docs-modal/Suggestions';
import '../../../components/search-navigator.css';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import {
addSideBarClass,
canCreate={canCreate}
refreshQualityGates={this.fetchQualityGates}
/>
- <DeferredSpinner loading={this.state.loading}>
+ <Spinner loading={this.state.loading}>
<List qualityGates={qualityGates} currentQualityGate={name} />
- </DeferredSpinner>
+ </Spinner>
</div>
</div>
</nav>
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { fetchQualityGate } from '../../../api/quality-gates';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { addGlobalSuccessMessage } from '../../../helpers/globalMessages';
import { translate } from '../../../helpers/l10n';
import { Condition, QualityGate } from '../../../types/types';
return (
<main className="layout-page-main">
- <DeferredSpinner loading={loading} timeout={200}>
+ <Spinner loading={loading}>
{qualityGate && (
<>
<Helmet defer={false} title={qualityGate.name} />
/>
</>
)}
- </DeferredSpinner>
+ </Spinner>
</main>
);
}
*/
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
-import { Button } from '../../../components/controls/buttons';
import ConfirmModal from '../../../components/controls/ConfirmModal';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { Button } from '../../../components/controls/buttons';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { Group, isUser } from '../../../types/quality-gates';
import { QualityGate } from '../../../types/types';
<h3 className="spacer-bottom">{translate('quality_gates.permissions')}</h3>
<p className="spacer-bottom">{translate('quality_gates.permissions.help')}</p>
<div>
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<ul>
{users.map((user) => (
<li key={user.login}>
</li>
))}
</ul>
- </DeferredSpinner>
+ </Spinner>
</div>
<Button className="big-spacer-top" onClick={props.onClickAddPermission}>
import * as React from 'react';
import { ChangelogResponse, getProfileChangelog } from '../../../api/quality-profiles';
import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { parseDate, toISO8601WithOffsetString } from '../../../helpers/dates';
import { translate } from '../../../helpers/l10n';
import { withQualityProfilesContext } from '../qualityProfilesContext';
onDateRangeChange={this.handleDateRangeChange}
onReset={this.handleReset}
/>
- <DeferredSpinner loading={this.state.loading} className="spacer-left" />
+ <Spinner loading={this.state.loading} className="spacer-left" />
</div>
{this.state.events != null && this.state.events.length === 0 && <ChangelogEmpty />}
import * as React from 'react';
import { Profile } from '../../../api/quality-profiles';
import { getRuleDetails } from '../../../api/rules';
-import { Button } from '../../../components/controls/buttons';
import Tooltip from '../../../components/controls/Tooltip';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import { Button } from '../../../components/controls/buttons';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { RuleDetails } from '../../../types/types';
import ActivationFormModal from '../../coding-rules/components/ActivationFormModal';
const { profile } = this.props;
return (
- <DeferredSpinner loading={this.state.state === 'opening'}>
+ <Spinner loading={this.state.state === 'opening'}>
<Tooltip
placement="bottom"
overlay={translateWithParameters(
rule={this.state.rule}
/>
)}
- </DeferredSpinner>
+ </Spinner>
);
}
}
import { withTheme } from '@emotion/react';
import styled from '@emotion/styled';
import {
- DeferredSpinner,
LAYOUT_FOOTER_HEIGHT,
LAYOUT_GLOBAL_NAV_HEIGHT,
LAYOUT_PROJECT_NAV_HEIGHT,
LargeCenteredLayout,
PageContentFontWrapper,
+ Spinner,
themeBorder,
themeColor,
} from 'design-system';
}px`,
}}
>
- <DeferredSpinner className="sw-mt-3" loading={loading}>
- <HotspotFilterByStatus
- filters={filters}
- isStaticListOfHotspots={isStaticListOfHotspots}
- onChangeFilters={onChangeFilters}
- onShowAllHotspots={onShowAllHotspots}
- />
+ <HotspotFilterByStatus
+ filters={filters}
+ isStaticListOfHotspots={isStaticListOfHotspots}
+ onChangeFilters={onChangeFilters}
+ onShowAllHotspots={onShowAllHotspots}
+ />
+ <Spinner className="sw-mt-3" loading={loading}>
{hotspots.length > 0 && selectedHotspot && (
<>
{filterByCategory || filterByCWE || filterByFile ? (
)}
</>
)}
- </DeferredSpinner>
+ </Spinner>
</StyledSidebarContent>
</StyledSidebar>
PopupPlacement,
} from 'design-system';
import * as React from 'react';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { addGlobalErrorMessage, addGlobalSuccessMessage } from '../../../helpers/globalMessages';
import { translate } from '../../../helpers/l10n';
import { openHotspot, probeSonarLintServers } from '../../../helpers/sonarlint';
>
<ButtonSecondary onClick={this.handleOnClick}>
{translate('hotspots.open_in_ide.open')}
- <DeferredSpinner loading={loading} className="sw-ml-4" />
+ <Spinner loading={loading} className="sw-ml-4" />
</ButtonSecondary>
</DropdownToggler>
</div>
import HelpTooltip from '../../../components/controls/HelpTooltip';
import Tooltip from '../../../components/controls/Tooltip';
import Measure from '../../../components/measure/Measure';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { PopupPlacement } from '../../../components/ui/popups';
import { isBranch } from '../../../helpers/branch-like';
import { translate } from '../../../helpers/l10n';
return (
<div className="sw-flex sw-h-6 sw-items-center sw-px-4 sw-py-4">
- <DeferredSpinner loading={loadingMeasure}>
+ <Spinner loading={loadingMeasure}>
{hotspotsReviewedMeasure !== undefined && (
<CoverageIndicator value={hotspotsReviewedMeasure} />
)}
metricType={MetricType.Percent}
value={hotspotsReviewedMeasure}
/>
-
- <span className="sw-body-sm sw-ml-1">
- {translate('metric.security_hotspots_reviewed.name')}
- </span>
-
- <HelpTooltip className="sw-ml-1" overlay={translate('hotspots.reviewed.tooltip')}>
- <HelperHintIcon aria-label="help-tooltip" />
- </HelpTooltip>
-
- {!isStaticListOfHotspots && (isBranch(branchLike) || userLoggedIn || isFiltered) && (
- <div className="sw-flex sw-flex-grow sw-justify-end">
- <Dropdown
- allowResizing
- closeOnClick={false}
- id="filter-hotspots-menu"
- isPortal
- overlay={
- <>
- <ItemHeader>{translate('hotspot.filters.title')}</ItemHeader>
-
- {isBranch(branchLike) && (
+ </Spinner>
+
+ <span className="sw-body-sm sw-ml-1">
+ {translate('metric.security_hotspots_reviewed.name')}
+ </span>
+
+ <HelpTooltip className="sw-ml-1" overlay={translate('hotspots.reviewed.tooltip')}>
+ <HelperHintIcon aria-label="help-tooltip" />
+ </HelpTooltip>
+
+ {!isStaticListOfHotspots && (isBranch(branchLike) || userLoggedIn || isFiltered) && (
+ <div className="sw-flex sw-flex-grow sw-justify-end">
+ <Dropdown
+ allowResizing
+ closeOnClick={false}
+ id="filter-hotspots-menu"
+ isPortal
+ overlay={
+ <>
+ <ItemHeader>{translate('hotspot.filters.title')}</ItemHeader>
+
+ {isBranch(branchLike) && (
+ <ItemCheckbox
+ checked={Boolean(filters.inNewCodePeriod)}
+ onCheck={(inNewCodePeriod: boolean) =>
+ props.onChangeFilters({ inNewCodePeriod })
+ }
+ >
+ <span className="sw-mx-2">
+ {translate('hotspot.filters.period.since_leak_period')}
+ </span>
+ </ItemCheckbox>
+ )}
+
+ {userLoggedIn && (
+ <Tooltip
+ classNameSpace={component?.needIssueSync ? 'tooltip' : 'sw-hidden'}
+ overlay={<HotspotDisabledFilterTooltip />}
+ placement="right"
+ >
<ItemCheckbox
- checked={Boolean(filters.inNewCodePeriod)}
- onCheck={(inNewCodePeriod: boolean) =>
- props.onChangeFilters({ inNewCodePeriod })
- }
+ checked={Boolean(filters.assignedToMe)}
+ disabled={component?.needIssueSync}
+ onCheck={(assignedToMe: boolean) => props.onChangeFilters({ assignedToMe })}
>
<span className="sw-mx-2">
- {translate('hotspot.filters.period.since_leak_period')}
+ {translate('hotspot.filters.assignee.assigned_to_me')}
</span>
</ItemCheckbox>
- )}
-
- {userLoggedIn && (
- <Tooltip
- classNameSpace={component?.needIssueSync ? 'tooltip' : 'sw-hidden'}
- overlay={<HotspotDisabledFilterTooltip />}
- placement="right"
- >
- <ItemCheckbox
- checked={Boolean(filters.assignedToMe)}
- disabled={component?.needIssueSync}
- onCheck={(assignedToMe: boolean) => props.onChangeFilters({ assignedToMe })}
- >
- <span className="sw-mx-2">
- {translate('hotspot.filters.assignee.assigned_to_me')}
- </span>
- </ItemCheckbox>
- </Tooltip>
- )}
-
- {isFiltered && <ItemDivider />}
-
- {isFiltered && (
- <ItemDangerButton
- onClick={() =>
- props.onChangeFilters({
- assignedToMe: false,
- inNewCodePeriod: false,
- })
- }
- >
- {translate('hotspot.filters.clear')}
- </ItemDangerButton>
- )}
- </>
- }
- placement={PopupPlacement.BottomRight}
+ </Tooltip>
+ )}
+
+ {isFiltered && <ItemDivider />}
+
+ {isFiltered && (
+ <ItemDangerButton
+ onClick={() =>
+ props.onChangeFilters({
+ assignedToMe: false,
+ inNewCodePeriod: false,
+ })
+ }
+ >
+ {translate('hotspot.filters.clear')}
+ </ItemDangerButton>
+ )}
+ </>
+ }
+ placement={PopupPlacement.BottomRight}
+ >
+ <DiscreetInteractiveIcon
+ Icon={FilterIcon}
+ aria-label={translate('hotspot.filters.title')}
>
- <DiscreetInteractiveIcon
- Icon={FilterIcon}
- aria-label={translate('hotspot.filters.title')}
- >
- {isFiltered ? filtersCount : null}
- </DiscreetInteractiveIcon>
- </Dropdown>
- </div>
- )}
- </DeferredSpinner>
+ {isFiltered ? filtersCount : null}
+ </DiscreetInteractiveIcon>
+ </Dropdown>
+ </div>
+ )}
</div>
);
}
import styled from '@emotion/styled';
import { themeBorder, themeColor } from 'design-system';
import * as React from 'react';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import { Hotspot } from '../../../types/security-hotspots';
<SourceFileWrapper className="sw-box-border sw-w-full sw-rounded-1" ref={scrollableRef}>
<HotspotSnippetHeader hotspot={hotspot} component={component} branchLike={branchLike} />
- <DeferredSpinner className="big-spacer" loading={loading} />
+ <Spinner className="big-spacer" loading={loading} />
{!loading && sourceLines.length > 0 && (
<SnippetViewer
import * as React from 'react';
import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { fillBranchLike } from '../../../helpers/branch-like';
import { Standards } from '../../../types/security';
import { Hotspot, HotspotStatusOption } from '../../../types/security-hotspots';
return (
<>
- <DeferredSpinner className="sw-ml-4 sw-mt-4" loading={loading} />
+ <Spinner className="sw-ml-4 sw-mt-4" loading={loading} />
{showStatusUpdateSuccessModal && (
<StatusUpdateSuccessModal
import { Helmet } from 'react-helmet-async';
import { Location } from '../../../components/hoc/withRouter';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import { sanitizeUserInput } from '../../../helpers/sanitize';
import { getReturnUrl } from '../../../helpers/urls';
</h1>
<Helmet defer={false} title={translate('login.page')} />
{loading ? (
- <DeferredSpinner loading={loading} timeout={0} />
+ <Spinner loading={loading} />
) : (
<>
{displayError && (
import * as React from 'react';
import Link from '../../../components/common/Link';
import { ButtonLink, SubmitButton } from '../../../components/controls/buttons';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import './LoginForm.css';
<div>
<div className="text-right overflow-hidden">
- <DeferredSpinner className="spacer-right" loading={this.state.loading} />
+ <Spinner className="spacer-right" loading={this.state.loading} />
<SubmitButton disabled={this.state.loading}>
{translate('sessions.log_in')}
</SubmitButton>
import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
import { SubmitButton } from '../../../components/controls/buttons';
import { Alert } from '../../../components/ui/Alert';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
import MandatoryFieldMarker from '../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { parseError } from '../../../helpers/request';
import { LoggedInUser } from '../../../types/users';
<SubmitButton disabled={loading}>
{translate('email_configuration.test.send')}
</SubmitButton>
- {loading && <DeferredSpinner className="spacer-left" />}
+ {loading && <Spinner className="spacer-left" />}
</form>
</div>
);
import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
import NewCodeDefinitionWarning from '../../../components/new-code-definition/NewCodeDefinitionWarning';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import {
getNumberOfDaysDefaultValue,
</div>
<div className="settings-definition-right">
- <DeferredSpinner loading={loading} timeout={500}>
+ <Spinner loading={loading}>
<form onSubmit={this.onSubmit}>
<NewCodeDefinitionPreviousVersionOption
isDefault
<p className="spacer-bottom">
{translate('baseline.next_analysis_notice')}
</p>
- <DeferredSpinner className="spacer-right" loading={saving} />
+ <Spinner className="spacer-right" loading={saving} />
<SubmitButton disabled={saving || !isValid}>
{translate('save')}
</SubmitButton>
</div>
)}
</form>
- </DeferredSpinner>
+ </Spinner>
</div>
</div>
</li>
import Modal from '../../../../components/controls/Modal';
import { ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
+import Spinner from '../../../../components/ui/Spinner';
import { translate } from '../../../../helpers/l10n';
import {
AlmBindingDefinition,
<div className="modal-foot">
<SubmitButton disabled={!canSubmit || submitting}>
{translate('settings.almintegration.form.save')}
- <DeferredSpinner className="spacer-left" loading={submitting} />
+ <Spinner className="spacer-left" loading={submitting} />
</SubmitButton>
<ResetButtonLink onClick={this.props.onCancel}>{translate('cancel')}</ResetButtonLink>
</div>
import { getTabId, getTabPanelId } from '../../../../components/controls/BoxedTabs';
import { Button } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
+import Spinner from '../../../../components/ui/Spinner';
import { translate } from '../../../../helpers/l10n';
import {
AlmBindingDefinition,
aria-labelledby={getTabId(almTab)}
>
<div className="big-padded">
- <DeferredSpinner loading={loadingAlmDefinitions}>
+ <Spinner loading={loadingAlmDefinitions}>
{definitions.length === 0 && (
<p className="spacer-top">{translate('settings.almintegration.empty', almTab)}</p>
)}
afterSubmit={props.afterSubmit}
/>
)}
- </DeferredSpinner>
+ </Spinner>
</div>
{AUTHENTICATION_AVAILABLE_PLATFORMS.includes(almTab) && (
<Alert variant="info" className="spacer">
import Modal from '../../../../components/controls/Modal';
import { ResetButtonLink, SubmitButton } from '../../../../components/controls/buttons';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
+import Spinner from '../../../../components/ui/Spinner';
import { translate } from '../../../../helpers/l10n';
import { useSaveValuesMutation } from '../../../../queries/settings';
import { Dict } from '../../../../types/types';
<h2>{headerLabel}</h2>
</div>
<div className="modal-body modal-container">
- <DeferredSpinner
- loading={loading}
- ariaLabel={translate('settings.authentication.form.loading')}
- >
+ <Spinner loading={loading} ariaLabel={translate('settings.authentication.form.loading')}>
<Alert variant={hasLegacyConfiguration ? 'warning' : 'info'}>
<FormattedMessage
id={`settings.authentication.${
</div>
);
})}
- </DeferredSpinner>
+ </Spinner>
</div>
<div className="modal-foot">
<SubmitButton disabled={!canBeSave}>
{translate('settings.almintegration.form.save')}
- <DeferredSpinner className="spacer-left" loading={loading} />
+ <Spinner className="spacer-left" loading={loading} />
</SubmitButton>
<ResetButtonLink onClick={props.onClose}>{translate('cancel')}</ResetButtonLink>
</div>
import AlmSettingsInstanceSelector from '../../../../components/devops-platform/AlmSettingsInstanceSelector';
import AlertSuccessIcon from '../../../../components/icons/AlertSuccessIcon';
import { Alert } from '../../../../components/ui/Alert';
-import DeferredSpinner from '../../../../components/ui/DeferredSpinner';
import MandatoryFieldMarker from '../../../../components/ui/MandatoryFieldMarker';
import MandatoryFieldsExplanation from '../../../../components/ui/MandatoryFieldsExplanation';
+import Spinner from '../../../../components/ui/Spinner';
import { translate } from '../../../../helpers/l10n';
import { getGlobalSettingsUrl } from '../../../../helpers/urls';
import {
} = props;
if (loading) {
- return <DeferredSpinner />;
+ return <Spinner />;
}
if (instances.length < 1) {
{isChanged && (
<SubmitButton className="spacer-right button-success" disabled={updating || !isValid}>
<span data-test="project-settings__alm-save">{translate('save')}</span>
- <DeferredSpinner className="spacer-left" loading={updating} />
+ <Spinner className="spacer-left" loading={updating} />
</SubmitButton>
)}
{!updating && successfullyUpdated && (
{!isChanged && (
<Button onClick={props.onCheckConfiguration} disabled={checkingConfiguration}>
{translate('settings.pr_decoration.binding.check_configuration')}
- <DeferredSpinner className="spacer-left" loading={checkingConfiguration} />
+ <Spinner className="spacer-left" loading={checkingConfiguration} />
</Button>
)}
</>
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
import { checkSecretKey, generateSecretKey } from '../../../api/settings';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import EncryptionForm from './EncryptionForm';
import GenerateSecretKeyForm from './GenerateSecretKeyForm';
<Helmet defer={false} title={translate('property.category.security.encryption')} />
<header className="page-header">
<h1 className="page-title">{translate('property.category.security.encryption')}</h1>
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
</header>
{!loading && !secretKeyAvailable && (
import DocLink from '../../../components/common/DocLink';
import { SubmitButton } from '../../../components/controls/buttons';
import { ClipboardButton } from '../../../components/controls/clipboard';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
interface Props {
<SubmitButton disabled={encrypting || generating}>
{translate('encryption.encrypt')}
</SubmitButton>
- <DeferredSpinner className="spacer-left" loading={encrypting} />
+ <Spinner className="spacer-left" loading={encrypting} />
</div>
</form>
<SubmitButton disabled={generating || encrypting}>
{translate('encryption.generate_new_secret_key')}{' '}
</SubmitButton>
- <DeferredSpinner className="spacer-left" loading={generating} />
+ <Spinner className="spacer-left" loading={generating} />
</form>
</div>
);
import DocLink from '../../../components/common/DocLink';
import { SubmitButton } from '../../../components/controls/buttons';
import { ClipboardButton } from '../../../components/controls/clipboard';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
interface Props {
<SubmitButton disabled={submitting}>
{translate('encryption.generate_secret_key')}
</SubmitButton>
- <DeferredSpinner className="spacer-left" loading={submitting} />
+ <Spinner className="spacer-left" loading={submitting} />
</form>
)}
</div>
import Select, { LabelValueSelectOption } from '../../components/controls/Select';
import Suggestions from '../../components/embed-docs-modal/Suggestions';
import { Provider, useManageProvider } from '../../components/hooks/useManageProvider';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
+import Spinner from '../../components/ui/Spinner';
import { now, toISO8601WithOffsetString } from '../../helpers/dates';
import { translate } from '../../helpers/l10n';
import { useUsersQueries } from '../../queries/users';
/>
</div>
</div>
- <DeferredSpinner loading={isLoading}>
+ <Spinner loading={isLoading}>
<UsersList
identityProviders={identityProviders}
users={users}
manageProvider={manageProvider}
/>
- </DeferredSpinner>
+ </Spinner>
<ListFooter
count={users.length}
import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
import Select, { LabelValueSelectOption } from '../../../components/controls/Select';
import { SubmitButton } from '../../../components/controls/buttons';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate } from '../../../helpers/l10n';
import {
EXPIRATION_OPTIONS,
</tr>
</thead>
<tbody>
- <DeferredSpinner customSpinner={customSpinner} loading={loading && tokens.length <= 0}>
+ <Spinner customSpinner={customSpinner} loading={loading && tokens.length <= 0}>
{this.renderItems()}
- </DeferredSpinner>
+ </Spinner>
</tbody>
</table>
</>
import WarningIcon from '../../../components/icons/WarningIcon';
import DateFormatter from '../../../components/intl/DateFormatter';
import DateFromNow from '../../../components/intl/DateFromNow';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { UserToken } from '../../../types/token';
onClick={this.handleRevoke}
aria-label={translateWithParameters('users.tokens.remove_label', token.name)}
>
- <DeferredSpinner className="little-spacer-right" loading={loading}>
+ <Spinner className="little-spacer-right" loading={loading}>
{translate('remove')}
- </DeferredSpinner>
+ </Spinner>
</Button>
)}
{!token.isExpired && deleteConfirmation === 'modal' && (
}
onClick={this.handleClick}
>
- <DeferredSpinner className="little-spacer-right" loading={loading} />
+ <Spinner className="little-spacer-right" loading={loading} />
{showConfirmation ? translate('users.tokens.sure') : translate('users.tokens.revoke')}
</Button>
)}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import styled from '@emotion/styled';
-import { DeferredSpinner, LargeCenteredLayout, PageContentFontWrapper, Title } from 'design-system';
+import { LargeCenteredLayout, PageContentFontWrapper, Spinner, Title } from 'design-system';
import { omit } from 'lodash';
import React, { useMemo } from 'react';
import { Helmet } from 'react-helmet-async';
<LargeCenteredLayout>
<PageContentFontWrapper className="sw-body-sm">
<Helmet defer={false} title={translate('api_documentation.page')} />
- <DeferredSpinner loading={isLoading}>
+ <Spinner loading={isLoading}>
{data && (
<div className="sw-w-full sw-flex">
<NavContainer aria-label={translate('api_documentation.page')} className="sw--mx-2">
className="sw-relative sw-ml-12 sw-flex-1 sw-overflow-y-auto sw-py-6"
style={{ height: 'calc(100vh - 160px)' }}
>
- <DeferredSpinner loading={isLoading}>
+ <Spinner loading={isLoading}>
{!activeData && (
<>
<Title>{translate('about')}</Title>
method={activeData.method}
/>
)}
- </DeferredSpinner>
+ </Spinner>
</main>
</div>
)}
- </DeferredSpinner>
+ </Spinner>
</PageContentFontWrapper>
</LargeCenteredLayout>
);
import * as React from 'react';
import SimpleModal from '../../../components/controls/SimpleModal';
import { ResetButtonLink, SubmitButton } from '../../../components/controls/buttons';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { WebhookResponse } from '../../../types/webhook';
</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton className="button-red" disabled={submitting}>
{translate('delete')}
</SubmitButton>
import ListFooter from '../../../components/controls/ListFooter';
import Modal from '../../../components/controls/Modal';
import { ResetButtonLink } from '../../../components/controls/buttons';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { Paging } from '../../../types/types';
import { WebhookDelivery, WebhookResponse } from '../../../types/webhook';
<DeliveryAccordion delivery={delivery} key={delivery.id} />
))}
<div className="text-center">
- <DeferredSpinner loading={loading} />
+ <Spinner loading={loading} />
</div>
{paging !== undefined && (
<ListFooter
*/
import * as React from 'react';
import CodeSnippet from '../../../components/common/CodeSnippet';
-import DeferredSpinner from '../../../components/ui/DeferredSpinner';
+import Spinner from '../../../components/ui/Spinner';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
import { WebhookDelivery } from '../../../types/webhook';
)}
</p>
<p className="spacer-bottom">{translate('webhooks.delivery.payload')}</p>
- <DeferredSpinner className="spacer-left spacer-top" loading={loading}>
+ <Spinner className="spacer-left spacer-top" loading={loading}>
{payload && <CodeSnippet noCopy snippet={formatPayload(payload)} />}
- </DeferredSpinner>
+ </Spinner>
</div>
);
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { ButtonSecondary, DeferredSpinner, LightLabel, SonarCodeColorizer } from 'design-system';
+import { ButtonSecondary, LightLabel, SonarCodeColorizer, Spinner } from 'design-system';
import * as React from 'react';
import { decorateWithUnderlineFlags } from '../../helpers/code-viewer';
import { translate } from '../../helpers/l10n';
<div className="sw-flex sw-justify-center sw-p-6">
{loadingSourcesBefore ? (
<div className="sw-flex sw-items-center">
- <DeferredSpinner loading />
+ <Spinner loading />
<LightLabel className="sw-ml-2">
{translate('source_viewer.loading_more_code')}
</LightLabel>
<div className="sw-flex sw-justify-center sw-p-6">
{loadingSourcesAfter ? (
<div className="sw-flex sw-items-center">
- <DeferredSpinner loading />
+ <Spinner loading />
<LightLabel className="sw-ml-2">
{translate('source_viewer.loading_more_code')}
</LightLabel>
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { DeferredSpinner, LightLabel } from 'design-system';
+import { LightLabel, Spinner } from 'design-system';
import { isEqual, uniqBy } from 'lodash';
import * as React from 'react';
import { translate, translateWithParameters } from '../../helpers/l10n';
return (
<div className="sw-flex sw-justify-center sw-flex-col sw-items-stretch sw-grow">
<div className="sw-text-center">
- <DeferredSpinner ariaLabel={translate('loading')} loading={loading} />
+ <Spinner ariaLabel={translate('loading')} loading={loading} />
</div>
</div>
);
describe('rendering', () => {
it('should render correctly when loading', async () => {
renderActivityGraph({ loading: true });
- expect(await screen.findByLabelText('loading')).toBeInTheDocument();
+ expect(await screen.findByText('loading')).toBeInTheDocument();
});
it('should show the correct legend items', async () => {
import classNames from 'classnames';
import * as React from 'react';
-import DeferredSpinner from '../ui/DeferredSpinner';
+import Spinner from '../ui/Spinner';
import './Checkbox.css';
interface Props {
title={title}
>
{right && children}
- <DeferredSpinner loading={Boolean(loading)}>
+ <Spinner loading={Boolean(loading)}>
<i className={className} />
- </DeferredSpinner>
+ </Spinner>
{!right && children}
</a>
);
}
if (loading) {
- return <DeferredSpinner ariaLabel={label} />;
+ return <Spinner ariaLabel={label} />;
}
return (
*/
import * as React from 'react';
import { translate } from '../../helpers/l10n';
-import DeferredSpinner from '../ui/DeferredSpinner';
-import { ResetButtonLink, SubmitButton } from './buttons';
+import Spinner from '../ui/Spinner';
import ClickEventBoundary from './ClickEventBoundary';
import { ModalProps } from './Modal';
import SimpleModal, { ChildrenProps } from './SimpleModal';
+import { ResetButtonLink, SubmitButton } from './buttons';
export interface ConfirmModalProps<T> extends ModalProps {
cancelButtonText?: string;
</header>
<div className="modal-body">{children}</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={submitting} />
+ <Spinner className="spacer-right" loading={submitting} />
<SubmitButton
autoFocus
className={isDestructive ? 'button-red' : undefined}
*/
import styled from '@emotion/styled';
import classNames from 'classnames';
-import { ButtonSecondary, DeferredSpinner, themeColor } from 'design-system';
+import { ButtonSecondary, Spinner, themeColor } from 'design-system';
import * as React from 'react';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { formatMeasure } from '../../helpers/measures';
import { MetricType } from '../../types/metrics';
-import LegacySpinner from '../ui/DeferredSpinner';
+import LegacySpinner from '../ui/Spinner';
import { Button } from './buttons';
export interface ListFooterProps {
{button}
{/* eslint-disable local-rules/no-conditional-rendering-of-deferredspinner */}
{useMIUIButtons ? (
- <DeferredSpinner loading={loading} className="sw-ml-2" />
+ <Spinner loading={loading} className="sw-ml-2" />
) : (
<LegacySpinner loading={loading} className="sw-ml-2" />
)}
transition: color 0.3s ease;
}
-.search-box > .deferred-spinner {
+.search-box > .spinner {
position: absolute;
top: 4px;
left: 5px;
import { KeyboardKeys } from '../../helpers/keycodes';
import { translate, translateWithParameters } from '../../helpers/l10n';
import SearchIcon from '../icons/SearchIcon';
-import DeferredSpinner from '../ui/DeferredSpinner';
+import Spinner from '../ui/Spinner';
import { ClearButton } from './buttons';
import './SearchBox.css';
value={value}
/>
- <DeferredSpinner loading={loading !== undefined ? loading : false}>
+ <Spinner loading={loading !== undefined ? loading : false}>
<SearchIcon className="search-box-magnifier" />
- </DeferredSpinner>
+ </Spinner>
{value && (
<ClearButton
IsMulti extends boolean = boolean,
Group extends GroupBase<Option> = GroupBase<Option>
>({ innerProps }: LoadingIndicatorProps<Option, IsMulti, Group>) {
- return (
- <i className={classNames('deferred-spinner spacer-left spacer-right', innerProps.className)} />
- );
+ return <i className={classNames('spinner spacer-left spacer-right', innerProps.className)} />;
}
export function multiValueRemove<
import { uniqueId } from 'lodash';
import * as React from 'react';
import { translate } from '../../helpers/l10n';
-import DeferredSpinner from '../ui/DeferredSpinner';
+import Spinner from '../ui/Spinner';
import Checkbox from './Checkbox';
import { SelectListFilter } from './SelectList';
import SelectListListElement from './SelectListListElement';
>
<span className="big-spacer-left">
{translate('bulk_change')}
- <DeferredSpinner className="spacer-left" loading={this.state.loading} timeout={10} />
+ <Spinner className="spacer-left" loading={this.state.loading} />
</span>
</Checkbox>
</li>
import { FormikValues } from 'formik';
import * as React from 'react';
import { translate } from '../../helpers/l10n';
-import DeferredSpinner from '../ui/DeferredSpinner';
-import { ResetButtonLink, SubmitButton } from './buttons';
+import Spinner from '../ui/Spinner';
import Modal, { ModalProps } from './Modal';
import ValidationForm, { ChildrenProps } from './ValidationForm';
+import { ResetButtonLink, SubmitButton } from './buttons';
interface Props<V> extends ModalProps {
children: (props: ChildrenProps<V>) => React.ReactNode;
<div className="modal-body">{this.props.children(props)}</div>
<footer className="modal-foot">
- <DeferredSpinner className="spacer-right" loading={props.isSubmitting} />
+ <Spinner className="spacer-right" loading={props.isSubmitting} />
<SubmitButton
className={this.props.isDestructive ? 'button-red' : undefined}
disabled={props.isSubmitting || !props.isValid || !props.dirty}
});
it('should render loading state', () => {
- jest.useFakeTimers();
renderCheckbox({ label: 'me', children, loading: true });
- jest.runAllTimers();
- expect(screen.getByTestId('deferred-spinner')).toMatchSnapshot();
- jest.useRealTimers();
+ expect(screen.getByTestId('spinner')).toMatchSnapshot();
});
});
describe('rendering', () => {
it('should render correctly when loading', async () => {
renderListFooter({ loading: true });
- expect(await screen.findByLabelText('loading')).toBeInTheDocument();
+ expect(await screen.findByText('loading')).toBeInTheDocument();
});
it('should not render if there are neither loadmore nor reload props', () => {
exports[`Checkbox with children should render loading state 1`] = `
<i
aria-live="polite"
- class="deferred-spinner is-loading"
- data-testid="deferred-spinner"
+ class="spinner is-loading"
+ data-testid="spinner"
>
<span
class="a11y-hidden"
exports[`Checkbox with no children should render loading state 1`] = `
<i
aria-live="polite"
- class="deferred-spinner is-loading"
- data-testid="deferred-spinner"
+ class="spinner is-loading"
+ data-testid="spinner"
>
<span
class="a11y-hidden"
>
<i
aria-live="polite"
- class="deferred-spinner a11y-hidden"
- data-testid="deferred-spinner"
+ class="spinner a11y-hidden"
+ data-testid="spinner"
/>
</div>
<i
<footer
className="modal-foot"
>
- <DeferredSpinner
+ <Spinner
className="spacer-right"
loading={true}
/>
<footer
className="modal-foot"
>
- <DeferredSpinner
+ <Spinner
className="spacer-right"
loading={false}
/>
type="search"
value="foo"
/>
- <DeferredSpinner
+ <Spinner
loading={false}
>
<SearchIcon
className="search-box-magnifier"
/>
- </DeferredSpinner>
+ </Spinner>
<ClearButton
aria-label="clear"
className="button-tiny search-box-clear"
exports[`Select should render loadingIndicator correctly 1`] = `
<i
- className="deferred-spinner spacer-left spacer-right additional-class"
+ className="spinner spacer-left spacer-right additional-class"
/>
`;
className="big-spacer-left"
>
bulk_change
- <DeferredSpinner
+ <Spinner
className="spacer-left"
loading={false}
- timeout={10}
/>
</span>
</Checkbox>
<footer
className="modal-foot"
>
- <DeferredSpinner
+ <Spinner
className="spacer-right"
loading={false}
/>
import HelpTooltip from '../../components/controls/HelpTooltip';
import { Button, ButtonLink } from '../../components/controls/buttons';
import OpenCloseIcon from '../../components/icons/OpenCloseIcon';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
import { translate, translateWithParameters } from '../../helpers/l10n';
import Tooltip from '../controls/Tooltip';
+import Spinner from '../ui/Spinner';
interface Props {
children?: React.ReactNode;
{fetching && (
<span className="little-spacer-right">
- <DeferredSpinner />
+ <Spinner />
</span>
)}
import {
ButtonSecondary,
ClipboardIconButton,
- DeferredSpinner,
DestructiveIcon,
FlagMessage,
InputField,
LabelValueSelectOption,
Link,
Modal,
+ Spinner,
TrashIcon,
} from 'design-system';
import * as React from 'react';
) : (
<>
<div className="sw-flex sw-pt-4">
- <DeferredSpinner loading={loading}>
+ <Spinner loading={loading}>
<div className="sw-flex-col sw-mr-2">
<label className="sw-block" htmlFor="token-name">
{translate('onboarding.token.name.label')}
</ButtonSecondary>
</div>
</div>
- </DeferredSpinner>
+ </Spinner>
</div>
{type === TokenType.Project && <ProjectTokenScopeInfo />}
</>
import {
ButtonPrimary,
ButtonSecondary,
- DeferredSpinner,
DestructiveIcon,
FlagMessage,
FlagSuccessIcon,
Link,
Note,
RadioButton,
+ Spinner,
TrashIcon,
} from 'design-system';
import * as React from 'react';
<ButtonSecondary
type="submit"
disabled={!tokenName || loading}
- icon={<DeferredSpinner className="sw-mr-1" loading={loading} />}
+ icon={<Spinner className="sw-mr-1" loading={loading} />}
>
{translate('onboarding.token.generate')}
</ButtonSecondary>
<strong className="sw-font-semibold">{token}</strong>
</span>
- <DeferredSpinner className="sw-ml-3 sw-my-2" loading={loading}>
+ <Spinner className="sw-ml-3 sw-my-2" loading={loading}>
<DestructiveIcon
className="sw-ml-1"
Icon={TrashIcon}
aria-label={translate('onboarding.token.delete')}
onClick={this.handleTokenRevoke}
/>
- </DeferredSpinner>
+ </Spinner>
</form>
) : (
<div>
import AlertSuccessIcon from '../icons/AlertSuccessIcon';
import AlertWarnIcon from '../icons/AlertWarnIcon';
import InfoIcon from '../icons/InfoIcon';
-import DeferredSpinner from './DeferredSpinner';
+import Spinner from './Spinner';
type AlertDisplay = 'banner' | 'inline' | 'block';
export type AlertVariant = 'error' | 'warning' | 'success' | 'info' | 'loading';
backGroundColor: colors.alertBackgroundInfo,
},
loading: {
- icon: <DeferredSpinner timeout={0} />,
+ icon: <Spinner />,
color: colors.alertTextInfo,
borderColor: colors.alertBorderInfo,
backGroundColor: colors.alertBackgroundInfo,
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-.deferred-spinner {
- position: relative;
- vertical-align: middle;
- width: 16px;
- height: 16px;
- border: 2px solid var(--blue);
- border-radius: 50%;
- animation: spin 0.75s infinite linear;
-}
-
-.deferred-spinner:before,
-.deferred-spinner:after {
- left: -2px;
- top: -2px;
- display: none;
- position: absolute;
- content: '';
- width: inherit;
- height: inherit;
- border: inherit;
- border-radius: inherit;
-}
-
-.deferred-spinner,
-.deferred-spinner:before,
-.deferred-spinner:after {
- display: inline-block;
- box-sizing: border-box;
- border-color: transparent;
- border-top-color: var(--info500);
- animation-duration: 1.2s;
-}
-
-.deferred-spinner:before {
- transform: rotate(120deg);
-}
-
-.deferred-spinner:after {
- transform: rotate(240deg);
-}
-
-.deferred-spinner-placeholder {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- width: 16px;
- height: 16px;
- visibility: hidden;
-}
-
-@keyframes spin {
- from {
- transform: rotate(0deg);
- }
-
- to {
- transform: rotate(360deg);
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import * as React from 'react';
-import { translate } from '../../helpers/l10n';
-import './DeferredSpinner.css';
-
-interface Props {
- ariaLabel?: string;
- children?: React.ReactNode;
- className?: string;
- customSpinner?: JSX.Element;
- loading?: boolean;
- timeout?: number;
-}
-
-interface State {
- showSpinner: boolean;
-}
-
-const DEFAULT_TIMEOUT = 100;
-
-/**
- * Recommendation: do not render this component conditionally based on any loading state:
- * // Don't do this:
- * {loading && <DeferredSpinner />}
- * Instead, pass the loading state as a prop:
- * // Do this:
- * <DeferredSpinner loading={loading} />
- */
-export default class DeferredSpinner extends React.PureComponent<Props, State> {
- timer?: number;
-
- state: State = { showSpinner: false };
-
- componentDidMount() {
- if (this.props.loading == null || this.props.loading === true) {
- this.startTimer();
- }
- }
-
- componentDidUpdate(prevProps: Props) {
- if (prevProps.loading === false && this.props.loading === true) {
- this.stopTimer();
- this.startTimer();
- }
- if (prevProps.loading === true && this.props.loading === false) {
- this.stopTimer();
- this.setState({ showSpinner: false });
- }
- }
-
- componentWillUnmount() {
- this.stopTimer();
- }
-
- startTimer = () => {
- this.timer = window.setTimeout(
- () => this.setState({ showSpinner: true }),
- this.props.timeout || DEFAULT_TIMEOUT
- );
- };
-
- stopTimer = () => {
- window.clearTimeout(this.timer);
- };
-
- render() {
- const { ariaLabel = translate('loading'), children, className, customSpinner } = this.props;
- const { showSpinner } = this.state;
-
- if (customSpinner) {
- return showSpinner ? customSpinner : children;
- }
-
- return (
- <>
- <div className="sw-overflow-hidden">
- <i
- aria-live="polite"
- data-testid="deferred-spinner"
- className={classNames('deferred-spinner', className, {
- 'a11y-hidden': !showSpinner,
- 'is-loading': showSpinner,
- })}
- >
- {showSpinner && <span className="a11y-hidden">{ariaLabel}</span>}
- </i>
- </div>
- {!showSpinner && children}
- </>
- );
- }
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+.spinner {
+ position: relative;
+ vertical-align: middle;
+ width: 16px;
+ height: 16px;
+ border: 2px solid var(--blue);
+ border-radius: 50%;
+ animation: spin 0.75s infinite linear;
+}
+
+.spinner:before,
+.spinner:after {
+ left: -2px;
+ top: -2px;
+ display: none;
+ position: absolute;
+ content: '';
+ width: inherit;
+ height: inherit;
+ border: inherit;
+ border-radius: inherit;
+}
+
+.spinner,
+.spinner:before,
+.spinner:after {
+ display: inline-block;
+ box-sizing: border-box;
+ border-color: transparent;
+ border-top-color: var(--info500);
+ animation-duration: 1.2s;
+}
+
+.spinner:before {
+ transform: rotate(120deg);
+}
+
+.spinner:after {
+ transform: rotate(240deg);
+}
+
+.spinner-placeholder {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ width: 16px;
+ height: 16px;
+ visibility: hidden;
+}
+
+@keyframes spin {
+ from {
+ transform: rotate(0deg);
+ }
+
+ to {
+ transform: rotate(360deg);
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import classNames from 'classnames';
+import * as React from 'react';
+import { translate } from '../../helpers/l10n';
+import './Spinner.css';
+
+interface Props {
+ ariaLabel?: string;
+ children?: React.ReactNode;
+ className?: string;
+ customSpinner?: JSX.Element;
+ loading?: boolean;
+}
+
+export default function Spinner(props: Props) {
+ const {
+ ariaLabel = translate('loading'),
+ children,
+ className,
+ customSpinner,
+ loading = true,
+ } = props;
+
+ if (customSpinner) {
+ return <>{loading ? customSpinner : children}</>;
+ }
+
+ return (
+ <>
+ <div className="sw-overflow-hidden">
+ <i
+ aria-live="polite"
+ data-testid="spinner"
+ className={classNames('spinner', className, {
+ 'a11y-hidden': !loading,
+ 'is-loading': loading,
+ })}
+ >
+ {loading && <span className="a11y-hidden">{ariaLabel}</span>}
+ </i>
+ </div>
+ {!loading && children}
+ </>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import { render, screen } from '@testing-library/react';
-import * as React from 'react';
-import DeferredSpinner from '../DeferredSpinner';
-
-beforeEach(() => {
- jest.useFakeTimers();
-});
-
-afterEach(() => {
- jest.runOnlyPendingTimers();
- jest.useRealTimers();
-});
-
-it('renders children before timeout', () => {
- renderDeferredSpinner({ children: <a href="#">foo</a> });
- expect(screen.getByRole('link')).toBeInTheDocument();
- jest.runAllTimers();
- expect(screen.queryByRole('link')).not.toBeInTheDocument();
-});
-
-it('renders spinner after timeout', () => {
- renderDeferredSpinner();
- expect(screen.queryByText('loading')).not.toBeInTheDocument();
- jest.runAllTimers();
- expect(screen.getByText('loading')).toBeInTheDocument();
-});
-
-it('allows setting a custom class name', () => {
- renderDeferredSpinner({ className: 'foo' });
- jest.runAllTimers();
- expect(screen.getByTestId('deferred-spinner')).toHaveClass('foo');
-});
-
-it('can be controlled by the loading prop', () => {
- const { rerender } = renderDeferredSpinner({ loading: true });
- jest.runAllTimers();
- expect(screen.getByText('loading')).toBeInTheDocument();
-
- rerender(prepareDeferredSpinner({ loading: false }));
- expect(screen.queryByText('loading')).not.toBeInTheDocument();
-});
-
-function renderDeferredSpinner(props: Partial<DeferredSpinner['props']> = {}) {
- // We don't use our renderComponent() helper here, as we have some tests that
- // require changes in props.
- return render(prepareDeferredSpinner(props));
-}
-
-function prepareDeferredSpinner(props: Partial<DeferredSpinner['props']> = {}) {
- return <DeferredSpinner ariaLabel="loading" {...props} />;
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2023 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { render, screen } from '@testing-library/react';
+import * as React from 'react';
+import Spinner from '../Spinner';
+
+it('can be controlled by the loading prop', () => {
+ const { rerender } = renderSpinner({ loading: true });
+ expect(screen.getByText('loading')).toBeInTheDocument();
+
+ rerender(prepareSpinner({ loading: false }));
+ expect(screen.queryByText('loading')).not.toBeInTheDocument();
+});
+
+function renderSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
+ // We don't use our renderComponent() helper here, as we have some tests that
+ // require changes in props.
+ return render(prepareSpinner(props));
+}
+
+function prepareSpinner(props: Partial<Parameters<typeof Spinner>[0]> = {}) {
+ return <Spinner ariaLabel="loading" {...props} />;
+}
import RuleDetailsDescription from '../../apps/coding-rules/components/RuleDetailsDescription';
import RuleDetailsMeta from '../../apps/coding-rules/components/RuleDetailsMeta';
import '../../apps/coding-rules/styles.css';
-import DeferredSpinner from '../../components/ui/DeferredSpinner';
import { Dict, RuleDetails } from '../../types/types';
+import Spinner from '../ui/Spinner';
interface Props {
onLoad: (details: { name: string }) => void;
render() {
return (
- <DeferredSpinner loading={this.state.loading}>
+ <Spinner loading={this.state.loading}>
{this.state.ruleDetails && (
<>
<RuleDetailsMeta
/>
</>
)}
- </DeferredSpinner>
+ </Spinner>
);
}
}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render 1`] = `
-<DeferredSpinner
+<Spinner
loading={true}
/>
`;
exports[`should render 2`] = `
-<DeferredSpinner
+<Spinner
loading={false}
>
<RuleDetailsMeta
}
}
/>
-</DeferredSpinner>
+</Spinner>
`;
import { omit } from 'lodash';
import * as React from 'react';
import { HelmetProvider } from 'react-helmet-async';
-import { IntlProvider } from 'react-intl';
+import { IntlProvider, ReactIntlErrorCode } from 'react-intl';
import { MemoryRouter, Outlet, Route, Routes, parsePath } from 'react-router-dom';
import AdminContext from '../app/components/AdminContext';
import GlobalMessagesContainer from '../app/components/GlobalMessagesContainer';
const queryClient = new QueryClient();
return (
- <IntlProvider defaultLocale="en" locale="en">
+ <IntlWrapper>
<QueryClientProvider client={queryClient}>
<HelmetProvider>
<AvailableFeaturesContext.Provider value={featureList}>
</AvailableFeaturesContext.Provider>
</HelmetProvider>
</QueryClientProvider>
- </IntlProvider>
+ </IntlWrapper>
);
}
return render(
<HelmetProvider context={{}}>
- <IntlProvider defaultLocale="en" locale="en">
+ <IntlWrapper>
<MetricsContext.Provider value={metrics}>
<LanguagesContext.Provider value={languages}>
<AvailableFeaturesContext.Provider value={featureList}>
</AvailableFeaturesContext.Provider>
</LanguagesContext.Provider>
</MetricsContext.Provider>
- </IntlProvider>
+ </IntlWrapper>
</HelmetProvider>
);
}
? within(target).getByText(text, { selector })
: screen.getByText(text, { selector });
}
+
+export function IntlWrapper({
+ children,
+ messages = {},
+}: {
+ children: React.ReactNode;
+ messages?: Record<string, string>;
+}) {
+ return (
+ <IntlProvider
+ defaultLocale="en"
+ locale="en"
+ messages={messages}
+ onError={(e) => {
+ // ignore missing translations, there are none!
+ if (e.code !== ReactIntlErrorCode.MISSING_TRANSLATION) {
+ // eslint-disable-next-line no-console
+ console.error(e);
+ }
+ }}
+ >
+ {children}
+ </IntlProvider>
+ );
+}