diff --git a/static/app/views/detectors/components/details/common/actions.tsx b/static/app/views/detectors/components/details/common/actions.tsx index 9afc02efb5ac2f..8c259191f38347 100644 --- a/static/app/views/detectors/components/details/common/actions.tsx +++ b/static/app/views/detectors/components/details/common/actions.tsx @@ -16,6 +16,7 @@ import { makeMonitorBasePathname, makeMonitorDetailsPathname, } from 'sentry/views/detectors/pathnames'; +import {detectorTypeIsUserCreateable} from 'sentry/views/detectors/utils/detectorTypeConfig'; import {useCanEditDetector} from 'sentry/views/detectors/utils/useCanEditDetector'; export function DisableDetectorAction({detector}: {detector: Detector}) { @@ -59,19 +60,23 @@ export function EditDetectorAction({detector}: {detector: Detector}) { projectId: detector.projectId, }); - const permissionTooltipText = tct( - 'You do not have permission to edit this monitor. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.', - { - settingsLink: ( - - ), - } - ); + const permissionTooltipText = detectorTypeIsUserCreateable(detector.type) + ? tct( + 'You do not have permission to edit this monitor. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.', + { + settingsLink: ( + + ), + } + ) + : t( + 'This monitor is managed by Sentry. Only organization owners and managers can edit it.' + ); return ( } + actions={} title={TITLE} description={DESCRIPTION} docsUrl={DOCS_URL} diff --git a/static/app/views/detectors/list/common/detectorListActions.tsx b/static/app/views/detectors/list/common/detectorListActions.tsx index 68e6becc922ba7..da3e37c644f165 100644 --- a/static/app/views/detectors/list/common/detectorListActions.tsx +++ b/static/app/views/detectors/list/common/detectorListActions.tsx @@ -1,20 +1,50 @@ +import {Link} from '@sentry/scraps/link'; + import {LinkButton} from 'sentry/components/core/button/linkButton'; import {Flex} from 'sentry/components/core/layout'; import {ALL_ACCESS_PROJECTS} from 'sentry/constants/pageFilters'; import {IconAdd} from 'sentry/icons'; -import {t} from 'sentry/locale'; +import {t, tct} from 'sentry/locale'; +import type {Organization} from 'sentry/types/organization'; import type {DetectorType} from 'sentry/types/workflowEngine/detectors'; import useOrganization from 'sentry/utils/useOrganization'; import usePageFilters from 'sentry/utils/usePageFilters'; import {MonitorFeedbackButton} from 'sentry/views/detectors/components/monitorFeedbackButton'; import {makeMonitorCreatePathname} from 'sentry/views/detectors/pathnames'; +import {detectorTypeIsUserCreateable} from 'sentry/views/detectors/utils/detectorTypeConfig'; +import {useCanCreateDetector} from 'sentry/views/detectors/utils/useCanCreateDetector'; interface DetectorListActionsProps { + detectorType: DetectorType | null; children?: React.ReactNode; - /** - * Pass a detector type to skip type selection on the create monitor page - */ - detectorType?: DetectorType; +} + +function getPermissionTooltipText({ + organization, + detectorType, +}: { + detectorType: DetectorType | null; + organization: Organization; +}) { + const noPermissionText = tct( + 'You do not have permission to create monitors. Ask your organization owner or manager to [settingsLink:enable monitor access] for you.', + { + settingsLink: ( + + ), + } + ); + + if (!detectorType || detectorTypeIsUserCreateable(detectorType)) { + return noPermissionText; + } + + return t('This monitor type is managed by Sentry.'); } export function DetectorListActions({detectorType, children}: DetectorListActionsProps) { @@ -24,6 +54,7 @@ export function DetectorListActions({detectorType, children}: DetectorListAction const createPath = makeMonitorCreatePathname(organization.slug); const project = selection.projects.find(pid => pid !== ALL_ACCESS_PROJECTS); const createQuery = detectorType ? {project, detectorType} : {project}; + const canCreateDetector = useCanCreateDetector(detectorType); return ( @@ -37,6 +68,15 @@ export function DetectorListActions({detectorType, children}: DetectorListAction priority="primary" icon={} size="sm" + disabled={!canCreateDetector} + title={ + canCreateDetector + ? undefined + : getPermissionTooltipText({ + organization, + detectorType, + }) + } > {t('Create Monitor')} diff --git a/static/app/views/detectors/list/myMonitors.tsx b/static/app/views/detectors/list/myMonitors.tsx index af56e6d160b57c..072026629cccef 100644 --- a/static/app/views/detectors/list/myMonitors.tsx +++ b/static/app/views/detectors/list/myMonitors.tsx @@ -18,7 +18,7 @@ export default function MyMonitorsList() { return ( } + actions={} title={TITLE} description={DESCRIPTION} docsUrl={DOCS_URL} diff --git a/static/app/views/detectors/utils/useCanCreateDetector.tsx b/static/app/views/detectors/utils/useCanCreateDetector.tsx new file mode 100644 index 00000000000000..ae5d1b50d09dc5 --- /dev/null +++ b/static/app/views/detectors/utils/useCanCreateDetector.tsx @@ -0,0 +1,15 @@ +import {hasEveryAccess} from 'sentry/components/acl/access'; +import type {DetectorType} from 'sentry/types/workflowEngine/detectors'; +import useOrganization from 'sentry/utils/useOrganization'; + +import {detectorTypeIsUserCreateable} from './detectorTypeConfig'; + +export function useCanCreateDetector(detectorType: DetectorType | null) { + const organization = useOrganization(); + + if (!detectorType) { + return hasEveryAccess(['alerts:write'], {organization}); + } + + return detectorTypeIsUserCreateable(detectorType); +}