view.tsx 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {useEffect, useState} from 'react';
  2. import {browserHistory, RouteComponentProps} from 'react-router';
  3. import pick from 'lodash/pick';
  4. import {updateDashboardVisit} from 'sentry/actionCreators/dashboards';
  5. import Feature from 'sentry/components/acl/feature';
  6. import Alert from 'sentry/components/alert';
  7. import ErrorBoundary from 'sentry/components/errorBoundary';
  8. import NotFound from 'sentry/components/errors/notFound';
  9. import LoadingIndicator from 'sentry/components/loadingIndicator';
  10. import {t} from 'sentry/locale';
  11. import {PageContent} from 'sentry/styles/organization';
  12. import {Organization} from 'sentry/types';
  13. import useApi from 'sentry/utils/useApi';
  14. import withOrganization from 'sentry/utils/withOrganization';
  15. import DashboardDetail from './detail';
  16. import OrgDashboards from './orgDashboards';
  17. import {DashboardState, Widget} from './types';
  18. import {constructWidgetFromQuery} from './utils';
  19. const ALLOWED_PARAMS = ['start', 'end', 'utc', 'period', 'project', 'environment'];
  20. type Props = RouteComponentProps<
  21. {dashboardId: string; orgId: string; widgetId?: number},
  22. {}
  23. > & {
  24. children: React.ReactNode;
  25. organization: Organization;
  26. };
  27. function ViewEditDashboard(props: Props) {
  28. const api = useApi();
  29. const {organization, params, location} = props;
  30. const dashboardId = params.dashboardId;
  31. const orgSlug = organization.slug;
  32. const [newWidget, setNewWidget] = useState<Widget | undefined>();
  33. const [dashboardInitialState, setDashboardInitialState] = useState(DashboardState.VIEW);
  34. useEffect(() => {
  35. if (dashboardId && dashboardId !== 'default-overview') {
  36. updateDashboardVisit(api, orgSlug, dashboardId);
  37. }
  38. }, [api, orgSlug, dashboardId]);
  39. useEffect(() => {
  40. const constructedWidget = constructWidgetFromQuery(location.query);
  41. setNewWidget(constructedWidget);
  42. // Clean up url after constructing widget from query string, only allow GHS params
  43. if (constructedWidget) {
  44. setDashboardInitialState(DashboardState.EDIT);
  45. browserHistory.replace({
  46. pathname: location.pathname,
  47. query: pick(location.query, ALLOWED_PARAMS),
  48. });
  49. }
  50. }, [location.pathname]);
  51. return (
  52. <DashboardBasicFeature organization={organization}>
  53. <OrgDashboards
  54. api={api}
  55. location={location}
  56. params={params}
  57. organization={organization}
  58. >
  59. {({dashboard, dashboards, error, onDashboardUpdate}) => {
  60. return error ? (
  61. <NotFound />
  62. ) : dashboard ? (
  63. <ErrorBoundary>
  64. <DashboardDetail
  65. {...props}
  66. initialState={dashboardInitialState}
  67. dashboard={dashboard}
  68. dashboards={dashboards}
  69. onDashboardUpdate={onDashboardUpdate}
  70. newWidget={newWidget}
  71. onSetNewWidget={() => setNewWidget(undefined)}
  72. />
  73. </ErrorBoundary>
  74. ) : (
  75. <LoadingIndicator />
  76. );
  77. }}
  78. </OrgDashboards>
  79. </DashboardBasicFeature>
  80. );
  81. }
  82. export default withOrganization(ViewEditDashboard);
  83. type FeatureProps = {
  84. children: React.ReactNode;
  85. organization: Organization;
  86. };
  87. export const DashboardBasicFeature = ({organization, children}: FeatureProps) => {
  88. const renderDisabled = () => (
  89. <PageContent>
  90. <Alert type="warning">{t("You don't have access to this feature")}</Alert>
  91. </PageContent>
  92. );
  93. return (
  94. <Feature
  95. hookName="feature-disabled:dashboards-page"
  96. features={['organizations:dashboards-basic']}
  97. organization={organization}
  98. renderDisabled={renderDisabled}
  99. >
  100. {children}
  101. </Feature>
  102. );
  103. };