Browse Source

ref(saved-searches): Remove old saved searches UI (#42085)

Ref https://github.com/getsentry/team-coreui/issues/22

`issue-list-saved-searches-v2` is at 100% rollout (and has been for a
few weeks without issue), so this cleans up all the old saved searches
code.

- Kills SavedSearchesStore 🎉 
- Removes all feature flag checks and code paths with
`issue-list-saved-searches-v2` = false
Malachi Willey 2 years ago
parent
commit
90b81a0a14

+ 1 - 156
static/app/actionCreators/savedSearches.tsx

@@ -1,40 +1,8 @@
-import {addErrorMessage} from 'sentry/actionCreators/indicator';
 import {Client} from 'sentry/api';
 import {MAX_AUTOCOMPLETE_RECENT_SEARCHES} from 'sentry/constants';
-import {t} from 'sentry/locale';
-import SavedSearchesStore from 'sentry/stores/savedSearchesStore';
-import {
-  RecentSearch,
-  SavedSearch,
-  SavedSearchType,
-  SavedSearchVisibility,
-} from 'sentry/types';
+import {RecentSearch, SavedSearch, SavedSearchType} from 'sentry/types';
 import handleXhrErrorResponse from 'sentry/utils/handleXhrErrorResponse';
 
-export function resetSavedSearches() {
-  SavedSearchesStore.onReset();
-}
-
-export function fetchSavedSearches(api: Client, orgSlug: string): Promise<SavedSearch[]> {
-  const url = `/organizations/${orgSlug}/searches/`;
-  SavedSearchesStore.onStartFetchSavedSearches();
-
-  const promise = api.requestPromise(url, {
-    method: 'GET',
-  });
-
-  promise
-    .then(resp => {
-      SavedSearchesStore.onFetchSavedSearchesSuccess(resp);
-    })
-    .catch(err => {
-      SavedSearchesStore.onFetchSavedSearchesError(err);
-      addErrorMessage(t('Unable to load saved searches'));
-    });
-
-  return promise;
-}
-
 const getRecentSearchUrl = (orgSlug: string): string =>
   `/organizations/${orgSlug}/recent-searches/`;
 
@@ -66,42 +34,6 @@ export function saveRecentSearch(
   return promise;
 }
 
-/**
- * Creates a saved search
- *
- * @param api API client
- * @param orgSlug Organization slug
- * @param name Saved search name
- * @param query Query to save
- */
-export function createSavedSearch(
-  api: Client,
-  orgSlug: string,
-  name: string,
-  query: string,
-  sort: string | null,
-  visibility: SavedSearchVisibility
-): Promise<SavedSearch> {
-  const promise = api.requestPromise(`/organizations/${orgSlug}/searches/`, {
-    method: 'POST',
-    data: {
-      type: SavedSearchType.ISSUE,
-      query,
-      name,
-      sort,
-      visibility,
-    },
-  });
-
-  // Need to wait for saved search to save unfortunately because we need to redirect
-  // to saved search URL
-  promise.then(resp => {
-    SavedSearchesStore.onCreateSavedSearchSuccess(resp);
-  });
-
-  return promise;
-}
-
 /**
  * Fetches a list of recent search terms conducted by `user` for `orgSlug`
  *
@@ -135,90 +67,3 @@ export function fetchRecentSearches(
 
   return promise;
 }
-
-const getPinSearchUrl = (orgSlug: string): string =>
-  `/organizations/${orgSlug}/pinned-searches/`;
-
-export function pinSearch(
-  api: Client,
-  orgSlug: string,
-  type: SavedSearchType,
-  query: string,
-  sort?: string
-): Promise<SavedSearch> {
-  const url = getPinSearchUrl(orgSlug);
-
-  // Optimistically update store
-  SavedSearchesStore.onPinSearch(type, query, sort);
-
-  const promise = api.requestPromise(url, {
-    method: 'PUT',
-    data: {
-      query,
-      type,
-      sort,
-    },
-  });
-
-  promise.then(SavedSearchesStore.onPinSearchSuccess);
-
-  promise.catch(handleXhrErrorResponse('Unable to pin search'));
-
-  promise.catch(() => {
-    SavedSearchesStore.onUnpinSearch(type);
-  });
-
-  return promise;
-}
-
-export function unpinSearch(
-  api: Client,
-  orgSlug: string,
-  type: SavedSearchType,
-  pinnedSearch: SavedSearch
-) {
-  const url = getPinSearchUrl(orgSlug);
-
-  // Optimistically update store
-  SavedSearchesStore.onUnpinSearch(type);
-
-  const promise = api.requestPromise(url, {
-    method: 'DELETE',
-    data: {
-      type,
-    },
-  });
-
-  promise.catch(handleXhrErrorResponse('Unable to un-pin search'));
-
-  promise.catch(() => {
-    const {type: pinnedType, query} = pinnedSearch;
-    SavedSearchesStore.onPinSearch(pinnedType, query);
-  });
-
-  return promise;
-}
-
-/**
- * Send a DELETE request to remove a saved search
- *
- * @param api API client
- * @param orgSlug Organization slug
- * @param search The search to remove.
- */
-export function deleteSavedSearch(
-  api: Client,
-  orgSlug: string,
-  search: SavedSearch
-): Promise<void> {
-  const url = `/organizations/${orgSlug}/searches/${search.id}/`;
-
-  const promise = api
-    .requestPromise(url, {
-      method: 'DELETE',
-    })
-    .then(() => SavedSearchesStore.onDeleteSavedSearchSuccess(search))
-    .catch(handleXhrErrorResponse('Unable to delete a saved search'));
-
-  return promise;
-}

+ 2 - 4
static/app/components/modals/savedSearchModal/createSavedSearchModal.spec.tsx

@@ -64,7 +64,7 @@ describe('CreateSavedSearchModal', function () {
             query: 'is:unresolved assigned:lyn@sentry.io',
             sort: IssueSortOptions.DATE,
             type: 0,
-            visibility: SavedSearchVisibility.Organization,
+            visibility: SavedSearchVisibility.Owner,
           },
         })
       );
