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

replace methods to call api client

Yuki Takei 4 лет назад
Родитель
Сommit
0bdafb112b
44 измененных файлов с 350 добавлено и 302 удалено
  1. 5 4
      packages/app/src/components/Admin/Customize/CustomizeLayoutSetting.jsx
  2. 11 8
      packages/app/src/components/Admin/ElasticsearchManagement/ElasticsearchManagement.jsx
  3. 6 3
      packages/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.jsx
  4. 10 7
      packages/app/src/components/Admin/ExportArchiveDataPage.jsx
  5. 9 7
      packages/app/src/components/Admin/ImportData/GrowiArchive/ImportForm.jsx
  6. 5 2
      packages/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx
  7. 7 4
      packages/app/src/components/Admin/ImportData/GrowiArchiveSection.jsx
  8. 8 5
      packages/app/src/components/Admin/Notification/GlobalNotificationList.jsx
  9. 10 6
      packages/app/src/components/Admin/Notification/ManageGlobalNotification.jsx
  10. 7 5
      packages/app/src/components/Admin/Security/LdapAuthTest.jsx
  11. 8 6
      packages/app/src/components/Admin/Security/ShareLinkSetting.jsx
  12. 12 8
      packages/app/src/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx
  13. 8 4
      packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx
  14. 9 5
      packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx
  15. 5 3
      packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx
  16. 5 3
      packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx
  17. 12 7
      packages/app/src/components/Admin/SlackIntegration/OfficialBotSettings.jsx
  18. 17 11
      packages/app/src/components/Admin/SlackIntegration/SlackIntegration.jsx
  19. 13 13
      packages/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx
  20. 7 4
      packages/app/src/components/Admin/UserGroupDetail/UserGroupPageList.jsx
  21. 5 2
      packages/app/src/components/Admin/Users/PasswordResetModal.jsx
  22. 8 4
      packages/app/src/components/Admin/Users/SendInvitationEmailButton.jsx
  23. 6 2
      packages/app/src/components/ArchiveCreateModal.jsx
  24. 7 6
      packages/app/src/components/EmptyTrashModal.jsx
  25. 2 1
      packages/app/src/components/Me/ApiSettings.jsx
  26. 6 25
      packages/app/src/components/Me/EditorSettings.tsx
  27. 6 11
      packages/app/src/components/Me/PasswordSettings.jsx
  28. 6 7
      packages/app/src/components/MyDraftList/MyDraftList.jsx
  29. 7 4
      packages/app/src/components/Page/RevisionLoader.jsx
  30. 5 2
      packages/app/src/components/PageAttachment.jsx
  31. 9 7
      packages/app/src/components/PageComment.tsx
  32. 17 16
      packages/app/src/components/PageEditor.jsx
  33. 10 11
      packages/app/src/components/PageEditor/LinkEditModal.jsx
  34. 6 5
      packages/app/src/components/PageEditor/OptionsSelector.jsx
  35. 12 13
      packages/app/src/components/PageEditorByHackmd.jsx
  36. 9 14
      packages/app/src/components/PageList/BookmarkList.jsx
  37. 5 4
      packages/app/src/components/PageTimeline.jsx
  38. 7 3
      packages/app/src/components/PasswordResetExecutionForm.jsx
  39. 5 2
      packages/app/src/components/PasswordResetRequestForm.jsx
  40. 5 12
      packages/app/src/components/RecentCreated/RecentCreated.jsx
  41. 3 4
      packages/app/src/components/SavePageControls/GrantSelector.jsx
  42. 14 14
      packages/app/src/components/ShareLink/ShareLink.jsx
  43. 10 11
      packages/app/src/components/ShareLink/ShareLinkForm.jsx
  44. 6 7
      packages/app/src/components/StaffCredit/StaffCredit.jsx

+ 5 - 4
packages/app/src/components/Admin/Customize/CustomizeLayoutSetting.jsx

@@ -1,10 +1,11 @@
 import React, { useCallback, useEffect, useState } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
 import AppContainer from '~/client/services/AppContainer';
-
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 import { isDarkMode as isDarkModeByUtil } from '~/client/util/color-scheme';
 
 const isDarkMode = isDarkModeByUtil();
