Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fixtures/page_objects/dashboard_detail.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def save_dashboard(self):
# until the API call finishes. Since the loading indicator isn't used
# we can't rely on self.wait_until_loaded(). The UI shows a
# success toast, however if a previous step of a test shows a success
# toast, a wait_until([data-test-id="toast-success"]) will return
# toast, a wait for the status role will return
# immediately due to the previous toast still being in the DOM.
# Since clicking the save dasboard button is removed once the API
# call is complete, we can wait for that as a signal
Expand Down
5 changes: 3 additions & 2 deletions fixtures/page_objects/issue_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ def resolve_issues(self):
self.browser.click('[aria-label="Resolve"]')

def wait_for_issue_removal(self):
self.browser.click_when_visible('[data-test-id="toast-success"]')
self.browser.wait_until_not('[data-test-id="toast-success"]')
toast_selector = '[role="status"]'
self.browser.click_when_visible(f'{toast_selector} [aria-label="Dismiss"]')
self.browser.wait_until_not(toast_selector)

def wait_for_issue(self):
self.browser.wait_until('[data-test-id="group"]')
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@
"remark-gfm": "^4.0.1",
"remark-mdx-frontmatter": "^5.2.0",
"screenfull": "^6.0.2",
"sonner": "2.0.8",
"sprintf-js": "1.0.3",
"style-loader": "4.0.0",
"swc-plugin-component-annotate": "1.18.0",
Expand Down
20 changes: 20 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

82 changes: 52 additions & 30 deletions static/app/actionCreators/indicator.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {isValidElement} from 'react';
import * as Sentry from '@sentry/react';

import type {FormModel} from 'sentry/components/forms/model';
import {DEFAULT_TOAST_DURATION} from 'sentry/constants';
import {toast, type ToastOptions} from '@sentry/scraps/toast';

import {IconRefresh} from 'sentry/icons';
import {t} from 'sentry/locale';
import {IndicatorStore} from 'sentry/stores/indicatorStore';
import {isDemoModeActive} from 'sentry/utils/demoMode';

