Browse Source

feat(discover-homepage): Allow reset homepage query after saving (#39635)

Update the button so when a user saves a query as their homepage
and makes no other changes, they have an opportunity to reset the query
to its default
Nar Saynorath 2 years ago
parent
commit
2e4bc86553

+ 6 - 0
static/app/actionCreators/discoverHomepageQueries.tsx

@@ -11,3 +11,9 @@ export function updateHomepageQuery(
     data: query,
   });
 }
+
+export function deleteHomepageQuery(api: Client, orgId: string): Promise<void> {
+  return api.requestPromise(`/organizations/${orgId}/discover/homepage/`, {
+    method: 'DELETE',
+  });
+}

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

@@ -524,7 +524,7 @@ class EventView {
     return EventView.fromLocation(location);
   }
 
-  isEqualTo(other: EventView): boolean {
+  isEqualTo(other: EventView, omitList: string[] = []): boolean {
     const defaults = {
       id: undefined,
       name: undefined,
@@ -539,7 +539,7 @@ class EventView {
       display: DisplayModes.DEFAULT,
       topEvents: '5',
     };
-    const keys = Object.keys(defaults);
+    const keys = Object.keys(defaults).filter(key => !omitList.includes(key));
     for (const key of keys) {
       const currentValue = this[key] ?? defaults[key];
       const otherValue = other[key] ?? defaults[key];

+ 138 - 0
static/app/views/eventsV2/results.spec.jsx

@@ -7,9 +7,12 @@ import {triggerPress} from 'sentry-test/utils';
 
 import * as PageFilterPersistence from 'sentry/components/organizations/pageFilters/persistence';
 import ProjectsStore from 'sentry/stores/projectsStore';
+import EventView from 'sentry/utils/discover/eventView';
 import Results from 'sentry/views/eventsV2/results';
 import {OrganizationContext} from 'sentry/views/organizationContext';
 
+import {DEFAULT_EVENT_VIEW} from './data';
+
 const FIELDS = [
   {
     field: 'title',
@@ -1749,4 +1752,139 @@ describe('Results', function () {
       })
     );
   });
+
+  it('Changes the Use as Discover button to a reset button for saved query', async () => {
+    MockApiClient.addMockResponse({
+      url: '/organizations/org-slug/discover/homepage/',
+      method: 'PUT',
+      statusCode: 200,
+      body: {
+        id: '2',
+        name: 'new',
+        projects: [],
+        version: 2,
+        expired: false,
+        dateCreated: '2021-04-08T17:53:25.195782Z',
+        dateUpdated: '2021-04-09T12:13:18.567264Z',
+        createdBy: {
+          id: '2',
+        },
+        environment: [],
+        fields: ['title', 'event.type', 'project', 'user.display', 'timestamp'],
+        widths: ['-1', '-1', '-1', '-1', '-1'],
+        range: '14d',
+        orderby: '-user.display',
+      },
+    });
+    const organization = TestStubs.Organization({
+      features: [
+        'discover-basic',
+        'discover-query',
+        'discover-query-builder-as-landing-page',
+      ],
+    });
+
+    const initialData = initializeOrg({
+      organization,
+      router: {
+        location: {query: {id: '1'}},
+      },
+    });
+
+    ProjectsStore.loadInitialData([TestStubs.Project()]);
+
+    const {rerender} = render(
+      <Results
+        organization={organization}
+        location={initialData.router.location}
+        router={initialData.router}
+      />,
+      {context: initialData.routerContext, organization}
+    );
+
+    userEvent.click(screen.getByText('Use as Discover Home'));
+    expect(await screen.findByText('Reset Discover Home')).toBeInTheDocument();
+
+    userEvent.click(screen.getByText('Total Period'));
+    userEvent.click(screen.getByText('Previous Period'));
+    const rerenderData = initializeOrg({
+      organization,
+      router: {
+        location: {query: {...initialData.router.location.query, display: 'previous'}},
+      },
+    });
+    rerender(
+      <Results
+        organization={organization}
+        location={rerenderData.router.location}
+        router={rerenderData.router}
+      />
+    );
+    screen.getByText('Previous Period');
+    expect(await screen.findByText('Use as Discover Home')).toBeInTheDocument();
+  });
+
+  it('Changes the Use as Discover button to a reset button for prebuilt query', async () => {
+    MockApiClient.addMockResponse({
+      url: '/organizations/org-slug/discover/homepage/',
+      method: 'PUT',
+      statusCode: 200,
+      body: DEFAULT_EVENT_VIEW,
+    });
+    const organization = TestStubs.Organization({
+      features: [
+        'discover-basic',
+        'discover-query',
+        'discover-query-builder-as-landing-page',
+      ],
+    });
+
+    const initialData = initializeOrg({
+      organization,
+      router: {
+        location: {
+          ...TestStubs.location(),
+          query: {
+            ...EventView.fromNewQueryWithLocation(
+              DEFAULT_EVENT_VIEW,
+              TestStubs.location()
+            ).generateQueryStringObject(),
+          },
+        },
+      },
+    });
+
+    ProjectsStore.loadInitialData([TestStubs.Project()]);
+
+    const {rerender} = render(
+      <Results
+        organization={organization}
+        location={initialData.router.location}
+        router={initialData.router}
+      />,
+      {context: initialData.routerContext, organization}
+    );
+
+    await screen.findAllByText('All Events');
+    userEvent.click(screen.getByText('Use as Discover Home'));
+    expect(await screen.findByText('Reset Discover Home')).toBeInTheDocument();
+
+    userEvent.click(screen.getByText('Total Period'));
+    userEvent.click(screen.getByText('Previous Period'));
+    const rerenderData = initializeOrg({
+      organization,
+      router: {
+        location: {query: {...initialData.router.location.query, display: 'previous'}},
+      },
+    });
+    rerender(
+      <Results
+        organization={organization}
+        location={rerenderData.router.location}
+        router={rerenderData.router}
+      />
+    );
+    screen.getByText('Previous Period');
+    expect(await screen.findByText('Use as Discover Home')).toBeInTheDocument();
+  });
 });

+ 8 - 1
static/app/views/eventsV2/resultsHeader.tsx

@@ -30,12 +30,14 @@ type Props = {
 };
 
 type State = {
+  homepageQuery: SavedQuery | undefined;
   loading: boolean;
   savedQuery: SavedQuery | undefined;
 };
 
 class ResultsHeader extends Component<Props, State> {
   state: State = {
+    homepageQuery: undefined,
     savedQuery: undefined,
     loading: true,
   };
@@ -97,7 +99,7 @@ class ResultsHeader extends Component<Props, State> {
       setSavedQuery,
       isHomepage,
     } = this.props;
-    const {savedQuery, loading} = this.state;
+    const {savedQuery, loading, homepageQuery} = this.state;
 
     return (
       <Layout.Header>
@@ -128,6 +130,11 @@ class ResultsHeader extends Component<Props, State> {
             updateCallback={() => this.fetchData()}
             yAxis={yAxis}
             router={router}
+            isHomepage={isHomepage}
+            setHomepageQuery={updatedHomepageQuery =>
+              this.setState({homepageQuery: updatedHomepageQuery})
+            }
+            homepageQuery={homepageQuery}
           />
         </Layout.HeaderActions>
       </Layout.Header>

+ 2 - 0
static/app/views/eventsV2/savedQuery/index.spec.tsx

@@ -38,6 +38,7 @@ function mount(
       router={router}
       savedQueryLoading={false}
       setSavedQuery={jest.fn()}
+      setHomepageQuery={jest.fn()}
     />
   );
 }
@@ -65,6 +66,7 @@ function generateWrappedComponent(
         router={router}
         savedQueryLoading={false}
         setSavedQuery={mockSetSavedQuery}
+        setHomepageQuery={jest.fn()}
       />
     ),
   };

+ 53 - 3
static/app/views/eventsV2/savedQuery/index.tsx

@@ -31,9 +31,12 @@ import withApi from 'sentry/utils/withApi';
 import withProjects from 'sentry/utils/withProjects';
 import {handleAddQueryToDashboard} from 'sentry/views/eventsV2/utils';
 
+import {DEFAULT_EVENT_VIEW} from '../data';
+
 import {
   handleCreateQuery,
   handleDeleteQuery,
+  handleResetHomepageQuery,
   handleUpdateHomepageQuery,
   handleUpdateQuery,
 } from './utils';
@@ -114,9 +117,12 @@ type Props = DefaultProps & {
   router: InjectedRouter;
   savedQuery: SavedQuery | undefined;
   savedQueryLoading: boolean;
+  setHomepageQuery: (homepageQuery?: SavedQuery) => void;
   setSavedQuery: (savedQuery: SavedQuery) => void;
   updateCallback: () => void;
   yAxis: string[];
+  homepageQuery?: SavedQuery;
+  isHomepage?: boolean;
 };
 
 type State = {
@@ -389,13 +395,57 @@ class SavedQueryButtonGroup extends PureComponent<Props, State> {
   }
 
   renderSaveAsHomepage() {
-    const {api, organization, eventView} = this.props;
+    const {
+      api,
+      organization,
+      eventView,
+      location,
+      isHomepage,
+      setHomepageQuery,
+      homepageQuery,
+    } = this.props;
+    if (
+      homepageQuery &&
+      eventView.isEqualTo(EventView.fromSavedQuery(homepageQuery), ['id'])
+    ) {
+      return (
+        <Button
+          key="reset-discover-homepage"
+          data-test-id="reset-discover-homepage"
+          onClick={async () => {
+            await handleResetHomepageQuery(api, organization);
+            setHomepageQuery(undefined);
+            if (isHomepage) {
+              const nextEventView = EventView.fromNewQueryWithLocation(
+                DEFAULT_EVENT_VIEW,
+                location
+              );
+              browserHistory.push({
+                pathname: location.pathname,
+                query: nextEventView.generateQueryStringObject(),
+              });
+            }
+          }}
+        >
+          {t('Reset Discover Home')}
+          <FeatureBadge type="alpha" />
+        </Button>
+      );
+    }
+
     return (
       <Button
         key="save-query-as-homepage"
         data-test-id="save-query-as-homepage"
-        onClick={() => {
-          handleUpdateHomepageQuery(api, organization, eventView.toNewQuery());
+        onClick={async () => {
+          const updatedHomepageQuery = await handleUpdateHomepageQuery(
+            api,
+            organization,
+            eventView.toNewQuery()
+          );
+          if (updatedHomepageQuery) {
+            setHomepageQuery(updatedHomepageQuery);
+          }
         }}
       >
         {t('Use as Discover Home')}

+ 18 - 2
static/app/views/eventsV2/savedQuery/utils.tsx

@@ -1,4 +1,7 @@
-import {updateHomepageQuery} from 'sentry/actionCreators/discoverHomepageQueries';
+import {
+  deleteHomepageQuery,
+  updateHomepageQuery,
+} from 'sentry/actionCreators/discoverHomepageQueries';
 import {
   createSavedQuery,
   deleteSavedQuery,
@@ -220,14 +223,27 @@ export function handleUpdateHomepageQuery(
   const promise = updateHomepageQuery(api, organization.slug, query);
 
   return promise
-    .then(() => {
+    .then(savedQuery => {
       addSuccessMessage(t('Saved as Discover home'));
+      return savedQuery;
     })
     .catch(() => {
       addErrorMessage(t('Unable to set query as Discover home'));
     });
 }
 
+export function handleResetHomepageQuery(api: Client, organization: Organization) {
+  const promise = deleteHomepageQuery(api, organization.slug);
+
+  return promise
+    .then(() => {
+      addSuccessMessage(t('Successfully reset Discover home'));
+    })
+    .catch(() => {
+      addErrorMessage(t('Unable to reset Discover home'));
+    });
+}
+
 export function getAnalyticsCreateEventKeyName(
   // True if this is a brand new query being saved
   // False if this is a modification from a saved query