Bladeren bron

disable bulk export btn when not available

Futa Arai 1 jaar geleden
bovenliggende
commit
250ef045a9

+ 2 - 1
apps/app/public/static/locales/en_US/translation.json

@@ -642,7 +642,8 @@
     "bulk_export_started": "Please wait a moment...",
     "bulk_export_download_expired": "Download period has expired",
     "bulk_export_job_expired": "Export process was canceled because it took too long",
-    "duplicate_bulk_export_job_error": "Export for the same page and its children is in progress"
+    "duplicate_bulk_export_job_error": "Export for the same page and its children is in progress",
+    "bulk_export_only_available_for": "Only available for AWS or GCP"
   },
   "message": {
     "successfully_connected": "Successfully Connected!",

+ 2 - 1
apps/app/public/static/locales/fr_FR/translation.json

@@ -636,7 +636,8 @@
     "bulk_export_started": "Patientez s'il-vous-plait...",
     "bulk_export_download_expired": "La période de téléchargement a expiré",
     "bulk_export_job_expired": "Le traitement a été interrompu car le temps d'exportation était trop long",
-    "duplicate_bulk_export_job_error": "L'export pour la même page et ses enfants est en cours"
+    "duplicate_bulk_export_job_error": "L'export pour la même page et ses enfants est en cours",
+    "bulk_export_only_available_for": "Uniquement disponible pour AWS ou GCP"
   },
   "message": {
     "successfully_connected": "Connecté!",

+ 2 - 1
apps/app/public/static/locales/ja_JP/translation.json

@@ -675,7 +675,8 @@
     "bulk_export_started": "ただいま準備中です...",
     "bulk_export_download_expired": "ダウンロード期限が切れました",
     "bulk_export_job_expired": "エクスポート時間が長すぎるため、処理が中断されました",
-    "duplicate_bulk_export_job_error": "既に同じページとその配下のエクスポートが進行中です"
+    "duplicate_bulk_export_job_error": "既に同じページとその配下のエクスポートが進行中です",
+    "bulk_export_only_available_for": "AWS と GCP のみ対応しています"
   },
   "message": {
     "successfully_connected": "接続に成功しました!",

+ 2 - 1
apps/app/public/static/locales/zh_CN/translation.json

@@ -645,7 +645,8 @@
     "bulk_export_started": "目前我们正在准备...",
     "bulk_export_download_expired": "下载期限已过",
     "bulk_export_job_expired": "由于导出时间太长,处理被中断",
-    "duplicate_bulk_export_job_error": "正在导出同一页面及其子页面"
+    "duplicate_bulk_export_job_error": "正在导出同一页面及其子页面",
+    "bulk_export_only_available_for": "仅适用于 AWS 或 GCP"
   },
   "message": {
     "successfully_connected": "连接成功!",

+ 2 - 4
apps/app/src/client/components/Admin/App/FileUploadSetting.tsx

@@ -5,6 +5,7 @@ import { useTranslation } from 'next-i18next';
 
 import AdminAppContainer from '~/client/services/AdminAppContainer';
 import { toastSuccess, toastError } from '~/client/util/toastr';
+import { FileUploadType } from '~/interfaces/file-uploader';
 
 import { withUnstatedContainers } from '../../UnstatedUtils';
 import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
@@ -16,9 +17,6 @@ import type { AzureSettingMoleculeProps } from './AzureSetting';
 import { GcsSettingMolecule } from './GcsSetting';
 import type { GcsSettingMoleculeProps } from './GcsSetting';
 
-
-const fileUploadTypes = ['aws', 'gcs', 'azure', 'gridfs', 'local'] as const;
-
 type FileUploadSettingMoleculeProps = {
   fileUploadType: string
   isFixedFileUploadByEnvVar: boolean
@@ -45,7 +43,7 @@ export const FileUploadSettingMolecule = React.memo((props: FileUploadSettingMol
         </label>
 
         <div className="col-md-6 py-2">
-          {fileUploadTypes.map((type) => {
+          {Object.values(FileUploadType).map((type) => {
             return (
               <div key={type} className="form-check form-check-inline">
                 <input

+ 23 - 8
apps/app/src/client/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -14,7 +14,7 @@ import dynamic from 'next/dynamic';
 import Link from 'next/link';
 import { useRouter } from 'next/router';
 import Sticky from 'react-stickynode';
-import { DropdownItem } from 'reactstrap';
+import { DropdownItem, Tooltip } from 'reactstrap';
 
 import { exportAsMarkdown, updateContentWidth, syncLatestRevisionBody } from '~/client/services/page-operation';
 import { toastSuccess, toastError, toastWarning } from '~/client/util/toastr';
@@ -24,7 +24,7 @@ import type { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from
 import { useShouldExpandContent } from '~/services/layout/use-should-expand-content';
 import {
   useCurrentPathname,
-  useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsSharedUser, useShareLinkId,
+  useCurrentUser, useIsGuestUser, useIsPageBulkExportEnabled, useIsReadOnlyUser, useIsSharedUser, useShareLinkId,
 } from '~/stores-universal/context';
 import { useEditorMode } from '~/stores-universal/ui';
 import {
@@ -76,6 +76,7 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
   const { data: isGuestUser } = useIsGuestUser();
   const { data: isReadOnlyUser } = useIsReadOnlyUser();
   const { data: isSharedUser } = useIsSharedUser();
+  const { data: isPageBulkExportEnabled } = useIsPageBulkExportEnabled();
 
   const { open: openPresentationModal } = usePagePresentationModal();
   const { open: openAccessoriesModal } = usePageAccessoriesModal();
@@ -83,6 +84,8 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
 
   const { data: codeMirrorEditor } = useCodeMirrorEditorIsolated(GlobalCodeMirrorEditorKey.MAIN);
 
+  const [isBulkExportTooltipOpen, setIsBulkExportTooltipOpen] = useState(false);
+
   const syncLatestRevisionBodyHandler = useCallback(async() => {
     // eslint-disable-next-line no-alert
     const answer = window.confirm(t('sync-latest-revision-body.confirm'));
@@ -140,13 +143,25 @@ const PageOperationMenuItems = (props: PageOperationMenuItemsProps): JSX.Element
       </DropdownItem>
 
       {/* Bulk export */}
-      <DropdownItem
-        onClick={openPageBulkExportSelectModal}
-        className="grw-page-control-dropdown-item"
+      <span id="bulkExportDropdownItem">
+        <DropdownItem
+          disabled={!isPageBulkExportEnabled}
+          onClick={openPageBulkExportSelectModal}
+          className="grw-page-control-dropdown-item"
+        >
+          <span className="material-symbols-outlined me-1 grw-page-control-dropdown-icon">cloud_download</span>
+          {t('page_export.bulk_export')}
+        </DropdownItem>
+      </span>
+      <Tooltip
+        placement="left"
+        isOpen={isBulkExportTooltipOpen}
+        // Tooltip cannot be activated when target is disabled so set the target to wrapper span
+        target="bulkExportDropdownItem"
+        toggle={() => setIsBulkExportTooltipOpen(!isBulkExportTooltipOpen)}
       >
-        <span className="material-symbols-outlined me-1 grw-page-control-dropdown-icon">cloud_download</span>
-        {t('page_export.bulk_export')}
-      </DropdownItem>
+        {t('page_export.bulk_export_only_available_for')}
+      </Tooltip>
 
       <DropdownItem divider />
 

+ 4 - 0
apps/app/src/features/page-bulk-export/interfaces/page-bulk-export.ts

@@ -3,6 +3,8 @@ import type {
   IAttachment, IPage, IRevision, IUser, Ref,
 } from '@growi/core';
 
+import { FileUploadEnvVarType } from '~/interfaces/file-uploader';
+
 export const PageBulkExportFormat = {
   md: 'md',
   pdf: 'pdf',
@@ -44,3 +46,5 @@ export interface IPageBulkExportPageSnapshot {
   path: string, // page path when export was stared
   revision: Ref<IRevision>, // page revision when export was stared
 }
+
+export const PageBulkExportEnabledFileUploadTypes = [FileUploadEnvVarType.aws, FileUploadEnvVarType.gcs, FileUploadEnvVarType.gcp] as const;

+ 18 - 0
apps/app/src/interfaces/file-uploader.ts

@@ -0,0 +1,18 @@
+export const FileUploadType = {
+  aws: 'aws',
+  gcs: 'gcs',
+  azure: 'azure',
+  gridfs: 'gridfs',
+  local: 'local',
+} as const;
+
+export type FileUploadType = typeof FileUploadType[keyof typeof FileUploadType]
+
+export const FileUploadEnvVarType = {
+  ...FileUploadType,
+  mongo:   'mongo',
+  mongodb: 'mongodb',
+  gcp:     'gcp',
+} as const;
+
+export type FileUploadEnvVarType = typeof FileUploadEnvVarType[keyof typeof FileUploadEnvVarType]

+ 5 - 1
apps/app/src/pages/[[...path]].page.tsx

@@ -23,6 +23,7 @@ import superjson from 'superjson';
 import { BasicLayout } from '~/components/Layout/BasicLayout';
 import { PageView } from '~/components/PageView/PageView';
 import { DrawioViewerScript } from '~/components/Script/DrawioViewerScript';
+import { PageBulkExportEnabledFileUploadTypes } from '~/features/page-bulk-export/interfaces/page-bulk-export';
 import { SupportedAction, type SupportedActionType } from '~/interfaces/activity';
 import type { CrowiRequest } from '~/interfaces/crowi-request';
 import type { RendererConfig } from '~/interfaces/services/renderer';
@@ -41,7 +42,7 @@ import {
   useCsrfToken, useIsSearchScopeChildrenAsDefault, useIsEnabledMarp, useCurrentPathname,
   useIsSlackConfigured, useRendererConfig, useGrowiCloudUri,
   useIsAllReplyShown, useIsContainerFluid, useIsNotCreatable,
-  useIsUploadAllFileAllowed, useIsUploadEnabled,
+  useIsUploadAllFileAllowed, useIsUploadEnabled, useIsPageBulkExportEnabled,
   useElasticsearchMaxBodyLengthToIndex,
 } from '~/stores-universal/context';
 import { useEditingMarkdown } from '~/stores/editor';
@@ -174,6 +175,7 @@ type Props = CommonProps & {
   isContainerFluid: boolean,
   isUploadEnabled: boolean,
   isUploadAllFileAllowed: boolean,
+  isPageBulkExportEnabled: boolean,
   isEnabledStaleNotification: boolean,
   isEnabledAttachTitleHeader: boolean,
   // isEnabledLinebreaks: boolean,
@@ -236,6 +238,7 @@ const Page: NextPageWithLayout<Props> = (props: Props) => {
 
   useIsUploadAllFileAllowed(props.isUploadAllFileAllowed);
   useIsUploadEnabled(props.isUploadEnabled);
+  useIsPageBulkExportEnabled(props.isPageBulkExportEnabled);
 
   const { pageWithMeta } = props;
 
@@ -555,6 +558,7 @@ function injectServerConfigurations(context: GetServerSidePropsContext, props: P
   props.disableLinkSharing = configManager.getConfig('crowi', 'security:disableLinkSharing');
   props.isUploadAllFileAllowed = crowi.fileUploadService.getFileUploadEnabled();
   props.isUploadEnabled = crowi.fileUploadService.getIsUploadable();
+  props.isPageBulkExportEnabled = PageBulkExportEnabledFileUploadTypes.includes(crowi.configManager.getConfig('crowi', 'app:fileUploadType'));
 
   props.adminPreferredIndentSize = configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize');
   props.isIndentSizeForced = configManager.getConfig('markdown', 'markdown:isIndentSizeForced');

+ 0 - 1
apps/app/src/server/routes/apiv3/app-settings.js

@@ -301,7 +301,6 @@ module.exports = (crowi) => {
 
   });
 
-
   /**
    * @swagger
    *

+ 3 - 6
apps/app/src/server/service/file-uploader/index.ts

@@ -1,3 +1,4 @@
+import { FileUploadEnvVarType } from '~/interfaces/file-uploader';
 import type Crowi from '~/server/crowi';
 import loggerFactory from '~/utils/logger';
 
@@ -10,15 +11,11 @@ export type { FileUploader } from './file-uploader';
 const logger = loggerFactory('growi:service:FileUploaderServise');
 
 const envToModuleMappings = {
-  aws:     'aws',
-  local:   'local',
+  ...FileUploadEnvVarType,
   mongo:   'gridfs',
   mongodb: 'gridfs',
-  gridfs:  'gridfs',
   gcp:     'gcs',
-  gcs:     'gcs',
-  azure:   'azure',
-};
+} as const;
 
 export const getUploader = (crowi: Crowi): FileUploader => {
   const method = envToModuleMappings[configManager.getConfig('crowi', 'app:fileUploadType')];

+ 4 - 0
apps/app/src/stores-universal/context.tsx

@@ -168,6 +168,10 @@ export const useIsUploadAllFileAllowed = (initialData?: boolean): SWRResponse<bo
   return useContextSWR('isUploadAllFileAllowed', initialData);
 };
 
+export const useIsPageBulkExportEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
+  return useContextSWR('isPageBulkExportEnabled', initialData);
+};
+
 export const useShowPageLimitationL = (initialData?: number): SWRResponse<number, Error> => {
   return useContextSWR('showPageLimitationL', initialData);
 };