|
@@ -4,9 +4,11 @@ import omitBy from 'lodash/omitBy';
|
|
|
|
|
|
import {addErrorMessage} from 'sentry/actionCreators/indicator';
|
|
|
import {Client} from 'sentry/api';
|
|
|
-import {getInterval} from 'sentry/components/charts/utils';
|
|
|
+import {getInterval, shouldFetchPreviousPeriod} from 'sentry/components/charts/utils';
|
|
|
+import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
|
|
|
import {t} from 'sentry/locale';
|
|
|
import {DateString, MetricsApiResponse, Organization} from 'sentry/types';
|
|
|
+import {getPeriod} from 'sentry/utils/getPeriod';
|
|
|
|
|
|
const propNamesToIgnore = ['api', 'children'];
|
|
|
const omitIgnoredProps = (props: Props) =>
|
|
@@ -17,9 +19,17 @@ export type MetricsRequestRenderProps = {
|
|
|
reloading: boolean;
|
|
|
errored: boolean;
|
|
|
response: MetricsApiResponse | null;
|
|
|
+ responsePrevious: MetricsApiResponse | null;
|
|
|
};
|
|
|
|
|
|
-type Props = {
|
|
|
+type DefaultProps = {
|
|
|
+ /**
|
|
|
+ * Include data for previous period
|
|
|
+ */
|
|
|
+ includePrevious: boolean;
|
|
|
+};
|
|
|
+
|
|
|
+type Props = DefaultProps & {
|
|
|
api: Client;
|
|
|
organization: Organization;
|
|
|
field: string[];
|
|
@@ -41,13 +51,19 @@ type State = {
|
|
|
reloading: boolean;
|
|
|
errored: boolean;
|
|
|
response: MetricsApiResponse | null;
|
|
|
+ responsePrevious: MetricsApiResponse | null;
|
|
|
};
|
|
|
|
|
|
class MetricsRequest extends React.Component<Props, State> {
|
|
|
+ static defaultProps: DefaultProps = {
|
|
|
+ includePrevious: false,
|
|
|
+ };
|
|
|
+
|
|
|
state: State = {
|
|
|
reloading: false,
|
|
|
errored: false,
|
|
|
response: null,
|
|
|
+ responsePrevious: null,
|
|
|
};
|
|
|
|
|
|
componentDidMount() {
|
|
@@ -74,7 +90,7 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
return `/organizations/${organization.slug}/metrics/data/`;
|
|
|
}
|
|
|
|
|
|
- get baseQueryParams() {
|
|
|
+ baseQueryParams({previousPeriod = false} = {}) {
|
|
|
const {
|
|
|
project,
|
|
|
environment,
|
|
@@ -89,23 +105,40 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
interval,
|
|
|
} = this.props;
|
|
|
|
|
|
- return {
|
|
|
+ const commonQuery = {
|
|
|
project,
|
|
|
environment,
|
|
|
field,
|
|
|
- statsPeriod,
|
|
|
query: query || undefined,
|
|
|
groupBy,
|
|
|
orderBy,
|
|
|
limit,
|
|
|
- start: start ?? undefined,
|
|
|
- end: end ?? undefined,
|
|
|
interval: interval ? interval : getInterval({start, end, period: statsPeriod}),
|
|
|
};
|
|
|
+
|
|
|
+ if (!previousPeriod) {
|
|
|
+ return {
|
|
|
+ ...commonQuery,
|
|
|
+ statsPeriod,
|
|
|
+ start: start ?? undefined,
|
|
|
+ end: end ?? undefined,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ const doubledStatsPeriod = getPeriod(
|
|
|
+ {period: statsPeriod, start: undefined, end: undefined},
|
|
|
+ {shouldDoublePeriod: true}
|
|
|
+ ).statsPeriod;
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...commonQuery,
|
|
|
+ statsPeriodStart: doubledStatsPeriod,
|
|
|
+ statsPeriodEnd: statsPeriod ?? DEFAULT_STATS_PERIOD,
|
|
|
+ };
|
|
|
}
|
|
|
|
|
|
fetchData = async () => {
|
|
|
- const {api, isDisabled} = this.props;
|
|
|
+ const {api, isDisabled, start, end, statsPeriod, includePrevious} = this.props;
|
|
|
|
|
|
if (isDisabled) {
|
|
|
return;
|
|
@@ -116,10 +149,21 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
errored: false,
|
|
|
}));
|
|
|
|
|
|
+ const promises = [api.requestPromise(this.path, {query: this.baseQueryParams()})];
|
|
|
+
|
|
|
+ if (shouldFetchPreviousPeriod({start, end, period: statsPeriod, includePrevious})) {
|
|
|
+ promises.push(
|
|
|
+ api.requestPromise(this.path, {
|
|
|
+ query: this.baseQueryParams({previousPeriod: true}),
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
try {
|
|
|
- const response: MetricsApiResponse = await api.requestPromise(this.path, {
|
|
|
- query: this.baseQueryParams,
|
|
|
- });
|
|
|
+ const [response, responsePrevious] = (await Promise.all(promises)) as [
|
|
|
+ MetricsApiResponse,
|
|
|
+ MetricsApiResponse | undefined
|
|
|
+ ];
|
|
|
|
|
|
if (this.unmounting) {
|
|
|
return;
|
|
@@ -128,6 +172,7 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
this.setState({
|
|
|
reloading: false,
|
|
|
response,
|
|
|
+ responsePrevious: responsePrevious ?? null,
|
|
|
});
|
|
|
} catch (error) {
|
|
|
addErrorMessage(error.responseJSON?.detail ?? t('Error loading metrics data'));
|
|
@@ -139,7 +184,7 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
};
|
|
|
|
|
|
render() {
|
|
|
- const {reloading, errored, response} = this.state;
|
|
|
+ const {reloading, errored, response, responsePrevious} = this.state;
|
|
|
const {children, isDisabled} = this.props;
|
|
|
|
|
|
const loading = response === null && !isDisabled;
|
|
@@ -149,6 +194,7 @@ class MetricsRequest extends React.Component<Props, State> {
|
|
|
reloading,
|
|
|
errored,
|
|
|
response,
|
|
|
+ responsePrevious,
|
|
|
});
|
|
|
}
|
|
|
}
|