Browse Source

ref(page-filters): Remove unused Global Selection Header (#35442)

* ref(page-filters): Remove unused Global Selection Header

* remove tests relevant to old global header

* rename test suite
David Wang 2 years ago
parent
commit
df1a891222

+ 9 - 3
static/app/actionCreators/pageFilters.tsx

@@ -114,7 +114,7 @@ function mergeDatetime(
   return datetime;
 }
 
-type InitializeUrlStateParams = {
+export type InitializeUrlStateParams = {
   memberProjects: Project[];
   organization: Organization;
   queryParams: Location['query'];
@@ -125,11 +125,17 @@ type InitializeUrlStateParams = {
   shouldForceProject?: boolean;
   showAbsolute?: boolean;
   /**
-   * Skip setting the query parameters
+   * When used with shouldForceProject it will not persist the project id
+   * to url query parameters on load. This is useful when global selection header
+   * is used for display purposes rather than selection.
    */
   skipInitializeUrlParams?: boolean;
+
   /**
-   * If true, do not load from local storage
+   * Skip loading from local storage
+   * An example is Issue Details, in the case where it is accessed directly (e.g. from email).
+   * We do not want to load the user's last used env/project in this case, otherwise will
+   * lead to very confusing behavior.
    */
   skipLoadLastUsed?: boolean;
 };

+ 10 - 49
static/app/components/organizations/pageFilters/container.tsx

@@ -2,58 +2,36 @@ import {Fragment, useEffect, useRef} from 'react';
 import {withRouter, WithRouterProps} from 'react-router';
 import isEmpty from 'lodash/isEmpty';
 import isEqual from 'lodash/isEqual';
-import partition from 'lodash/partition';
 
 import {
   initializeUrlState,
+  InitializeUrlStateParams,
   updateDateTime,
   updateEnvironments,
   updateProjects,
 } from 'sentry/actionCreators/pageFilters';
 import DesyncedFilterAlert from 'sentry/components/organizations/pageFilters/desyncedFiltersAlert';
 import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
-import ConfigStore from 'sentry/stores/configStore';
 import {PageContent} from 'sentry/styles/organization';
 import usePageFilters from 'sentry/utils/usePageFilters';
 import useProjects from 'sentry/utils/useProjects';
 import withOrganization from 'sentry/utils/withOrganization';
 
-import GlobalSelectionHeader from './globalSelectionHeader';
 import {getDatetimeFromState, getStateFromQuery} from './parse';
 import {extractSelectionParameters} from './utils';
 
-type GlobalSelectionHeaderProps = Omit<
-  React.ComponentPropsWithoutRef<typeof GlobalSelectionHeader>,
-  | 'router'
-  | 'memberProjects'
-  | 'nonMemberProjects'
-  | 'selection'
-  | 'projects'
-  | 'loadingProjects'
+type InitializeUrlStateProps = Omit<
+  InitializeUrlStateParams,
+  'memberProjects' | 'queryParams' | 'router' | 'shouldEnforceSingleProject'
 >;
 
 type Props = WithRouterProps &
-  GlobalSelectionHeaderProps & {
+  InitializeUrlStateProps & {
+    children?: React.ReactNode;
     /**
-     * Hide the global header
-     * Mainly used for pages which are using the new style page filters
+     * Slugs of projects to display in project selector
      */
-    hideGlobalHeader?: boolean;
-
-    /**
-     * When used with shouldForceProject it will not persist the project id
-     * to url query parameters on load. This is useful when global selection header
-     * is used for display purposes rather than selection.
-     */
-    skipInitializeUrlParams?: boolean;
-
-    /**
-     * Skip loading from local storage
-     * An example is Issue Details, in the case where it is accessed directly (e.g. from email).
-     * We do not want to load the user's last used env/project in this case, otherwise will
-     * lead to very confusing behavior.
-     */
-    skipLoadLastUsed?: boolean;
+    specificProjectSlugs?: string[];
   };
 
 /**
@@ -70,7 +48,6 @@ function Container({skipLoadLastUsed, children, ...props}: Props) {
     showAbsolute,
     shouldForceProject,
     specificProjectSlugs,
-    hideGlobalHeader,
     skipInitializeUrlParams,
   } = props;
 
@@ -78,27 +55,12 @@ function Container({skipLoadLastUsed, children, ...props}: Props) {
 
   const {projects, initiallyLoaded: projectsLoaded} = useProjects();
 
-  const {isSuperuser} = ConfigStore.get('user');
-  const isOrgAdmin = organization.access.includes('org:admin');
   const enforceSingleProject = !organization.features.includes('global-views');
 
   const specifiedProjects = specificProjectSlugs
     ? projects.filter(project => specificProjectSlugs.includes(project.slug))
     : projects;
-
-  const [memberProjects, otherProjects] = partition(
-    specifiedProjects,
-    project => project.isMember
-  );
-
-  const nonMemberProjects = isSuperuser || isOrgAdmin ? otherProjects : [];
-
-  const additionalProps = {
-    loadingProjects: !projectsLoaded,
-    projects,
-    memberProjects,
-    nonMemberProjects,
-  };
+  const memberProjects = specifiedProjects.filter(project => project.isMember);
 
   const doInitialization = () =>
     initializeUrlState({
@@ -198,8 +160,7 @@ function Container({skipLoadLastUsed, children, ...props}: Props) {
 
   return (
     <Fragment>
-      {!hideGlobalHeader && <GlobalSelectionHeader {...props} {...additionalProps} />}
-      {hideGlobalHeader && <DesyncedFilterAlert router={router} />}
+      <DesyncedFilterAlert router={router} />
       {children}
     </Fragment>
   );

+ 0 - 431
static/app/components/organizations/pageFilters/globalSelectionHeader.tsx

@@ -1,431 +0,0 @@
-import {Component, Fragment} from 'react';
-import {WithRouterProps} from 'react-router';
-import styled from '@emotion/styled';
-import debounce from 'lodash/debounce';
-
-import {
-  updateDateTime,
-  updateEnvironments,
-  updateProjects,
-} from 'sentry/actionCreators/pageFilters';
-import BackToIssues from 'sentry/components/organizations/backToIssues';
-import EnvironmentSelector from 'sentry/components/organizations/environmentSelector';
-import HeaderItemPosition from 'sentry/components/organizations/headerItemPosition';
-import HeaderSeparator from 'sentry/components/organizations/headerSeparator';
-import ProjectSelector from 'sentry/components/organizations/projectSelector';
-import TimeRangeSelector, {
-  ChangeData,
-} from 'sentry/components/organizations/timeRangeSelector';
-import Tooltip from 'sentry/components/tooltip';
-import {DEFAULT_STATS_PERIOD} from 'sentry/constants';
-import {IconArrow} from 'sentry/icons';
-import {t} from 'sentry/locale';
-import space from 'sentry/styles/space';
-import {MinimalProject, Organization, PageFilters, Project} from 'sentry/types';
-import {callIfFunction} from 'sentry/utils/callIfFunction';
-import Projects from 'sentry/utils/projects';
-import withPageFilters from 'sentry/utils/withPageFilters';
-
-const PROJECTS_PER_PAGE = 50;
-
-const defaultProps = {
-  /**
-   * Display Environment selector?
-   */
-  showEnvironmentSelector: true,
-
-  /**
-   * Display date selector?
-   */
-  showDateSelector: true,
-
-  /**
-   * Reset these URL params when we fire actions
-   * (custom routing only)
-   */
-  resetParamsOnChange: [] as string[],
-
-  /**
-   * Remove ability to select multiple projects even if organization has feature 'global-views'
-   */
-  disableMultipleProjectSelection: false,
-};
-
-type Props = {
-  /**
-   * Whether or not the projects are currently being loaded in
-   */
-  loadingProjects: boolean;
-
-  memberProjects: Project[];
-  nonMemberProjects: Project[];
-
-  organization: Organization;
-
-  /**
-   * List of projects to display in project selector (comes from HoC)
-   */
-  projects: Project[];
-
-  /**
-   * Currently selected values(s)
-   */
-  selection: PageFilters;
-
-  className?: string;
-
-  /**
-   * Custom default selection values (e.g. a different default period)
-   */
-  defaultSelection?: Partial<PageFilters>;
-
-  /**
-   * If a forced environment is passed, selection is disabled
-   */
-  forceEnvironment?: string;
-
-  /**
-   * If a forced project is passed, selection is disabled
-   */
-  forceProject?: MinimalProject | null;
-
-  /**
-   * Is global selection store still loading (i.e. not ready)
-   */
-  isGlobalSelectionReady?: boolean;
-
-  /**
-   * Subject that will be used in a tooltip that is shown on a lock icon hover
-   * E.g. This 'issue' is unique to a project
-   */
-  lockedMessageSubject?: string;
-
-  /**
-   * The maximum number of days in the past you can pick
-   */
-  maxPickableDays?: number;
-
-  onChangeProjects?: (val: number[]) => void;
-
-  onChangeTime?: (datetime: any) => void;
-
-  onUpdateEnvironments?: (environments: string[]) => void;
-  onUpdateProjects?: (selectedProjects: number[]) => void;
-  onUpdateTime?: (datetime: any) => void;
-  /**
-   * Message to display at the bottom of project list
-   */
-  projectsFooterMessage?: React.ReactNode;
-  /**
-   * Override default relative date options from DEFAULT_RELATIVE_PERIODS
-   */
-  relativeDateOptions?: Record<string, React.ReactNode>;
-  /**
-   * A project will be forced from parent component (selection is disabled, and if user
-   * does not have multi-project support enabled, it will not try to auto select a project).
-   *
-   * Project will be specified in the prop `forceProject` (since its data is async)
-   */
-  shouldForceProject?: boolean;
-
-  /// Props passed to child components ///
-  /**
-   * Show absolute date selectors
-   */
-  showAbsolute?: boolean;
-
-  /**
-   * If true, there will be a back to issues stream icon link
-   */
-  showIssueStreamLink?: boolean;
-
-  /**
-   * If true, there will be a project settings icon link
-   * (forceProject prop needs to be present to know the right project slug)
-   */
-  showProjectSettingsLink?: boolean;
-
-  /**
-   * Show relative date selectors
-   */
-  showRelative?: boolean;
-
-  /**
-   * Slugs of projects to display in project selector
-   */
-  specificProjectSlugs?: string[];
-
-  /**
-   * Small info icon with tooltip hint text
-   */
-  timeRangeHint?: string;
-} & Partial<typeof defaultProps> &
-  Omit<WithRouterProps, 'router'> & {
-    router: WithRouterProps['router'] | null;
-  };
-
-type State = {
-  projects: number[] | null;
-  searchQuery: string;
-};
-
-class GlobalSelectionHeader extends Component<Props, State> {
-  static defaultProps = defaultProps;
-
-  state: State = {
-    projects: null,
-    searchQuery: '',
-  };
-
-  // Returns an options object for `update*` actions
-  getUpdateOptions = () => ({
-    save: true,
-    resetParams: this.props.resetParamsOnChange,
-  });
-
-  handleChangeTime = ({start, end, relative: period, utc}: ChangeData) => {
-    callIfFunction(this.props.onChangeTime, {start, end, period, utc});
-  };
-
-  handleUpdateTime = ({
-    relative: period,
-    start,
-    end,
-    utc,
-  }: {end?; relative?; start?; utc?} = {}) => {
-    const newValueObj = {
-      period,
-      start,
-      end,
-      utc,
-    };
-
-    updateDateTime(newValueObj, this.props.router, this.getUpdateOptions());
-    callIfFunction(this.props.onUpdateTime, newValueObj);
-  };
-
-  handleUpdateEnvironments = (environments: string[]) => {
-    updateEnvironments(environments, this.props.router, this.getUpdateOptions());
-    callIfFunction(this.props.onUpdateEnvironments, environments);
-  };
-
-  handleChangeProjects = (projects: State['projects']) => {
-    this.setState({projects});
-    callIfFunction(this.props.onChangeProjects, projects);
-  };
-
-  handleUpdateProjects = (projects: State['projects']) => {
-    // Clear environments when switching projects
-    updateProjects(projects || [], this.props.router, {
-      ...this.getUpdateOptions(),
-      environments: [],
-    });
-    this.setState({projects: null});
-    callIfFunction(this.props.onUpdateProjects, projects);
-  };
-
-  getBackButton = () => {
-    const {organization, location} = this.props;
-    return (
-      <BackButtonWrapper>
-        <Tooltip title={t('Back to Issues Stream')} position="bottom">
-          <BackToIssues
-            data-test-id="back-to-issues"
-            to={`/organizations/${organization.slug}/issues/${location.search}`}
-          >
-            <IconArrow direction="left" size="sm" />
-          </BackToIssues>
-        </Tooltip>
-      </BackButtonWrapper>
-    );
-  };
-
-  scrollFetchDispatcher = debounce(
-    (onSearch, options) => {
-      onSearch(this.state.searchQuery, options);
-    },
-    200,
-    {leading: true, trailing: false}
-  );
-
-  searchDispatcher = debounce((onSearch, searchQuery, options) => {
-    // in the case that a user repeats a search query (because search is
-    // debounced this is possible if the user types and then deletes what they
-    // typed) we should switch to an append strategy to not override all results
-    // with a new page.
-    if (this.state.searchQuery === searchQuery) {
-      options.append = true;
-    }
-    onSearch(searchQuery, options);
-    this.setState({
-      searchQuery,
-    });
-  }, 200);
-
-  render() {
-    const {
-      className,
-      shouldForceProject,
-      forceEnvironment,
-      forceProject,
-      isGlobalSelectionReady,
-      loadingProjects,
-      organization,
-      showAbsolute,
-      showRelative,
-      showDateSelector,
-      showEnvironmentSelector,
-      memberProjects,
-      nonMemberProjects,
-      showIssueStreamLink,
-      showProjectSettingsLink,
-      lockedMessageSubject,
-      timeRangeHint,
-      specificProjectSlugs,
-      disableMultipleProjectSelection,
-      projectsFooterMessage,
-      defaultSelection,
-      relativeDateOptions,
-      maxPickableDays,
-    } = this.props;
-
-    const {period, start, end, utc} = this.props.selection.datetime || {};
-    const defaultPeriod = defaultSelection?.datetime?.period || DEFAULT_STATS_PERIOD;
-
-    const selectedProjects = forceProject
-      ? [parseInt(forceProject.id, 10)]
-      : this.props.selection.projects;
-
-    return (
-      <Header className={className}>
-        <HeaderItemPosition>
-          {showIssueStreamLink && this.getBackButton()}
-          <Projects
-            orgId={organization.slug}
-            limit={PROJECTS_PER_PAGE}
-            slugs={specificProjectSlugs}
-          >
-            {({projects, hasMore, onSearch, fetching}) => {
-              const paginatedProjectSelectorCallbacks = {
-                onScroll: ({clientHeight, scrollHeight, scrollTop}) => {
-                  // check if no new projects are being fetched and the user has
-                  // scrolled far enough to fetch a new page of projects
-                  if (
-                    !fetching &&
-                    scrollTop + clientHeight >= scrollHeight - clientHeight &&
-                    hasMore
-                  ) {
-                    this.scrollFetchDispatcher(onSearch, {append: true});
-                  }
-                },
-                onFilterChange: event => {
-                  this.searchDispatcher(onSearch, event.target.value, {
-                    append: false,
-                  });
-                },
-                searching: fetching,
-                paginated: true,
-              };
-              return (
-                <ProjectSelector
-                  organization={organization}
-                  shouldForceProject={shouldForceProject}
-                  forceProject={forceProject}
-                  memberProjects={
-                    loadingProjects ? (projects as Project[]) : memberProjects
-                  }
-                  isGlobalSelectionReady={isGlobalSelectionReady}
-                  nonMemberProjects={nonMemberProjects}
-                  value={this.state.projects || this.props.selection.projects}
-                  onChange={this.handleChangeProjects}
-                  onApplyChange={this.handleUpdateProjects}
-                  disableMultipleProjectSelection={disableMultipleProjectSelection}
-                  {...(loadingProjects ? paginatedProjectSelectorCallbacks : {})}
-                  showIssueStreamLink={showIssueStreamLink}
-                  showProjectSettingsLink={showProjectSettingsLink}
-                  lockedMessageSubject={lockedMessageSubject}
-                  footerMessage={projectsFooterMessage}
-                />
-              );
-            }}
-          </Projects>
-        </HeaderItemPosition>
-
-        {showEnvironmentSelector && (
-          <Fragment>
-            <HeaderSeparator />
-            <HeaderItemPosition>
-              <EnvironmentSelector
-                organization={organization}
-                projects={this.props.projects}
-                loadingProjects={loadingProjects}
-                selectedProjects={selectedProjects}
-                forceEnvironment={forceEnvironment}
-                value={this.props.selection.environments}
-                onUpdate={this.handleUpdateEnvironments}
-              />
-            </HeaderItemPosition>
-          </Fragment>
-        )}
-
-        {showDateSelector && (
-          <Fragment>
-            <HeaderSeparator />
-            <HeaderItemPosition>
-              <TimeRangeSelector
-                key={`period:${period}-start:${start}-end:${end}-utc:${utc}-defaultPeriod:${defaultPeriod}`}
-                showAbsolute={showAbsolute}
-                showRelative={showRelative}
-                relative={period}
-                start={start}
-                end={end}
-                utc={utc}
-                onChange={this.handleChangeTime}
-                onUpdate={this.handleUpdateTime}
-                organization={organization}
-                defaultPeriod={defaultPeriod}
-                hint={timeRangeHint}
-                relativeOptions={relativeDateOptions}
-                maxPickableDays={maxPickableDays}
-              />
-            </HeaderItemPosition>
-          </Fragment>
-        )}
-
-        {!showEnvironmentSelector && <HeaderItemPosition isSpacer />}
-        {!showDateSelector && <HeaderItemPosition isSpacer />}
-      </Header>
-    );
-  }
-}
-
-export default withPageFilters(GlobalSelectionHeader);
-
-const BackButtonWrapper = styled('div')`
-  display: flex;
-  align-items: center;
-  height: 100%;
-  position: relative;
-  left: ${space(2)};
-`;
-
-const Header = styled('div')`
-  position: relative;
-  display: flex;
-  width: 100%;
-  height: 60px;
-
-  border-bottom: 1px solid ${p => p.theme.border};
-  box-shadow: ${p => p.theme.dropShadowLight};
-  z-index: ${p => p.theme.zIndex.globalSelectionHeader};
-
-  background: ${p => p.theme.headerBackground};
-  font-size: ${p => p.theme.fontSizeExtraLarge};
-  @media (min-width: ${p => p.theme.breakpoints.small} and max-width: ${p =>
-      p.theme.breakpoints.medium}) {
-    margin-top: 54px;
-  }
-  @media (max-width: calc(${p => p.theme.breakpoints.small} - 1px)) {
-    margin-top: 0;
-  }
-`;

+ 1 - 5
static/app/views/alerts/list/incidents/index.tsx

@@ -263,11 +263,7 @@ class IncidentsList extends AsyncComponent<Props, State & AsyncComponent['state'
 
     return (
       <SentryDocumentTitle title={t('Alerts')} orgSlug={orgId}>
-        <PageFiltersContainer
-          organization={organization}
-          showDateSelector={false}
-          hideGlobalHeader
-        >
+        <PageFiltersContainer>
           <AlertHeader
             organization={organization}
             router={router}

+ 1 - 6
static/app/views/alerts/list/rules/index.tsx

@@ -273,12 +273,7 @@ class AlertRulesList extends AsyncComponent<Props, State & AsyncComponent['state
 
     return (
       <SentryDocumentTitle title={t('Alerts')} orgSlug={orgId}>
-        <PageFiltersContainer
-          organization={organization}
-          showDateSelector={false}
-          showEnvironmentSelector={false}
-          hideGlobalHeader
-        >
+        <PageFiltersContainer>
           <AlertHeader
             organization={organization}
             router={router}

+ 0 - 4
static/app/views/alerts/rules/issue/details/ruleDetails.tsx

@@ -219,10 +219,6 @@ class AlertRuleDetails extends AsyncComponent<Props, State> {
         skipLoadLastUsed
         shouldForceProject
         forceProject={project}
-        forceEnvironment={rule.environment ?? ''}
-        lockedMessageSubject={t('alert rule')}
-        showDateSelector={false}
-        hideGlobalHeader
       >
         <SentryDocumentTitle title={rule.name} orgSlug={orgId} projectSlug={projectId} />
 

+ 0 - 5
static/app/views/alerts/rules/metric/details/index.tsx

@@ -219,13 +219,8 @@ class MetricAlertDetails extends Component<Props, State> {
       <PageFiltersContainer
         skipLoadLastUsed
         skipInitializeUrlParams
-        isGlobalSelectionReady={isGlobalSelectionReady}
         shouldForceProject={isGlobalSelectionReady}
         forceProject={project}
-        forceEnvironment={rule?.environment ?? ''}
-        lockedMessageSubject={t('alert rule')}
-        showDateSelector={false}
-        hideGlobalHeader
       >
         <SentryDocumentTitle title={rule?.name ?? ''} />
 

+ 0 - 2
static/app/views/dashboardsV2/detail.tsx

@@ -598,7 +598,6 @@ class DashboardDetail extends Component<Props, State> {
 
     return (
       <PageFiltersContainer
-        hideGlobalHeader
         defaultSelection={{
           datetime: {
             start: null,
@@ -685,7 +684,6 @@ class DashboardDetail extends Component<Props, State> {
     return (
       <SentryDocumentTitle title={dashboard.title} orgSlug={organization.slug}>
         <PageFiltersContainer
-          hideGlobalHeader
           defaultSelection={{
             datetime: {
               start: null,

+ 0 - 1
static/app/views/dashboardsV2/widgetBuilder/widgetBuilder.tsx

@@ -1003,7 +1003,6 @@ function WidgetBuilder({
         defaultSelection={{
           datetime: {start: null, end: null, utc: false, period: DEFAULT_STATS_PERIOD},
         }}
-        hideGlobalHeader
       >
         <PageContentWithoutPadding>
           <Header

+ 0 - 1
static/app/views/eventsV2/results.tsx

@@ -639,7 +639,6 @@ function ResultsContainer(props: Props) {
       skipLoadLastUsed={
         props.organization.features.includes('global-views') && !!props.savedQuery
       }
-      hideGlobalHeader
     >
       <SavedQueryAPI {...props} />
     </PageFiltersContainer>

Some files were not shown because too many files changed in this diff