feat: Add sentry apps to integration directory
diff --git a/src/sentry/static/sentry/app/views/organizationIntegrations/integrationListDirectory.tsx b/src/sentry/static/sentry/app/views/organizationIntegrations/integrationListDirectory.tsx
index 47627e5306ad2..d8b8e56e07d31 100644
--- a/src/sentry/static/sentry/app/views/organizationIntegrations/integrationListDirectory.tsx
+++ b/src/sentry/static/sentry/app/views/organizationIntegrations/integrationListDirectory.tsx
@@ -24,7 +24,7 @@ import LoadingIndicator from 'app/components/loadingIndicator';
 import MigrationWarnings from 'app/views/organizationIntegrations/migrationWarnings';
 import PermissionAlert from 'app/views/settings/organization/permissionAlert';
 import ProviderRow from 'app/views/organizationIntegrations/integrationProviderRow';
-import SentryAppInstallationDetail from 'app/views/organizationIntegrations/sentryAppInstallationDetail';
+import IntegrationDirectoryApplicationRow from 'app/views/settings/organizationDeveloperSettings/sentryApplicationRow/integrationDirectoryApplicationRow';
 import SentryApplicationRow from 'app/views/settings/organizationDeveloperSettings/sentryApplicationRow';
 import SentryDocumentTitle from 'app/components/sentryDocumentTitle';
 import SentryTypes from 'app/sentryTypes';
@@ -190,15 +190,6 @@ class OrganizationIntegrations extends AsyncComponent<
     );
   };
 
-  handleRemoveAppInstallation = (app: SentryApp): void => {
-    const appInstalls = this.state.appInstalls.filter(i => i.app.slug !== app.slug);
-    this.setState({appInstalls});
-  };
-
-  handleAppInstallation = (install: SentryAppInstallation): void => {
-    this.setState({appInstalls: [install, ...this.state.appInstalls]});
-  };
-
   getAppInstall = (app: SentryApp) => {
     return this.state.appInstalls.find(i => i.app.slug === app.slug);
   };
@@ -233,13 +224,7 @@ class OrganizationIntegrations extends AsyncComponent<
         key={`row-${provider.key}`}
         data-test-id="integration-row"
         provider={provider}
-        orgId={this.props.params.orgId}
         integrations={integrations}
-        onInstall={this.onInstall}
-        onRemove={this.onRemove}
-        onDisable={this.onDisable}
-        onReinstall={this.onInstall}
-        newlyInstalledIntegrationId={this.state.newlyInstalledIntegrationId}
       />
     );
   };
