Browse Source

ref(app-platform): Disable sentry apps delete button for inadequate permissions (#12439)

* disable delete when permissions arent high enough
MeredithAnya 6 years ago
parent
commit
0dccf4b707

+ 16 - 2
src/sentry/static/sentry/app/views/settings/organizationDeveloperSettings/sentryApplicationRow.jsx

@@ -1,6 +1,7 @@
 import React from 'react';
 import {Box, Flex} from 'grid-emotion';
 import {Link} from 'react-router';
+import Access from 'app/components/acl/access';
 import Button from 'app/components/button';
 import Confirm from 'app/components/confirm';
 import ConfirmDelete from 'app/components/confirmDelete';
@@ -111,10 +112,23 @@ export default class SentryApplicationRow extends React.PureComponent {
           ) : (
             <Box>
               {app.status === 'unpublished' ? (
-                this.renderRemoveApp(app)
+                <Access access={['org:admin']}>
+                  {({hasAccess}) => (
+                    <React.Fragment>
+                      {!hasAccess && (
+                        <Tooltip
+                          title={t('Owner permissions are required for this action.')}
+                        >
+                          <Button disabled size="small" icon="icon-trash" />
+                        </Tooltip>
+                      )}
+                      {hasAccess && this.renderRemoveApp(app)}
+                    </React.Fragment>
+                  )}
+                </Access>
               ) : (
                 <Tooltip title={t('Published apps cannot be removed.')}>
-                  <Button disabled={true} size="small" icon="icon-trash" />
+                  <Button disabled size="small" icon="icon-trash" />
                 </Tooltip>
               )}
             </Box>

+ 959 - 164
tests/js/spec/views/settings/organizationDeveloperSettings/__snapshots__/index.spec.jsx.snap

@@ -1288,200 +1288,995 @@ exports[`Organization Developer Settings with unpublished apps displays all Apps
                                       className="css-roynbj"
                                       is={null}
                                     >
-                                      <ConfirmDelete
-                                        cancelText="Cancel"
-                                        confirmInput="sample-app"
-                                        confirmText="Confirm"
-                                        message="Deleting sample-app will also delete any and all of its installations.        This is a permanent action. Do you wish to continue?"
-                                        onConfirm={[Function]}
-                                        priority="danger"
+                                      <withConfig(AccessContainer)
+                                        access={
+                                          Array [
+                                            "org:admin",
+                                          ]
+                                        }
+                                      >
+                                        <AccessContainer
+                                          access={
+                                            Array [
+                                              "org:admin",
+                                            ]
+                                          }
+                                          config={
+                                            Object {
+                                              "features": Set {},
+                                              "messages": Array [],
+                                              "user": Object {
+                                                "email": "foo@example.com",
+                                                "flags": Object {
+                                                  "newsletter_consent_prompt": false,
+                                                },
+                                                "hasPasswordAuth": true,
+                                                "id": "1",
+                                                "isAuthenticated": true,
+                                                "name": "Foo Bar",
+                                                "options": Object {
+                                                  "timezone": "UTC",
+                                                },
+                                                "permissions": Set {},
+                                                "username": "foo@example.com",
+                                              },
+                                            }
+                                          }
+                                        >
+                                          <Access
+                                            access={
+                                              Array [
+                                                "org:admin",
+                                              ]
+                                            }
+                                            config={
+                                              Object {
+                                                "features": Set {},
+                                                "messages": Array [],
+                                                "user": Object {
+                                                  "email": "foo@example.com",
+                                                  "flags": Object {
+                                                    "newsletter_consent_prompt": false,
+                                                  },
+                                                  "hasPasswordAuth": true,
+                                                  "id": "1",
+                                                  "isAuthenticated": true,
+                                                  "name": "Foo Bar",
+                                                  "options": Object {
+                                                    "timezone": "UTC",
+                                                  },
+                                                  "permissions": Set {},
+                                                  "username": "foo@example.com",
+                                                },
+                                              }
+                                            }
+                                            configUser={
+                                              Object {
+                                                "email": "foo@example.com",
+                                                "flags": Object {
+                                                  "newsletter_consent_prompt": false,
+                                                },
+                                                "hasPasswordAuth": true,
+                                                "id": "1",
+                                                "isAuthenticated": true,
+                                                "name": "Foo Bar",
+                                                "options": Object {
+                                                  "timezone": "UTC",
+                                                },
+                                                "permissions": Set {},
+                                                "username": "foo@example.com",
+                                              }
+                                            }
+                                            organization={
+                                              Object {
+                                                "access": Array [
+                                                  "org:read",
+                                                  "org:write",
+                                                  "org:admin",
+                                                  "org:integrations",
+                                                  "project:read",
+                                                  "project:write",
+                                                  "project:admin",
+                                                  "team:read",
+                                                  "team:write",
+                                                  "team:admin",
+                                                ],
+                                                "features": Array [],
+                                                "id": "3",
+                                                "name": "Organization Name",
+                                                "onboardingTasks": Array [],
+                                                "projects": Array [],
+                                                "scrapeJavaScript": true,
+                                                "slug": "org-slug",
+                                                "status": Object {
+                                                  "id": "active",
+                                                  "name": "active",
+                                                },
+                                                "teams": Array [],
+                                              }
+                                            }
+                                            renderNoAccessMessage={false}
+                                            requireAll={true}
+                                          >
+                                            <ConfirmDelete
+                                              cancelText="Cancel"
+                                              confirmInput="sample-app"
+                                              confirmText="Confirm"
+                                              message="Deleting sample-app will also delete any and all of its installations.        This is a permanent action. Do you wish to continue?"
+                                              onConfirm={[Function]}
+                                              priority="danger"
+                                            >
+                                              <Confirm
+                                                bypass={false}
+                                                cancelText="Cancel"
+                                                confirmText="Confirm"
+                                                disableConfirmButton={true}
+                                                message={
+                                                  <React.Fragment>
+                                                    <Alert
+                                                      iconSize="24px"
+                                                      type="error"
+                                                    >
+                                                      Deleting sample-app will also delete any and all of its installations.        This is a permanent action. Do you wish to continue?
+                                                    </Alert>
+                                                    <Field
+                                                      alignRight={false}
+                                                      disabled={false}
+                                                      flexibleControlStateSize={true}
+                                                      inline={false}
+                                                      label={
+                                                        <div>
+                                                          Please enter 
+                                                          <code>
+                                                            sample-app
+                                                          </code>
+                                                           to confirm the deletion
+                                                        </div>
+                                                      }
+                                                      p={0}
+                                                      required={false}
+                                                      visible={true}
+                                                    >
+                                                      <Input
+                                                        onChange={[Function]}
+                                                        placeholder="sample-app"
+                                                        type="text"
+                                                        value=""
+                                                      />
+                                                    </Field>
+                                                  </React.Fragment>
+                                                }
+                                                onConfirm={[Function]}
+                                                priority="danger"
+                                              >
+                                                <Button
+                                                  disabled={false}
+                                                  icon="icon-trash"
+                                                  onClick={[Function]}
+                                                  size="small"
+                                                >
+                                                  <StyledButton
+                                                    aria-disabled={false}
+                                                    disabled={false}
+                                                    onClick={[Function]}
+                                                    role="button"
+                                                    size="small"
+                                                  >
+                                                    <Component
+                                                      aria-disabled={false}
+                                                      className="css-dkprmi-StyledButton-getColors eqrebog0"
+                                                      onClick={[Function]}
+                                                      role="button"
+                                                      size="small"
+                                                    >
+                                                      <button
+                                                        aria-disabled={false}
+                                                        className="css-dkprmi-StyledButton-getColors eqrebog0"
+                                                        onClick={[Function]}
+                                                        role="button"
+                                                        size="small"
+                                                      >
+                                                        <ButtonLabel
+                                                          size="small"
+                                                        >
+                                                          <Component
+                                                            className="css-7ui8bl-ButtonLabel eqrebog1"
+                                                            size="small"
+                                                          >
+                                                            <span
+                                                              className="css-7ui8bl-ButtonLabel eqrebog1"
+                                                            >
+                                                              <Icon
+                                                                hasChildren={false}
+                                                                size="small"
+                                                              >
+                                                                <Component
+                                                                  className="css-ljhpxy-Icon eqrebog2"
+                                                                  hasChildren={false}
+                                                                  size="small"
+                                                                >
+                                                                  <span
+                                                                    className="css-ljhpxy-Icon eqrebog2"
+                                                                    size="small"
+                                                                  >
+                                                                    <StyledInlineSvg
+                                                                      size="12px"
+                                                                      src="icon-trash"
+                                                                    >
+                                                                      <InlineSvg
+                                                                        className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                                        size="12px"
+                                                                        src="icon-trash"
+                                                                      >
+                                                                        <StyledSvg
+                                                                          className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                                          height="12px"
+                                                                          viewBox={Object {}}
+                                                                          width="12px"
+                                                                        >
+                                                                          <svg
+                                                                            className="eqrebog3 css-1jjmnki-StyledSvg-StyledInlineSvg e2idor0"
+                                                                            height="12px"
+                                                                            viewBox={Object {}}
+                                                                            width="12px"
+                                                                          >
+                                                                            <use
+                                                                              href="#test"
+                                                                              xlinkHref="#test"
+                                                                            />
+                                                                          </svg>
+                                                                        </StyledSvg>
+                                                                      </InlineSvg>
+                                                                    </StyledInlineSvg>
+                                                                  </span>
+                                                                </Component>
+                                                              </Icon>
+                                                            </span>
+                                                          </Component>
+                                                        </ButtonLabel>
+                                                      </button>
+                                                    </Component>
+                                                  </StyledButton>
+                                                </Button>
+                                                <Modal
+                                                  animation={false}
+                                                  autoFocus={true}
+                                                  backdrop={true}
+                                                  bsClass="modal"
+                                                  dialogComponentClass={[Function]}
+                                                  enforceFocus={true}
+                                                  keyboard={true}
+                                                  manager={
+                                                    ModalManager {
+                                                      "add": [Function],
+                                                      "containers": Array [],
+                                                      "data": Array [],
+                                                      "handleContainerOverflow": true,
+                                                      "hideSiblingNodes": true,
+                                                      "isTopModal": [Function],
+                                                      "modals": Array [],
+                                                      "remove": [Function],
+                                                    }
+                                                  }
+                                                  onHide={[Function]}
+                                                  renderBackdrop={[Function]}
+                                                  restoreFocus={true}
+                                                  show={false}
+                                                >
+                                                  <Modal
+                                                    autoFocus={true}
+                                                    backdrop={true}
+                                                    backdropClassName="modal-backdrop"
+                                                    containerClassName="modal-open"
+                                                    enforceFocus={true}
+                                                    keyboard={true}
+                                                    manager={
+                                                      ModalManager {
+                                                        "add": [Function],
+                                                        "containers": Array [],
+                                                        "data": Array [],
+                                                        "handleContainerOverflow": true,
+                                                        "hideSiblingNodes": true,
+                                                        "isTopModal": [Function],
+                                                        "modals": Array [],
+                                                        "remove": [Function],
+                                                      }
+                                                    }
+                                                    onEntering={[Function]}
+                                                    onExited={[Function]}
+                                                    onHide={[Function]}
+                                                    renderBackdrop={[Function]}
+                                                    restoreFocus={true}
+                                                    show={false}
+                                                  />
+                                                </Modal>
+                                              </Confirm>
+                                            </ConfirmDelete>
+                                          </Access>
+                                        </AccessContainer>
+                                      </withConfig(AccessContainer)>
+                                    </div>
+                                  </Base>
+                                </Box>
+                              </div>
+                            </Base>
+                          </StyledFlex>
+                        </div>
+                      </Base>
+                    </SentryAppItem>
+                  </SentryApplicationRow>
+                </div>
+              </PanelBody>
+            </div>
+          </Component>
+        </Panel>
+      </div>
+    </DocumentTitle>
+  </SideEffect(DocumentTitle)>
+</OrganizationDeveloperSettings>
+`;
+
+exports[`Organization Developer Settings without Owner permissions trash button is disabled 1`] = `
+<OrganizationDeveloperSettings
+  params={
+    Object {
+      "orgId": "org-slug",
+    }
+  }
+>
+  <SideEffect(DocumentTitle)
+    title="Sentry"
+  >
+    <DocumentTitle
+      title="Sentry"
+    >
+      <div>
+        <SettingsPageHeading
+          action={
+            <Button
+              disabled={false}
+              icon="icon-circle-add"
+              priority="primary"
+              size="small"
+              to="/settings/org-slug/developer-settings/new/"
+            >
+              Create New Application
+            </Button>
+          }
+          noTitleStyles={false}
+          title="Developer Settings"
+        >
+          <Wrapper>
+            <div
+              className="css-1r5ylk7-Wrapper e1kblvez2"
+            >
+              <Flex
+                align="center"
+              >
+                <Base
+                  align="center"
+                  className="css-5ipae5"
+                >
+                  <div
+                    className="css-5ipae5"
+                    is={null}
+                  >
+                    <Title
+                      styled={false}
+                    >
+                      <Base
+                        className="css-1ky52ze-Title e1kblvez0"
+                      >
+                        <div
+                          className="css-1ky52ze-Title e1kblvez0"
+                          is={null}
+                        >
+                          <HeaderTitle>
+                            <h4
+                              className="css-1w8ttcn-HeaderTitle e6lvex72"
+                            >
+                              Developer Settings
+                            </h4>
+                          </HeaderTitle>
+                        </div>
+                      </Base>
+                    </Title>
+                    <Action>
+                      <div
+                        className="css-18luhfc-Action e1kblvez1"
+                      >
+                        <Button
+                          disabled={false}
+                          icon="icon-circle-add"
+                          priority="primary"
+                          size="small"
+                          to="/settings/org-slug/developer-settings/new/"
+                        >
+                          <StyledButton
+                            aria-disabled={false}
+                            aria-label="Create New Application"
+                            disabled={false}
+                            onClick={[Function]}
+                            priority="primary"
+                            role="button"
+                            size="small"
+                            to="/settings/org-slug/developer-settings/new/"
+                          >
+                            <Component
+                              aria-disabled={false}
+                              aria-label="Create New Application"
+                              className="css-zvpqlo-StyledButton-getColors eqrebog0"
+                              onClick={[Function]}
+                              role="button"
+                              size="small"
+                              to="/settings/org-slug/developer-settings/new/"
+                            >
+                              <Link
+                                aria-disabled={false}
+                                aria-label="Create New Application"
+                                className="css-zvpqlo-StyledButton-getColors eqrebog0"
+                                onClick={[Function]}
+                                onlyActiveOnIndex={false}
+                                role="button"
+                                size="small"
+                                style={Object {}}
+                                to="/settings/org-slug/developer-settings/new/"
+                              >
+                                <a
+                                  aria-disabled={false}
+                                  aria-label="Create New Application"
+                                  className="css-zvpqlo-StyledButton-getColors eqrebog0"
+                                  onClick={[Function]}
+                                  role="button"
+                                  size="small"
+                                  style={Object {}}
+                                >
+                                  <ButtonLabel
+                                    priority="primary"
+                                    size="small"
+                                  >
+                                    <Component
+                                      className="css-7ui8bl-ButtonLabel eqrebog1"
+                                      priority="primary"
+                                      size="small"
+                                    >
+                                      <span
+                                        className="css-7ui8bl-ButtonLabel eqrebog1"
+                                      >
+                                        <Icon
+                                          hasChildren={true}
+                                          size="small"
+                                        >
+                                          <Component
+                                            className="css-1vdnsie-Icon eqrebog2"
+                                            hasChildren={true}
+                                            size="small"
+                                          >
+                                            <span
+                                              className="css-1vdnsie-Icon eqrebog2"
+                                              size="small"
+                                            >
+                                              <StyledInlineSvg
+                                                size="12px"
+                                                src="icon-circle-add"
+                                              >
+                                                <InlineSvg
+                                                  className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                  size="12px"
+                                                  src="icon-circle-add"
+                                                >
+                                                  <StyledSvg
+                                                    className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                    height="12px"
+                                                    viewBox={Object {}}
+                                                    width="12px"
+                                                  >
+                                                    <svg
+                                                      className="eqrebog3 css-1jjmnki-StyledSvg-StyledInlineSvg e2idor0"
+                                                      height="12px"
+                                                      viewBox={Object {}}
+                                                      width="12px"
+                                                    >
+                                                      <use
+                                                        href="#test"
+                                                        xlinkHref="#test"
+                                                      />
+                                                    </svg>
+                                                  </StyledSvg>
+                                                </InlineSvg>
+                                              </StyledInlineSvg>
+                                            </span>
+                                          </Component>
+                                        </Icon>
+                                        Create New Application
+                                      </span>
+                                    </Component>
+                                  </ButtonLabel>
+                                </a>
+                              </Link>
+                            </Component>
+                          </StyledButton>
+                        </Button>
+                      </div>
+                    </Action>
+                  </div>
+                </Base>
+              </Flex>
+            </div>
+          </Wrapper>
+        </SettingsPageHeading>
+        <Panel>
+          <Component
+            className="css-yahxlu-Panel e1laxa7d0"
+          >
+            <div
+              className="css-yahxlu-Panel e1laxa7d0"
+            >
+              <PanelHeader>
+                <Component
+                  className="css-xhx6pj-PanelHeader-getPadding e1p8v8nv0"
+                >
+                  <Flex
+                    align="center"
+                    className="css-xhx6pj-PanelHeader-getPadding e1p8v8nv0"
+                    justify="space-between"
+                  >
+                    <Base
+                      align="center"
+                      className="e1p8v8nv0 css-b7ices-PanelHeader-getPadding"
+                      justify="space-between"
+                    >
+                      <div
+                        className="e1p8v8nv0 css-b7ices-PanelHeader-getPadding"
+                        is={null}
+                      >
+                        Applications
+                      </div>
+                    </Base>
+                  </Flex>
+                </Component>
+              </PanelHeader>
+              <PanelBody
+                direction="column"
+                disablePadding={true}
+                flex={false}
+              >
+                <div
+                  className="css-9vq8an-textStyles"
+                >
+                  <SentryApplicationRow
+                    app={
+                      Object {
+                        "clientId": "client-id",
+                        "clientSecret": "client-secret",
+                        "events": Array [],
+                        "isAlertable": false,
+                        "name": "Sample App",
+                        "overview": "This is an app.",
+                        "redirectUrl": "https://example/com/setup",
+                        "schema": Object {},
+                        "scopes": Array [
+                          "project:read",
+                        ],
+                        "slug": "sample-app",
+                        "status": "unpublished",
+                        "uuid": "123456123456123456123456",
+                        "webhookUrl": "https://example.com/webhook",
+                      }
+                    }
+                    key="123456123456123456123456"
+                    onRemoveApp={[Function]}
+                    orgId="org-slug"
+                    showPublishStatus={true}
+                  >
+                    <SentryAppItem>
+                      <Base
+                        className="css-h9gjd5-PanelItem-SentryAppItem eac2pqx0"
+                      >
+                        <div
+                          className="css-h9gjd5-PanelItem-SentryAppItem eac2pqx0"
+                          is={null}
+                        >
+                          <StyledFlex>
+                            <Base
+                              className="css-14n192s-StyledFlex eac2pqx1"
+                            >
+                              <div
+                                className="css-14n192s-StyledFlex eac2pqx1"
+                                is={null}
+                              >
+                                <SentryAppAvatar
+                                  sentryApp={
+                                    Object {
+                                      "clientId": "client-id",
+                                      "clientSecret": "client-secret",
+                                      "events": Array [],
+                                      "isAlertable": false,
+                                      "name": "Sample App",
+                                      "overview": "This is an app.",
+                                      "redirectUrl": "https://example/com/setup",
+                                      "schema": Object {},
+                                      "scopes": Array [
+                                        "project:read",
+                                      ],
+                                      "slug": "sample-app",
+                                      "status": "unpublished",
+                                      "uuid": "123456123456123456123456",
+                                      "webhookUrl": "https://example.com/webhook",
+                                    }
+                                  }
+                                  size={36}
+                                >
+                                  <BaseAvatar
+                                    hasTooltip={false}
+                                    letterId="123456123456123456123456"
+                                    size={36}
+                                    style={Object {}}
+                                    title="Sample App"
+                                    tooltip="Sample App"
+                                    type="letter_avatar"
+                                    uploadId=""
+                                    uploadPath="avatar"
+                                  >
+                                    <Tooltip
+                                      disabled={true}
+                                      title="Sample App"
+                                    >
+                                      <StyledBaseAvatar
+                                        className="avatar"
+                                        loaded={true}
+                                        style={
+                                          Object {
+                                            "height": "36px",
+                                            "width": "36px",
+                                          }
+                                        }
                                       >
-                                        <Confirm
-                                          bypass={false}
-                                          cancelText="Cancel"
-                                          confirmText="Confirm"
-                                          disableConfirmButton={true}
-                                          message={
-                                            <React.Fragment>
-                                              <Alert
-                                                iconSize="24px"
-                                                type="error"
-                                              >
-                                                Deleting sample-app will also delete any and all of its installations.        This is a permanent action. Do you wish to continue?
-                                              </Alert>
-                                              <Field
-                                                alignRight={false}
-                                                disabled={false}
-                                                flexibleControlStateSize={true}
-                                                inline={false}
-                                                label={
-                                                  <div>
-                                                    Please enter 
-                                                    <code>
-                                                      sample-app
-                                                    </code>
-                                                     to confirm the deletion
-                                                  </div>
-                                                }
-                                                p={0}
-                                                required={false}
-                                                visible={true}
+                                        <span
+                                          className="avatar css-1i62700-StyledBaseAvatar e1z0ohzl0"
+                                          style={
+                                            Object {
+                                              "height": "36px",
+                                              "width": "36px",
+                                            }
+                                          }
+                                        >
+                                          <LetterAvatar
+                                            displayName="Sample App"
+                                            identifier="123456123456123456123456"
+                                          >
+                                            <Svg
+                                              viewBox="0 0 120 120"
+                                            >
+                                              <svg
+                                                className="css-123ijso-Svg e1knxa8x0"
+                                                viewBox="0 0 120 120"
                                               >
-                                                <Input
-                                                  onChange={[Function]}
-                                                  placeholder="sample-app"
-                                                  type="text"
-                                                  value=""
+                                                <rect
+                                                  fill="#4674ca"
+                                                  height="120"
+                                                  rx="15"
+                                                  ry="15"
+                                                  width="120"
+                                                  x="0"
+                                                  y="0"
                                                 />
-                                              </Field>
-                                            </React.Fragment>
-                                          }
-                                          onConfirm={[Function]}
-                                          priority="danger"
+                                                <text
+                                                  fill="#FFFFFF"
+                                                  fontSize="65"
+                                                  style={
+                                                    Object {
+                                                      "dominantBaseline": "central",
+                                                    }
+                                                  }
+                                                  textAnchor="middle"
+                                                  x="50%"
+                                                  y="50%"
+                                                >
+                                                  SA
+                                                </text>
+                                              </svg>
+                                            </Svg>
+                                          </LetterAvatar>
+                                        </span>
+                                      </StyledBaseAvatar>
+                                    </Tooltip>
+                                  </BaseAvatar>
+                                </SentryAppAvatar>
+                                <SentryAppBox>
+                                  <Base
+                                    className="css-161g25b-SentryAppBox eac2pqx2"
+                                  >
+                                    <div
+                                      className="css-161g25b-SentryAppBox eac2pqx2"
+                                      is={null}
+                                    >
+                                      <SentryAppName>
+                                        <div
+                                          className="css-uiwo8x-SentryAppName eac2pqx4"
                                         >
-                                          <Button
-                                            disabled={false}
-                                            icon="icon-trash"
-                                            onClick={[Function]}
-                                            size="small"
+                                          <SentryAppLink
+                                            to="/settings/org-slug/developer-settings/sample-app/"
                                           >
-                                            <StyledButton
-                                              aria-disabled={false}
-                                              disabled={false}
-                                              onClick={[Function]}
-                                              role="button"
-                                              size="small"
+                                            <Link
+                                              className="css-gg019v-SentryAppLink eac2pqx6"
+                                              onlyActiveOnIndex={false}
+                                              style={Object {}}
+                                              to="/settings/org-slug/developer-settings/sample-app/"
                                             >
-                                              <Component
-                                                aria-disabled={false}
-                                                className="css-dkprmi-StyledButton-getColors eqrebog0"
+                                              <a
+                                                className="css-gg019v-SentryAppLink eac2pqx6"
                                                 onClick={[Function]}
-                                                role="button"
+                                                style={Object {}}
+                                              >
+                                                Sample App
+                                              </a>
+                                            </Link>
+                                          </SentryAppLink>
+                                        </div>
+                                      </SentryAppName>
+                                      <SentryAppDetails>
+                                        <Base
+                                          className="css-f0t6d-SentryAppDetails eac2pqx3"
+                                        >
+                                          <div
+                                            className="css-f0t6d-SentryAppDetails eac2pqx3"
+                                            is={null}
+                                          >
+                                            <PublishStatus
+                                              published={false}
+                                            >
+                                              <Component
+                                                className="css-1h03aoe-PublishStatus eac2pqx9"
+                                                published={false}
+                                              >
+                                                <Flex
+                                                  align="center"
+                                                >
+                                                  <Base
+                                                    align="center"
+                                                    className="css-5ipae5"
+                                                  >
+                                                    <div
+                                                      className="css-5ipae5"
+                                                      is={null}
+                                                    >
+                                                      <div
+                                                        className="css-1h03aoe-PublishStatus eac2pqx9"
+                                                      >
+                                                        unpublished
+                                                      </div>
+                                                    </div>
+                                                  </Base>
+                                                </Flex>
+                                              </Component>
+                                            </PublishStatus>
+                                          </div>
+                                        </Base>
+                                      </SentryAppDetails>
+                                    </div>
+                                  </Base>
+                                </SentryAppBox>
+                                <Box>
+                                  <Base
+                                    className="css-roynbj"
+                                  >
+                                    <div
+                                      className="css-roynbj"
+                                      is={null}
+                                    >
+                                      <withConfig(AccessContainer)
+                                        access={
+                                          Array [
+                                            "org:admin",
+                                          ]
+                                        }
+                                      >
+                                        <AccessContainer
+                                          access={
+                                            Array [
+                                              "org:admin",
+                                            ]
+                                          }
+                                          config={
+                                            Object {
+                                              "features": Set {},
+                                              "messages": Array [],
+                                              "user": Object {
+                                                "email": "foo@example.com",
+                                                "flags": Object {
+                                                  "newsletter_consent_prompt": false,
+                                                },
+                                                "hasPasswordAuth": true,
+                                                "id": "1",
+                                                "isAuthenticated": true,
+                                                "name": "Foo Bar",
+                                                "options": Object {
+                                                  "timezone": "UTC",
+                                                },
+                                                "permissions": Set {},
+                                                "username": "foo@example.com",
+                                              },
+                                            }
+                                          }
+                                        >
+                                          <Access
+                                            access={
+                                              Array [
+                                                "org:admin",
+                                              ]
+                                            }
+                                            config={
+                                              Object {
+                                                "features": Set {},
+                                                "messages": Array [],
+                                                "user": Object {
+                                                  "email": "foo@example.com",
+                                                  "flags": Object {
+                                                    "newsletter_consent_prompt": false,
+                                                  },
+                                                  "hasPasswordAuth": true,
+                                                  "id": "1",
+                                                  "isAuthenticated": true,
+                                                  "name": "Foo Bar",
+                                                  "options": Object {
+                                                    "timezone": "UTC",
+                                                  },
+                                                  "permissions": Set {},
+                                                  "username": "foo@example.com",
+                                                },
+                                              }
+                                            }
+                                            configUser={
+                                              Object {
+                                                "email": "foo@example.com",
+                                                "flags": Object {
+                                                  "newsletter_consent_prompt": false,
+                                                },
+                                                "hasPasswordAuth": true,
+                                                "id": "1",
+                                                "isAuthenticated": true,
+                                                "name": "Foo Bar",
+                                                "options": Object {
+                                                  "timezone": "UTC",
+                                                },
+                                                "permissions": Set {},
+                                                "username": "foo@example.com",
+                                              }
+                                            }
+                                            organization={
+                                              Object {
+                                                "access": Array [
+                                                  "org:read",
+                                                ],
+                                                "features": Array [],
+                                                "id": "3",
+                                                "name": "Organization Name",
+                                                "onboardingTasks": Array [],
+                                                "projects": Array [],
+                                                "scrapeJavaScript": true,
+                                                "slug": "org-slug",
+                                                "status": Object {
+                                                  "id": "active",
+                                                  "name": "active",
+                                                },
+                                                "teams": Array [],
+                                              }
+                                            }
+                                            renderNoAccessMessage={false}
+                                            requireAll={true}
+                                          >
+                                            <Tooltip
+                                              title="Owner permissions are required for this action."
+                                            >
+                                              <Button
+                                                className="tip"
+                                                disabled={true}
+                                                icon="icon-trash"
                                                 size="small"
+                                                title="Owner permissions are required for this action."
                                               >
-                                                <button
-                                                  aria-disabled={false}
-                                                  className="css-dkprmi-StyledButton-getColors eqrebog0"
-                                                  onClick={[Function]}
-                                                  role="button"
-                                                  size="small"
+                                                <Tooltip
+                                                  title="Owner permissions are required for this action."
                                                 >
-                                                  <ButtonLabel
+                                                  <StyledButton
+                                                    aria-disabled={true}
+                                                    className="tip tip"
+                                                    disabled={true}
+                                                    href={null}
+                                                    onClick={[Function]}
+                                                    role="button"
                                                     size="small"
+                                                    title="Owner permissions are required for this action."
+                                                    to={null}
                                                   >
                                                     <Component
-                                                      className="css-7ui8bl-ButtonLabel eqrebog1"
+                                                      aria-disabled={true}
+                                                      className="tip tip css-1ujzp8g-StyledButton-getColors eqrebog0"
+                                                      href={null}
+                                                      onClick={[Function]}
+                                                      role="button"
                                                       size="small"
+                                                      title="Owner permissions are required for this action."
+                                                      to={null}
                                                     >
-                                                      <span
-                                                        className="css-7ui8bl-ButtonLabel eqrebog1"
+                                                      <button
+                                                        aria-disabled={true}
+                                                        className="tip tip css-1ujzp8g-StyledButton-getColors eqrebog0"
+                                                        href={null}
+                                                        onClick={[Function]}
+                                                        role="button"
+                                                        size="small"
+                                                        title="Owner permissions are required for this action."
+                                                        to={null}
                                                       >
-                                                        <Icon
-                                                          hasChildren={false}
+                                                        <ButtonLabel
                                                           size="small"
                                                         >
                                                           <Component
-                                                            className="css-ljhpxy-Icon eqrebog2"
-                                                            hasChildren={false}
+                                                            className="css-7ui8bl-ButtonLabel eqrebog1"
                                                             size="small"
                                                           >
                                                             <span
-                                                              className="css-ljhpxy-Icon eqrebog2"
-                                                              size="small"
+                                                              className="css-7ui8bl-ButtonLabel eqrebog1"
                                                             >
-                                                              <StyledInlineSvg
-                                                                size="12px"
-                                                                src="icon-trash"
+                                                              <Icon
+                                                                hasChildren={false}
+                                                                size="small"
                                                               >
-                                                                <InlineSvg
-                                                                  className="css-1ov3rcq-StyledInlineSvg eqrebog3"
-                                                                  size="12px"
-                                                                  src="icon-trash"
+                                                                <Component
+                                                                  className="css-ljhpxy-Icon eqrebog2"
+                                                                  hasChildren={false}
+                                                                  size="small"
                                                                 >
-                                                                  <StyledSvg
-                                                                    className="css-1ov3rcq-StyledInlineSvg eqrebog3"
-                                                                    height="12px"
-                                                                    viewBox={Object {}}
-                                                                    width="12px"
+                                                                  <span
+                                                                    className="css-ljhpxy-Icon eqrebog2"
+                                                                    size="small"
                                                                   >
-                                                                    <svg
-                                                                      className="eqrebog3 css-1jjmnki-StyledSvg-StyledInlineSvg e2idor0"
-                                                                      height="12px"
-                                                                      viewBox={Object {}}
-                                                                      width="12px"
+                                                                    <StyledInlineSvg
+                                                                      size="12px"
+                                                                      src="icon-trash"
                                                                     >
-                                                                      <use
-                                                                        href="#test"
-                                                                        xlinkHref="#test"
-                                                                      />
-                                                                    </svg>
-                                                                  </StyledSvg>
-                                                                </InlineSvg>
-                                                              </StyledInlineSvg>
+                                                                      <InlineSvg
+                                                                        className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                                        size="12px"
+                                                                        src="icon-trash"
+                                                                      >
+                                                                        <StyledSvg
+                                                                          className="css-1ov3rcq-StyledInlineSvg eqrebog3"
+                                                                          height="12px"
+                                                                          viewBox={Object {}}
+                                                                          width="12px"
+                                                                        >
+                                                                          <svg
+                                                                            className="eqrebog3 css-1jjmnki-StyledSvg-StyledInlineSvg e2idor0"
+                                                                            height="12px"
+                                                                            viewBox={Object {}}
+                                                                            width="12px"
+                                                                          >
+                                                                            <use
+                                                                              href="#test"
+                                                                              xlinkHref="#test"
+                                                                            />
+                                                                          </svg>
+                                                                        </StyledSvg>
+                                                                      </InlineSvg>
+                                                                    </StyledInlineSvg>
+                                                                  </span>
+                                                                </Component>
+                                                              </Icon>
                                                             </span>
                                                           </Component>
-                                                        </Icon>
-                                                      </span>
+                                                        </ButtonLabel>
+                                                      </button>
                                                     </Component>
-                                                  </ButtonLabel>
-                                                </button>
-                                              </Component>
-                                            </StyledButton>
-                                          </Button>
-                                          <Modal
-                                            animation={false}
-                                            autoFocus={true}
-                                            backdrop={true}
-                                            bsClass="modal"
-                                            dialogComponentClass={[Function]}
-                                            enforceFocus={true}
-                                            keyboard={true}
-                                            manager={
-                                              ModalManager {
-                                                "add": [Function],
-                                                "containers": Array [],
-                                                "data": Array [],
-                                                "handleContainerOverflow": true,
-                                                "hideSiblingNodes": true,
-                                                "isTopModal": [Function],
-                                                "modals": Array [],
-                                                "remove": [Function],
-                                              }
-                                            }
-                                            onHide={[Function]}
-                                            renderBackdrop={[Function]}
-                                            restoreFocus={true}
-                                            show={false}
-                                          >
-                                            <Modal
-                                              autoFocus={true}
-                                              backdrop={true}
-                                              backdropClassName="modal-backdrop"
-                                              containerClassName="modal-open"
-                                              enforceFocus={true}
-                                              keyboard={true}
-                                              manager={
-                                                ModalManager {
-                                                  "add": [Function],
-                                                  "containers": Array [],
-                                                  "data": Array [],
-                                                  "handleContainerOverflow": true,
-                                                  "hideSiblingNodes": true,
-                                                  "isTopModal": [Function],
-                                                  "modals": Array [],
-                                                  "remove": [Function],
-                                                }
-                                              }
-                                              onEntering={[Function]}
-                                              onExited={[Function]}
-                                              onHide={[Function]}
-                                              renderBackdrop={[Function]}
-                                              restoreFocus={true}
-                                              show={false}
-                                            />
-                                          </Modal>
-                                        </Confirm>
-                                      </ConfirmDelete>
+                                                  </StyledButton>
+                                                </Tooltip>
+                                              </Button>
+                                            </Tooltip>
+                                          </Access>
+                                        </AccessContainer>
+                                      </withConfig(AccessContainer)>
                                     </div>
                                   </Base>
                                 </Box>

+ 17 - 0
tests/js/spec/views/settings/organizationDeveloperSettings/index.spec.jsx

@@ -84,4 +84,21 @@ describe('Organization Developer Settings', function() {
       expect(wrapper.find('[icon="icon-trash"]').prop('disabled')).toEqual(true);
     });
   });
+
+  describe('without Owner permissions', () => {
+    const newOrg = TestStubs.Organization({access: ['org:read']});
+    Client.addMockResponse({
+      url: `/organizations/${newOrg.slug}/sentry-apps/`,
+      body: [sentryApp],
+    });
+    const wrapper = mount(
+      <OrganizationDeveloperSettings params={{orgId: newOrg.slug}} />,
+      TestStubs.routerContext([{organization: newOrg}])
+    );
+
+    it('trash button is disabled', () => {
+      expect(wrapper).toMatchSnapshot();
+      expect(wrapper.find('[icon="icon-trash"]').prop('disabled')).toEqual(true);
+    });
+  });
 });