From dd11adfdc3f3707380da5fdf0fa6f38c4e358b3d Mon Sep 17 00:00:00 2001 From: Antoine Clausse Date: Tue, 14 Oct 2025 17:00:47 +0200 Subject: [PATCH] [web] Fix FileTreeModalCreateFile modal style on "too many files" error (#28995) * Temporarily update `maxEntitiesPerProject` to test `FileTreeModalCreateFile` * Remove unused CSS * Move project_has_too_many_files Notification to the modal body * Turn project_approaching_file_limit message into a Notification * Update project_has_too_many_files translation with `fileCount.limit` * Update other project_has_too_many_files with limit parameter * Add translations for project_has_too_many_files_limit * Revert "Temporarily update `maxEntitiesPerProject` to test `FileTreeModalCreateFile`" This reverts commit 704996aa96c9ba592c7e44d165def0b97d30bed1. * Fix unit tests * Move the warning notification to the modal's body --------- Co-authored-by: Rebeka GitOrigin-RevId: 0f54db7021e4cd4537a14e4f9e1d8ef54337778c --- .../Features/Editor/EditorHttpController.mjs | 12 +++++-- .../web/frontend/extracted-translations.json | 2 +- .../file-tree-create/error-message.tsx | 10 ++++-- .../file-tree-modal-create-file-body.tsx | 32 ++++++++++++++++--- .../file-tree-modal-create-file-footer.tsx | 29 ----------------- .../stylesheets/pages/editor/file-tree.scss | 10 ------ services/web/locales/da.json | 1 + services/web/locales/de.json | 1 + services/web/locales/en.json | 1 + services/web/locales/fr.json | 1 + services/web/locales/sv.json | 1 + services/web/locales/zh-CN.json | 1 + .../src/Editor/EditorHttpController.test.mjs | 4 +-- 13 files changed, 55 insertions(+), 50 deletions(-) diff --git a/services/web/app/src/Features/Editor/EditorHttpController.mjs b/services/web/app/src/Features/Editor/EditorHttpController.mjs index e81f122494..fb47ccc940 100644 --- a/services/web/app/src/Features/Editor/EditorHttpController.mjs +++ b/services/web/app/src/Features/Editor/EditorHttpController.mjs @@ -152,7 +152,11 @@ async function addDoc(req, res, next) { res.json(doc) } catch (err) { if (err.message === 'project_has_too_many_files') { - res.status(400).json(req.i18n.translate('project_has_too_many_files')) + res.status(400).json( + req.i18n.translate('project_has_too_many_files_limit', { + limit: Settings.maxEntitiesPerProject, + }) + ) } else { next(err) } @@ -178,7 +182,11 @@ async function addFolder(req, res, next) { res.json(doc) } catch (err) { if (err.message === 'project_has_too_many_files') { - res.status(400).json(req.i18n.translate('project_has_too_many_files')) + res.status(400).json( + req.i18n.translate('project_has_too_many_files_limit', { + limit: Settings.maxEntitiesPerProject, + }) + ) } else if (err.message === 'invalid element name') { res.status(400).json(req.i18n.translate('invalid_file_name')) } else { diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index bacd4ffc42..ba9e16e4d3 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -1341,7 +1341,7 @@ "project_files_history": "", "project_files_outline": "", "project_flagged_too_many_compiles": "", - "project_has_too_many_files": "", + "project_has_too_many_files_limit": "", "project_history_labels": "", "project_last_published_at": "", "project_linked_to": "", diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.tsx index 244ef1a76b..899f311bbf 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/error-message.tsx @@ -16,7 +16,7 @@ export default function ErrorMessage({ error: string | Record }) { const { t } = useTranslation() - const { isOverleaf } = getMeta('ol-ExposedSettings') + const { isOverleaf, maxEntitiesPerProject } = getMeta('ol-ExposedSettings') const fileNameLimit = 150 // the error is a string @@ -27,7 +27,13 @@ export default function ErrorMessage({ return {t('file_already_exists')} case 'too-many-files': - return {t('project_has_too_many_files')} + return ( + + {t('project_has_too_many_files_limit', { + limit: maxEntitiesPerProject, + })} + + ) case 'remote-service-error': return {t('remote_service_error')} diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.tsx index fa8c4a3858..42cb64ce45 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-body.tsx @@ -11,6 +11,7 @@ import importOverleafModules from '../../../../../macros/import-overleaf-module. import { ElementType, lazy, Suspense } from 'react' import { FullSizeLoadingSpinner } from '@/shared/components/loading-spinner' import getMeta from '@/utils/meta' +import OLNotification from '@/shared/components/ol/ol-notification' const createFileModeModules = importOverleafModules('createFileModes') as { import: { CreateFilePane: ElementType; CreateFileMode: ElementType } @@ -30,10 +31,20 @@ export default function FileTreeModalCreateFileBody() { hasLinkUrlFeature, } = getMeta('ol-ExposedSettings') - if ( - !fileCount || - (typeof fileCount === 'object' && fileCount.status === 'error') - ) { + if (typeof fileCount !== 'number' && fileCount.status === 'error') { + return ( +
+ +
+ ) + } + + if (!fileCount) { return null } @@ -83,6 +94,19 @@ export default function FileTreeModalCreateFileBody() { + {typeof fileCount !== 'number' && + fileCount.status === 'warning' && ( + + {t('project_approaching_file_limit')} ({fileCount.value}/ + {fileCount.limit}) + + } + /> + )} {newFileCreateMode === 'doc' && ( diff --git a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.tsx b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.tsx index 299a0df3d1..26d01e1ab7 100644 --- a/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.tsx +++ b/services/web/frontend/js/features/file-tree/components/file-tree-create/file-tree-modal-create-file-footer.tsx @@ -1,14 +1,11 @@ import { useTranslation } from 'react-i18next' import { useFileTreeCreateForm } from '../../contexts/file-tree-create-form' import { useFileTreeActionable } from '../../contexts/file-tree-actionable' -import { useFileTreeData } from '../../../../shared/context/file-tree-data-context' import OLButton from '@/shared/components/ol/ol-button' -import OLNotification from '@/shared/components/ol/ol-notification' export default function FileTreeModalCreateFileFooter() { const { valid } = useFileTreeCreateForm() const { newFileCreateMode, inFlight, cancel } = useFileTreeActionable() - const { fileCount } = useFileTreeData() return ( ) } export function FileTreeModalCreateFileFooterContent({ valid, - fileCount, inFlight, cancel, newFileCreateMode, }: { valid: boolean - fileCount: - | { - limit: number - status: string - value: number - } - | number inFlight: boolean cancel: () => void newFileCreateMode?: string @@ -44,23 +32,6 @@ export function FileTreeModalCreateFileFooterContent({ return ( <> - {typeof fileCount !== 'number' && fileCount.status === 'warning' && ( -
- {t('project_approaching_file_limit')} ({fileCount.value}/ - {fileCount.limit}) -
- )} - - {typeof fileCount !== 'number' && fileCount.status === 'error' && ( - - {/* TODO: add parameter for fileCount.limit */} - - )} - { ctx.res.callback = () => { - expect(ctx.res.body).to.equal('"project_has_too_many_files"') + expect(ctx.res.body).to.equal('"project_has_too_many_files_limit"') expect(ctx.res.status).to.have.been.calledWith(400) resolve() } @@ -584,7 +584,7 @@ describe('EditorHttpController', function () { new Error('project_has_too_many_files') ) ctx.res.callback = () => { - expect(ctx.res.body).to.equal('"project_has_too_many_files"') + expect(ctx.res.body).to.equal('"project_has_too_many_files_limit"') expect(ctx.res.statusCode).to.equal(400) resolve() }