@@ -18,14 +19,14 @@ const CustomizeLayoutSetting = (props) => {
 
   const retrieveData = useCallback(async() => {
     try {
-      const res = await appContainer.apiv3Get('/customize-setting/layout');
+      const res = await apiv3Get('/customize-setting/layout');
       setIsContainerFluid(res.data.isContainerFluid);
     }
     catch (err) {
       setRetrieveError(err);
       toastError(err);
     }
-  }, [appContainer]);
+  }, []);
 
   useEffect(() => {
     retrieveData();
@@ -33,7 +34,7 @@ const CustomizeLayoutSetting = (props) => {
 
   const onClickSubmit = async() => {
     try {
-      await appContainer.apiv3Put('/customize-setting/layout', { isContainerFluid });
+      await apiv3Put('/customize-setting/layout', { isContainerFluid });
       toastSuccess(t('toaster.update_successed', { target: t('admin:customize_setting.layout') }));
       retrieveData();
     }

+ 11 - 8
packages/app/src/components/Admin/ElasticsearchManagement/ElasticsearchManagement.jsx

@@ -1,16 +1,19 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
 import AdminSocketIoContainer from '~/client/services/AdminSocketIoContainer';
+import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Get, apiv3Post, apiv3Put } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
-import StatusTable from './StatusTable';
-import ReconnectControls from './ReconnectControls';
 import NormalizeIndicesControls from './NormalizeIndicesControls';
 import RebuildIndexControls from './RebuildIndexControls';
+import ReconnectControls from './ReconnectControls';
+import StatusTable from './StatusTable';
 
 class ElasticsearchManagement extends React.Component {
 
@@ -70,7 +73,7 @@ class ElasticsearchManagement extends React.Component {
     const { appContainer } = this.props;
 
     try {
-      const { data } = await appContainer.apiv3Get('/search/indices');
+      const { data } = await apiv3Get('/search/indices');
       const { info } = data;
 
       this.setState({
@@ -105,7 +108,7 @@ class ElasticsearchManagement extends React.Component {
     this.setState({ isReconnectingProcessing: true });
 
     try {
-      await appContainer.apiv3Post('/search/connection');
+      await apiv3Post('/search/connection');
     }
     catch (e) {
       toastError(e);
@@ -120,7 +123,7 @@ class ElasticsearchManagement extends React.Component {
     const { appContainer } = this.props;
 
     try {
-      await appContainer.apiv3Put('/search/indices', { operation: 'normalize' });
+      await apiv3Put('/search/indices', { operation: 'normalize' });
     }
     catch (e) {
       toastError(e);
@@ -137,7 +140,7 @@ class ElasticsearchManagement extends React.Component {
     this.setState({ isRebuildingProcessing: true });
 
     try {
-      await appContainer.apiv3Put('/search/indices', { operation: 'rebuild' });
+      await apiv3Put('/search/indices', { operation: 'rebuild' });
       toastSuccess('Rebuilding is requested');
     }
     catch (e) {

+ 6 - 3
packages/app/src/components/Admin/ExportArchiveData/SelectCollectionsModal.jsx

@@ -1,4 +1,5 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import {
@@ -6,8 +7,10 @@ import {
 } from 'reactstrap';
 import * as toastr from 'toastr';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
+import { apiPost } from '~/client/util/apiv1-client';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
 // import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
 
@@ -67,8 +70,8 @@ class SelectCollectionsModal extends React.Component {
     e.preventDefault();
 
     try {
-      // TODO: use appContainer.apiv3.post
-      const result = await this.props.appContainer.apiPost('/v3/export', { collections: Array.from(this.state.selectedCollections) });
+      // TODO: use apiv3Post
+      const result = await apiPost('/v3/export', { collections: Array.from(this.state.selectedCollections) });
       // TODO: toastSuccess, toastError
 
       if (!result.ok) {

+ 10 - 7
packages/app/src/components/Admin/ExportArchiveDataPage.jsx

@@ -1,19 +1,22 @@
 import React, { Fragment } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import * as toastr from 'toastr';
 
 
+import AdminSocketIoContainer from '~/client/services/AdminSocketIoContainer';
+import AppContainer from '~/client/services/AppContainer';
+import { apiDelete, apiGet } from '~/client/util/apiv1-client';
+
 import { withUnstatedContainers } from '../UnstatedUtils';
 // import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
-import AppContainer from '~/client/services/AppContainer';
-import AdminSocketIoContainer from '~/client/services/AdminSocketIoContainer';
 
 import LabeledProgressBar from './Common/LabeledProgressBar';
-
-import SelectCollectionsModal from './ExportArchiveData/SelectCollectionsModal';
 import ArchiveFilesTable from './ExportArchiveData/ArchiveFilesTable';
+import SelectCollectionsModal from './ExportArchiveData/SelectCollectionsModal';
+
 
 const IGNORED_COLLECTION_NAMES = [
   'sessions',
@@ -45,8 +48,8 @@ class ExportArchiveDataPage extends React.Component {
     // TODO:: use apiv3.get
     // eslint-disable-next-line no-unused-vars
     const [{ collections }, { status }] = await Promise.all([
-      this.props.appContainer.apiGet('/v3/mongo/collections', {}),
-      this.props.appContainer.apiGet('/v3/export/status', {}),
+      apiGet('/v3/mongo/collections', {}),
+      apiGet('/v3/export/status', {}),
     ]);
     // TODO: toastSuccess, toastError
 
@@ -118,7 +121,7 @@ class ExportArchiveDataPage extends React.Component {
 
   async onZipFileStatRemove(fileName) {
     try {
-      await this.props.appContainer.apiDelete(`/v3/export/${fileName}`, {});
+      await apiDelete(`/v3/export/${fileName}`, {});
 
       this.setState((prevState) => {
         return {

+ 9 - 7
packages/app/src/components/Admin/ImportData/GrowiArchive/ImportForm.jsx

@@ -1,20 +1,22 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
+import AdminSocketIoContainer from '~/client/services/AdminSocketIoContainer';
+import AppContainer from '~/client/services/AppContainer';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
 import GrowiArchiveImportOption from '~/models/admin/growi-archive-import-option';
 import ImportOptionForPages from '~/models/admin/import-option-for-pages';
 import ImportOptionForRevisions from '~/models/admin/import-option-for-revisions';
 
 import { withUnstatedContainers } from '../../../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
-import AdminSocketIoContainer from '~/client/services/AdminSocketIoContainer';
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
 
-import ImportCollectionItem, { DEFAULT_MODE, MODE_RESTRICTED_COLLECTION } from './ImportCollectionItem';
-import ImportCollectionConfigurationModal from './ImportCollectionConfigurationModal';
 import ErrorViewer from './ErrorViewer';
+import ImportCollectionConfigurationModal from './ImportCollectionConfigurationModal';
+import ImportCollectionItem, { DEFAULT_MODE, MODE_RESTRICTED_COLLECTION } from './ImportCollectionItem';
 
 
 const GROUPS_PAGE = [
@@ -300,8 +302,8 @@ class ImportForm extends React.Component {
     });
 
     try {
-      // TODO: use appContainer.apiv3.post
-      await appContainer.apiv3Post('/import', {
+      // TODO: use apiv3Post
+      await apiv3Post('/import', {
         fileName,
         collections: Array.from(selectedCollections),
         optionsMap,

+ 5 - 2
packages/app/src/components/Admin/ImportData/GrowiArchive/UploadForm.jsx

@@ -1,10 +1,13 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import { withUnstatedContainers } from '../../../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
 import { toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../../../UnstatedUtils';
 
 class UploadForm extends React.Component {
 
@@ -32,7 +35,7 @@ class UploadForm extends React.Component {
     formData.append('file', this.inputRef.current.files[0]);
 
     try {
-      const { data } = await this.props.appContainer.apiv3Post('/import/upload', formData);
+      const { data } = await apiv3Post('/import/upload', formData);
       // TODO: toastSuccess, toastError
       this.props.onUpload(data);
     }

+ 7 - 4
packages/app/src/components/Admin/ImportData/GrowiArchiveSection.jsx

@@ -1,14 +1,17 @@
 import React, { Fragment } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import * as toastr from 'toastr';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
+import { apiv3Delete, apiv3Get } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
 // import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
-import UploadForm from './GrowiArchive/UploadForm';
 import ImportForm from './GrowiArchive/ImportForm';
+import UploadForm from './GrowiArchive/UploadForm';
 
 class GrowiArchiveSection extends React.Component {
 
@@ -32,7 +35,7 @@ class GrowiArchiveSection extends React.Component {
 
   async componentWillMount() {
     // get uploaded file status
-    const res = await this.props.appContainer.apiv3Get('/import/status');
+    const res = await apiv3Get('/import/status');
 
     if (res.data.zipFileStat != null) {
       const { fileName, innerFileStats } = res.data.zipFileStat;
@@ -55,7 +58,7 @@ class GrowiArchiveSection extends React.Component {
   async discardData() {
     try {
       const { fileName } = this.state;
-      await this.props.appContainer.apiv3Delete('/import/all');
+      await apiv3Delete('/import/all');
       this.resetState();
 
       // TODO: toastSuccess, toastError

+ 8 - 5
packages/app/src/components/Admin/Notification/GlobalNotificationList.jsx

@@ -1,18 +1,21 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import urljoin from 'url-join';
-import loggerFactory from '~/utils/logger';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
+import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
+import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+import loggerFactory from '~/utils/logger';
 
-import AppContainer from '~/client/services/AppContainer';
-import AdminNotificationContainer from '~/client/services/AdminNotificationContainer';
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
 import NotificationDeleteModal from './NotificationDeleteModal';
 import NotificationTypeIcon from './NotificationTypeIcon';
 
+
 const logger = loggerFactory('growi:GolobalNotificationList');
 
 class GlobalNotificationList extends React.Component {
@@ -34,7 +37,7 @@ class GlobalNotificationList extends React.Component {
     const { t } = this.props;
     const isEnabled = !notification.isEnabled;
     try {
-      await this.props.appContainer.apiv3.put(`/notification-setting/global-notification/${notification._id}/enabled`, {
+      await apiv3Put(`/notification-setting/global-notification/${notification._id}/enabled`, {
         isEnabled,
       });
       toastSuccess(t('notification_setting.toggle_notification', { path: notification.triggerPath }));

+ 10 - 6
packages/app/src/components/Admin/Notification/ManageGlobalNotification.jsx

@@ -1,16 +1,20 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import urljoin from 'url-join';
 
+import AppContainer from '~/client/services/AppContainer';
+import { toastError } from '~/client/util/apiNotification';
+import { apiv3Post, apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
 
-import { toastError } from '~/client/util/apiNotification';
 
-import TriggerEventCheckBox from './TriggerEventCheckBox';
-import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
-import AppContainer from '~/client/services/AppContainer';
 import { withUnstatedContainers } from '../../UnstatedUtils';
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+
+import TriggerEventCheckBox from './TriggerEventCheckBox';
+
 
 const logger = loggerFactory('growi:manageGlobalNotification');
 
@@ -81,10 +85,10 @@ class ManageGlobalNotification extends React.Component {
 
     try {
       if (this.state.globalNotificationId != null) {
-        await this.props.appContainer.apiv3.put(`/notification-setting/global-notification/${this.state.globalNotificationId}`, requestParams);
+        await apiv3Put(`/notification-setting/global-notification/${this.state.globalNotificationId}`, requestParams);
       }
       else {
-        await this.props.appContainer.apiv3.post('/notification-setting/global-notification', requestParams);
+        await apiv3Post('/notification-setting/global-notification', requestParams);
       }
       window.location.href = urljoin(window.location.origin, '/admin/notification#global-notification');
     }

+ 7 - 5
packages/app/src/components/Admin/Security/LdapAuthTest.jsx

@@ -1,13 +1,15 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import loggerFactory from '~/utils/logger';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
+import AdminLdapSecurityContainer from '~/client/services/AdminLdapSecurityContainer';
+import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiPost } from '~/client/util/apiv1-client';
+import loggerFactory from '~/utils/logger';
 
-import AppContainer from '~/client/services/AppContainer';
-import AdminLdapSecurityContainer from '~/client/services/AdminLdapSecurityContainer';
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
 const logger = loggerFactory('growi:security:AdminLdapSecurityContainer');
 
@@ -41,7 +43,7 @@ class LdapAuthTest extends React.Component {
    */
   async testLdapCredentials() {
     try {
-      const response = await this.props.appContainer.apiPost('/login/testLdap', {
+      const response = await apiPost('/login/testLdap', {
         loginForm: {
           username: this.props.username,
           password: this.props.password,

+ 8 - 6
packages/app/src/components/Admin/Security/ShareLinkSetting.jsx

@@ -1,17 +1,19 @@
 import React, { Fragment } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
+import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurityContainer';
+import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Delete } from '~/client/util/apiv3-client';
 
 import PaginationWrapper from '../../PaginationWrapper';
+import ShareLinkList from '../../ShareLink/ShareLinkList';
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
-import AppContainer from '~/client/services/AppContainer';
-import AdminGeneralSecurityContainer from '~/client/services/AdminGeneralSecurityContainer';
 
 import DeleteAllShareLinksModal from './DeleteAllShareLinksModal';
-import ShareLinkList from '../../ShareLink/ShareLinkList';
 
 
 const Pager = (props) => {
@@ -80,7 +82,7 @@ class ShareLinkSetting extends React.Component {
     const { t, appContainer } = this.props;
 
     try {
-      const res = await appContainer.apiv3Delete('/share-links/all');
+      const res = await apiv3Delete('/share-links/all');
       const { deletedCount } = res.data;
       toastSuccess(t('toaster.remove_share_link', { count: deletedCount }));
     }
@@ -95,7 +97,7 @@ class ShareLinkSetting extends React.Component {
     const { shareLinksActivePage } = adminGeneralSecurityContainer.state;
 
     try {
-      const res = await appContainer.apiv3Delete(`/share-links/${shareLinkId}`);
+      const res = await apiv3Delete(`/share-links/${shareLinkId}`);
       const { deletedShareLink } = res.data;
       toastSuccess(t('toaster.remove_share_link_success', { shareLinkId: deletedShareLink._id }));
     }

+ 12 - 8
packages/app/src/components/Admin/SlackIntegration/CustomBotWithProxySettings.jsx

@@ -1,15 +1,19 @@
 import React, { useState, useEffect, useCallback } from 'react';
-import { useTranslation } from 'react-i18next';
+
 import PropTypes from 'prop-types';
+import { useTranslation } from 'react-i18next';
 
-import loggerFactory from '~/utils/logger';
 import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Delete, apiv3Put } from '~/client/util/apiv3-client';
+import loggerFactory from '~/utils/logger';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
+
 import CustomBotWithProxyConnectionStatus from './CustomBotWithProxyConnectionStatus';
-import WithProxyAccordions from './WithProxyAccordions';
 import DeleteSlackBotSettingsModal from './DeleteSlackBotSettingsModal';
 import { SlackAppIntegrationControl } from './SlackAppIntegrationControl';
+import WithProxyAccordions from './WithProxyAccordions';
 
 const logger = loggerFactory('growi:cli:SlackIntegration:CustomBotWithProxySettings');
 
@@ -42,7 +46,7 @@ const CustomBotWithProxySettings = (props) => {
     }
 
     try {
-      await appContainer.apiv3.put(`/slack-integration-settings/slack-app-integrations/${slackIntegrationToChange._id}/make-primary`);
+      await apiv3Put(`/slack-integration-settings/slack-app-integrations/${slackIntegrationToChange._id}/make-primary`);
       if (onPrimaryUpdated != null) {
         onPrimaryUpdated();
       }
@@ -52,11 +56,11 @@ const CustomBotWithProxySettings = (props) => {
       toastError(err, 'Failed to change isPrimary');
       logger.error('Failed to change isPrimary', err);
     }
-  }, [appContainer.apiv3, t, onPrimaryUpdated]);
+  }, [t, onPrimaryUpdated]);
 
   const deleteSlackAppIntegrationHandler = async() => {
     try {
-      await appContainer.apiv3.delete(`/slack-integration-settings/slack-app-integrations/${integrationIdToDelete}`);
+      await apiv3Delete(`/slack-integration-settings/slack-app-integrations/${integrationIdToDelete}`);
       if (props.onDeleteSlackAppIntegration != null) {
         props.onDeleteSlackAppIntegration();
       }
@@ -70,7 +74,7 @@ const CustomBotWithProxySettings = (props) => {
 
   const updateProxyUri = async() => {
     try {
-      await appContainer.apiv3.put('/slack-integration-settings/proxy-uri', {
+      await apiv3Put('/slack-integration-settings/proxy-uri', {
         proxyUri: newProxyServerUri,
       });
       toastSuccess(t('toaster.update_successed', { target: 'Proxy URL' }));

+ 8 - 4
packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySecretTokenSection.jsx

@@ -1,10 +1,14 @@
 import React, { useState, useEffect } from 'react';
-import { useTranslation } from 'react-i18next';
+
 import PropTypes from 'prop-types';
-import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+import { useTranslation } from 'react-i18next';
+
 import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
 
 
 const CustomBotWithoutProxySecretTokenSection = (props) => {
@@ -26,7 +30,7 @@ const CustomBotWithoutProxySecretTokenSection = (props) => {
 
   const updatedSecretToken = async() => {
     try {
-      await appContainer.apiv3.put('/slack-integration-settings/without-proxy/update-settings', {
+      await apiv3Put('/slack-integration-settings/without-proxy/update-settings', {
         slackSigningSecret: inputSigningSecret,
         slackBotToken: inputBotToken,
       });

+ 9 - 5
packages/app/src/components/Admin/SlackIntegration/CustomBotWithoutProxySettingsAccordion.jsx

@@ -1,13 +1,18 @@
 import React, { useState } from 'react';
+
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
-import Accordion from '../Common/Accordion';
+
 import AppContainer from '~/client/services/AppContainer';
+import { apiv3Post } from '~/client/util/apiv3-client';
+
 import { withUnstatedContainers } from '../../UnstatedUtils';
-import MessageBasedOnConnection from './MessageBasedOnConnection';
+import Accordion from '../Common/Accordion';
+
 import CustomBotWithoutProxySecretTokenSection from './CustomBotWithoutProxySecretTokenSection';
-import { addLogs } from './slak-integration-util';
 import ManageCommandsProcessWithoutProxy from './ManageCommandsProcessWithoutProxy';
+import MessageBasedOnConnection from './MessageBasedOnConnection';
+import { addLogs } from './slak-integration-util';
 
 
 export const botInstallationStep = {
@@ -34,7 +39,7 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
 
   const testConnection = async() => {
     try {
-      await appContainer.apiv3.post('/slack-integration-settings/without-proxy/test', { channel: testChannel });
+      await apiv3Post('/slack-integration-settings/without-proxy/test', { channel: testChannel });
       setIsLatestConnectionSuccess(true);
       if (onTestConnectionInvoked != null) {
         onTestConnectionInvoked();
@@ -130,7 +135,6 @@ const CustomBotWithoutProxySettingsAccordion = (props) => {
         <ManageCommandsProcessWithoutProxy
           commandPermission={commandPermission}
           eventActionsPermission={eventActionsPermission}
-          apiv3Put={props.appContainer.apiv3.put}
         />
       </Accordion>
       <Accordion

+ 5 - 3
packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcess.jsx

@@ -1,7 +1,10 @@
 import React, { useCallback, useState } from 'react';
+
+import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
-import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
+
+import { apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
 
 import { toastSuccess, toastError } from '../../../client/util/apiNotification';
@@ -170,7 +173,7 @@ PermissionSettingForEachPermissionTypeComponent.propTypes = {
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
 const ManageCommandsProcess = ({
-  apiv3Put, slackAppIntegrationId, permissionsForBroadcastUseCommands, permissionsForSingleUseCommands, permissionsForSlackEventActions,
+  slackAppIntegrationId, permissionsForBroadcastUseCommands, permissionsForSingleUseCommands, permissionsForSlackEventActions,
 }) => {
   const { t } = useTranslation();
 
@@ -401,7 +404,6 @@ const ManageCommandsProcess = ({
 };
 
 ManageCommandsProcess.propTypes = {
-  apiv3Put: PropTypes.func,
   slackAppIntegrationId: PropTypes.string.isRequired,
   permissionsForBroadcastUseCommands: PropTypes.object.isRequired,
   permissionsForSingleUseCommands: PropTypes.object.isRequired,

+ 5 - 3
packages/app/src/components/Admin/SlackIntegration/ManageCommandsProcessWithoutProxy.jsx

@@ -1,7 +1,10 @@
 import React, { useCallback, useEffect, useState } from 'react';
+
+import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
-import { defaultSupportedCommandsNameForBroadcastUse, defaultSupportedCommandsNameForSingleUse, defaultSupportedSlackEventActions } from '@growi/slack';
+
+import { apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
 
 import { toastSuccess, toastError } from '../../../client/util/apiNotification';
@@ -153,7 +156,7 @@ SinglePermissionSettingComponent.propTypes = {
 
 
 // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
-const ManageCommandsProcessWithoutProxy = ({ apiv3Put, commandPermission, eventActionsPermission }) => {
+const ManageCommandsProcessWithoutProxy = ({ commandPermission, eventActionsPermission }) => {
   const { t } = useTranslation();
   const [editingCommandPermission, setEditingCommandPermission] = useState({});
   const [editingEventActionsPermission, setEditingEventActionsPermission] = useState({});
@@ -267,7 +270,6 @@ const ManageCommandsProcessWithoutProxy = ({ apiv3Put, commandPermission, eventA
 };
 
 ManageCommandsProcessWithoutProxy.propTypes = {
-  apiv3Put: PropTypes.func,
   commandPermission: PropTypes.object,
   eventActionsPermission: PropTypes.object,
 };

+ 12 - 7
packages/app/src/components/Admin/SlackIntegration/OfficialBotSettings.jsx

@@ -1,17 +1,22 @@
 import React, { useState, useEffect, useCallback } from 'react';
+
+import { SlackbotType } from '@growi/slack';
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
-import { SlackbotType } from '@growi/slack';
 
-import loggerFactory from '~/utils/logger';
 import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Delete, apiv3Put } from '~/client/util/apiv3-client';
+import loggerFactory from '~/utils/logger';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
+
+
 import CustomBotWithProxyConnectionStatus from './CustomBotWithProxyConnectionStatus';
-import WithProxyAccordions from './WithProxyAccordions';
 import DeleteSlackBotSettingsModal from './DeleteSlackBotSettingsModal';
 import { SlackAppIntegrationControl } from './SlackAppIntegrationControl';
+import WithProxyAccordions from './WithProxyAccordions';
 
 const logger = loggerFactory('growi:cli:SlackIntegration:OfficialBotSettings');
 
@@ -38,7 +43,7 @@ const OfficialBotSettings = (props) => {
     }
 
     try {
-      await appContainer.apiv3.put(`/slack-integration-settings/slack-app-integrations/${slackIntegrationToChange._id}/make-primary`);
+      await apiv3Put(`/slack-integration-settings/slack-app-integrations/${slackIntegrationToChange._id}/make-primary`);
       if (onPrimaryUpdated != null) {
         onPrimaryUpdated();
       }
@@ -48,10 +53,10 @@ const OfficialBotSettings = (props) => {
       toastError(err, 'Failed to change isPrimary');
       logger.error('Failed to change isPrimary', err);
     }
-  }, [appContainer.apiv3, t, onPrimaryUpdated]);
+  }, [t, onPrimaryUpdated]);
 
   const deleteSlackAppIntegrationHandler = async() => {
-    await appContainer.apiv3.delete(`/slack-integration-settings/slack-app-integrations/${integrationIdToDelete}`);
+    await apiv3Delete(`/slack-integration-settings/slack-app-integrations/${integrationIdToDelete}`);
     try {
       if (props.onDeleteSlackAppIntegration != null) {
         props.onDeleteSlackAppIntegration();

+ 17 - 11
packages/app/src/components/Admin/SlackIntegration/SlackIntegration.jsx

@@ -1,19 +1,25 @@
 import React, { useState, useEffect, useCallback } from 'react';
+
+import { SlackbotType } from '@growi/slack';
 import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
-import { SlackbotType } from '@growi/slack';
 
 import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import {
+  apiv3Delete, apiv3Get, apiv3Post, apiv3Put,
+} from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../../UnstatedUtils';
 
-import OfficialBotSettings from './OfficialBotSettings';
-import CustomBotWithoutProxySettings from './CustomBotWithoutProxySettings';
-import CustomBotWithProxySettings from './CustomBotWithProxySettings';
-import ConfirmBotChangeModal from './ConfirmBotChangeModal';
 import BotTypeCard from './BotTypeCard';
+import ConfirmBotChangeModal from './ConfirmBotChangeModal';
+import CustomBotWithProxySettings from './CustomBotWithProxySettings';
+import CustomBotWithoutProxySettings from './CustomBotWithoutProxySettings';
 import DeleteSlackBotSettingsModal from './DeleteSlackBotSettingsModal';
+import OfficialBotSettings from './OfficialBotSettings';
+
 
 const botTypes = Object.values(SlackbotType);
 
@@ -40,7 +46,7 @@ const SlackIntegration = (props) => {
 
   const fetchSlackIntegrationData = useCallback(async() => {
     try {
-      const { data } = await appContainer.apiv3.get('/slack-integration-settings');
+      const { data } = await apiv3Get('/slack-integration-settings');
       const {
         slackSigningSecret,
         slackBotToken,
@@ -71,11 +77,11 @@ const SlackIntegration = (props) => {
     finally {
       setIsLoading(false);
     }
-  }, [appContainer.apiv3]);
+  }, []);
 
   const resetAllSettings = async() => {
     try {
-      await appContainer.apiv3.delete('/slack-integration-settings/bot-type');
+      await apiv3Delete('/slack-integration-settings/bot-type');
       fetchSlackIntegrationData();
       toastSuccess(t('admin:slack_integration.bot_all_reset_successful'));
     }
@@ -86,7 +92,7 @@ const SlackIntegration = (props) => {
 
   const createSlackIntegrationData = async() => {
     try {
-      await appContainer.apiv3.post('/slack-integration-settings/slack-app-integrations');
+      await apiv3Post('/slack-integration-settings/slack-app-integrations');
       fetchSlackIntegrationData();
       toastSuccess(t('admin:slack_integration.adding_slack_ws_integration_settings_successful'));
     }
@@ -106,7 +112,7 @@ const SlackIntegration = (props) => {
 
   const changeCurrentBotSettings = async(botType) => {
     try {
-      await appContainer.apiv3.put('/slack-integration-settings/bot-type', {
+      await apiv3Put('/slack-integration-settings/bot-type', {
         currentBotType: botType,
       });
       setSelectedBotType(null);

+ 13 - 13
packages/app/src/components/Admin/SlackIntegration/WithProxyAccordions.jsx

@@ -1,21 +1,23 @@
 /* eslint-disable react/prop-types */
 import React, { useState, useCallback } from 'react';
-import PropTypes from 'prop-types';
-import { useTranslation } from 'react-i18next';
-import { CopyToClipboard } from 'react-copy-to-clipboard';
 
 import { SlackbotType } from '@growi/slack';
-
+import PropTypes from 'prop-types';
+import { CopyToClipboard } from 'react-copy-to-clipboard';
+import { useTranslation } from 'react-i18next';
 import { Tooltip } from 'reactstrap';
+
+import AppContainer from '~/client/services/AppContainer';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
 
 import { withUnstatedContainers } from '../../UnstatedUtils';
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import AppContainer from '~/client/services/AppContainer';
 import Accordion from '../Common/Accordion';
-import { addLogs } from './slak-integration-util';
-import MessageBasedOnConnection from './MessageBasedOnConnection';
+
 import ManageCommandsProcess from './ManageCommandsProcess';
+import MessageBasedOnConnection from './MessageBasedOnConnection';
+import { addLogs } from './slak-integration-util';
 
 const logger = loggerFactory('growi:SlackIntegration:WithProxyAccordionsWrapper');
 
@@ -147,7 +149,7 @@ const GeneratingTokensAndRegisteringProxyServiceProcess = withUnstatedContainers
 
   const regenerateTokensHandler = async() => {
     try {
-      await appContainer.apiv3.put(`/slack-integration-settings/slack-app-integrations/${slackAppIntegrationId}/regenerate-tokens`);
+      await apiv3Put(`/slack-integration-settings/slack-app-integrations/${slackAppIntegrationId}/regenerate-tokens`);
       if (props.onUpdateTokens != null) {
         props.onUpdateTokens();
       }
@@ -342,7 +344,6 @@ const WithProxyAccordions = (props) => {
     '③': {
       title: 'manage_permission',
       content: <ManageCommandsProcess
-        apiv3Put={props.appContainer.apiv3.put}
         slackAppIntegrationId={props.slackAppIntegrationId}
         permissionsForBroadcastUseCommands={props.permissionsForBroadcastUseCommands}
         permissionsForSingleUseCommands={props.permissionsForSingleUseCommands}
@@ -352,7 +353,7 @@ const WithProxyAccordions = (props) => {
     '④': {
       title: 'test_connection',
       content: <TestProcess
-        apiv3Post={props.appContainer.apiv3.post}
+        apiv3Post={props.apiv3Post}
         slackAppIntegrationId={props.slackAppIntegrationId}
         onSubmitForm={submitForm}
         onSubmitFormFailed={submitFormFailed}
@@ -387,7 +388,6 @@ const WithProxyAccordions = (props) => {
     '⑤': {
       title: 'manage_permission',
       content: <ManageCommandsProcess
-        apiv3Put={props.appContainer.apiv3.put}
         slackAppIntegrationId={props.slackAppIntegrationId}
         permissionsForBroadcastUseCommands={props.permissionsForBroadcastUseCommands}
         permissionsForSingleUseCommands={props.permissionsForSingleUseCommands}
@@ -397,7 +397,7 @@ const WithProxyAccordions = (props) => {
     '⑥': {
       title: 'test_connection',
       content: <TestProcess
-        apiv3Post={props.appContainer.apiv3.post}
+        apiv3Post={props.apiv3Post}
         slackAppIntegrationId={props.slackAppIntegrationId}
         onSubmitForm={submitForm}
         onSubmitFormFailed={submitFormFailed}

+ 7 - 4
packages/app/src/components/Admin/UserGroupDetail/UserGroupPageList.jsx

@@ -1,13 +1,16 @@
 import React, { Fragment } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
+import AdminUserGroupDetailContainer from '~/client/services/AdminUserGroupDetailContainer';
+import AppContainer from '~/client/services/AppContainer';
+import { toastError } from '~/client/util/apiNotification';
+import { apiv3Get } from '~/client/util/apiv3-client';
+
 import PageListItemS from '../../PageList/PageListItemS';
 import PaginationWrapper from '../../PaginationWrapper';
 import { withUnstatedContainers } from '../../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
-import AdminUserGroupDetailContainer from '~/client/services/AdminUserGroupDetailContainer';
-import { toastError } from '~/client/util/apiNotification';
 
 class UserGroupPageList extends React.Component {
 
@@ -33,7 +36,7 @@ class UserGroupPageList extends React.Component {
     const offset = (pageNum - 1) * limit;
 
     try {
-      const res = await this.props.appContainer.apiv3.get(`/user-groups/${this.props.adminUserGroupDetailContainer.state.userGroup._id}/pages`, {
+      const res = await apiv3Get(`/user-groups/${this.props.adminUserGroupDetailContainer.state.userGroup._id}/pages`, {
         limit,
         offset,
       });

+ 5 - 2
packages/app/src/components/Admin/Users/PasswordResetModal.jsx

@@ -1,13 +1,16 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
+import AppContainer from '~/client/services/AppContainer';
 import { toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+
 import { withUnstatedContainers } from '../../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
 
 class PasswordResetModal extends React.Component {
 
@@ -25,7 +28,7 @@ class PasswordResetModal extends React.Component {
   async resetPassword() {
     const { t, appContainer, userForPasswordResetModal } = this.props;
     try {
-      const res = await appContainer.apiv3Put('/users/reset-password', { id: userForPasswordResetModal._id });
+      const res = await apiv3Put('/users/reset-password', { id: userForPasswordResetModal._id });
       const { newPassword } = res.data;
       this.setState({ temporaryPassword: newPassword, isPasswordResetDone: true });
     }

+ 8 - 4
packages/app/src/components/Admin/Users/SendInvitationEmailButton.jsx

@@ -1,9 +1,13 @@
 import React from 'react';
-import { useTranslation } from 'react-i18next';
+
 import PropTypes from 'prop-types';
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import AppContainer from '~/client/services/AppContainer';
+import { useTranslation } from 'react-i18next';
+
 import AdminUsersContainer from '~/client/services/AdminUsersContainer';
+import AppContainer from '~/client/services/AppContainer';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+
 import { withUnstatedContainers } from '../../UnstatedUtils';
 
 const SendInvitationEmailButton = (props) => {
@@ -16,7 +20,7 @@ const SendInvitationEmailButton = (props) => {
 
   const onClickSendInvitationEmailButton = async() => {
     try {
-      const res = await appContainer.apiv3Put('users/send-invitation-email', { id: user._id });
+      const res = await apiv3Put('/users/send-invitation-email', { id: user._id });
       const { failedToSendEmail } = res.data;
       if (failedToSendEmail == null) {
         const msg = `Email has been sent<br>・${user.email}`;

+ 6 - 2
packages/app/src/components/ArchiveCreateModal.jsx

@@ -1,12 +1,16 @@
 import React, { useState, useCallback } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
+
 import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from './UnstatedUtils';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from './UnstatedUtils';
 
 
 const ArchiveCreateModal = (props) => {
@@ -56,7 +60,7 @@ const ArchiveCreateModal = (props) => {
 
   async function done() {
     try {
-      await appContainer.apiv3Post('/page/archive', {
+      await apiv3Post('/page/archive', {
         rootPagePath: props.path,
         isCommentDownload,
         isAttachmentFileDownload,

+ 7 - 6
packages/app/src/components/EmptyTrashModal.jsx

@@ -1,16 +1,17 @@
 import React, { useState } from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
 import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
-import { withTranslation } from 'react-i18next';
-import { withUnstatedContainers } from './UnstatedUtils';
-
-import SocketIoContainer from '~/client/services/SocketIoContainer';
 import AppContainer from '~/client/services/AppContainer';
+import SocketIoContainer from '~/client/services/SocketIoContainer';
+import { apiv3Delete } from '~/client/util/apiv3-client';
+
 import ApiErrorMessageList from './PageManagement/ApiErrorMessageList';
+import { withUnstatedContainers } from './UnstatedUtils';
 
 const EmptyTrashModal = (props) => {
   const {
@@ -23,7 +24,7 @@ const EmptyTrashModal = (props) => {
     setErrs(null);
 
     try {
-      await appContainer.apiv3Delete('/pages/empty-trash');
+      await apiv3Delete('/pages/empty-trash');
       window.location.reload();
     }
     catch (err) {

+ 2 - 1
packages/app/src/components/Me/ApiSettings.jsx

@@ -7,6 +7,7 @@ import { withTranslation } from 'react-i18next';
 import AppContainer from '~/client/services/AppContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
@@ -23,7 +24,7 @@ class ApiSettings extends React.Component {
     const { t, appContainer, personalContainer } = this.props;
 
     try {
-      await appContainer.apiv3Put('/personal-setting/api-token');
+      await apiv3Put('/personal-setting/api-token');
 
       await personalContainer.retrievePersonalData();
       toastSuccess(t('toaster.update_successed', { target: t('page_me_apitoken.api_token') }));

+ 6 - 25
packages/app/src/components/Me/EditorSettings.tsx

@@ -3,17 +3,13 @@ import React, {
   FC, SetStateAction, useCallback, useEffect, useState,
 } from 'react';
 
-import PropTypes from 'prop-types';
 import { useTranslation } from 'react-i18next';
 
-import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
-
-import { withUnstatedContainers } from '../UnstatedUtils';
+import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 
 
 type EditorSettingsBodyProps = {
-  appContainer: AppContainer
 }
 
 type RuleListGroupProps = {
@@ -153,7 +149,7 @@ const japaneseRulesMenuItems = [
 
 const RuleListGroup: FC<RuleListGroupProps> = ({
   title, ruleList, textlintRules, setTextlintRules,
-}) => {
+}: RuleListGroupProps) => {
   const { t } = useTranslation();
 
   const isCheckedRule = (ruleName: string) => (
@@ -200,21 +196,12 @@ const RuleListGroup: FC<RuleListGroupProps> = ({
 };
 
 
-RuleListGroup.propTypes = {
-  title: PropTypes.string.isRequired,
-  ruleList: PropTypes.array.isRequired,
-  textlintRules: PropTypes.array.isRequired,
-  setTextlintRules: PropTypes.func.isRequired,
-};
-
-
-const EditorSettingsBody: FC<EditorSettingsBodyProps> = (props) => {
+export const EditorSettings: FC<EditorSettingsBodyProps> = () => {
   const { t } = useTranslation();
-  const { appContainer } = props;
   const [textlintRules, setTextlintRules] = useState<LintRule[]>([]);
 
   const initializeEditorSettings = useCallback(async() => {
-    const { data } = await appContainer.apiv3Get('/personal-setting/editor-settings');
+    const { data } = await apiv3Get('/personal-setting/editor-settings');
     const retrievedRules: LintRule[] = data?.textlintSettings?.textlintRules;
 
     // If database is empty, add default rules to state
@@ -234,7 +221,7 @@ const EditorSettingsBody: FC<EditorSettingsBodyProps> = (props) => {
       setTextlintRules([...defaultCommonRules, ...defaultJapaneseRules]);
     }
 
-  }, [appContainer]);
+  }, []);
 
   useEffect(() => {
     initializeEditorSettings();
@@ -242,7 +229,7 @@ const EditorSettingsBody: FC<EditorSettingsBodyProps> = (props) => {
 
   const updateRulesHandler = async() => {
     try {
-      const { data } = await appContainer.apiv3Put('/personal-setting/editor-settings', { textlintSettings: { textlintRules: [...textlintRules] } });
+      const { data } = await apiv3Put('/personal-setting/editor-settings', { textlintSettings: { textlintRules: [...textlintRules] } });
       setTextlintRules(data.textlintSettings.textlintRules);
       toastSuccess(t('toaster.update_successed', { target: 'Updated Textlint Settings' }));
     }
@@ -285,9 +272,3 @@ const EditorSettingsBody: FC<EditorSettingsBodyProps> = (props) => {
     </div>
   );
 };
-
-export const EditorSettings = withUnstatedContainers(EditorSettingsBody, [AppContainer]);
-
-EditorSettingsBody.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-};

+ 6 - 11
packages/app/src/components/Me/PasswordSettings.jsx

@@ -4,20 +4,18 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import AppContainer from '~/client/services/AppContainer';
 import PersonalContainer from '~/client/services/PersonalContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
 
 class PasswordSettings extends React.Component {
 
-  constructor(appContainer) {
+  constructor() {
     super();
 
-    this.appContainer = appContainer;
-
     this.state = {
       retrieveError: null,
       oldPassword: '',
@@ -32,10 +30,8 @@ class PasswordSettings extends React.Component {
   }
 
   async componentDidMount() {
-    const { appContainer } = this.props;
-
     try {
-      const res = await appContainer.apiv3Get('/personal-setting/is-password-set');
+      const res = await apiv3Get('/personal-setting/is-password-set');
       const { isPasswordSet } = res.data;
       this.setState({ isPasswordSet });
     }
@@ -47,11 +43,11 @@ class PasswordSettings extends React.Component {
   }
 
   async onClickSubmit() {
-    const { t, appContainer, personalContainer } = this.props;
+    const { t, personalContainer } = this.props;
     const { oldPassword, newPassword, newPasswordConfirm } = this.state;
 
     try {
-      await appContainer.apiv3Put('/personal-setting/password', {
+      await apiv3Put('/personal-setting/password', {
         oldPassword, newPassword, newPasswordConfirm,
       });
       this.setState({ oldPassword: '', newPassword: '', newPasswordConfirm: '' });
@@ -159,11 +155,10 @@ class PasswordSettings extends React.Component {
 }
 
 
-const PasswordSettingsWrapper = withUnstatedContainers(PasswordSettings, [AppContainer, PersonalContainer]);
+const PasswordSettingsWrapper = withUnstatedContainers(PasswordSettings, [PersonalContainer]);
 
 PasswordSettings.propTypes = {
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   personalContainer: PropTypes.instanceOf(PersonalContainer).isRequired,
 };
 

+ 6 - 7
packages/app/src/components/MyDraftList/MyDraftList.jsx

@@ -1,14 +1,14 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
 import EditorContainer from '~/client/services/EditorContainer';
+import PageContainer from '~/client/services/PageContainer';
+import { apiGet } from '~/client/util/apiv1-client';
 
 import PaginationWrapper from '../PaginationWrapper';
+import { withUnstatedContainers } from '../UnstatedUtils';
 
 import Draft from './Draft';
 
@@ -49,7 +49,7 @@ class MyDraftList extends React.Component {
       return;
     }
 
-    const res = await this.props.appContainer.apiGet('/pages.exist', {
+    const res = await apiGet('/pages.exist', {
       pagePaths: JSON.stringify(Object.keys(draftsAsObj)),
     });
 
@@ -174,13 +174,12 @@ class MyDraftList extends React.Component {
 /**
  * Wrapper component for using unstated
  */
-const MyDraftListWrapper = withUnstatedContainers(MyDraftList, [AppContainer, PageContainer, EditorContainer]);
+const MyDraftListWrapper = withUnstatedContainers(MyDraftList, [PageContainer, EditorContainer]);
 
 
 MyDraftList.propTypes = {
   t: PropTypes.func.isRequired, // react-i18next
 
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
   editorContainer: PropTypes.instanceOf(EditorContainer).isRequired,
 };

+ 7 - 4
packages/app/src/components/Page/RevisionLoader.jsx

@@ -1,16 +1,19 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import { Waypoint } from 'react-waypoint';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
-import GrowiRenderer from '~/client/util/GrowiRenderer';
 import AppContainer from '~/client/services/AppContainer';
+import GrowiRenderer from '~/client/util/GrowiRenderer';
+import { apiv3Get } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
 
+import { withUnstatedContainers } from '../UnstatedUtils';
+
 import RevisionRenderer from './RevisionRenderer';
 
+
 /**
  * Load data from server and render RevisionBody component
  */
@@ -47,7 +50,7 @@ class LegacyRevisionLoader extends React.Component {
 
     // load data with REST API
     try {
-      const res = await this.props.appContainer.apiv3Get(`/revisions/${revisionId}`, { pageId });
+      const res = await apiv3Get(`/revisions/${revisionId}`, { pageId });
 
       this.setState({
         markdown: res.data?.revision?.body,

+ 5 - 2
packages/app/src/components/PageAttachment.jsx

@@ -6,12 +6,15 @@ import { withTranslation } from 'react-i18next';
 
 import AppContainer from '~/client/services/AppContainer';
 import PageContainer from '~/client/services/PageContainer';
+import { apiPost } from '~/client/util/apiv1-client';
+import { apiv3Get } from '~/client/util/apiv3-client';
 
 import DeleteAttachmentModal from './PageAttachment/DeleteAttachmentModal';
 import PageAttachmentList from './PageAttachment/PageAttachmentList';
 import PaginationWrapper from './PaginationWrapper';
 import { withUnstatedContainers } from './UnstatedUtils';
 
+
 class PageAttachment extends React.Component {
 
   constructor(props) {
@@ -40,7 +43,7 @@ class PageAttachment extends React.Component {
 
     if (!pageId) { return }
 
-    const res = await this.props.appContainer.apiv3Get('/attachment/list', { pageId, page });
+    const res = await apiv3Get('/attachment/list', { pageId, page });
     const attachments = res.data.paginateResult.docs;
     const totalAttachments = res.data.paginateResult.totalDocs;
     const pagingLimit = res.data.paginateResult.limit;
@@ -88,7 +91,7 @@ class PageAttachment extends React.Component {
       deleting: true,
     });
 
-    this.props.appContainer.apiPost('/attachments.remove', { attachment_id: attachmentId })
+    apiPost('/attachments.remove', { attachment_id: attachmentId })
       .then((res) => {
         this.setState({
           attachments: this.state.attachments.filter((at) => {

+ 9 - 7
packages/app/src/components/PageComment.tsx

@@ -4,17 +4,19 @@ import React, {
 
 import { Button } from 'reactstrap';
 
-import CommentEditor from './PageComment/CommentEditor';
-import Comment from './PageComment/Comment';
-import ReplayComments from './PageComment/ReplayComments';
-import DeleteCommentModal from './PageComment/DeleteCommentModal';
 
 import AppContainer from '~/client/services/AppContainer';
 import { toastError } from '~/client/util/apiNotification';
+import { apiPost } from '~/client/util/apiv1-client';
 
+import { ICommentHasId, ICommentHasIdList } from '../interfaces/comment';
 import { useSWRxPageComment } from '../stores/comment';
 
-import { ICommentHasId, ICommentHasIdList } from '../interfaces/comment';
+
+import Comment from './PageComment/Comment';
+import CommentEditor from './PageComment/CommentEditor';
+import DeleteCommentModal from './PageComment/DeleteCommentModal';
+import ReplayComments from './PageComment/ReplayComments';
 
 type Props = {
   appContainer: AppContainer,
@@ -97,14 +99,14 @@ const PageComment:FC<Props> = memo((props:Props):JSX.Element => {
   const onDeleteComment = useCallback(async() => {
     if (commentToBeDeleted == null) return;
     try {
-      await appContainer.apiPost('/comments.remove', { comment_id: commentToBeDeleted._id });
+      await apiPost('/comments.remove', { comment_id: commentToBeDeleted._id });
       onDeleteCommentAfterOperation();
     }
     catch (error:unknown) {
       setErrorMessageOnDelete(error as string);
       toastError(`error: ${error}`);
     }
-  }, [appContainer, commentToBeDeleted, onDeleteCommentAfterOperation]);
+  }, [commentToBeDeleted, onDeleteCommentAfterOperation]);
 
   const generateCommentInnerElement = (comment: ICommentHasId) => (
     <Comment

+ 17 - 16
packages/app/src/components/PageEditor.jsx

@@ -1,30 +1,31 @@
 import React from 'react';
-import PropTypes from 'prop-types';
-import detectIndent from 'detect-indent';
 
-import { throttle, debounce } from 'throttle-debounce';
 import { envUtils } from '@growi/core';
-import loggerFactory from '~/utils/logger';
+import detectIndent from 'detect-indent';
+import PropTypes from 'prop-types';
+import { throttle, debounce } from 'throttle-debounce';
 
 import AppContainer from '~/client/services/AppContainer';
+import EditorContainer from '~/client/services/EditorContainer';
 import PageContainer from '~/client/services/PageContainer';
+import { apiGet, apiPost } from '~/client/util/apiv1-client';
+import { getOptionsToSave } from '~/client/util/editor';
+import { useIsEditable, useSlackChannels } from '~/stores/context';
+import { useIsSlackEnabled } from '~/stores/editor';
+import {
+  useEditorMode, useSelectedGrant, useSelectedGrantGroupId, useSelectedGrantGroupName,
+} from '~/stores/ui';
+import loggerFactory from '~/utils/logger';
 
-import { withUnstatedContainers } from './UnstatedUtils';
+
+import { ConflictDiffModal } from './PageEditor/ConflictDiffModal';
 import Editor from './PageEditor/Editor';
 import Preview from './PageEditor/Preview';
 import scrollSyncHelper from './PageEditor/ScrollSyncHelper';
-import { ConflictDiffModal } from './PageEditor/ConflictDiffModal';
-
-import EditorContainer from '~/client/services/EditorContainer';
+import { withUnstatedContainers } from './UnstatedUtils';
 
-import { getOptionsToSave } from '~/client/util/editor';
 
 // TODO: remove this when omitting unstated is completed
-import {
-  useEditorMode, useSelectedGrant, useSelectedGrantGroupId, useSelectedGrantGroupName,
-} from '~/stores/ui';
-import { useIsEditable, useSlackChannels } from '~/stores/context';
-import { useIsSlackEnabled } from '~/stores/editor';
 
 const logger = loggerFactory('growi:PageEditor');
 
@@ -170,7 +171,7 @@ class PageEditor extends React.Component {
     } = this.props;
 
     try {
-      let res = await appContainer.apiGet('/attachments.limit', {
+      let res = await apiGet('/attachments.limit', {
         fileSize: file.size,
       });
 
@@ -187,7 +188,7 @@ class PageEditor extends React.Component {
         formData.append('page_id', pageContainer.state.pageId);
       }
 
-      res = await appContainer.apiPost('/attachments.add', formData);
+      res = await apiPost('/attachments.add', formData);
       const attachment = res.attachment;
       const fileName = attachment.originalName;
 

+ 10 - 11
packages/app/src/components/PageEditor/LinkEditModal.jsx

@@ -1,6 +1,9 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import path from 'path';
+
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
 import {
   Modal,
   ModalHeader,
@@ -9,21 +12,18 @@ import {
   Popover,
   PopoverBody,
 } from 'reactstrap';
-
-import path from 'path';
 import validator from 'validator';
-import { withTranslation } from 'react-i18next';
 
-import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
 import Linker from '~/client/models/Linker';
+import PageContainer from '~/client/services/PageContainer';
+import { apiv3Get } from '~/client/util/apiv3-client';
 
-import PreviewWithSuspense from './PreviewWithSuspense';
 import PagePreviewIcon from '../Icons/PagePreviewIcon';
 import SearchTypeahead from '../SearchTypeahead';
-
 import { withUnstatedContainers } from '../UnstatedUtils';
 
+import PreviewWithSuspense from './PreviewWithSuspense';
+
 
 class LinkEditModal extends React.PureComponent {
 
@@ -164,7 +164,7 @@ class LinkEditModal extends React.PureComponent {
       const pageId = isPermanentLink ? pathWithoutFragment.slice(1) : null;
 
       try {
-        const { data } = await this.props.appContainer.apiv3Get('/page', { path: pathWithoutFragment, page_id: pageId });
+        const { data } = await apiv3Get('/page', { path: pathWithoutFragment, page_id: pageId });
         const { page } = data;
         markdown = page.revision.body;
         pagePath = page.path;
@@ -460,7 +460,6 @@ class LinkEditModal extends React.PureComponent {
 
 LinkEditModal.propTypes = {
   t: PropTypes.func.isRequired,
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
   onSave: PropTypes.func,
 };
@@ -468,6 +467,6 @@ LinkEditModal.propTypes = {
 /**
  * Wrapper component for using unstated
  */
-const LinkEditModalWrapper = withUnstatedContainers(LinkEditModal, [AppContainer, PageContainer]);
+const LinkEditModalWrapper = withUnstatedContainers(LinkEditModal, [PageContainer]);
 
 export default withTranslation('translation', { withRef: true })(LinkEditModalWrapper);

+ 6 - 5
packages/app/src/components/PageEditor/OptionsSelector.jsx

@@ -1,16 +1,18 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-
 import {
   Dropdown, DropdownToggle, DropdownMenu, DropdownItem,
 } from 'reactstrap';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
 import AppContainer from '~/client/services/AppContainer';
 import EditorContainer from '~/client/services/EditorContainer';
 import { toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../UnstatedUtils';
+
 import { DownloadDictModal } from './DownloadDictModal';
 
 
@@ -133,9 +135,8 @@ class OptionsSelector extends React.Component {
   }
 
   async updateIsTextlintEnabledToDB(newVal) {
-    const { appContainer } = this.props;
     try {
-      await appContainer.apiv3Put('/personal-setting/editor-settings', { textlintSettings: { isTextlintEnabled: newVal } });
+      await apiv3Put('/personal-setting/editor-settings', { textlintSettings: { isTextlintEnabled: newVal } });
     }
     catch (err) {
       toastError(err);

+ 12 - 13
packages/app/src/components/PageEditorByHackmd.jsx

@@ -1,24 +1,23 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import loggerFactory from '~/utils/logger';
 
 
 import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
 import EditorContainer from '~/client/services/EditorContainer';
-
-import { withUnstatedContainers } from './UnstatedUtils';
-import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
-
+import PageContainer from '~/client/services/PageContainer';
+import { apiPost } from '~/client/util/apiv1-client';
 import { getOptionsToSave } from '~/client/util/editor';
-
-// TODO: remove this when omitting unstated is completed
+import { useSlackChannels } from '~/stores/context';
+import { useIsSlackEnabled } from '~/stores/editor';
 import {
   useEditorMode, useSelectedGrant, useSelectedGrantGroupId, useSelectedGrantGroupName,
 } from '~/stores/ui';
-import { useSlackChannels } from '~/stores/context';
-import { useIsSlackEnabled } from '~/stores/editor';
+import loggerFactory from '~/utils/logger';
+
+import HackmdEditor from './PageEditorByHackmd/HackmdEditor';
+import { withUnstatedContainers } from './UnstatedUtils';
 
 const logger = loggerFactory('growi:PageEditorByHackmd');
 
@@ -105,7 +104,7 @@ class PageEditorByHackmd extends React.Component {
     };
 
     try {
-      const res = await this.props.appContainer.apiPost('/hackmd.integrate', params);
+      const res = await apiPost('/hackmd.integrate', params);
 
       if (!res.ok) {
         throw new Error(res.error);
@@ -147,7 +146,7 @@ class PageEditorByHackmd extends React.Component {
     const { pageId } = pageContainer.state;
 
     try {
-      const res = await this.props.appContainer.apiPost('/hackmd.discard', { pageId });
+      const res = await apiPost('/hackmd.discard', { pageId });
 
       if (!res.ok) {
         throw new Error(res.error);
@@ -220,7 +219,7 @@ class PageEditorByHackmd extends React.Component {
       pageId: pageContainer.state.pageId,
     };
     try {
-      await this.props.appContainer.apiPost('/hackmd.saveOnHackmd', params);
+      await apiPost('/hackmd.saveOnHackmd', params);
     }
     catch (err) {
       logger.error(err);

+ 9 - 14
packages/app/src/components/PageList/BookmarkList.jsx

@@ -1,21 +1,22 @@
 import React, { useState, useCallback, useEffect } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import loggerFactory from '~/utils/logger';
-import { withUnstatedContainers } from '../UnstatedUtils';
 
-
-import AppContainer from '~/client/services/AppContainer';
 import { toastError } from '~/client/util/apiNotification';
+import { apiv3Get } from '~/client/util/apiv3-client';
+import loggerFactory from '~/utils/logger';
 
 import PaginationWrapper from '../PaginationWrapper';
 
+
 import PageListItemS from './PageListItemS';
 
+
 const logger = loggerFactory('growi:BookmarkList');
 
 const BookmarkList = (props) => {
-  const { t, appContainer, userId } = props;
+  const { t, userId } = props;
 
   const [pages, setPages] = useState([]);
 
@@ -31,7 +32,7 @@ const BookmarkList = (props) => {
     const page = activePage;
 
     try {
-      const res = await appContainer.apiv3Get(`/bookmarks/${userId}`, { page });
+      const res = await apiv3Get(`/bookmarks/${userId}`, { page });
       const { paginationResult } = res.data;
 
       setPages(paginationResult.docs);
@@ -42,7 +43,7 @@ const BookmarkList = (props) => {
       logger.error('failed to fetch data', error);
       toastError(error, 'Error occurred in bookmark page list');
     }
-  }, [appContainer, activePage, userId]);
+  }, [activePage, userId]);
 
   useEffect(() => {
     getMyBookmarkList();
@@ -82,16 +83,10 @@ const BookmarkList = (props) => {
 
 };
 
-/**
- * Wrapper component for using unstated
- */
-const BookmarkListWrapper = withUnstatedContainers(BookmarkList, [AppContainer]);
-
 BookmarkList.propTypes = {
   t: PropTypes.func.isRequired,
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 
   userId: PropTypes.string.isRequired,
 };
 
-export default withTranslation()(BookmarkListWrapper);
+export default BookmarkList;

+ 5 - 4
packages/app/src/components/PageTimeline.jsx

@@ -1,14 +1,15 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 
 import AppContainer from '~/client/services/AppContainer';
 import PageContainer from '~/client/services/PageContainer';
-import PaginationWrapper from './PaginationWrapper';
-import { withUnstatedContainers } from './UnstatedUtils';
+import { apiv3Get } from '~/client/util/apiv3-client';
 
 import RevisionLoader from './Page/RevisionLoader';
+import PaginationWrapper from './PaginationWrapper';
+import { withUnstatedContainers } from './UnstatedUtils';
 
 
 class PageTimeline extends React.Component {
@@ -34,7 +35,7 @@ class PageTimeline extends React.Component {
     const { path } = pageContainer.state;
     const page = selectedPage;
 
-    const res = await appContainer.apiv3Get('/pages/list', { path, page });
+    const res = await apiv3Get('/pages/list', { path, page });
     const totalPageItems = res.data.totalCount;
     const pages = res.data.pages;
     const pagingLimit = res.data.limit;

+ 7 - 3
packages/app/src/components/PasswordResetExecutionForm.jsx

@@ -1,10 +1,14 @@
 import React, { useState } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import loggerFactory from '~/utils/logger';
-import { withUnstatedContainers } from './UnstatedUtils';
+
 import AppContainer from '~/client/services/AppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Put } from '~/client/util/apiv3-client';
+import loggerFactory from '~/utils/logger';
+
+import { withUnstatedContainers } from './UnstatedUtils';
 
 const logger = loggerFactory('growi:passwordReset');
 
@@ -34,7 +38,7 @@ const PasswordResetExecutionForm = (props) => {
     }
 
     try {
-      await appContainer.apiv3Put('/forgot-password', {
+      await apiv3Put('/forgot-password', {
         token, newPassword, newPasswordConfirm,
       });
 

+ 5 - 2
packages/app/src/components/PasswordResetRequestForm.jsx

@@ -1,9 +1,12 @@
 import React, { useState } from 'react';
+
 import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
 
 import AppContainer from '~/client/services/AppContainer';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
+
 import { withUnstatedContainers } from './UnstatedUtils';
 
 
@@ -23,7 +26,7 @@ const PasswordResetRequestForm = (props) => {
     }
 
     try {
-      await appContainer.apiv3Post('/forgot-password', { email });
+      await apiv3Post('/forgot-password', { email });
       toastSuccess(t('forgot_password.success_to_send_email'));
     }
     catch (err) {

+ 5 - 12
packages/app/src/components/RecentCreated/RecentCreated.jsx

@@ -1,8 +1,8 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 
-import { withUnstatedContainers } from '../UnstatedUtils';
-import AppContainer from '~/client/services/AppContainer';
+import { apiv3Get } from '~/client/util/apiv3-client';
 
 import PageListItemS from '../PageList/PageListItemS';
 import PaginationWrapper from '../PaginationWrapper';
@@ -32,11 +32,11 @@ class RecentCreated extends React.Component {
   }
 
   async getRecentCreatedList(selectedPage) {
-    const { appContainer, userId } = this.props;
+    const { userId } = this.props;
     const page = selectedPage;
 
     // pagesList get and pagination calculate
-    const res = await appContainer.apiv3Get(`/users/${userId}/recent`, { page });
+    const res = await apiv3Get(`/users/${userId}/recent`, { page });
     const { totalCount, pages, limit } = res.data;
 
     this.setState({
@@ -84,15 +84,8 @@ class RecentCreated extends React.Component {
 
 }
 
-/**
- * Wrapper component for using unstated
- */
-const RecentCreatedWrapper = withUnstatedContainers(RecentCreated, [AppContainer]);
-
 RecentCreated.propTypes = {
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-
   userId: PropTypes.string.isRequired,
 };
 
-export default RecentCreatedWrapper;
+export default RecentCreated;

+ 3 - 4
packages/app/src/components/SavePageControls/GrantSelector.jsx

@@ -1,9 +1,7 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-
-
 import {
   UncontrolledDropdown,
   DropdownToggle, DropdownMenu, DropdownItem,
@@ -13,6 +11,7 @@ import {
 
 
 import AppContainer from '~/client/services/AppContainer';
+import { apiGet } from '~/client/util/apiv1-client';
 
 import { withUnstatedContainers } from '../UnstatedUtils';
 
@@ -69,7 +68,7 @@ class GrantSelector extends React.Component {
    * Retrieve user-group-relations data from backend
    */
   retrieveUserGroupRelations() {
-    this.props.appContainer.apiGet('/me/user-group-relations')
+    apiGet('/me/user-group-relations')
       .then((res) => {
         return res.userGroupRelations;
       })

+ 14 - 14
packages/app/src/components/ShareLink/ShareLink.jsx

@@ -1,16 +1,17 @@
 import React from 'react';
-import PropTypes from 'prop-types';
 
+import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
-import { withUnstatedContainers } from '../UnstatedUtils';
 
-import AppContainer from '~/client/services/AppContainer';
+
 import PageContainer from '~/client/services/PageContainer';
+import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Delete, apiv3Get } from '~/client/util/apiv3-client';
 
-import ShareLinkList from './ShareLinkList';
-import ShareLinkForm from './ShareLinkForm';
+import { withUnstatedContainers } from '../UnstatedUtils';
 
-import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import ShareLinkForm from './ShareLinkForm';
+import ShareLinkList from './ShareLinkList';
 
 class ShareLink extends React.Component {
 
@@ -31,11 +32,11 @@ class ShareLink extends React.Component {
   }
 
   async retrieveShareLinks() {
-    const { appContainer, pageContainer } = this.props;
+    const { pageContainer } = this.props;
     const { pageId } = pageContainer.state;
 
     try {
-      const res = await appContainer.apiv3.get('/share-links/', { relatedPage: pageId });
+      const res = await apiv3Get('/share-links/', { relatedPage: pageId });
       const { shareLinksResult } = res.data;
       this.setState({ shareLinks: shareLinksResult });
     }
@@ -51,11 +52,11 @@ class ShareLink extends React.Component {
   }
 
   async deleteAllLinksButtonHandler() {
-    const { t, appContainer, pageContainer } = this.props;
+    const { t, pageContainer } = this.props;
     const { pageId } = pageContainer.state;
 
     try {
-      const res = await appContainer.apiv3.delete('/share-links/', { relatedPage: pageId });
+      const res = await apiv3Delete('/share-links/', { relatedPage: pageId });
       const count = res.data.n;
       toastSuccess(t('toaster.remove_share_link', { count }));
     }
@@ -67,10 +68,10 @@ class ShareLink extends React.Component {
   }
 
   async deleteLinkById(shareLinkId) {
-    const { t, appContainer } = this.props;
+    const { t } = this.props;
 
     try {
-      const res = await appContainer.apiv3Delete(`/share-links/${shareLinkId}`);
+      const res = await apiv3Delete(`/share-links/${shareLinkId}`);
       const { deletedShareLink } = res.data;
       toastSuccess(t('toaster.remove_share_link_success', { shareLinkId: deletedShareLink._id }));
     }
@@ -114,11 +115,10 @@ class ShareLink extends React.Component {
 /**
  * Wrapper component for using unstated
  */
-const ShareLinkWrapper = withUnstatedContainers(ShareLink, [AppContainer, PageContainer]);
+const ShareLinkWrapper = withUnstatedContainers(ShareLink, [PageContainer]);
 
 ShareLink.propTypes = {
   t: PropTypes.func.isRequired, //  i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
 };
 

+ 10 - 11
packages/app/src/components/ShareLink/ShareLinkForm.jsx

@@ -1,16 +1,16 @@
 import React from 'react';
-import PropTypes from 'prop-types';
-
-import { withTranslation } from 'react-i18next';
-import { format, parse } from 'date-fns';
 
 import { isInteger } from 'core-js/fn/number';
-import { withUnstatedContainers } from '../UnstatedUtils';
+import { format, parse } from 'date-fns';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
 
+import PageContainer from '~/client/services/PageContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
+import { apiv3Post } from '~/client/util/apiv3-client';
+
+import { withUnstatedContainers } from '../UnstatedUtils';
 
-import AppContainer from '~/client/services/AppContainer';
-import PageContainer from '~/client/services/PageContainer';
 
 class ShareLinkForm extends React.Component {
 
@@ -110,7 +110,7 @@ class ShareLinkForm extends React.Component {
 
   async handleIssueShareLink() {
     const {
-      t, appContainer, pageContainer,
+      t, pageContainer,
     } = this.props;
     const { pageId } = pageContainer.state;
     const { description } = this.state;
@@ -125,7 +125,7 @@ class ShareLinkForm extends React.Component {
     }
 
     try {
-      await appContainer.apiv3Post('/share-links/', { relatedPage: pageId, expiredAt, description });
+      await apiv3Post('/share-links/', { relatedPage: pageId, expiredAt, description });
       this.closeForm();
       toastSuccess(t('toaster.issue_share_link'));
     }
@@ -261,11 +261,10 @@ class ShareLinkForm extends React.Component {
 /**
  * Wrapper component for using unstated
  */
-const ShareLinkFormWrapper = withUnstatedContainers(ShareLinkForm, [AppContainer, PageContainer]);
+const ShareLinkFormWrapper = withUnstatedContainers(ShareLinkForm, [PageContainer]);
 
 ShareLinkForm.propTypes = {
   t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
   onCloseForm: PropTypes.func,
 };

+ 6 - 7
packages/app/src/components/StaffCredit/StaffCredit.jsx

@@ -1,11 +1,13 @@
 import React from 'react';
+
 import PropTypes from 'prop-types';
 import {
   Modal, ModalBody,
 } from 'reactstrap';
+
+import { apiv3Get } from '~/client/util/apiv3-client';
 import loggerFactory from '~/utils/logger';
-import AppContainer from '~/client/services/AppContainer';
-import { withUnstatedContainers } from '../UnstatedUtils';
+
 
 /**
  * Page staff credit component
@@ -86,7 +88,7 @@ class StaffCredit extends React.Component {
   }
 
   async componentDidMount() {
-    const res = await this.props.appContainer.apiv3Get('/staffs');
+    const res = await apiv3Get('/staffs');
     const contributors = res.data.contributors;
     this.setState({ contributors });
 
@@ -134,11 +136,8 @@ class StaffCredit extends React.Component {
 
 }
 
-const StaffCreditWrapper = withUnstatedContainers(StaffCredit, [AppContainer]);
-
 StaffCredit.propTypes = {
   onClosed: PropTypes.func,
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
 };
 
-export default StaffCreditWrapper;
+export default StaffCredit;