type IndicatorType = 'loading' | 'error' | 'success' | 'undo' | '';
Expand All @@ -18,27 +18,17 @@ interface IndicatorOptions {

type UndoIndicatorOptions = IndicatorOptions & {undo: () => void};

interface UndoableIndicatorOptions extends IndicatorOptions {
formModel: {
id: string;
model: FormModel;
};
}

export type Indicator = {
id: string | number;
message: React.ReactNode;
options: IndicatorOptions;
type: IndicatorType;
clearId?: null | number;
};

// Clears all indicators
/**
* @deprecated Use `toast.dismiss()` from `@sentry/scraps/toast` instead.
*/
export function clearIndicators() {
IndicatorStore.clear();
toast.dismiss();
}

// Note previous IndicatorStore.add behavior was to default to "loading" if no type was supplied
/**
* @deprecated Use the namespaced API from `@sentry/scraps/toast` instead.
*/
export function addMessage(
msg: React.ReactNode,
type: 'undo',
Expand All @@ -54,7 +44,7 @@ export function addMessage(
type: IndicatorType,
options: IndicatorOptions = {}
): void {
const {duration: optionsDuration, append, ...rest} = options;
const {duration: optionsDuration, disableDismiss, undo} = options;

// XXX: Debug for https://sentry.io/organizations/sentry/issues/1595204979/
if (
Expand All @@ -70,24 +60,53 @@ export function addMessage(
);
}

// use default only if undefined, as 0 is a valid duration
const duration =
optionsDuration === undefined ? DEFAULT_TOAST_DURATION : optionsDuration;
const toastOptions: ToastOptions = {
dismissible: disableDismiss !== true,
};

const action = append ? 'append' : 'add';
// XXX: This differs from `IndicatorStore.add` since it won't return the indicator that is created
// because we are firing an action. You can just add a new message and it will, by default,
// replace active indicator
IndicatorStore[action](msg, type, {...rest, duration});
if (optionsDuration !== undefined) {
toastOptions.duration =
optionsDuration === null || optionsDuration === 0 ? Infinity : optionsDuration;
}

if (typeof undo === 'function') {
toastOptions.action = {
label: t('Undo'),
icon: <IconRefresh size="xs" />,
onClick: undo,
};
}

switch (type) {
case 'loading':
toast.loading(msg, toastOptions);
break;
case 'error':
toast.error(msg, toastOptions);
break;
case 'success':
toast.success(msg, toastOptions);
break;
case 'undo':
case '':
toast.message(msg, toastOptions);
break;
}
}

/**
* @deprecated Use `toast.loading()` from `@sentry/scraps/toast` instead.
*/
export function addLoadingMessage(
msg: React.ReactNode = t('Saving changes...'),
options?: IndicatorOptions
) {
return addMessage(msg, 'loading', options);
}

/**
* @deprecated Use `toast.error()` from `@sentry/scraps/toast` instead.
*/
export function addErrorMessage(msg: React.ReactNode, options?: IndicatorOptions) {
if (isDemoModeActive()) {
return addMessage(t('This action is not allowed in demo mode.'), 'error', options);
Expand All @@ -108,9 +127,12 @@ export function addErrorMessage(msg: React.ReactNode, options?: IndicatorOptions
);
}

/**
* @deprecated Use `toast.success()` from `@sentry/scraps/toast` instead.
*/
export function addSuccessMessage(
msg: React.ReactNode,
options?: IndicatorOptions | UndoableIndicatorOptions
options?: IndicatorOptions | UndoIndicatorOptions
) {
return addMessage(msg, 'success', options);
}
16 changes: 0 additions & 16 deletions static/app/bootstrap/processInitQueue.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {TeamFixture} from 'sentry-fixture/team';
import {screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';

import {processInitQueue} from 'sentry/bootstrap/processInitQueue';
import {IndicatorStore} from 'sentry/stores/indicatorStore';
import {SentryInitRenderReactComponent} from 'sentry/types/system';

describe('processInitQueue', () => {
Expand Down Expand Up @@ -45,21 +44,6 @@ describe('processInitQueue', () => {
expect(await screen.findByText('Very Strong')).toBeInTheDocument();
});

it('renders indicators', async () => {
window.__onSentryInit = [
{
component: SentryInitRenderReactComponent.INDICATORS,
container: '#indicator-container',
name: 'renderReact',
},
];

IndicatorStore.add('Indicator Alert', 'success');

render(<div id="indicator-container" />);
processInitQueue();
expect(await screen.findByText('Indicator Alert')).toBeInTheDocument();
});
it('renders setup wizard', async () => {
window.__onSentryInit = [
{
Expand Down
2 changes: 0 additions & 2 deletions static/app/bootstrap/processInitQueue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ import {renderOnDomReady} from './renderOnDomReady';
const queryClient = new QueryClient(DEFAULT_QUERY_CLIENT_CONFIG);

const COMPONENT_MAP = {
[SentryInitRenderReactComponent.INDICATORS]: () =>
import(/* webpackChunkName: "Indicators" */ 'sentry/components/indicators'),
[SentryInitRenderReactComponent.SETUP_WIZARD]: () =>
import(/* webpackChunkName: "SetupWizard" */ 'sentry/views/setupWizard'),
[SentryInitRenderReactComponent.WEB_AUTHN_ASSSERT]: () =>
Expand Down
5 changes: 4 additions & 1 deletion static/app/components/core/toast/index.tsx
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
export {Toast} from './toast';
export {toast} from './toastApi';
export {ToastProvider} from './toaster';
export {DEFAULT_TOAST_DURATION} from './types';
export type {ToastAction, ToastOptions, ToastVariant} from './types';
Loading
Loading