Yuki Takei 2 месяцев назад
Родитель
Сommit
ecf66f384c

+ 27 - 39
apps/app/src/client/components/Admin/AdminHome/AdminHome.tsx

@@ -1,41 +1,33 @@
 import type { FC } from 'react';
-import { useCallback, useEffect, useId } from 'react';
+import { useId, useState } from 'react';
 import { useTranslation } from 'next-i18next';
 import { CopyToClipboard } from 'react-copy-to-clipboard';
 import { Tooltip } from 'reactstrap';
 
-import AdminHomeContainer from '~/client/services/AdminHomeContainer';
-import { toastError } from '~/client/util/toastr';
+import { useSWRxAdminHome } from '~/stores/admin/admin-home';
 import { useSWRxV5MigrationStatus } from '~/stores/page-listing';
-import loggerFactory from '~/utils/logger';
+import { generatePrefilledHostInformationMarkdown } from '~/utils/admin-home';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
 import { EnvVarsTable } from './EnvVarsTable';
 import SystemInfomationTable from './SystemInfomationTable';
 
-const logger = loggerFactory('growi:admin');
+const COPY_STATE = {
+  DEFAULT: 'default',
+  DONE: 'done',
+} as const;
 
-type Props = {
-  adminHomeContainer: AdminHomeContainer;
-};
-
-const AdminHome: FC<Props> = (props) => {
-  const { adminHomeContainer } = props;
+const AdminHome: FC = () => {
   const { t } = useTranslation();
+  const { data: adminHomeData } = useSWRxAdminHome();
   const { data: migrationStatus } = useSWRxV5MigrationStatus();
+  const [copyState, setCopyState] = useState<string>(COPY_STATE.DEFAULT);
 
-  const fetchAdminHomeData = useCallback(async () => {
-    try {
-      await adminHomeContainer.retrieveAdminHomeData();
-    } catch (err) {
-      toastError(err);
-      logger.error(err);
-    }
-  }, [adminHomeContainer]);
-
-  useEffect(() => {
-    fetchAdminHomeData();
-  }, [fetchAdminHomeData]);
+  const handleCopyPrefilledHostInformation = () => {
+    setCopyState(COPY_STATE.DONE);
+    setTimeout(() => {
+      setCopyState(COPY_STATE.DEFAULT);
+    }, 500);
+  };
 
   // Generate CSS-safe ID by removing colons from useId() result
   const copyButtonIdRaw = useId();
@@ -45,7 +37,7 @@ const AdminHome: FC<Props> = (props) => {
     <div data-testid="admin-home">
       {
         // Alert message will be displayed in case that the GROWI is under maintenance
-        adminHomeContainer.state.isMaintenanceMode && (
+        adminHomeData?.isMaintenanceMode && (
           <div className="alert alert-danger alert-link" role="alert">
             <h3 className="alert-heading">
               {t('admin:maintenance_mode.maintenance_mode')}
@@ -112,7 +104,7 @@ const AdminHome: FC<Props> = (props) => {
               __html: t('admin:admin_top.about_security'),
             }}
           />
-          <EnvVarsTable envVars={adminHomeContainer.state.envVars} />
+          <EnvVarsTable envVars={adminHomeData?.envVars} />
         </div>
       </div>
 
@@ -124,10 +116,13 @@ const AdminHome: FC<Props> = (props) => {
           <ol className="mb-0">
             <li className="mb-3">
               <CopyToClipboard
-                text={adminHomeContainer.generatePrefilledHostInformationMarkdown()}
-                onCopy={() =>
-                  adminHomeContainer.onCopyPrefilledHostInformation()
-                }
+                text={generatePrefilledHostInformationMarkdown({
+                  growiVersion: adminHomeData?.growiVersion,
+                  nodeVersion: adminHomeData?.nodeVersion,
+                  npmVersion: adminHomeData?.npmVersion,
+                  pnpmVersion: adminHomeData?.pnpmVersion,
+                })}
+                onCopy={handleCopyPrefilledHostInformation}
               >
                 <button
                   type="button"
@@ -147,10 +142,7 @@ const AdminHome: FC<Props> = (props) => {
               </CopyToClipboard>
               <Tooltip
                 placement="bottom"
-                isOpen={
-                  adminHomeContainer.state.copyState ===
-                  adminHomeContainer.copyStateValues?.DONE
-                }
+                isOpen={copyState === COPY_STATE.DONE}
                 target={copyButtonId}
                 fade={false}
               >
@@ -175,8 +167,4 @@ const AdminHome: FC<Props> = (props) => {
   );
 };
 
-const AdminHomeWrapper = withUnstatedContainers(AdminHome, [
-  AdminHomeContainer,
-]);
-
-export default AdminHomeWrapper;
+export default AdminHome;

+ 5 - 20
apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx

@@ -1,19 +1,12 @@
-import React from 'react';
 import { LoadingSpinner } from '@growi/ui/dist/components';
 
-import AdminHomeContainer from '~/client/services/AdminHomeContainer';
+import { useSWRxAdminHome } from '~/stores/admin/admin-home';
 
-import { withUnstatedContainers } from '../../UnstatedUtils';
-
-type Props = {
-  adminHomeContainer: AdminHomeContainer;
-};
-
-const SystemInformationTable = (props: Props) => {
-  const { adminHomeContainer } = props;
+const SystemInformationTable = () => {
+  const { data: adminHomeData } = useSWRxAdminHome();
 
   const { growiVersion, nodeVersion, npmVersion, pnpmVersion } =
-    adminHomeContainer.state;
+    adminHomeData ?? {};
 
   if (
     growiVersion == null ||
@@ -51,12 +44,4 @@ const SystemInformationTable = (props: Props) => {
   );
 };
 
-/**
- * Wrapper component for using unstated
- */
-const SystemInformationTableWrapper = withUnstatedContainers(
-  SystemInformationTable,
-  [AdminHomeContainer],
-);
-
-export default SystemInformationTableWrapper;
+export default SystemInformationTable;

+ 0 - 111
apps/app/src/client/services/AdminHomeContainer.js

@@ -1,111 +0,0 @@
-import { isServer } from '@growi/core/dist/utils';
-import { Container } from 'unstated';
-
-import loggerFactory from '~/utils/logger';
-
-import { apiv3Get } from '../util/apiv3-client';
-
-// eslint-disable-next-line no-unused-vars
-const logger = loggerFactory('growi:services:AdminHomeContainer');
-
-/**
- * Service container for admin homepage (AdminHome.jsx)
- * @extends {Container} unstated Container
- */
-export default class AdminHomeContainer extends Container {
-  constructor() {
-    super();
-
-    if (isServer()) {
-      return;
-    }
-
-    this.copyStateValues = {
-      DEFAULT: 'default',
-      DONE: 'done',
-    };
-    this.timer = null;
-
-    this.state = {
-      growiVersion: null,
-      nodeVersion: null,
-      npmVersion: null,
-      pnpmVersion: null,
-      copyState: this.copyStateValues.DEFAULT,
-      installedPlugins: null,
-      isV5Compatible: null,
-      isMaintenanceMode: null,
-    };
-  }
-
-  /**
-   * Workaround for the mangling in production build to break constructor.name
-   */
-  static getClassName() {
-    return 'AdminHomeContainer';
-  }
-
-  componentWillUnmount() {
-    clearTimeout(this.timer);
-  }
-
-  /**
-   * retrieve admin home data
-   */
-  async retrieveAdminHomeData() {
-    try {
-      const response = await apiv3Get('/admin-home/');
-      const { adminHomeParams } = response.data;
-
-      this.setState((prevState) => ({
-        ...prevState,
-        growiVersion: adminHomeParams.growiVersion,
-        nodeVersion: adminHomeParams.nodeVersion,
-        npmVersion: adminHomeParams.npmVersion,
-        pnpmVersion: adminHomeParams.pnpmVersion,
-        envVars: adminHomeParams.envVars,
-        isV5Compatible: adminHomeParams.isV5Compatible,
-        isMaintenanceMode: adminHomeParams.isMaintenanceMode,
-      }));
-    } catch (err) {
-      logger.error(err);
-      throw new Error('Failed to retrive AdminHome data');
-    }
-  }
-
-  /**
-   * sets button text when copying system information
-   */
-  onCopyPrefilledHostInformation() {
-    this.setState((prevState) => ({
-      ...prevState,
-      copyState: this.copyStateValues.DONE,
-    }));
-
-    this.timer = setTimeout(() => {
-      this.setState((prevState) => ({
-        ...prevState,
-        copyState: this.copyStateValues.DEFAULT,
-      }));
-    }, 500);
-  }
-
-  /**
-   * generates prefilled host information as markdown
-   */
-  generatePrefilledHostInformationMarkdown() {
-    return `| item     | version |
-| ---      | --- |
-|OS        ||
-|GROWI     |${this.state.growiVersion}|
-|node.js   |${this.state.nodeVersion}|
-|npm       |${this.state.npmVersion}|
-|pnpm      |${this.state.pnpmVersion}|
-|Using Docker|yes/no|
-|Using [growi-docker-compose][growi-docker-compose]|yes/no|
-
-[growi-docker-compose]: https://github.com/growilabs/growi-docker-compose
-
-*(Accessing https://{GROWI_HOST}/admin helps you to fill in above versions)*`;
-  }
-}

+ 0 - 8
apps/app/src/pages/admin/index.page.tsx

@@ -44,14 +44,6 @@ const AdminHomepage: NextPageWithLayout<Props> = ({
 
 AdminHomepage.getLayout = createAdminPageLayout<Props>({
   title: (_p, t) => t('wiki_management_homepage'),
-  containerFactories: [
-    async () => {
-      const AdminHomeContainer =
-        // biome-ignore lint/style/noRestrictedImports: no-problem dynamic import
-        (await import('~/client/services/AdminHomeContainer')).default;
-      return new AdminHomeContainer();
-    },
-  ],
 });
 
 export const getServerSideProps: GetServerSideProps<Props> = async (

+ 22 - 0
apps/app/src/stores/admin/admin-home.tsx

@@ -0,0 +1,22 @@
+import type { SWRResponse } from 'swr';
+import useSWR from 'swr';
+
+import { apiv3Get } from '~/client/util/apiv3-client';
+
+export type AdminHomeData = {
+  growiVersion: string;
+  nodeVersion: string;
+  npmVersion: string;
+  pnpmVersion: string;
+  envVars: Record<string, string>;
+  isV5Compatible: boolean;
+  isMaintenanceMode: boolean;
+};
+
+export const useSWRxAdminHome = (): SWRResponse<AdminHomeData, Error> => {
+  return useSWR('/admin-home/', (endpoint) =>
+    apiv3Get(endpoint).then((response) => {
+      return response.data.adminHomeParams;
+    }),
+  );
+};

+ 31 - 0
apps/app/src/utils/admin-home.ts

@@ -0,0 +1,31 @@
+type SystemInfo = {
+  growiVersion?: string;
+  nodeVersion?: string;
+  npmVersion?: string;
+  pnpmVersion?: string;
+};
+
+/**
+ * Generates prefilled host information as markdown for bug reports
+ * @param systemInfo System version information
+ * @returns Markdown formatted string with system information
+ */
+export const generatePrefilledHostInformationMarkdown = (
+  systemInfo: SystemInfo,
+): string => {
+  const { growiVersion, nodeVersion, npmVersion, pnpmVersion } = systemInfo;
+
+  return `| item     | version |
+| ---      | --- |
+|OS        ||
+|GROWI     |${growiVersion ?? ''}|
+|node.js   |${nodeVersion ?? ''}|
+|npm       |${npmVersion ?? ''}|
+|pnpm      |${pnpmVersion ?? ''}|
+|Using Docker|yes/no|
+|Using [growi-docker-compose][growi-docker-compose]|yes/no|
+
+[growi-docker-compose]: https://github.com/growilabs/growi-docker-compose
+
+*(Accessing https://{GROWI_HOST}/admin helps you to fill in above versions)*`;
+};