Просмотр исходного кода

chore(settings): Convert OrganizationRepositoriesContainer to FC and useApiQuery (#59546)

this pr updates OrganizationRepositoriesContainer to be a functional
component that uses useApiQuery
Richard Roggenkemper 1 год назад
Родитель
Сommit
cdd06727bf

+ 3 - 20
static/app/views/settings/organizationRepositories/index.spec.tsx

@@ -1,14 +1,10 @@
-import {Organization} from 'sentry-fixture/organization';
-
+import {initializeOrg} from 'sentry-test/initializeOrg';
 import {render} from 'sentry-test/reactTestingLibrary';
 import {render} from 'sentry-test/reactTestingLibrary';
 
 
 import OrganizationRepositoriesContainer from 'sentry/views/settings/organizationRepositories';
 import OrganizationRepositoriesContainer from 'sentry/views/settings/organizationRepositories';
 
 
 describe('OrganizationRepositoriesContainer', function () {
 describe('OrganizationRepositoriesContainer', function () {
-  const context = TestStubs.routerContext();
-  const organization = Organization();
-  const router = TestStubs.router();
-
+  const {routerContext} = initializeOrg();
   beforeEach(function () {
   beforeEach(function () {
     MockApiClient.clearMockResponses();
     MockApiClient.clearMockResponses();
   });
   });
@@ -26,20 +22,7 @@ describe('OrganizationRepositoriesContainer', function () {
     });
     });
 
 
     it('is loading when initially rendering', function () {
     it('is loading when initially rendering', function () {
-      render(
-        <OrganizationRepositoriesContainer
-          router={router}
-          routes={router.routes}
-          params={router.params}
-          routeParams={router.params}
-          route={router.routes[0]}
-          location={router.location}
-          organization={organization}
-        />,
-        {
-          context,
-        }
-      );
+      render(<OrganizationRepositoriesContainer />, {context: routerContext});
     });
     });
   });
   });
 });
 });

+ 49 - 43
static/app/views/settings/organizationRepositories/index.tsx

@@ -1,61 +1,67 @@
 import {Fragment} from 'react';
 import {Fragment} from 'react';
-import {RouteComponentProps} from 'react-router';
 
 
+import LoadingError from 'sentry/components/loadingError';
+import LoadingIndicator from 'sentry/components/loadingIndicator';
 import Pagination from 'sentry/components/pagination';
 import Pagination from 'sentry/components/pagination';
+import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
 import {t} from 'sentry/locale';
 import {t} from 'sentry/locale';
-import {Organization, Repository} from 'sentry/types';
+import {Repository} from 'sentry/types';
+import {setApiQueryData, useApiQuery, useQueryClient} from 'sentry/utils/queryClient';
 import routeTitleGen from 'sentry/utils/routeTitle';
 import routeTitleGen from 'sentry/utils/routeTitle';
-import withOrganization from 'sentry/utils/withOrganization';
-import DeprecatedAsyncView from 'sentry/views/deprecatedAsyncView';
+import {useLocation} from 'sentry/utils/useLocation';
+import useOrganization from 'sentry/utils/useOrganization';
 
 
 import OrganizationRepositories from './organizationRepositories';
 import OrganizationRepositories from './organizationRepositories';
 
 
-type Props = RouteComponentProps<{}, {}> & {
-  organization: Organization;
-} & DeprecatedAsyncView['props'];
+function OrganizationRepositoriesContainer() {
+  const organization = useOrganization();
+  const location = useLocation();
+  const queryClient = useQueryClient();
 
 
-type State = DeprecatedAsyncView['state'] & {
-  itemList: Repository[] | null;
-};
+  const {
+    data: itemList,
+    isLoading,
+    isError,
+    getResponseHeader,
+  } = useApiQuery<Repository[]>(
+    [`/organizations/${organization.slug}/repos/`, {query: location.query}],
+    {staleTime: 0}
+  );
+  const itemListPageLinks = getResponseHeader?.('Link');
 
 
-class OrganizationRepositoriesContainer extends DeprecatedAsyncView<Props, State> {
-  getEndpoints(): ReturnType<DeprecatedAsyncView['getEndpoints']> {
-    const {organization} = this.props;
-    return [['itemList', `/organizations/${organization.slug}/repos/`]];
+  if (isLoading) {
+    return <LoadingIndicator />;
   }
   }
 
 
-  // Callback used by child component to signal state change
-  onRepositoryChange = (data: Pick<Repository, 'id' | 'status'>) => {
-    const itemList = this.state.itemList;
-    itemList?.forEach(item => {
-      if (item.id === data.id) {
-        item.status = data.status;
-      }
-    });
-    this.setState({itemList});
-  };
-
-  getTitle() {
-    const {organization} = this.props;
-    return routeTitleGen(t('Repositories'), organization.slug, false);
+  if (isError) {
+    return <LoadingError />;
   }
   }
 
 
-  renderBody() {
-    const {itemList, itemListPageLinks} = this.state;
-
-    return (
-      <Fragment>
-        <OrganizationRepositories
-          {...this.props}
-          itemList={itemList!}
-          onRepositoryChange={this.onRepositoryChange}
-        />
-        {itemListPageLinks && (
-          <Pagination pageLinks={itemListPageLinks} {...this.props} />
-        )}
-      </Fragment>
+  // Callback used by child component to signal state change
+  function onRepositoryChange(data: Pick<Repository, 'id' | 'status'>) {
+    setApiQueryData<Repository[]>(
+      queryClient,
+      [`/organizations/${organization.slug}/repos/`, {query: location.query}],
+      oldItemList =>
+        oldItemList.map(item =>
+          item.id === data.id ? {...item, status: data.status} : item
+        )
     );
     );
   }
   }
+
+  return (
+    <Fragment>
+      <SentryDocumentTitle
+        title={routeTitleGen(t('Repositories'), organization.slug, false)}
+      />
+      <OrganizationRepositories
+        organization={organization}
+        itemList={itemList!}
+        onRepositoryChange={onRepositoryChange}
+      />
+      {itemListPageLinks && <Pagination pageLinks={itemListPageLinks} />}
+    </Fragment>
+  );
 }
 }
 
 
-export default withOrganization(OrganizationRepositoriesContainer);
+export default OrganizationRepositoriesContainer;