@@ -92,7 +92,7 @@ describe('CreateSavedSearchModal', function () {
             query: 'is:resolved',
             sort: IssueSortOptions.PRIORITY,
             type: 0,
-            visibility: SavedSearchVisibility.Organization,
+            visibility: SavedSearchVisibility.Owner,
           },
         })
       );
@@ -102,7 +102,6 @@ describe('CreateSavedSearchModal', function () {
   describe('visibility', () => {
     it('only allows owner-level visibility without org:write permission', async function () {
       const org = TestStubs.Organization({
-        features: ['issue-list-saved-searches-v2'],
         access: [],
       });
 
@@ -134,7 +133,6 @@ describe('CreateSavedSearchModal', function () {
 
   it('can change to org-level visibility with org:write permission', async function () {
     const org = TestStubs.Organization({
-      features: ['issue-list-saved-searches-v2'],
       access: ['org:write'],
     });
     render(<CreateSavedSearchModal {...defaultProps} organization={org} />);

+ 10 - 30
static/app/components/modals/savedSearchModal/createSavedSearchModal.tsx

@@ -2,7 +2,6 @@ import {useState} from 'react';
 
 import {addLoadingMessage, clearIndicators} from 'sentry/actionCreators/indicator';
 import {ModalRenderProps} from 'sentry/actionCreators/modal';
-import {createSavedSearch} from 'sentry/actionCreators/savedSearches';
 import Alert from 'sentry/components/alert';
 import {Form} from 'sentry/components/forms';
 import {OnSubmitCallback} from 'sentry/components/forms/types';
@@ -10,7 +9,6 @@ import {SavedSearchModalContent} from 'sentry/components/modals/savedSearchModal
 import {t} from 'sentry/locale';
 import {Organization, SavedSearchType, SavedSearchVisibility} from 'sentry/types';
 import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
-import useApi from 'sentry/utils/useApi';
 import {useCreateSavedSearch} from 'sentry/views/issueList/mutations/useCreateSavedSearch';
 import {IssueSortOptions} from 'sentry/views/issueList/utils';
 
@@ -56,22 +54,15 @@ export function CreateSavedSearchModal({
   query,
   sort,
 }: CreateSavedSearchModalProps) {
-  const savedSearchesV2Enabled = organization.features.includes(
-    'issue-list-saved-searches-v2'
-  );
-
-  const api = useApi();
   const [error, setError] = useState(null);
 
-  const {mutateAsync: createSavedSearchV2} = useCreateSavedSearch();
+  const {mutateAsync: createSavedSearch} = useCreateSavedSearch();
 
   const initialData = {
     name: '',
     query,
     sort: validateSortOption({organization, sort}),
-    visibility: organization.features.includes('issue-list-saved-searches-v2')
-      ? SavedSearchVisibility.Owner
-      : SavedSearchVisibility.Organization,
+    visibility: SavedSearchVisibility.Owner,
   };
 
   const handleSubmit: OnSubmitCallback = async (
@@ -95,25 +86,14 @@ export function CreateSavedSearchModal({
     });
 
     try {
-      if (savedSearchesV2Enabled) {
-        await createSavedSearchV2({
-          orgSlug: organization.slug,
-          name: data.name,
-          query: data.query,
-          sort: data.sort,
-          type: SavedSearchType.ISSUE,
-          visibility: data.visibility,
-        });
-      } else {
-        await createSavedSearch(
-          api,
-          organization.slug,
-          data.name,
-          data.query,
-          data.sort,
-          data.visibility
-        );
-      }
+      await createSavedSearch({
+        orgSlug: organization.slug,
+        name: data.name,
+        query: data.query,
+        sort: data.sort,
+        type: SavedSearchType.ISSUE,
+        visibility: data.visibility,
+      });
 
       closeModal();
       clearIndicators();

+ 1 - 2
static/app/components/modals/savedSearchModal/editSavedSearchModal.spec.tsx

@@ -34,7 +34,7 @@ describe('EditSavedSearchModal', function () {
     Footer: ModalFooter,
     CloseButton: makeCloseButton(jest.fn()),
     closeModal: jest.fn(),
-    organization: TestStubs.Organization({features: ['issue-list-saved-searches-v2']}),
+    organization: TestStubs.Organization(),
     savedSearch: {
       id: 'saved-search-id',
       name: 'Saved search name',
@@ -109,7 +109,6 @@ describe('EditSavedSearchModal', function () {
         {...defaultProps}
         organization={TestStubs.Organization({
           access: [],
-          features: ['issue-list-saved-searches-v2'],
         })}
       />
     );

+ 12 - 14
static/app/components/modals/savedSearchModal/savedSearchModalContent.tsx

@@ -86,20 +86,18 @@ export function SavedSearchModalContent({organization}: SavedSearchModalContentP
         stacked
         flexibleControlStateSize
       />
-      {organization.features.includes('issue-list-saved-searches-v2') && (
-        <SelectField
-          disabled={!canChangeVisibility}
-          disabledReason={t('Only organization admins can create global saved searches.')}
-          name="visibility"
-          label={t('Choose who can view this saved search')}
-          options={SELECT_FIELD_VISIBILITY_OPTIONS}
-          required
-          clearable={false}
-          inline={false}
-          stacked
-          flexibleControlStateSize
-        />
-      )}
+      <SelectField
+        disabled={!canChangeVisibility}
+        disabledReason={t('Only organization admins can create global saved searches.')}
+        name="visibility"
+        label={t('Choose who can view this saved search')}
+        options={SELECT_FIELD_VISIBILITY_OPTIONS}
+        required
+        clearable={false}
+        inline={false}
+        stacked
+        flexibleControlStateSize
+      />
     </Fragment>
   );
 }

+ 28 - 0
static/app/components/smartSearchBar/actionButton.tsx

@@ -0,0 +1,28 @@
+// eslint-disable-next-line no-restricted-imports
+import styled from '@emotion/styled';
+
+import Button from 'sentry/components/button';
+
+export const ActionButton = styled(Button)<{isActive?: boolean}>`
+  color: ${p => (p.isActive ? p.theme.linkColor : p.theme.subText)};
+  width: 18px;
+  height: 18px;
+  padding: 2px;
+  min-height: auto;
+
+  &,
+  &:hover,
+  &:focus {
+    background: transparent;
+  }
+
+  &:hover {
+    color: ${p => p.theme.gray400};
+  }
+`;
+
+ActionButton.defaultProps = {
+  type: 'button',
+  borderless: true,
+  size: 'zero',
+};

+ 0 - 91
static/app/components/smartSearchBar/actions.spec.jsx

@@ -1,91 +0,0 @@
-import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
-
-import {makePinSearchAction} from 'sentry/components/smartSearchBar/actions';
-
-describe('SmartSearchBar', () => {
-  describe('actions', function () {
-    const organization = TestStubs.Organization({id: '123'});
-    const api = new MockApiClient();
-
-    let pinRequest, unpinRequest, location;
-
-    beforeEach(function () {
-      location = {
-        pathname: `/organizations/${organization.slug}/recent-searches/`,
-        query: {
-          projectId: '0',
-        },
-      };
-
-      pinRequest = MockApiClient.addMockResponse({
-        url: `/organizations/${organization.slug}/pinned-searches/`,
-        method: 'PUT',
-        body: [],
-      });
-      unpinRequest = MockApiClient.addMockResponse({
-        url: `/organizations/${organization.slug}/pinned-searches/`,
-        method: 'DELETE',
-        body: [],
-      });
-      MockApiClient.addMockResponse({
-        url: `/organizations/${organization.slug}/recent-searches/`,
-        method: 'POST',
-        body: {},
-      });
-    });
-
-    it('does not pin when query is empty', function () {
-      const {makeAction} = makePinSearchAction({sort: '', location});
-
-      const Action = makeAction({
-        api,
-        organization,
-        query: '',
-        savedSearchType: 0,
-      }).Button;
-
-      render(<Action />);
-
-      userEvent.click(screen.getByRole('button'));
-
-      expect(pinRequest).not.toHaveBeenCalled();
-    });
-
-    it('adds pins', function () {
-      const {makeAction} = makePinSearchAction({sort: '', location});
-
-      const Action = makeAction({
-        api,
-        organization,
-        query: 'is:unresolved',
-        savedSearchType: 0,
-      }).Button;
-
-      render(<Action />);
-
-      userEvent.click(screen.getByRole('button'));
-
-      expect(pinRequest).toHaveBeenCalled();
-      expect(unpinRequest).not.toHaveBeenCalled();
-    });
-
-    it('removes pins', function () {
-      const pinnedSearch = TestStubs.Search({isPinned: true});
-      const {makeAction} = makePinSearchAction({pinnedSearch, sort: '', location});
-
-      const Action = makeAction({
-        api,
-        organization,
-        query: 'is:unresolved',
-        savedSearchType: 0,
-      }).Button;
-
-      render(<Action />);
-
-      userEvent.click(screen.getByRole('button'));
-
-      expect(pinRequest).not.toHaveBeenCalled();
-      expect(unpinRequest).toHaveBeenCalled();
-    });
-  });
-});

+ 0 - 199
static/app/components/smartSearchBar/actions.tsx

@@ -1,199 +0,0 @@
-// eslint-disable-next-line no-restricted-imports
-import {browserHistory} from 'react-router';
-import styled from '@emotion/styled';
-
-import {openModal} from 'sentry/actionCreators/modal';
-import {pinSearch, unpinSearch} from 'sentry/actionCreators/savedSearches';
-import Button from 'sentry/components/button';
-import {MenuItemProps} from 'sentry/components/dropdownMenuItem';
-import {CreateSavedSearchModal} from 'sentry/components/modals/savedSearchModal/createSavedSearchModal';
-import {IconAdd, IconPin} from 'sentry/icons';
-import {t} from 'sentry/locale';
-import {SavedSearch, SavedSearchType} from 'sentry/types';
-import trackAdvancedAnalyticsEvent from 'sentry/utils/analytics/trackAdvancedAnalyticsEvent';
-import {useLocation} from 'sentry/utils/useLocation';
-
-import type {ActionBarItem, ActionProps} from './index';
-import {removeSpace} from './utils';
-
-type PinSearchActionOpts = {
-  location: ReturnType<typeof useLocation>;
-  /**
-   * The current issue sort
-   */
-  sort: string;
-  /**
-   * The currently pinned search
-   */
-  pinnedSearch?: SavedSearch;
-};
-
-/**
- * The Pin Search action toggles the current as a pinned search
- */
-export function makePinSearchAction({
-  pinnedSearch,
-  sort,
-  location,
-}: PinSearchActionOpts): ActionBarItem {
-  const makeAction = ({api, organization, query, savedSearchType}: ActionProps) => {
-    const onTogglePinnedSearch = async () => {
-      if (savedSearchType === undefined) {
-        return;
-      }
-
-      const {cursor: _cursor, page: _page, ...currentQuery} = location.query;
-
-      trackAdvancedAnalyticsEvent('search.pin', {
-        organization,
-        action: pinnedSearch ? 'unpin' : 'pin',
-        search_type: savedSearchType === SavedSearchType.ISSUE ? 'issues' : 'events',
-        query: pinnedSearch?.query ?? query,
-      });
-
-      if (pinnedSearch) {
-        unpinSearch(api, organization.slug, savedSearchType, pinnedSearch).then(() => {
-          browserHistory.push({
-            ...location,
-            pathname: `/organizations/${organization.slug}/issues/`,
-            query: {
-              referrer: 'search-bar',
-              ...currentQuery,
-              query: pinnedSearch.query,
-              sort: pinnedSearch.sort,
-            },
-          });
-        });
-        return;
-      }
-
-      const resp = await pinSearch(
-        api,
-        organization.slug,
-        savedSearchType,
-        removeSpace(query),
-        sort
-      );
-
-      if (!resp || !resp.id) {
-        return;
-      }
-
-      browserHistory.push({
-        ...location,
-        pathname: `/organizations/${organization.slug}/issues/searches/${resp.id}/`,
-        query: {referrer: 'search-bar', ...currentQuery},
-      });
-    };
-
-    const pinSearchMenuItem: MenuItemProps = {
-      onAction: onTogglePinnedSearch,
-      label: pinnedSearch ? t('Unpin Search') : t('Pin Search'),
-      key: 'pinSearch',
-    };
-
-    const PinSearchActionButton = () => {
-      const pinTooltip = pinnedSearch ? t('Unpin this search') : t('Pin this search');
-
-      return (
-        <ActionButton
-          title={pinTooltip}
-          disabled={!query}
-          aria-label={pinTooltip}
-          onClick={e => {
-            e.preventDefault();
-            e.stopPropagation();
-
-            onTogglePinnedSearch();
-          }}
-          isActive={!!pinnedSearch}
-          data-test-id="pin-icon"
-          icon={<IconPin isSolid={!!pinnedSearch} size="xs" />}
-        />
-      );
-    };
-
-    return {Button: PinSearchActionButton, menuItem: pinSearchMenuItem};
-  };
-
-  return {key: 'pinSearch', makeAction};
-}
-
-type SaveSearchActionOpts = {
-  disabled: boolean;
-  /**
-   * The current issue sort
-   */
-  sort: string;
-};
-
-/**
- * The Save Search action triggers the create saved search modal from the
- * current query.
- */
-export function makeSaveSearchAction({
-  sort,
-  disabled,
-}: SaveSearchActionOpts): ActionBarItem {
-  const makeAction = ({query, organization}: ActionProps) => {
-    const onSaveSearch = () => {
-      trackAdvancedAnalyticsEvent('search.saved_search_open_create_modal', {
-        organization,
-      });
-      openModal(deps => (
-        <CreateSavedSearchModal {...deps} {...{organization, query, sort}} />
-      ));
-    };
-
-    const title = disabled
-      ? t('You do not have permission to create a saved search')
-      : t('Add to organization saved searches');
-
-    const menuItem: MenuItemProps = {
-      disabled,
-      onAction: onSaveSearch,
-      label: t('Create Saved Search'),
-      key: 'saveSearch',
-      details: disabled ? title : undefined,
-    };
-
-    const SaveSearchActionButton = () => (
-      <ActionButton
-        onClick={onSaveSearch}
-        disabled={disabled}
-        icon={<IconAdd size="xs" />}
-        title={title}
-        aria-label={title}
-        data-test-id="save-current-search"
-      />
-    );
-
-    return {Button: SaveSearchActionButton, menuItem};
-  };
-
-  return {key: 'saveSearch', makeAction};
-}
-
-export const ActionButton = styled(Button)<{isActive?: boolean}>`
-  color: ${p => (p.isActive ? p.theme.linkColor : p.theme.subText)};
-  width: 18px;
-  height: 18px;
-  padding: 2px;
-  min-height: auto;
-
-  &,
-  &:hover,
-  &:focus {
-    background: transparent;
-  }
-
-  &:hover {
-    color: ${p => p.theme.gray400};
-  }
-`;
-
-ActionButton.defaultProps = {
-  type: 'button',
-  borderless: true,
-  size: 'zero',
-};

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

@@ -51,7 +51,7 @@ import withSentryRouter from 'sentry/utils/withSentryRouter';
 import DropdownMenuControl from '../dropdownMenuControl';
 import {MenuItemProps} from '../dropdownMenuItem';
 
-import {ActionButton} from './actions';
+import {ActionButton} from './actionButton';
 import SearchBarDatePicker from './searchBarDatePicker';
 import SearchDropdown from './searchDropdown';
 import SearchHotkeysListener from './searchHotkeysListener';

+ 0 - 276
static/app/stores/savedSearchesStore.spec.jsx

@@ -1,276 +0,0 @@
-import {
-  deleteSavedSearch,
-  fetchSavedSearches,
-  pinSearch,
-  unpinSearch,
-} from 'sentry/actionCreators/savedSearches';
-import {Client} from 'sentry/api';
-import SavedSearchesStore from 'sentry/stores/savedSearchesStore';
-import {SavedSearchType} from 'sentry/types';
-
-describe('SavedSearchesStore', function () {
-  let api;
-
-  beforeAll(async function () {
-    api = new Client();
-    await SavedSearchesStore.reset();
-  });
-
-  beforeEach(function () {
-    Client.addMockResponse({
-      url: '/organizations/org-1/searches/',
-      body: TestStubs.Searches(),
-    });
-    Client.addMockResponse({
-      url: '/organizations/org-1/pinned-searches/',
-      method: 'PUT',
-      body: {},
-    });
-    Client.addMockResponse({
-      url: '/organizations/org-1/pinned-searches/',
-      method: 'DELETE',
-    });
-  });
-
-  afterEach(async function () {
-    Client.clearMockResponses();
-    SavedSearchesStore.reset();
-    await tick();
-  });
-
-  it('get', function () {
-    expect(SavedSearchesStore.get()).toEqual({
-      hasError: false,
-      isLoading: true,
-      savedSearches: [],
-    });
-  });
-
-  it('fetching saved searches updates store', async function () {
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
-    expect(SavedSearchesStore.get().isLoading).toBe(false);
-  });
-
-  it('failed fetches do not corrupt store', async function () {
-    Client.addMockResponse({
-      url: '/organizations/org-1/searches/',
-      body: '',
-    });
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(0);
-    expect(SavedSearchesStore.get().isLoading).toBe(false);
-  });
-
-  it('creates a new pin search', async function () {
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/pinned-searches/',
-      method: 'PUT',
-      body: {
-        id: '123',
-        query: 'level:info',
-        sort: 'freq',
-        isPinned: true,
-      },
-    });
-
-    pinSearch(api, 'org-1', 0, 'level:info', 'freq');
-    await tick();
-    await tick();
-
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(3);
-    expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
-      expect.objectContaining({
-        id: '123',
-        isPinned: true,
-        type: SavedSearchType.ISSUE,
-        query: 'level:info',
-        name: 'My Pinned Search',
-        sort: 'freq',
-      })
-    );
-  });
-
-  it('changes pinned search from a custom search to an existing search', async function () {
-    const searches = TestStubs.Searches();
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/searches/',
-      body: [
-        {
-          id: null,
-          isPinned: true,
-          type: SavedSearchType.ISSUE,
-          query: 'assigned:me',
-          sort: 'date',
-        },
-        ...searches,
-      ],
-    });
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/pinned-searches/',
-      method: 'PUT',
-      body: {
-        id: '1',
-        isGlobal: true,
-        isPinned: true,
-        query: 'is:unresolved',
-        sort: 'date',
-        name: 'Unresolved Issues',
-        type: SavedSearchType.ISSUE,
-      },
-    });
-
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    pinSearch(api, 'org-1', 0, searches[1].query, 'date');
-    await tick();
-    await tick();
-
-    // Order should remain the same
-    expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
-      expect.objectContaining({
-        id: '1',
-        isGlobal: true,
-        isPinned: true,
-        type: SavedSearchType.ISSUE,
-        name: 'Unresolved Issues',
-        query: 'is:unresolved',
-        sort: 'date',
-      })
-    );
-
-    // Saved custom search should be removed
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
-  });
-
-  it('changes pinned search from an existing search to another existing search', async function () {
-    const searches = TestStubs.Searches();
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/searches/',
-      body: [{...searches[0], isPinned: true}, searches[1]],
-    });
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/pinned-searches/',
-      method: 'PUT',
-      body: {
-        id: '1',
-        isGlobal: true,
-        isPinned: true,
-        query: 'is:unresolved',
-        sort: 'date',
-        name: 'Unresolved Issues',
-        type: SavedSearchType.ISSUE,
-      },
-    });
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    pinSearch(api, 'org-1', 0, searches[1].query, 'date');
-    await tick();
-    await tick();
-
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
-
-    expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
-      expect.objectContaining({
-        id: '2',
-        isPinned: false,
-        type: SavedSearchType.ISSUE,
-        name: 'Needs Triage',
-        query: 'is:unresolved is:unassigned',
-        sort: 'date',
-      })
-    );
-
-    expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
-      expect.objectContaining({
-        id: '1',
-        isGlobal: true,
-        isPinned: true,
-        type: SavedSearchType.ISSUE,
-        name: 'Unresolved Issues',
-        query: 'is:unresolved',
-        sort: 'date',
-      })
-    );
-  });
-
-  it('unpins a user custom search', async function () {
-    const searches = TestStubs.Searches();
-
-    Client.addMockResponse({
-      url: '/organizations/org-1/searches/',
-      body: [
-        {
-          id: null,
-          isPinned: true,
-          type: SavedSearchType.ISSUE,
-          query: 'assigned:me',
-          sort: 'date',
-        },
-        ...searches,
-      ],
-    });
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    unpinSearch(api, 'org-1', 0, searches[0]);
-    await tick();
-    await tick();
-
-    // Saved custom search should be removed
-    expect(SavedSearchesStore.get().savedSearches).toHaveLength(2);
-
-    expect(SavedSearchesStore.get().savedSearches[0]).toEqual(
-      expect.objectContaining({
-        id: '2',
-        isPinned: false,
-        type: SavedSearchType.ISSUE,
-        name: 'Needs Triage',
-        query: 'is:unresolved is:unassigned',
-        sort: 'date',
-      })
-    );
-
-    expect(SavedSearchesStore.get().savedSearches[1]).toEqual(
-      expect.objectContaining({
-        id: '1',
-        isPinned: false,
-        type: SavedSearchType.ISSUE,
-        name: 'Unresolved Issues',
-        query: 'is:unresolved',
-        sort: 'date',
-      })
-    );
-  });
-
-  it('removes deleted saved searches', async function () {
-    await fetchSavedSearches(api, 'org-1', {});
-    await tick();
-
-    const searches = SavedSearchesStore.get().savedSearches;
-    Client.addMockResponse({
-      url: `/organizations/org-1/searches/${searches[0].id}/`,
-      method: 'DELETE',
-      body: {},
-    });
-    await deleteSavedSearch(api, 'org-1', searches[0]);
-    await tick();
-
-    const newSearches = SavedSearchesStore.get().savedSearches;
-    expect(newSearches.length).toBeLessThan(searches.length);
-    expect(newSearches[0].id).not.toBe(searches[0].id);
-  });
-});

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