withSavedSearches.tsx 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. import * as React from 'react';
  2. import {RouteComponentProps} from 'react-router';
  3. import SavedSearchesStore from 'sentry/stores/savedSearchesStore';
  4. import {SavedSearch} from 'sentry/types';
  5. import getDisplayName from 'sentry/utils/getDisplayName';
  6. type InjectedSavedSearchesProps = {
  7. savedSearch: SavedSearch | null;
  8. savedSearchLoading: boolean;
  9. savedSearches: SavedSearch[];
  10. } & RouteComponentProps<{searchId?: string}, {}>;
  11. type State = {
  12. isLoading: boolean;
  13. savedSearches: SavedSearch[];
  14. };
  15. /**
  16. * Wrap a component with saved issue search data from the store.
  17. */
  18. function withSavedSearches<P extends InjectedSavedSearchesProps>(
  19. WrappedComponent: React.ComponentType<P>
  20. ) {
  21. class WithSavedSearches extends React.Component<
  22. Omit<P, keyof InjectedSavedSearchesProps> & Partial<InjectedSavedSearchesProps>,
  23. State
  24. > {
  25. static displayName = `withSavedSearches(${getDisplayName(WrappedComponent)})`;
  26. state = SavedSearchesStore.get();
  27. componentWillUnmount() {
  28. this.unsubscribe();
  29. }
  30. unsubscribe = SavedSearchesStore.listen(
  31. (searchesState: State) => this.onUpdate(searchesState),
  32. undefined
  33. );
  34. onUpdate(newState: State) {
  35. this.setState(newState);
  36. }
  37. render() {
  38. const {
  39. params,
  40. location,
  41. savedSearchLoading,
  42. savedSearch: savedSearchProp,
  43. savedSearches: savedSearchesProp,
  44. } = this.props as P;
  45. const {searchId} = params;
  46. const {savedSearches, isLoading} = this.state as State;
  47. let savedSearch: SavedSearch | null = null;
  48. // Switch to the current saved search or pinned result if available
  49. if (!isLoading && savedSearches) {
  50. if (searchId) {
  51. const match = savedSearches.find(search => search.id === searchId);
  52. savedSearch = match ? match : null;
  53. }
  54. // If there's no direct saved search being requested (via URL route)
  55. // *AND* there's no query in URL, then check if there is pinned search
  56. //
  57. // Note: Don't use pinned searches when there is an empty query (query === empty string)
  58. if (!savedSearch && typeof location.query.query === 'undefined') {
  59. const pin = savedSearches.find(search => search.isPinned);
  60. savedSearch = pin ? pin : null;
  61. }
  62. }
  63. return (
  64. <WrappedComponent
  65. {...(this.props as P)}
  66. savedSearches={savedSearchesProp ?? savedSearches}
  67. savedSearchLoading={savedSearchLoading ?? isLoading}
  68. savedSearch={savedSearchProp ?? savedSearch}
  69. />
  70. );
  71. }
  72. }
  73. return WithSavedSearches;
  74. }
  75. export default withSavedSearches;