Просмотр исходного кода

ref(pageFilters): Organize pageFilters parsing into parse module (#31027)

Evan Purkhiser 3 лет назад
Родитель
Сommit
6dc41ace06

+ 1 - 1
static/app/actionCreators/pageFilters.tsx

@@ -6,10 +6,10 @@ import pick from 'lodash/pick';
 import * as qs from 'query-string';
 
 import PageFiltersActions from 'sentry/actions/pageFiltersActions';
+import {getStateFromQuery} from 'sentry/components/organizations/pageFilters/parse';
 import {
   getDefaultSelection,
   getPageFilterStorage,
-  getStateFromQuery,
   setPageFiltersStorage,
 } from 'sentry/components/organizations/pageFilters/utils';
 import {DATE_TIME, URL_PARAM} from 'sentry/constants/pageFilters';

+ 4 - 2
static/app/actionCreators/tags.tsx

@@ -3,7 +3,7 @@ import {Query} from 'history';
 import AlertActions from 'sentry/actions/alertActions';
 import TagActions from 'sentry/actions/tagActions';
 import {Client} from 'sentry/api';
-import {getParams} from 'sentry/components/organizations/pageFilters/getParams';
+import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
 import {t} from 'sentry/locale';
 import TagStore from 'sentry/stores/tagStore';
 import {PageFilters, Tag} from 'sentry/types';
@@ -31,7 +31,9 @@ export function loadOrganizationTags(api: Client, orgId: string, selection: Page
   TagStore.reset();
 
   const url = `/organizations/${orgId}/tags/`;
-  const query: Query = selection.datetime ? {...getParams(selection.datetime)} : {};
+  const query: Query = selection.datetime
+    ? {...normalizeDateTimeParams(selection.datetime)}
+    : {};
   query.use_cache = '1';
 
   if (selection.projects) {

+ 1 - 1
static/app/components/organizations/pageFilters/container.tsx

@@ -18,7 +18,7 @@ import useProjects from 'sentry/utils/useProjects';
 import withOrganization from 'sentry/utils/withOrganization';
 
 import GlobalSelectionHeader from './globalSelectionHeader';
-import {getStateFromQuery} from './utils';
+import {getStateFromQuery} from './parse';
 
 const getDateObjectFromQuery = (query: Record<string, any>) =>
   Object.fromEntries(

+ 125 - 17
static/app/components/organizations/pageFilters/getParams.tsx → static/app/components/organizations/pageFilters/parse.tsx

@@ -1,8 +1,11 @@
+import {Location} from 'history';
 import moment from 'moment';
 
 import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
+import {URL_PARAM} from 'sentry/constants/pageFilters';
 import {IntervalPeriod} from 'sentry/types';
 import {defined} from 'sentry/utils';
+import {getUtcToLocalDateObject} from 'sentry/utils/dates';
 
 export type StatsPeriodType = 'h' | 'd' | 's' | 'm' | 'w';
 
@@ -117,35 +120,101 @@ function getUtcValue(maybe: boolean | ParamValue) {
   return parseUtcValue(result);
 }
 
-type ParsedParams = {
-  start?: string;
-  end?: string;
-  period?: string;
-  utc?: string;
-  [others: string]: string | null | undefined;
-};
+/**
+ * Normalizes a string or string[] into the project list parameter
+ */
+function getProject(maybe: ParamValue) {
+  if (!defined(maybe)) {
+    return undefined;
+  }
+
+  if (Array.isArray(maybe)) {
+    return maybe.map(p => parseInt(p, 10));
+  }
+
+  const projectFromQueryIdInt = parseInt(maybe, 10);
+  return isNaN(projectFromQueryIdInt) ? [] : [projectFromQueryIdInt];
+}
+
+/*
+ * Normalizes a string or string[] into the environment list parameter
+ */
+function getEnvironment(maybe: ParamValue) {
+  if (!defined(maybe)) {
+    return undefined;
+  }
+
+  if (Array.isArray(maybe)) {
+    return maybe;
+  }
+
+  return [maybe];
+}
 
 type InputParams = {
   pageStatsPeriod?: ParamValue;
-  pageStart?: Date | ParamValue;
-  pageEnd?: Date | ParamValue;
-  pageUtc?: boolean | ParamValue;
-  start?: Date | ParamValue;
-  end?: Date | ParamValue;
+  pageStart?: ParamValue | Date;
+  pageEnd?: ParamValue | Date;
+  pageUtc?: ParamValue | boolean;
+
+  start?: ParamValue | Date;
+  end?: ParamValue | Date;
   period?: ParamValue;
   statsPeriod?: ParamValue;
-  utc?: boolean | ParamValue;
+  utc?: ParamValue | boolean;
+
   [others: string]: any;
 };
 
-type Options = {
+type ParsedParams = {
+  start?: string;
+  end?: string;
+  statsPeriod?: string;
+  utc?: string;
+  [others: string]: Location['query'][string];
+};
+
+type DateTimeNormalizeOptions = {
+  /**
+   * When set to true allows the statsPeriod to result as `null`.
+   *
+   * @default false
+   */
   allowEmptyPeriod?: boolean;
+  /**
+   * Include this default statsPeriod in the resulting parsed parameters when
+   * no stats period is provided (or if it is an invalid stats period)
+   */
+  defaultStatsPeriod?: string;
+  /**
+   * Parse absolute date time (`start` / `end`) from the input parameters. When
+   * set to false the start and end will always be `null`.
+   *
+   * @default true
+   */
   allowAbsoluteDatetime?: boolean;
+  /**
+   * The page specific version of allowAbsolutePageDatetime
+   *
+   * @default false
+   */
   allowAbsolutePageDatetime?: boolean;
-  defaultStatsPeriod?: string;
 };
 
-export function getParams(params: InputParams, options: Options = {}): ParsedParams {
+/**
+ * Normalizes the DateTime components of the page filters.
+ *
+ * NOTE: This has some additional functionality for handling `page*` filters
+ *       that will override the standard `start`/`end`/`statsPeriod` filters.
+ *
+ * NOTE: This does *NOT* noramlize the `project` or `environment` components of
+ *       the page filter parameters. See `getStateFromQuery` for normalization
+ *       of the project and environment parameters.
+ */
+export function normalizeDateTimeParams(
+  params: InputParams,
+  options: DateTimeNormalizeOptions = {}
+): ParsedParams {
   const {
     allowEmptyPeriod = false,
     allowAbsoluteDatetime = true,
@@ -166,7 +235,7 @@ export function getParams(params: InputParams, options: Options = {}): ParsedPar
     ...otherParams
   } = params;
 
-  // `statsPeriod` takes precedence for now
+  // `statsPeriod` takes precedence for now. `period` is legacy.
   let coercedPeriod =
     getStatsPeriodValue(pageStatsPeriod) ||
     getStatsPeriodValue(statsPeriod) ||
@@ -202,3 +271,42 @@ export function getParams(params: InputParams, options: Options = {}): ParsedPar
 
   return Object.fromEntries(paramEntries);
 }
+
+/**
+ * Parses and normalizes all page filter relevant parameters from a location
+ * query.
+ *
+ * This includes the following operations
+ *
+ *  - Normalizes `project` and `environment` into a consistent list object.
+ *  - Normalizes date time filter parameters (using normalizeDateTimeParams).
+ *  - Parses `start` and `end` into Date objects.
+ */
+export function getStateFromQuery(
+  query: Location['query'],
+  normalizeOptions: DateTimeNormalizeOptions = {}
+) {
+  const {allowAbsoluteDatetime} = normalizeOptions;
+
+  const project = getProject(query[URL_PARAM.PROJECT]);
+  const environment = getEnvironment(query[URL_PARAM.ENVIRONMENT]);
+
+  const dateTimeParams = normalizeDateTimeParams(query, normalizeOptions);
+
+  const hasAbsolute =
+    allowAbsoluteDatetime && !!dateTimeParams.start && !!dateTimeParams.end;
+
+  const start = hasAbsolute ? getUtcToLocalDateObject(dateTimeParams.start) : null;
+  const end = hasAbsolute ? getUtcToLocalDateObject(dateTimeParams.end) : null;
+  const period = dateTimeParams.statsPeriod;
+  const utc = dateTimeParams.utc;
+
+  return {
+    project,
+    environment,
+    period: period || null,
+    start: start || null,
+    end: end || null,
+    utc: typeof utc !== 'undefined' ? utc === 'true' : null,
+  };
+}

+ 2 - 52
static/app/components/organizations/pageFilters/utils.tsx

@@ -8,64 +8,14 @@ import pickBy from 'lodash/pickBy';
 import {DATE_TIME_KEYS, URL_PARAM} from 'sentry/constants/pageFilters';
 import OrganizationsStore from 'sentry/stores/organizationsStore';
 import {Environment, PageFilters} from 'sentry/types';
-import {defined} from 'sentry/utils';
-import {getUtcToLocalDateObject} from 'sentry/utils/dates';
 import localStorage from 'sentry/utils/localStorage';
 
-import {getParams} from './getParams';
+import {normalizeDateTimeParams} from './parse';
 
-const DEFAULT_PARAMS = getParams({});
+const DEFAULT_PARAMS = normalizeDateTimeParams({});
 
 const LOCAL_STORAGE_KEY = 'global-selection';
 
-// Parses URL query parameters for values relevant to page filters
-type GetStateFromQueryOptions = {
-  allowEmptyPeriod?: boolean;
-  allowAbsoluteDatetime?: boolean;
-};
-
-export function getStateFromQuery(
-  query: Location['query'],
-  {allowEmptyPeriod = false, allowAbsoluteDatetime = true}: GetStateFromQueryOptions = {}
-) {
-  const parsedParams = getParams(query, {allowEmptyPeriod, allowAbsoluteDatetime});
-
-  const projectFromQuery = query[URL_PARAM.PROJECT];
-  const environmentFromQuery = query[URL_PARAM.ENVIRONMENT];
-  const period = parsedParams.statsPeriod;
-  const utc = parsedParams.utc;
-
-  const hasAbsolute = allowAbsoluteDatetime && !!parsedParams.start && !!parsedParams.end;
-
-  let project: number[] | null | undefined;
-  if (defined(projectFromQuery) && Array.isArray(projectFromQuery)) {
-    project = projectFromQuery.map(p => parseInt(p, 10));
-  } else if (defined(projectFromQuery)) {
-    const projectFromQueryIdInt = parseInt(projectFromQuery, 10);
-    project = isNaN(projectFromQueryIdInt) ? [] : [projectFromQueryIdInt];
-  } else {
-    project = projectFromQuery;
-  }
-
-  const environment =
-    defined(environmentFromQuery) && !Array.isArray(environmentFromQuery)
-      ? [environmentFromQuery]
-      : environmentFromQuery;
-
-  const start = hasAbsolute ? getUtcToLocalDateObject(parsedParams.start) : null;
-  const end = hasAbsolute ? getUtcToLocalDateObject(parsedParams.end) : null;
-
-  return {
-    project,
-    environment,
-    period: period || null,
-    start: start || null,
-    end: end || null,
-    // params from URL will be a string
-    utc: typeof utc !== 'undefined' ? utc === 'true' : null,
-  };
-}
-
 /**
  * Extract the page filter parameters from an object
  * Useful for extracting page filter properties from the current URL

+ 2 - 2
static/app/components/quickTrace/utils.tsx

@@ -1,6 +1,6 @@
 import {Location, LocationDescriptor} from 'history';
 
-import {getParams} from 'sentry/components/organizations/pageFilters/getParams';
+import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
 import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters';
 import {OrganizationSummary} from 'sentry/types';
 import {Event} from 'sentry/types/event';
@@ -143,7 +143,7 @@ export function generateTraceTarget(
 ): LocationDescriptor {
   const traceId = event.contexts?.trace?.trace_id ?? '';
 
-  const dateSelection = getParams(getTraceTimeRangeFromEvent(event));
+  const dateSelection = normalizeDateTimeParams(getTraceTimeRangeFromEvent(event));
 
   if (organization.features.includes('performance-view')) {
     // TODO(txiao): Should this persist the current query when going to trace view?

+ 2 - 2
static/app/components/smartSearchBar/index.tsx

@@ -11,7 +11,7 @@ import {fetchRecentSearches, saveRecentSearch} from 'sentry/actionCreators/saved
 import {Client} from 'sentry/api';
 import ButtonBar from 'sentry/components/buttonBar';
 import DropdownLink from 'sentry/components/dropdownLink';
-import {getParams} from 'sentry/components/organizations/pageFilters/getParams';
+import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
 import {
   FilterType,
   ParseResult,
@@ -779,7 +779,7 @@ class SmartSearchBar extends React.Component<Props, State> {
       }
 
       const {location} = this.props;
-      const endpointParams = getParams(location.query);
+      const endpointParams = normalizeDateTimeParams(location.query);
 
       this.setState({loading: true});
       let values: string[] = [];

+ 1 - 1
static/app/utils/dates.tsx

@@ -1,6 +1,6 @@
 import moment from 'moment';
 
-import {parseStatsPeriod} from 'sentry/components/organizations/pageFilters/getParams';
+import {parseStatsPeriod} from 'sentry/components/organizations/pageFilters/parse';
 import ConfigStore from 'sentry/stores/configStore';
 import {DateString} from 'sentry/types';
 

+ 5 - 5
static/app/utils/discover/eventView.tsx

@@ -9,7 +9,7 @@ import moment from 'moment';
 
 import {EventQuery} from 'sentry/actionCreators/events';
 import {COL_WIDTH_UNDEFINED} from 'sentry/components/gridEditable';
-import {getParams} from 'sentry/components/organizations/pageFilters/getParams';
+import {normalizeDateTimeParams} from 'sentry/components/organizations/pageFilters/parse';
 import {DEFAULT_PER_PAGE} from 'sentry/constants';
 import {URL_PARAM} from 'sentry/constants/pageFilters';
 import {t} from 'sentry/locale';
@@ -347,7 +347,7 @@ class EventView {
   }
 
   static fromLocation(location: Location): EventView {
-    const {start, end, statsPeriod} = getParams(location.query);
+    const {start, end, statsPeriod} = normalizeDateTimeParams(location.query);
 
     return new EventView({
       id: decodeScalar(location.query.id),
@@ -411,7 +411,7 @@ class EventView {
   static fromSavedQuery(saved: NewQuery | SavedQuery): EventView {
     const fields = EventView.getFields(saved);
     // normalize datetime selection
-    const {start, end, statsPeriod} = getParams({
+    const {start, end, statsPeriod} = normalizeDateTimeParams({
       start: saved.start,
       end: saved.end,
       statsPeriod: saved.range,
@@ -449,7 +449,7 @@ class EventView {
     location: Location
   ): EventView {
     let fields = decodeFields(location);
-    const {start, end, statsPeriod} = getParams(location.query);
+    const {start, end, statsPeriod} = normalizeDateTimeParams(location.query);
     const id = decodeScalar(location.query.id);
     const teams = decodeTeams(location);
     const projects = decodeProjects(location);
@@ -1083,7 +1083,7 @@ class EventView {
         };
 
     // normalize datetime selection
-    return getParams({
+    return normalizeDateTimeParams({
       ...dateSelection,
       utc: decodeScalar(query.utc),
     });

+ 1 - 1
static/app/views/alerts/rules/details/metricChart.tsx

@@ -23,7 +23,7 @@ import CircleIndicator from 'sentry/components/circleIndicator';
 import {
   parseStatsPeriod,
   StatsPeriodType,
-} from 'sentry/components/organizations/pageFilters/getParams';
+} from 'sentry/components/organizations/pageFilters/parse';
 import {Panel, PanelBody, PanelFooter} from 'sentry/components/panels';
 import Placeholder from 'sentry/components/placeholder';
 import Truncate from 'sentry/components/truncate';

Некоторые файлы не были показаны из-за большого количества измененных файлов