@@ -247,7 +232,6 @@ class OrganizationIntegrations extends AsyncComponent<
   //render either an internal or non-internal app
   renderSentryApp = (app: SentryApp) => {
     const {organization} = this.props;
-
     if (app.status === 'internal') {
       return (
         <SentryApplicationRow
@@ -261,19 +245,19 @@ class OrganizationIntegrations extends AsyncComponent<
         />
       );
     }
-
-    return (
-      <SentryAppInstallationDetail
-        key={`sentry-app-row-${app.slug}`}
-        data-test-id="integration-row"
-        api={this.api}
-        organization={organization}
-        install={this.getAppInstall(app)}
-        onAppUninstall={() => this.handleRemoveAppInstallation(app)}
-        onAppInstall={this.handleAppInstallation}
-        app={app}
-      />
-    );
+    if (app.status === 'published') {
+      return (
+        <IntegrationDirectoryApplicationRow
+          key={`sentry-app-row-${app.slug}`}
+          data-test-id="integration-row"
+          organization={organization}
+          install={this.getAppInstall(app)}
+          app={app}
+          isOnIntegrationPage
+        />
+      );
+    }
+    return null;
   };
 
   renderIntegration = (integration: AppOrProvider) => {
diff --git a/src/sentry/static/sentry/app/views/organizationIntegrations/integrationProviderRow.tsx b/src/sentry/static/sentry/app/views/organizationIntegrations/integrationProviderRow.tsx
index 6b8c5409041a2..2025d78ef8bd3 100644
--- a/src/sentry/static/sentry/app/views/organizationIntegrations/integrationProviderRow.tsx
+++ b/src/sentry/static/sentry/app/views/organizationIntegrations/integrationProviderRow.tsx
@@ -3,28 +3,16 @@ import PropTypes from 'prop-types';
 import React from 'react';
 import styled from '@emotion/styled';
 import Link from 'app/components/links/link';
-import {openIntegrationDetails} from 'app/actionCreators/modal';
 import {PanelItem} from 'app/components/panels';
 import {t} from 'app/locale';
-import Button from 'app/components/button';
 import CircleIndicator from 'app/components/circleIndicator';
-import InstalledIntegration, {
-  Props as InstalledIntegrationProps,
-} from 'app/views/organizationIntegrations/installedIntegration';
 import PluginIcon from 'app/plugins/components/pluginIcon';
 import SentryTypes from 'app/sentryTypes';
 import space from 'app/styles/space';
-import {growDown, highlight} from 'app/styles/animations';
 import {IntegrationProvider, Integration} from 'app/types';
 
 type Props = {
   provider: IntegrationProvider;
-  orgId: string;
-  onInstall: (integration: Integration) => void;
-  onRemove: (integration: Integration) => void;
-  onDisable: (integration: Integration) => void;
-  onReinstall: (integration: Integration) => void;
-  newlyInstalledIntegrationId: string;
   integrations: Integration[];
 };
 
@@ -32,80 +20,36 @@ export default class ProviderRow extends React.Component<Props> {
   static propTypes = {
     provider: PropTypes.object.isRequired,
     integrations: PropTypes.array.isRequired,
-    orgId: PropTypes.string.isRequired,
-    onInstall: PropTypes.func.isRequired,
-    onRemove: PropTypes.func.isRequired,
-    onDisable: PropTypes.func.isRequired,
-    onReinstall: PropTypes.func.isRequired,
-    newlyInstalledIntegrationId: PropTypes.string,
   };
 
   static contextTypes = {
     organization: SentryTypes.Organization,
   };
 
-  get integrations() {
-    return this.props.integrations;
-  }
-
   get isEnabled() {
-    return this.integrations.length > 0;
-  }
-
-  // Actions
-
-  openModal = () => {
-    const organization = this.context.organization;
-    const provider = this.props.provider;
-    const onAddIntegration = this.props.onInstall;
-    openIntegrationDetails({
-      provider,
-      organization,
-      onAddIntegration,
-      isInstalled: this.isEnabled,
-    });
-  };
-
-  // Rendering
-
-  get buttonProps() {
-    return {
-      icon: 'icon-circle-add',
-      children: this.isEnabled ? t('Add Configuration') : t('Install'),
-    };
-  }
-
-  renderIntegrations() {
-    return this.integrations.map(integration => (
-      <StyledInstalledIntegration
-        key={integration.id}
-        organization={this.context.organization}
-        provider={this.props.provider}
-        integration={integration}
-        onRemove={this.props.onRemove}
-        onDisable={this.props.onDisable}
-        onReinstallIntegration={this.props.onReinstall}
-        data-test-id={integration.id}
-        newlyAdded={integration.id === this.props.newlyInstalledIntegrationId}
-      />
-    ));
+    return this.props.integrations.length > 0;
   }
 
   render() {
+    const {provider, integrations} = this.props;
+    const {
+      organization: {slug},
+    } = this.context;
     return (
-      <PanelItem p={0} flexDirection="column" data-test-id={this.props.provider.key}>
+      <PanelItem p={0} flexDirection="column" data-test-id={provider.key}>
         <Flex style={{alignItems: 'center', padding: '16px'}}>
-          <PluginIcon size={36} pluginId={this.props.provider.key} />
+          <PluginIcon size={36} pluginId={provider.key} />
           <div style={{flex: '1', padding: '0 16px'}}>
-            <ProviderName>{this.props.provider.name}</ProviderName>
+            <ProviderName to={`/settings/${slug}/integrations/${provider.key}`}>
+              {provider.name}
+            </ProviderName>
             <ProviderDetails>
               <Status enabled={this.isEnabled} />
-              <StyledLink>{`${this.props.integrations.length} Configurations`}</StyledLink>
+              <StyledLink
+                to={`/settings/${slug}/integrations/${provider.key}?tab=configurations`}
+              >{`${integrations.length} Configurations`}</StyledLink>
             </ProviderDetails>
           </div>
-          <div>
-            <Button size="small" onClick={this.openModal} {...this.buttonProps} />
-          </div>
         </Flex>
       </PanelItem>
     );
@@ -116,8 +60,9 @@ const Flex = styled('div')`
   display: flex;
 `;
 
-const ProviderName = styled('div')`
+const ProviderName = styled(Link)`
   font-weight: bold;
+  color: ${props => props.theme.textColor};
 `;
 
 const ProviderDetails = styled(Flex)`
@@ -162,29 +107,6 @@ const StatusWrapper = styled('div')`
   align-items: center;
 `;
 
-const NewInstallation = styled('div')`
-  overflow: hidden;
-  transform-origin: 0 auto;
-  animation: ${growDown('59px')} 160ms 500ms ease-in-out forwards,
-    ${p => highlight(p.theme.yellowLightest)} 1000ms 500ms ease-in-out forwards;
-`;
-
-const StyledInstalledIntegration = styled(
-  (p: InstalledIntegrationProps & {newlyAdded: boolean}) =>
-    p.newlyAdded ? (
-      <NewInstallation>
-        <InstalledIntegration {...p} />
-      </NewInstallation>
-    ) : (
-      <InstalledIntegration {...p} />
-    )
-)`
-  padding: ${space(2)};
-  padding-left: 0;
-  margin-left: 68px;
-  border-top: 1px dashed ${p => p.theme.borderLight};
-`;
-
 const StyledLink = styled(Link)`
   color: ${p => p.theme.gray2};
 `;
diff --git a/src/sentry/static/sentry/app/views/settings/organizationDeveloperSettings/sentryApplicationRow/integrationDirectoryApplicationRow.tsx b/src/sentry/static/sentry/app/views/settings/organizationDeveloperSettings/sentryApplicationRow/integrationDirectoryApplicationRow.tsx
new file mode 100644
index 0000000000000..423348179e5f7
--- /dev/null
+++ b/src/sentry/static/sentry/app/views/settings/organizationDeveloperSettings/sentryApplicationRow/integrationDirectoryApplicationRow.tsx
@@ -0,0 +1,182 @@
+import React from 'react';
+import {Link} from 'react-router';
+import capitalize from 'lodash/capitalize';
+import omit from 'lodash/omit';
+import styled from '@emotion/styled';
+import PropTypes from 'prop-types';
+
+import SentryTypes from 'app/sentryTypes';
+import {PanelItem} from 'app/components/panels';
+import {t} from 'app/locale';
+import space from 'app/styles/space';
+import CircleIndicator from 'app/components/circleIndicator';
+import PluginIcon from 'app/plugins/components/pluginIcon';
+import {Organization, SentryApp, SentryAppInstallation} from 'app/types';
+import theme from 'app/utils/theme';
+
+const INSTALLED = 'Installed';
+const NOT_INSTALLED = 'Not Installed';
+const PENDING = 'Pending';
+
+type Props = {
+  app: SentryApp;
+  organization: Organization;
+  install?: SentryAppInstallation;
+  isOnIntegrationPage: boolean;
+  ['data-test-id']?: string;
+};
+
+export default class SentryApplicationRow extends React.PureComponent<Props> {
+  static propTypes = {
+    app: SentryTypes.SentryApplication,
+    organization: SentryTypes.Organization.isRequired,
+    install: PropTypes.object,
+    isOnIntegrationPage: PropTypes.bool,
+  };
+
+  get isInternal() {
+    return this.props.app.status === 'internal';
+  }
+
+  hideStatus() {
+    //no publishing for internal apps so hide the status on the developer settings page
+    return this.isInternal && !this.props.isOnIntegrationPage;
+  }
+
+  renderStatus() {
+    const {app, isOnIntegrationPage} = this.props;
+    const isInternal = this.isInternal;
+    const status = this.installationStatus;
+    if (this.hideStatus()) {
+      return null;
+    }
+    if (isOnIntegrationPage) {
+      return (
+        <React.Fragment>
+          <StatusIndicator status={status} isInternal={isInternal} />
+        </React.Fragment>
+      );
+    }
+    return <PublishStatus status={app.status} />;
+  }
+
+  get installationStatus() {
+    if (this.props.install) {
+      return capitalize(this.props.install.status);
+    }
+
+    return NOT_INSTALLED;
+  }
+
+  linkToEdit() {
+    const {isOnIntegrationPage} = this.props;
+    // show the link if the app is internal or we are on the developer settings page
+    // We don't want to show the link to edit on the main integrations list unless the app is internal
+    return this.isInternal || !isOnIntegrationPage;
+  }
+
+  render() {
+    const {app, organization} = this.props;
+    return (
+      <SentryAppItem data-test-id={app.slug}>
+        <StyledFlex>
+          <PluginIcon size={36} pluginId={app.slug} />
+          <SentryAppBox>
+            <SentryAppName hideStatus={this.hideStatus()}>
+              {this.linkToEdit() ? (
+                <SentryAppLink
+                  to={`/settings/${organization.slug}/developer-settings/${app.slug}/`}
+                >
+                  {app.name}
+                </SentryAppLink>
+              ) : (
+                <SentryAppLink
+                  to={`/settings/${organization.slug}/sentry-apps/${app.slug}`}
+                >
+                  {app.name}
+                </SentryAppLink>
+              )}
+            </SentryAppName>
+            <SentryAppDetails>{this.renderStatus()}</SentryAppDetails>
+          </SentryAppBox>
+        </StyledFlex>
+      </SentryAppItem>
+    );
+  }
+}
+
+const SentryAppItem = styled(PanelItem)`
+  flex-direction: column;
+  padding: 5px;
+`;
+
+const StyledFlex = styled('div')`
+  display: flex;
+  justify-content: center;
+  padding: 10px;
+`;
+
+const SentryAppBox = styled('div')`
+  padding-left: 15px;
+  padding-right: 15px;
+  flex: 1;
+`;
+
+const SentryAppDetails = styled('div')`
+  display: flex;
+  align-items: center;
+  margin-top: 6px;
+  font-size: 0.8em;
+`;
+
+const SentryAppName = styled('div')<{hideStatus: boolean}>`
+  font-weight: bold;
+  margin-top: ${p => (p.hideStatus ? '10px' : '0px')};
+`;
+
+const SentryAppLink = styled(Link)`
+  color: ${props => props.theme.textColor};
+`;
+
+const FlexContainer = styled('div')`
+  display: flex;
+  align-items: center;
+`;
+const color = {
+  [INSTALLED]: 'success',
+  [NOT_INSTALLED]: 'gray2',
+  [PENDING]: 'yellowOrange',
+};
+
+type StatusIndicatorProps = {status: string; theme?: any; isInternal: boolean};
+
+const StatusIndicator = styled(({status, ...props}: StatusIndicatorProps) => {
+  //need to omit isInternal
+  const propsToPass = omit(props, ['isInternal']);
+  return (
+    <FlexContainer>
+      <CircleIndicator size={6} color={theme[color[status]]} />
+      <div {...propsToPass}>{t(`${status}`)}</div>
+    </FlexContainer>
+  );
+})`
+  color: ${(props: StatusIndicatorProps) => props.theme[color[props.status]]};
+  margin-left: ${space(0.5)};
+  font-weight: light;
+  margin-right: ${space(0.75)};
+`;
+
+type PublishStatusProps = {status: SentryApp['status']; theme?: any};
+
+const PublishStatus = styled(({status, ...props}: PublishStatusProps) => {
+  return (
+    <FlexContainer>
+      <div {...props}>{t(`${status}`)}</div>
+    </FlexContainer>
+  );
+})`
+  color: ${(props: PublishStatusProps) =>
+    props.status === 'published' ? props.theme.success : props.theme.gray2};
+  font-weight: light;
+  margin-right: ${space(0.75)};
+`;

## Problem
Add sentry apps to integration directory and remove buttons from the right side of the list.

## Solution
Created new files for the IntegrationDIrectoryApplicationRow view.
Selectively delete methods, props and components related to the `Install`/`Add Another` buttons on the right side of the list.

## UI
<img width="1440" alt="Screen Shot 2020-01-30 at 2 56 55 PM" src="https://user-images.githubusercontent.com/10491193/73497954-d492a580-4370-11ea-92f8-d07f8f4b12d1.png">
