|
@@ -5,13 +5,15 @@ import styled from '@emotion/styled';
|
|
|
import {Button} from 'sentry/components/button';
|
|
|
import {ExportQueryType} from 'sentry/components/dataExport';
|
|
|
import {DateTime} from 'sentry/components/dateTime';
|
|
|
+import LoadingIndicator from 'sentry/components/loadingIndicator';
|
|
|
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
|
|
|
import {IconDownload} from 'sentry/icons';
|
|
|
import {t, tct} from 'sentry/locale';
|
|
|
import {space} from 'sentry/styles/space';
|
|
|
-import {browserHistory} from 'sentry/utils/browserHistory';
|
|
|
+import {useApiQuery} from 'sentry/utils/queryClient';
|
|
|
+import {useRouteContext} from 'sentry/utils/useRouteContext';
|
|
|
import {normalizeUrl} from 'sentry/utils/withDomainRequired';
|
|
|
import Layout from 'sentry/views/auth/layout';
|
|
|
-import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
|
|
|
|
|
|
export enum DownloadStatus {
|
|
|
EARLY = 'EARLY',
|
|
@@ -44,33 +46,43 @@ type Download = {
|
|
|
|
|
|
type Props = {} & RouteComponentProps<RouteParams, {}>;
|
|
|
|
|
|
-type State = {
|
|
|
- download: Download;
|
|
|
- errors: {
|
|
|
- download: {
|
|
|
- responseJSON: {
|
|
|
- detail: string;
|
|
|
- };
|
|
|
- status: number;
|
|
|
- statusText: string;
|
|
|
- };
|
|
|
- };
|
|
|
-} & DeprecatedAsyncView['state'];
|
|
|
+function DataDownload({params: {orgId, dataExportId}}: Props) {
|
|
|
+ const {
|
|
|
+ data: download,
|
|
|
+ isLoading,
|
|
|
+ isError,
|
|
|
+ error,
|
|
|
+ } = useApiQuery<Download>([`/organizations/${orgId}/data-export/${dataExportId}/`], {
|
|
|
+ staleTime: 0,
|
|
|
+ });
|
|
|
|
|
|
-class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
- disableErrorReport = false;
|
|
|
+ const route = useRouteContext();
|
|
|
|
|
|
- getTitle(): string {
|
|
|
- return t('Download Center');
|
|
|
+ if (isError) {
|
|
|
+ const errDetail = error?.responseJSON?.detail;
|
|
|
+ return (
|
|
|
+ <Layout>
|
|
|
+ <main>
|
|
|
+ <Header>
|
|
|
+ <h3>
|
|
|
+ {error.status} - {error.statusText}
|
|
|
+ </h3>
|
|
|
+ </Header>
|
|
|
+ {errDetail && (
|
|
|
+ <Body>
|
|
|
+ <p>{errDetail as string}</p>
|
|
|
+ </Body>
|
|
|
+ )}
|
|
|
+ </main>
|
|
|
+ </Layout>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
- getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
|
|
|
- const {orgId, dataExportId} = this.props.params;
|
|
|
- return [['download', `/organizations/${orgId}/data-export/${dataExportId}/`]];
|
|
|
+ if (isLoading) {
|
|
|
+ return <LoadingIndicator />;
|
|
|
}
|
|
|
|
|
|
- getActionLink(queryType): string {
|
|
|
- const {orgId} = this.props.params;
|
|
|
+ const getActionLink = (queryType): string => {
|
|
|
switch (queryType) {
|
|
|
case ExportQueryType.ISSUES_BY_TAG:
|
|
|
return `/organizations/${orgId}/issues/`;
|
|
@@ -79,9 +91,9 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
default:
|
|
|
return '/';
|
|
|
}
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderDate(date: string | undefined): React.ReactNode {
|
|
|
+ const renderDate = (date: string | undefined): React.ReactNode => {
|
|
|
if (!date) {
|
|
|
return null;
|
|
|
}
|
|
@@ -91,9 +103,9 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
<DateTime date={d} />
|
|
|
</strong>
|
|
|
);
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderEarly(): React.ReactNode {
|
|
|
+ const renderEarly = (): React.ReactNode => {
|
|
|
return (
|
|
|
<Fragment>
|
|
|
<Header>
|
|
@@ -113,11 +125,11 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
</Body>
|
|
|
</Fragment>
|
|
|
);
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderExpired(): React.ReactNode {
|
|
|
- const {query} = this.state.download;
|
|
|
- const actionLink = this.getActionLink(query.type);
|
|
|
+ const renderExpired = (): React.ReactNode => {
|
|
|
+ const {query} = download;
|
|
|
+ const actionLink = getActionLink(query.type);
|
|
|
return (
|
|
|
<Fragment>
|
|
|
<Header>
|
|
@@ -140,33 +152,29 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
</Body>
|
|
|
</Fragment>
|
|
|
);
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- openInDiscover() {
|
|
|
+ const openInDiscover = () => {
|
|
|
+ const navigator = route.router;
|
|
|
const {
|
|
|
- download: {
|
|
|
- query: {info},
|
|
|
- },
|
|
|
- } = this.state;
|
|
|
- const {orgId} = this.props.params;
|
|
|
+ query: {info},
|
|
|
+ } = download;
|
|
|
|
|
|
const to = {
|
|
|
pathname: `/organizations/${orgId}/discover/results/`,
|
|
|
query: info,
|
|
|
};
|
|
|
|
|
|
- browserHistory.push(normalizeUrl(to));
|
|
|
- }
|
|
|
+ navigator.push(normalizeUrl(to));
|
|
|
+ };
|
|
|
|
|
|
- renderOpenInDiscover() {
|
|
|
+ const renderOpenInDiscover = () => {
|
|
|
const {
|
|
|
- download: {
|
|
|
- query = {
|
|
|
- type: ExportQueryType.ISSUES_BY_TAG,
|
|
|
- info: {},
|
|
|
- },
|
|
|
+ query = {
|
|
|
+ type: ExportQueryType.ISSUES_BY_TAG,
|
|
|
+ info: {},
|
|
|
},
|
|
|
- } = this.state;
|
|
|
+ } = download;
|
|
|
|
|
|
// default to IssuesByTag because we don't want to
|
|
|
// display this unless we're sure its a discover query
|
|
@@ -175,19 +183,16 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
return type === 'Discover' ? (
|
|
|
<Fragment>
|
|
|
<p>{t('Need to make changes?')}</p>
|
|
|
- <Button priority="primary" onClick={() => this.openInDiscover()}>
|
|
|
+ <Button priority="primary" onClick={() => openInDiscover()}>
|
|
|
{t('Open in Discover')}
|
|
|
</Button>
|
|
|
<br />
|
|
|
</Fragment>
|
|
|
) : null;
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderValid(): React.ReactNode {
|
|
|
- const {
|
|
|
- download: {dateExpired, checksum},
|
|
|
- } = this.state;
|
|
|
- const {orgId, dataExportId} = this.props.params;
|
|
|
+ const renderValid = (): React.ReactNode => {
|
|
|
+ const {dateExpired, checksum} = download;
|
|
|
|
|
|
return (
|
|
|
<Fragment>
|
|
@@ -206,9 +211,9 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
<p>
|
|
|
{t("That link won't last forever — it expires:")}
|
|
|
<br />
|
|
|
- {this.renderDate(dateExpired)}
|
|
|
+ {renderDate(dateExpired)}
|
|
|
</p>
|
|
|
- {this.renderOpenInDiscover()}
|
|
|
+ {renderOpenInDiscover()}
|
|
|
<p>
|
|
|
<small>
|
|
|
<strong>SHA1:{checksum}</strong>
|
|
@@ -229,50 +234,26 @@ class DataDownload extends DeprecatedAsyncView<Props, State> {
|
|
|
</Body>
|
|
|
</Fragment>
|
|
|
);
|
|
|
- }
|
|
|
-
|
|
|
- renderError(): React.ReactNode {
|
|
|
- const {
|
|
|
- errors: {download: err},
|
|
|
- } = this.state;
|
|
|
- const errDetail = err?.responseJSON?.detail;
|
|
|
- return (
|
|
|
- <Layout>
|
|
|
- <main>
|
|
|
- <Header>
|
|
|
- <h3>
|
|
|
- {err.status} - {err.statusText}
|
|
|
- </h3>
|
|
|
- </Header>
|
|
|
- {errDetail && (
|
|
|
- <Body>
|
|
|
- <p>{errDetail}</p>
|
|
|
- </Body>
|
|
|
- )}
|
|
|
- </main>
|
|
|
- </Layout>
|
|
|
- );
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderContent(): React.ReactNode {
|
|
|
- const {download} = this.state;
|
|
|
+ const renderContent = () => {
|
|
|
switch (download.status) {
|
|
|
case DownloadStatus.EARLY:
|
|
|
- return this.renderEarly();
|
|
|
+ return renderEarly();
|
|
|
case DownloadStatus.EXPIRED:
|
|
|
- return this.renderExpired();
|
|
|
+ return renderExpired();
|
|
|
default:
|
|
|
- return this.renderValid();
|
|
|
+ return renderValid();
|
|
|
}
|
|
|
- }
|
|
|
+ };
|
|
|
|
|
|
- renderBody() {
|
|
|
- return (
|
|
|
+ return (
|
|
|
+ <SentryDocumentTitle title={t('Download Center')}>
|
|
|
<Layout>
|
|
|
- <main>{this.renderContent()}</main>
|
|
|
+ <main>{renderContent()}</main>
|
|
|
</Layout>
|
|
|
- );
|
|
|
- }
|
|
|
+ </SentryDocumentTitle>
|
|
|
+ );
|
|
|
}
|
|
|
|
|
|
const Header = styled('header')`
|