Browse Source

ref(js): Convert RepositoryRow to a FC (#34618)

Evan Purkhiser 2 years ago
parent
commit
9de732dd07

+ 110 - 129
static/app/components/repositoryRow.tsx

@@ -1,4 +1,4 @@
-import {Component, Fragment} from 'react';
+import {Fragment} from 'react';
 import styled from '@emotion/styled';
 
 import {
@@ -20,40 +20,45 @@ import space from 'sentry/styles/space';
 import {Organization, Repository, RepositoryStatus} from 'sentry/types';
 import withOrganization from 'sentry/utils/withOrganization';
 
-type DefaultProps = {
-  showProvider?: boolean;
-};
-
-type Props = DefaultProps & {
+type Props = {
   api: Client;
   orgId: string;
   organization: Organization;
   repository: Repository;
   onRepositoryChange?: (data: {id: string; status: RepositoryStatus}) => void;
+  showProvider?: boolean;
 };
 
-class RepositoryRow extends Component<Props> {
-  static defaultProps: DefaultProps = {
-    showProvider: false,
-  };
-
-  getStatusLabel(repo: Repository) {
-    switch (repo.status) {
-      case RepositoryStatus.PENDING_DELETION:
-        return 'Deletion Queued';
-      case RepositoryStatus.DELETION_IN_PROGRESS:
-        return 'Deletion in Progress';
-      case RepositoryStatus.DISABLED:
-        return 'Disabled';
-      case RepositoryStatus.HIDDEN:
-        return 'Disabled';
-      default:
-        return null;
-    }
+function getStatusLabel(repo: Repository) {
+  switch (repo.status) {
+    case RepositoryStatus.PENDING_DELETION:
+      return 'Deletion Queued';
+    case RepositoryStatus.DELETION_IN_PROGRESS:
+      return 'Deletion in Progress';
+    case RepositoryStatus.DISABLED:
+      return 'Disabled';
+    case RepositoryStatus.HIDDEN:
+      return 'Disabled';
+    default:
+      return null;
   }
+}
 
-  cancelDelete = () => {
-    const {api, orgId, repository, onRepositoryChange} = this.props;
+function RepositoryRow({
+  api,
+  repository,
+  onRepositoryChange,
+  organization,
+  orgId,
+  showProvider = false,
+}: Props) {
+  const isCustomRepo =
+    organization.features.includes('integrations-custom-scm') &&
+    repository.provider.id === 'integrations:custom_scm';
+
+  const isActive = repository.status === RepositoryStatus.ACTIVE;
+
+  const cancelDelete = () =>
     cancelDeleteRepository(api, orgId, repository.id).then(
       data => {
         if (onRepositoryChange) {
@@ -62,10 +67,8 @@ class RepositoryRow extends Component<Props> {
       },
       () => {}
     );
-  };
 
-  deleteRepo = () => {
-    const {api, orgId, repository, onRepositoryChange} = this.props;
+  const deleteRepo = () =>
     deleteRepository(api, orgId, repository.id).then(
       data => {
         if (onRepositoryChange) {
@@ -74,51 +77,38 @@ class RepositoryRow extends Component<Props> {
       },
       () => {}
     );
-  };
 
-  handleEditRepo = (data: Repository) => {
-    const {onRepositoryChange} = this.props;
-    if (onRepositoryChange) {
-      onRepositoryChange(data);
-    }
+  const handleEditRepo = (data: Repository) => {
+    onRepositoryChange?.(data);
   };
 
-  get isActive() {
-    return this.props.repository.status === RepositoryStatus.ACTIVE;
-  }
-
-  renderDeleteButton(hasAccess) {
-    const {repository} = this.props;
-    const isActive = this.isActive;
-    return (
-      <Tooltip
-        title={t(
-          'You must be an organization owner, manager or admin to remove a repository.'
+  const renderDeleteButton = (hasAccess: boolean) => (
+    <Tooltip
+      title={t(
+        'You must be an organization owner, manager or admin to remove a repository.'
+      )}
+      disabled={hasAccess}
+    >
+      <Confirm
+        disabled={
+          !hasAccess || (!isActive && repository.status !== RepositoryStatus.DISABLED)
+        }
+        onConfirm={deleteRepo}
+        message={t(
+          'Are you sure you want to remove this repository? All associated commit data will be removed in addition to the repository.'
         )}
-        disabled={hasAccess}
       >
-        <Confirm
-          disabled={
-            !hasAccess || (!isActive && repository.status !== RepositoryStatus.DISABLED)
-          }
-          onConfirm={this.deleteRepo}
-          message={t(
-            'Are you sure you want to remove this repository? All associated commit data will be removed in addition to the repository.'
-          )}
-        >
-          <StyledButton
-            size="xsmall"
-            icon={<IconDelete size="xs" />}
-            aria-label={t('delete')}
-            disabled={!hasAccess}
-          />
-        </Confirm>
-      </Tooltip>
-    );
-  }
-
-  openModal = () => {
-    const {repository, orgId} = this.props;
+        <StyledButton
+          size="xsmall"
+          icon={<IconDelete size="xs" />}
+          aria-label={t('delete')}
+          disabled={!hasAccess}
+        />
+      </Confirm>
+    </Tooltip>
+  );
+
+  const triggerModal = () =>
     openModal(({Body, Header, closeModal}) => (
       <Fragment>
         <Header closeButton>{t('Edit Repository')}</Header>
@@ -126,75 +116,66 @@ class RepositoryRow extends Component<Props> {
           <RepositoryEditForm
             orgSlug={orgId}
             repository={repository}
-            onSubmitSuccess={this.handleEditRepo}
+            onSubmitSuccess={handleEditRepo}
             closeModal={closeModal}
             onCancel={closeModal}
           />
         </Body>
       </Fragment>
     ));
-  };
 
-  render() {
-    const {repository, showProvider, organization} = this.props;
-    const isActive = this.isActive;
-    const isCustomRepo =
-      organization.features.includes('integrations-custom-scm') &&
-      repository.provider.id === 'integrations:custom_scm';
-
-    return (
-      <Access access={['org:integrations']}>
-        {({hasAccess}) => (
-          <StyledPanelItem status={repository.status}>
-            <RepositoryTitleAndUrl>
-              <RepositoryTitle>
-                <strong>{repository.name}</strong>
-                {!isActive && <small> &mdash; {this.getStatusLabel(repository)}</small>}
-                {repository.status === RepositoryStatus.PENDING_DELETION && (
-                  <StyledButton
-                    size="xsmall"
-                    onClick={this.cancelDelete}
-                    disabled={!hasAccess}
-                    data-test-id="repo-cancel"
-                  >
-                    {t('Cancel')}
-                  </StyledButton>
-                )}
-              </RepositoryTitle>
-              <div>
-                {showProvider && <small>{repository.provider.name}</small>}
-                {showProvider && repository.url && <span>&nbsp;&mdash;&nbsp;</span>}
-                {repository.url && (
-                  <small>
-                    <ExternalLink href={repository.url}>
-                      {repository.url.replace('https://', '')}
-                    </ExternalLink>
-                  </small>
-                )}
-              </div>
-            </RepositoryTitleAndUrl>
-            {isCustomRepo ? (
-              <EditAndDelete>
+  return (
+    <Access access={['org:integrations']}>
+      {({hasAccess}) => (
+        <StyledPanelItem status={repository.status}>
+          <RepositoryTitleAndUrl>
+            <RepositoryTitle>
+              <strong>{repository.name}</strong>
+              {!isActive && <small> &mdash; {getStatusLabel(repository)}</small>}
+              {repository.status === RepositoryStatus.PENDING_DELETION && (
                 <StyledButton
                   size="xsmall"
-                  icon={<IconEdit size="xs" />}
-                  aria-label={t('edit')}
-                  disabled={
-                    !hasAccess ||
-                    (!isActive && repository.status !== RepositoryStatus.DISABLED)
-                  }
-                  onClick={() => this.openModal()}
-                />
-                {this.renderDeleteButton(hasAccess)}
-              </EditAndDelete>
-            ) : (
-              this.renderDeleteButton(hasAccess)
-            )}
-          </StyledPanelItem>
-        )}
-      </Access>
-    );
-  }
+                  onClick={cancelDelete}
+                  disabled={!hasAccess}
+                  data-test-id="repo-cancel"
+                >
+                  {t('Cancel')}
+                </StyledButton>
+              )}
+            </RepositoryTitle>
+            <div>
+              {showProvider && <small>{repository.provider.name}</small>}
+              {showProvider && repository.url && <span>&nbsp;&mdash;&nbsp;</span>}
+              {repository.url && (
+                <small>
+                  <ExternalLink href={repository.url}>
+                    {repository.url.replace('https://', '')}
+                  </ExternalLink>
+                </small>
+              )}
+            </div>
+          </RepositoryTitleAndUrl>
+          {isCustomRepo ? (
+            <EditAndDelete>
+              <StyledButton
+                size="xsmall"
+                icon={<IconEdit size="xs" />}
+                aria-label={t('edit')}
+                disabled={
+                  !hasAccess ||
+                  (!isActive && repository.status !== RepositoryStatus.DISABLED)
+                }
+                onClick={triggerModal}
+              />
+              {renderDeleteButton(hasAccess)}
+            </EditAndDelete>
+          ) : (
+            renderDeleteButton(hasAccess)
+          )}
+        </StyledPanelItem>
+      )}
+    </Access>
+  );
 }
 
 const StyledPanelItem = styled(PanelItem)<{status: RepositoryStatus}>`

+ 1 - 1
static/app/views/organizationIntegrations/integrationRepos.tsx

@@ -239,10 +239,10 @@ class IntegrationRepos extends AsyncComponent<Props, State> {
             )}
             {itemList.map(repo => (
               <RepositoryRow
+                api={this.api}
                 key={repo.id}
                 repository={repo}
                 orgId={orgId}
-                api={this.api}
                 onRepositoryChange={this.onRepositoryChange}
               />
             ))}

+ 0 - 1
static/app/views/settings/organizationRepositories/index.tsx

@@ -45,7 +45,6 @@ export default class OrganizationRepositoriesContainer extends AsyncView<Props,
         <OrganizationRepositories
           {...this.props}
           itemList={itemList!}
-          api={this.api}
           onRepositoryChange={this.onRepositoryChange}
         />
         {itemListPageLinks && (

+ 6 - 5
static/app/views/settings/organizationRepositories/organizationRepositories.tsx

@@ -1,6 +1,5 @@
 import {RouteComponentProps} from 'react-router';
 
-import {Client} from 'sentry/api';
 import AlertLink from 'sentry/components/alertLink';
 import Button from 'sentry/components/button';
 import ExternalLink from 'sentry/components/links/externalLink';
@@ -9,17 +8,19 @@ import RepositoryRow from 'sentry/components/repositoryRow';
 import {IconCommit} from 'sentry/icons';
 import {t, tct} from 'sentry/locale';
 import {Repository, RepositoryStatus} from 'sentry/types';
+import useApi from 'sentry/utils/useApi';
 import EmptyMessage from 'sentry/views/settings/components/emptyMessage';
 import SettingsPageHeader from 'sentry/views/settings/components/settingsPageHeader';
 import TextBlock from 'sentry/views/settings/components/text/textBlock';
 
 type Props = RouteComponentProps<{orgId: string}, {}> & {
-  api: Client;
   itemList: Repository[];
   onRepositoryChange: (data: {id: string; status: RepositoryStatus}) => void;
 };
 
-const OrganizationRepositories = ({itemList, onRepositoryChange, api, params}: Props) => {
+function OrganizationRepositories({itemList, onRepositoryChange, params}: Props) {
+  const api = useApi();
+
   const {orgId} = params;
   const hasItemList = itemList && itemList.length > 0;
 
@@ -54,9 +55,9 @@ const OrganizationRepositories = ({itemList, onRepositoryChange, api, params}: P
             <div>
               {itemList.map(repo => (
                 <RepositoryRow
+                  api={api}
                   key={repo.id}
                   repository={repo}
-                  api={api}
                   showProvider
                   orgId={orgId}
                   onRepositoryChange={onRepositoryChange}
@@ -83,6 +84,6 @@ const OrganizationRepositories = ({itemList, onRepositoryChange, api, params}: P
       )}
     </div>
   );
-};
+}
 
 export default OrganizationRepositories;