From 14431c9be489bdff282bc62d06d690728cf79712 Mon Sep 17 00:00:00 2001 From: gopienkonikita Date: Thu, 18 Jul 2024 13:24:38 +0300 Subject: [PATCH 01/22] Web: Components: added scrolling around edges --- .../src/pages/Home/Section/Body/index.js | 10 ++- .../selection-area/SelectionArea.tsx | 4 ++ packages/shared/utils/edgeScrolling.ts | 62 +++++++++++++++++++ packages/shared/utils/index.ts | 3 + 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 packages/shared/utils/edgeScrolling.ts diff --git a/packages/client/src/pages/Home/Section/Body/index.js b/packages/client/src/pages/Home/Section/Body/index.js index 5c5063ad2d..0b1bb063ae 100644 --- a/packages/client/src/pages/Home/Section/Body/index.js +++ b/packages/client/src/pages/Home/Section/Body/index.js @@ -35,7 +35,13 @@ import EmptyContainer from "../../../../components/EmptyContainer"; import withLoader from "../../../../HOCs/withLoader"; import TableView from "./TableView/TableContainer"; import withHotkeys from "../../../../HOCs/withHotkeys"; -import { Consumer, isMobile, isTablet } from "@docspace/shared/utils"; +import { + clearEdgeScrollingTimer, + Consumer, + isMobile, + isTablet, + onEdgeScrolling, +} from "@docspace/shared/utils"; import { isElementInViewport } from "@docspace/shared/utils/common"; import { DeviceType } from "@docspace/shared/enums"; @@ -197,6 +203,7 @@ const SectionBodyContent = (props) => { setDragging(true); } + onEdgeScrolling(e); setTooltipPosition(e.pageX, e.pageY); const wrapperElement = document.elementFromPoint(e.clientX, e.clientY); if (!wrapperElement) { @@ -240,6 +247,7 @@ const SectionBodyContent = (props) => { }; const onMouseUp = (e) => { + clearEdgeScrollingTimer(); setStartDrag(false); setTimeout(() => { diff --git a/packages/shared/components/selection-area/SelectionArea.tsx b/packages/shared/components/selection-area/SelectionArea.tsx index c56dc86352..12df35c65b 100644 --- a/packages/shared/components/selection-area/SelectionArea.tsx +++ b/packages/shared/components/selection-area/SelectionArea.tsx @@ -30,6 +30,7 @@ import { useTheme } from "styled-components"; import { StyledSelectionArea } from "./SelectionArea.styled"; import { frames } from "./SelectionArea.utils"; import { SelectionAreaProps, TArrayTypes } from "./SelectionArea.types"; +import { onEdgeScrolling, clearEdgeScrollingTimer } from "../../utils"; const SelectionArea = ({ onMove, @@ -298,6 +299,8 @@ const SelectionArea = ({ areaLocation.current.x2 = e.clientX; areaLocation.current.y2 = e.clientY; + onEdgeScrolling(e); + frame().next(); }, [frame], @@ -358,6 +361,7 @@ const SelectionArea = ({ }, [onMoveAction, onScroll, onTapMove]); const onTapStop = React.useCallback(() => { + clearEdgeScrollingTimer(); removeListeners(); document.removeEventListener("mouseup", onTapStop); window.removeEventListener("blur", onTapStop); diff --git a/packages/shared/utils/edgeScrolling.ts b/packages/shared/utils/edgeScrolling.ts new file mode 100644 index 0000000000..09f338624c --- /dev/null +++ b/packages/shared/utils/edgeScrolling.ts @@ -0,0 +1,62 @@ +const edgeSize = 200; +const maxStep = 50; + +let timer: null | ReturnType = null; + +export const clearEdgeScrollingTimer = () => { + if (timer) clearTimeout(timer); +}; + +export const onEdgeScrolling = (e: React.MouseEvent) => { + const bodyScroll = document.querySelector(".section-scroll"); + + if (bodyScroll) { + const viewportY = e.clientY; + const viewportHeight = document.documentElement.clientHeight; + const edgeTop = edgeSize; + const edgeBottom = viewportHeight - edgeSize; + const isInTopEdge = viewportY < edgeTop; + const isInBottomEdge = viewportY > edgeBottom; + + if (!(isInTopEdge || isInBottomEdge)) { + clearEdgeScrollingTimer(); + return; + } + + const maxScrollY = bodyScroll.scrollHeight - viewportHeight; + + const adjustWindowScroll = () => { + const currentScrollY = bodyScroll.scrollTop; + + const canScrollUp = currentScrollY > 0; + const canScrollDown = currentScrollY < maxScrollY; + let nextScrollY = currentScrollY; + + if (isInTopEdge && canScrollUp) { + const intensity = (edgeTop - viewportY) / edgeSize; + nextScrollY -= maxStep * intensity; + } else if (isInBottomEdge && canScrollDown) { + const intensity = (viewportY - edgeBottom) / edgeSize; + + nextScrollY += maxStep * intensity; + } + + nextScrollY = Math.max(0, Math.min(maxScrollY, nextScrollY)); + + if (nextScrollY !== currentScrollY) { + bodyScroll.scrollTo(0, nextScrollY); + return true; + } + return false; + }; + + const checkForWindowScroll = () => { + clearEdgeScrollingTimer(); + if (adjustWindowScroll()) { + timer = setTimeout(checkForWindowScroll, 30); + } + }; + + checkForWindowScroll(); + } +}; diff --git a/packages/shared/utils/index.ts b/packages/shared/utils/index.ts index cab623a058..6f4d74fba9 100644 --- a/packages/shared/utils/index.ts +++ b/packages/shared/utils/index.ts @@ -77,6 +77,7 @@ import { } from "./common"; import { DeviceType } from "../enums"; import { TFile } from "../api/files/types"; +import { onEdgeScrolling, clearEdgeScrollingTimer } from "./edgeScrolling"; export { isBetaLanguage, @@ -127,6 +128,8 @@ export { ObjectUtils, getLogoUrl, isMobileDevice, + onEdgeScrolling, + clearEdgeScrollingTimer, }; export const getModalType = () => { From e22f39b6ad411190eb224745740290aff87b8ce3 Mon Sep 17 00:00:00 2001 From: Alexey Safronov Date: Fri, 19 Jul 2024 13:01:49 +0400 Subject: [PATCH 02/22] Client: Fix Common translation loading --- packages/client/src/i18n.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/client/src/i18n.js b/packages/client/src/i18n.js index 024c306d30..5c200fe821 100644 --- a/packages/client/src/i18n.js +++ b/packages/client/src/i18n.js @@ -61,6 +61,7 @@ newInstance }, ns: [ + "Common", "ArchiveDialog", "InfoPanel", "InviteDialog", From 080f560a38a45fc499bcee33ecc2194a73f2fe9f Mon Sep 17 00:00:00 2001 From: Alexey Safronov Date: Fri, 19 Jul 2024 13:17:40 +0400 Subject: [PATCH 03/22] Client: Added/applied ProductEditorsName translation key --- i18next/common.babel | 132 ++++++++++++++++++ .../client/src/pages/About/AboutContent.js | 3 +- public/locales/ar-SA/Common.json | 1 + public/locales/az/Common.json | 1 + public/locales/bg/Common.json | 1 + public/locales/cs/Common.json | 1 + public/locales/de/Common.json | 1 + public/locales/el-GR/Common.json | 1 + public/locales/en/Common.json | 1 + public/locales/es/Common.json | 1 + public/locales/fi/Common.json | 1 + public/locales/fr/Common.json | 1 + public/locales/hy-AM/Common.json | 1 + public/locales/it/Common.json | 1 + public/locales/ja-JP/Common.json | 1 + public/locales/ko-KR/Common.json | 1 + public/locales/lo-LA/Common.json | 1 + public/locales/lv/Common.json | 1 + public/locales/nl/Common.json | 1 + public/locales/pl/Common.json | 1 + public/locales/pt-BR/Common.json | 1 + public/locales/pt/Common.json | 1 + public/locales/ro/Common.json | 1 + public/locales/ru/Common.json | 1 + public/locales/si/Common.json | 1 + public/locales/sk/Common.json | 1 + public/locales/sl/Common.json | 1 + public/locales/sr-Cyrl-RS/Common.json | 1 + public/locales/sr-Latn-RS/Common.json | 1 + public/locales/tr/Common.json | 1 + public/locales/uk-UA/Common.json | 1 + public/locales/vi/Common.json | 1 + public/locales/zh-CN/Common.json | 1 + 33 files changed, 165 insertions(+), 1 deletion(-) diff --git a/i18next/common.babel b/i18next/common.babel index 5c98e9f5a0..cbec3e91ce 100644 --- a/i18next/common.babel +++ b/i18next/common.babel @@ -43054,6 +43054,138 @@ + + ProductEditorsName + + + + + + ar-SA + false + + + az-Latn-AZ + false + + + bg-BG + false + + + cs-CZ + false + + + de-DE + false + + + el-GR + false + + + en-US + false + + + es-ES + false + + + fi-FI + false + + + fr-FR + false + + + hy-AM + false + + + it-IT + false + + + ja-JP + false + + + ko-KR + false + + + lo-LA + false + + + lv-LV + false + + + nl-NL + false + + + pl-PL + false + + + pt-BR + false + + + pt-PT + false + + + ro-RO + false + + + ru-RU + false + + + si-SI + false + + + sk-SK + false + + + sl-SI + false + + + sr-Cyrl-RS + false + + + sr-Latn-RS + false + + + tr-TR + false + + + uk-UA + false + + + vi-VN + false + + + zh-CN + false + + + ProductName diff --git a/packages/client/src/pages/About/AboutContent.js b/packages/client/src/pages/About/AboutContent.js index 7007a5bb38..4b0e27285f 100644 --- a/packages/client/src/pages/About/AboutContent.js +++ b/packages/client/src/pages/About/AboutContent.js @@ -183,7 +183,8 @@ const AboutContent = (props) => { target="_blank" enableUserSelect > -  ONLYOFFICE Docs  +  {t("Common:OrganizationName")}{" "} + {t("Common:ProductEditorsName")}  v. diff --git a/public/locales/ar-SA/Common.json b/public/locales/ar-SA/Common.json index ca5c34b272..d10e3b968a 100644 --- a/public/locales/ar-SA/Common.json +++ b/public/locales/ar-SA/Common.json @@ -310,6 +310,7 @@ "PreparationPortalTitle": "جاري استعادة البوابة", "Preview": "معاينة ", "Previous": "السابق", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "الملف الشخصي", "Projects": "المشاريع", diff --git a/public/locales/az/Common.json b/public/locales/az/Common.json index 71118950f8..07239c3094 100644 --- a/public/locales/az/Common.json +++ b/public/locales/az/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Portalın bərpası davam edir", "Preview": "Öncədən bax", "Previous": "Əvvəlki ", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Layihələr", diff --git a/public/locales/bg/Common.json b/public/locales/bg/Common.json index 06efa9eaaa..1f672d1d34 100644 --- a/public/locales/bg/Common.json +++ b/public/locales/bg/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Възстановяването на портала е в ход.", "Preview": "Преглед", "Previous": "Предишен", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Профил", "Projects": "Проекти", diff --git a/public/locales/cs/Common.json b/public/locales/cs/Common.json index 965fe9f447..f79dbbcd4d 100644 --- a/public/locales/cs/Common.json +++ b/public/locales/cs/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Probíhá obnova portálu", "Preview": "Náhled", "Previous": "Předchozí", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekty", diff --git a/public/locales/de/Common.json b/public/locales/de/Common.json index 66b4387027..240c0b0e9c 100644 --- a/public/locales/de/Common.json +++ b/public/locales/de/Common.json @@ -310,6 +310,7 @@ "PreparationPortalTitle": "Wiederherstellung des Portals ist im Gange", "Preview": "Vorschau", "Previous": "Zurück", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekte", diff --git a/public/locales/el-GR/Common.json b/public/locales/el-GR/Common.json index f7256cafb8..2ff7f915c3 100644 --- a/public/locales/el-GR/Common.json +++ b/public/locales/el-GR/Common.json @@ -310,6 +310,7 @@ "PreparationPortalTitle": "Η αποκατάσταση της πύλης βρίσκεται σε εξέλιξη", "Preview": "Προεπισκόπηση", "Previous": "Προηγούμενο", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Προφίλ", "Projects": "Έργα", diff --git a/public/locales/en/Common.json b/public/locales/en/Common.json index a10a87019b..715e447fd7 100644 --- a/public/locales/en/Common.json +++ b/public/locales/en/Common.json @@ -325,6 +325,7 @@ "PreparationPortalTitle": "Portal restoring is underway", "Preview": "Preview", "Previous": "Previous", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profile", "Projects": "Projects", diff --git a/public/locales/es/Common.json b/public/locales/es/Common.json index b638f59daf..209f63769c 100644 --- a/public/locales/es/Common.json +++ b/public/locales/es/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Restauración de portal está en progreso", "Preview": "Vista previa", "Previous": "Anterior", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Perfil", "Projects": "Proyectos", diff --git a/public/locales/fi/Common.json b/public/locales/fi/Common.json index 31386c429a..7dedb85689 100644 --- a/public/locales/fi/Common.json +++ b/public/locales/fi/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Portaalin palautus on käynnissä.", "Preview": "Esikatselu", "Previous": "Edellinen", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profiili", "Projects": "Projektit", diff --git a/public/locales/fr/Common.json b/public/locales/fr/Common.json index ad72ea9991..b85694771f 100644 --- a/public/locales/fr/Common.json +++ b/public/locales/fr/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Restauration du portail est en cours.", "Preview": "Aperçu", "Previous": "Précédent", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projets", diff --git a/public/locales/hy-AM/Common.json b/public/locales/hy-AM/Common.json index b8ced740fb..b9a8ac419c 100644 --- a/public/locales/hy-AM/Common.json +++ b/public/locales/hy-AM/Common.json @@ -310,6 +310,7 @@ "PreparationPortalTitle": "Պորտալի վերականգնումն ընթացքի մեջ է", "Preview": "Նախադիտել", "Previous": "Նախորդ", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Անձնական էջ", "Projects": "Նախագծեր", diff --git a/public/locales/it/Common.json b/public/locales/it/Common.json index 687c03cc72..43dc0849a9 100644 --- a/public/locales/it/Common.json +++ b/public/locales/it/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Ripristino portale in corso.", "Preview": "Anteprima", "Previous": "Indietro", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profilo", "Projects": "Projects", diff --git a/public/locales/ja-JP/Common.json b/public/locales/ja-JP/Common.json index 6d699494bd..542bdbc806 100644 --- a/public/locales/ja-JP/Common.json +++ b/public/locales/ja-JP/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "ポータルの復元が実施中です。", "Preview": "プレビュー", "Previous": "前", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "プロフィール", "Projects": "プロジェクト", diff --git a/public/locales/ko-KR/Common.json b/public/locales/ko-KR/Common.json index 6c942528a0..fe3bae23de 100644 --- a/public/locales/ko-KR/Common.json +++ b/public/locales/ko-KR/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "포털 복원이 진행 중입니다", "Preview": "미리 보기", "Previous": "이전", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "프로필", "Projects": "프로젝트", diff --git a/public/locales/lo-LA/Common.json b/public/locales/lo-LA/Common.json index f1ab88141b..ed41db83ab 100644 --- a/public/locales/lo-LA/Common.json +++ b/public/locales/lo-LA/Common.json @@ -245,6 +245,7 @@ "PreparationPortalTitle": "ກໍາລັງດໍາເນີນການກູ້ຄືນພອດທັອນ", "Preview": "ເບິ່ງຕົວຢ່າງ", "Previous": "ທີ່ຜ່ານມາ", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "ຂໍ້ມູນສ່ວນໂຕ", "ProviderLoginError": "ອານຸຍາດຜິດພາດ", diff --git a/public/locales/lv/Common.json b/public/locales/lv/Common.json index e7dd3b8a60..d6bdd8ceb9 100644 --- a/public/locales/lv/Common.json +++ b/public/locales/lv/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Notiek portāla atjaunošana.", "Preview": "Priekšskatīt", "Previous": "Iepriekšējais", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profils", "Projects": "Projekti", diff --git a/public/locales/nl/Common.json b/public/locales/nl/Common.json index 6e073afba1..6e387a6ca4 100644 --- a/public/locales/nl/Common.json +++ b/public/locales/nl/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Portaal herstel is bezig.", "Preview": "Preview", "Previous": "Vorige", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profiel", "Projects": "Projecten", diff --git a/public/locales/pl/Common.json b/public/locales/pl/Common.json index 9d4750a813..ac9025c483 100644 --- a/public/locales/pl/Common.json +++ b/public/locales/pl/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Odtwarzanie portalu jest w toku.", "Preview": "Podgląd", "Previous": "Poprzednia", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekty", diff --git a/public/locales/pt-BR/Common.json b/public/locales/pt-BR/Common.json index fede931af0..58fbb90dbb 100644 --- a/public/locales/pt-BR/Common.json +++ b/public/locales/pt-BR/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Restauração do portal está em andamento.", "Preview": "Pré-visualizar", "Previous": "Anterior", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Perfil", "Projects": "Projetos", diff --git a/public/locales/pt/Common.json b/public/locales/pt/Common.json index 908c097619..e17b8700f6 100644 --- a/public/locales/pt/Common.json +++ b/public/locales/pt/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "A restauração do Portal está em curso", "Preview": "Pré-visualizar", "Previous": "Anterior", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Perfil", "Projects": "Projetos", diff --git a/public/locales/ro/Common.json b/public/locales/ro/Common.json index d631b1d5cb..414a4d1453 100644 --- a/public/locales/ro/Common.json +++ b/public/locales/ro/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Restaurarea portalului este în curs de desfășurare", "Preview": "Previzualizare", "Previous": "Anterior", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projecte", diff --git a/public/locales/ru/Common.json b/public/locales/ru/Common.json index 041c175403..439ac968fb 100644 --- a/public/locales/ru/Common.json +++ b/public/locales/ru/Common.json @@ -312,6 +312,7 @@ "PreparationPortalTitle": "Выполняется восстановление портала", "Preview": "Просмотр", "Previous": "Предыдущая", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Профиль", "Projects": "Проекты", diff --git a/public/locales/si/Common.json b/public/locales/si/Common.json index 1944930b46..e26c0f1a48 100644 --- a/public/locales/si/Common.json +++ b/public/locales/si/Common.json @@ -306,6 +306,7 @@ "PreparationPortalTitle": "ද්වාරය ප්‍රත්‍යර්පණය වෙමින්", "Preview": "පෙරදසුන", "Previous": "කලින්", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "පැතිකඩ", "Projects": "ව්‍යාපෘති", diff --git a/public/locales/sk/Common.json b/public/locales/sk/Common.json index 6e2bbe11a1..1b6dd6aebc 100644 --- a/public/locales/sk/Common.json +++ b/public/locales/sk/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Prebieha obnova portálu.", "Preview": "Náhľad", "Previous": "Predchádzajúci", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekty", diff --git a/public/locales/sl/Common.json b/public/locales/sl/Common.json index afca37fa9e..8a223163f5 100644 --- a/public/locales/sl/Common.json +++ b/public/locales/sl/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Obnavljanje portala je v teku", "Preview": "Predogled", "Previous": "Prejšnji", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekti", diff --git a/public/locales/sr-Cyrl-RS/Common.json b/public/locales/sr-Cyrl-RS/Common.json index 2bca74d16d..24ca92ae4e 100644 --- a/public/locales/sr-Cyrl-RS/Common.json +++ b/public/locales/sr-Cyrl-RS/Common.json @@ -315,6 +315,7 @@ "PreparationPortalTitle": "Обнова портала је у току", "Preview": "Преглед", "Previous": "Претходно", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Профил", "Projects": "Пројекти", diff --git a/public/locales/sr-Latn-RS/Common.json b/public/locales/sr-Latn-RS/Common.json index 9bcfc9bcda..ea74075e30 100644 --- a/public/locales/sr-Latn-RS/Common.json +++ b/public/locales/sr-Latn-RS/Common.json @@ -315,6 +315,7 @@ "PreparationPortalTitle": "Obnova portala je u toku", "Preview": "Pregled", "Previous": "Prethodno", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projekti", diff --git a/public/locales/tr/Common.json b/public/locales/tr/Common.json index 550a3e8cf7..ae85327a8a 100644 --- a/public/locales/tr/Common.json +++ b/public/locales/tr/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Portal geri yükleme yapılıyor.", "Preview": "Önizleme", "Previous": "Önceki", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Profil", "Projects": "Projeler", diff --git a/public/locales/uk-UA/Common.json b/public/locales/uk-UA/Common.json index af56352956..a0368e479e 100644 --- a/public/locales/uk-UA/Common.json +++ b/public/locales/uk-UA/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Портал відновлюється.", "Preview": "Попередній перегляд", "Previous": "Назад", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Профіль", "Projects": "Проєкти", diff --git a/public/locales/vi/Common.json b/public/locales/vi/Common.json index a1ca0dc991..43d7759b30 100644 --- a/public/locales/vi/Common.json +++ b/public/locales/vi/Common.json @@ -311,6 +311,7 @@ "PreparationPortalTitle": "Đang tiến hành khôi phục cổng.", "Preview": "Xem trước", "Previous": "Trước", + "ProductEditorsName": "Docs", "ProductName": "DocSpace", "Profile": "Hồ sơ", "Projects": "Kế hoạch", diff --git a/public/locales/zh-CN/Common.json b/public/locales/zh-CN/Common.json index 9d67f8a6b2..6ac4ba42b4 100644 --- a/public/locales/zh-CN/Common.json +++ b/public/locales/zh-CN/Common.json @@ -304,6 +304,7 @@ "PreparationPortalTitle": "门户恢复正在进行中。", "Preview": "预览", "Previous": "上一个", + "ProductEditorsName": "文档", "ProductName": "协作空间", "Profile": "个人资料", "Projects": "项目", From 24398334fc5a4abca996d32c3470fd7c7a2dc80f Mon Sep 17 00:00:00 2001 From: Aleksandr Lushkin Date: Fri, 19 Jul 2024 11:38:33 +0200 Subject: [PATCH 04/22] Shared: Filter: Fix clear filter button not showing when there are applied filters --- .../shared/components/filter/sub-components/FilterBlock.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/shared/components/filter/sub-components/FilterBlock.tsx b/packages/shared/components/filter/sub-components/FilterBlock.tsx index 6a678c4e19..857cddd827 100644 --- a/packages/shared/components/filter/sub-components/FilterBlock.tsx +++ b/packages/shared/components/filter/sub-components/FilterBlock.tsx @@ -479,6 +479,8 @@ const FilterBlock = ({ }; const showFooter = isLoading ? false : isEqualFilter(); + const showClearFilterBtn = + !isLoading && (selectedFilterValue.length > 0 || filterValues.length > 0); const filterBlockComponent = ( <> @@ -535,7 +537,7 @@ const FilterBlock = ({ {filterHeader} - {showFooter && ( + {showClearFilterBtn && ( Date: Fri, 19 Jul 2024 12:58:27 +0300 Subject: [PATCH 05/22] Client:PortalSettings: fix document title --- .../src/pages/PortalSettings/categories/common/appearance.js | 2 +- .../pages/PortalSettings/categories/common/customization.js | 2 +- .../categories/developer-tools/PluginSDK/index.js | 5 +++++ .../categories/integration/DocumentService/index.js | 2 ++ 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/client/src/pages/PortalSettings/categories/common/appearance.js b/packages/client/src/pages/PortalSettings/categories/common/appearance.js index 2e852c8ef7..519710dc2a 100644 --- a/packages/client/src/pages/PortalSettings/categories/common/appearance.js +++ b/packages/client/src/pages/PortalSettings/categories/common/appearance.js @@ -183,7 +183,7 @@ const Appearance = (props) => { useEffect(() => { getSettings(); - setDocumentTitle(t("Appearance")); + setDocumentTitle(t("Common:Appearance")); }, []); useEffect(() => { diff --git a/packages/client/src/pages/PortalSettings/categories/common/customization.js b/packages/client/src/pages/PortalSettings/categories/common/customization.js index ddc6df0e20..d7ba38af3d 100644 --- a/packages/client/src/pages/PortalSettings/categories/common/customization.js +++ b/packages/client/src/pages/PortalSettings/categories/common/customization.js @@ -110,7 +110,7 @@ const Customization = (props) => { const isLoadedSetting = isLoaded && tReady; useEffect(() => { - setDocumentTitle(t("Customization")); + setDocumentTitle(t("Settings:Customization")); return () => { resetIsInit(); diff --git a/packages/client/src/pages/PortalSettings/categories/developer-tools/PluginSDK/index.js b/packages/client/src/pages/PortalSettings/categories/developer-tools/PluginSDK/index.js index 04f7992488..5b895bca99 100644 --- a/packages/client/src/pages/PortalSettings/categories/developer-tools/PluginSDK/index.js +++ b/packages/client/src/pages/PortalSettings/categories/developer-tools/PluginSDK/index.js @@ -34,6 +34,7 @@ import { RectangleSkeleton } from "@docspace/shared/skeletons"; import GithubLight from "PUBLIC_DIR/images/github.light.react.svg"; import GithubDark from "PUBLIC_DIR/images/github.dark.react.svg"; +import { setDocumentTitle } from "SRC_DIR/helpers/utils"; import { StyledContainer } from "./StyledPluginSDK"; @@ -48,6 +49,10 @@ const PluginSDK = ({ }) => { const { t } = useTranslation(["WebPlugins", "VersionHistory", "Common"]); + React.useEffect(() => { + setDocumentTitle(t("WebPlugins:PluginSDK")); + }, []); + const isMobile = currentDeviceType === "mobile"; const icon = !theme.isBase ? : ; diff --git a/packages/client/src/pages/PortalSettings/categories/integration/DocumentService/index.js b/packages/client/src/pages/PortalSettings/categories/integration/DocumentService/index.js index 0fac44eb0e..2b56be8a0b 100644 --- a/packages/client/src/pages/PortalSettings/categories/integration/DocumentService/index.js +++ b/packages/client/src/pages/PortalSettings/categories/integration/DocumentService/index.js @@ -38,6 +38,7 @@ import { toastr } from "@docspace/shared/components/toast"; import { SettingsDSConnectSkeleton } from "@docspace/shared/skeletons/settings"; import { DeviceType } from "@docspace/shared/enums"; import { SaveCancelButtons } from "@docspace/shared/components/save-cancel-buttons"; +import { setDocumentTitle } from "SRC_DIR/helpers/utils"; const URL_REGEX = /^https?:\/\/[-a-zA-Z0-9@:%._\+~#=]{1,256}\/?$/; const DNS_PLACEHOLDER = `${window.location.protocol}///`; @@ -69,6 +70,7 @@ const DocumentService = ({ const [initInternalUrl, setInitInternalUrl] = useState(""); useEffect(() => { + setDocumentTitle(t("DocumentService")); setIsLoading(true); getDocumentServiceLocation() .then((result) => { From d05b44f582694c807e458e7e36badbe39148392a Mon Sep 17 00:00:00 2001 From: Viktor Fomin Date: Fri, 19 Jul 2024 13:21:47 +0300 Subject: [PATCH 06/22] Client: PortalSettings: Header: fix truncate --- .../Layout/Section/Header/index.js | 48 +++++++++---------- 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/packages/client/src/pages/PortalSettings/Layout/Section/Header/index.js b/packages/client/src/pages/PortalSettings/Layout/Section/Header/index.js index 59e302c4eb..07bd17a1ca 100644 --- a/packages/client/src/pages/PortalSettings/Layout/Section/Header/index.js +++ b/packages/client/src/pages/PortalSettings/Layout/Section/Header/index.js @@ -375,31 +375,29 @@ const SectionHeaderContent = (props) => { /> )} -
-
- {isMobile() && isServicePage && ( - - )} - {t(header, { organizationName: t("Common:OrganizationName") })} -
- {isNeedPaidIcon ? ( - - ) : ( - "" - )} -
+ {isMobile() && isServicePage && ( + + )} + {t(header, { + organizationName: t("Common:OrganizationName"), + })} + {isNeedPaidIcon ? ( + + ) : ( + "" + )}
From bf55d700eae44bbf7d2f90c2a8140146dd54df5f Mon Sep 17 00:00:00 2001 From: Alexey Safronov Date: Fri, 19 Jul 2024 14:47:18 +0400 Subject: [PATCH 07/22] Translations: Tests: Fix ForbiddenValueElementsTest/ForbiddenKeysElementsTest --- .../LocalesTest.cs | 721 +++++++++--------- 1 file changed, 363 insertions(+), 358 deletions(-) diff --git a/common/Tests/Frontend.Translations.Tests/LocalesTest.cs b/common/Tests/Frontend.Translations.Tests/LocalesTest.cs index 6923a49a18..b1b4840d4d 100644 --- a/common/Tests/Frontend.Translations.Tests/LocalesTest.cs +++ b/common/Tests/Frontend.Translations.Tests/LocalesTest.cs @@ -29,14 +29,14 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -using System.Reflection; +using System.Reflection; using System.Security.Cryptography; using System.Text; -using System.Text.RegularExpressions; - -using Frontend.Tests; -using Frontend.Tests.Models; - +using System.Text.RegularExpressions; + +using Frontend.Tests; +using Frontend.Tests.Models; + using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -47,7 +47,7 @@ using WeCantSpell.Hunspell; namespace Frontend.Tests; public class LocalesTest -{ +{ public static string BasePath { get @@ -56,18 +56,18 @@ public class LocalesTest } } - public static bool Save - { - get - { - bool save; - if (bool.TryParse(Environment.GetEnvironmentVariable("SAVE"), out save)) - { - return save; - } - - return false; - } + public static bool Save + { + get + { + bool save; + if (bool.TryParse(Environment.GetEnvironmentVariable("SAVE"), out save)) + { + return save; + } + + return false; + } } public List Workspaces { get; set; } @@ -77,13 +77,14 @@ public class LocalesTest public List> NotTranslatedToasts { get; set; } public List> NotTranslatedProps { get; set; } public List CommonTranslations { get; set; } - public List ParseJsonErrors { get; set; } - public static string ConvertPathToOS { get; private set; } - - - public List ForbiddenElements { get { return new List() { "ONLYOFFICE", "DOCSPACE" }; } } - //public List WrongEncodingJsonErrors { get; set; } - + public List ParseJsonErrors { get; set; } + public static string ConvertPathToOS { get; private set; } + + + public List ForbiddenElements { get { return new List() { "ONLYOFFICE", "DOCSPACE" }; } } + public List SkipForbiddenKeys = new List { "OrganizationName", "ProductName", "ProductEditorsName" }; + //public List WrongEncodingJsonErrors { get; set; } + private static readonly string _md5ExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../md5-excludes.json")); private static readonly string _spellCheckCommonExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../spellcheck-excludes-common.json")); private static readonly string _spellCheckExcludesPath = Path.GetFullPath(Utils.ConvertPathToOS("../../../spellcheck-excludes.json")); @@ -104,7 +105,7 @@ public class LocalesTest [OneTimeSetUp] public void Setup() - { + { ParseJsonErrors = new List(); //WrongEncodingJsonErrors = new List(); @@ -357,14 +358,14 @@ public class LocalesTest TestContext.Progress.WriteLine($"Found CommonTranslations = {CommonTranslations.Count()}. First path is '{CommonTranslations.FirstOrDefault()?.Path}'"); - TestContext.Progress.WriteLine($"Found Md5Excludes = {Md5Excludes.Count} Path to file '{_md5ExcludesPath}'"); - - TestContext.Progress.WriteLine($"Found SpellCheckCommonExcludes = {SpellCheckCommonExcludes.Count} Path to file '{_spellCheckCommonExcludesPath}'"); - - TestContext.Progress.WriteLine($"Save spell check excludes = {Save} Path to file '{_spellCheckExcludesPath}'"); - - } - + TestContext.Progress.WriteLine($"Found Md5Excludes = {Md5Excludes.Count} Path to file '{_md5ExcludesPath}'"); + + TestContext.Progress.WriteLine($"Found SpellCheckCommonExcludes = {SpellCheckCommonExcludes.Count} Path to file '{_spellCheckCommonExcludesPath}'"); + + TestContext.Progress.WriteLine($"Save spell check excludes = {Save} Path to file '{_spellCheckExcludesPath}'"); + + } + [Test, Order(1)] [Category("Locales")] public void LanguageTranslatedPercentTest() @@ -499,7 +500,7 @@ public class LocalesTest .ToList(); Assert.AreEqual(0, duplicates.Count, string.Join(", ", duplicates.Select(d => JObject.FromObject(d).ToString()))); - } + } [Test, Order(6)] [Category("Locales")] @@ -514,10 +515,10 @@ public class LocalesTest .Where(f => !f.Path.Contains("Banner.js")) // skip Banner.js (translations from firebase) .SelectMany(j => j.TranslationKeys) .Select(k => k.Substring(k.IndexOf(":") + 1)) - .Distinct(); - - //var foo = JavaScriptFiles - // .Where(f => !f.Path.Contains("Banner.js")) + .Distinct(); + + //var foo = JavaScriptFiles + // .Where(f => !f.Path.Contains("Banner.js")) // .Where(t => t.TranslationKeys.Any(k => k == "foo")).FirstOrDefault(); var notFoundJsKeys = allJsTranslationKeys.Except(allEnKeys); @@ -525,8 +526,8 @@ public class LocalesTest Assert.AreEqual(0, notFoundJsKeys.Count(), "Some i18n-keys are not exist in translations in 'en' language: Keys:\r\n{0}", string.Join("\r\n", notFoundJsKeys)); - } - + } + [Test, Order(7)] [Category("Locales")] public void DublicatesFilesByMD5HashTest() @@ -541,8 +542,8 @@ public class LocalesTest .ToList(); Assert.AreEqual(0, duplicatesByMD5.Count, "Dublicates by MD5 hash:\r\n" + string.Join("\r\n", duplicatesByMD5.Select(d => $"\r\nMD5='{d.Key}':\r\n{string.Join("\r\n", d.Paths.Select(p => p))}'"))); - } - + } + [Test, Order(8)] [Category("Locales")] public void UselessTranslationKeysTest() @@ -627,8 +628,8 @@ public class LocalesTest { Language = g.Key, TranslationsWithVariables = g.ToList() - .SelectMany(t => t.Translations.Select(k => new TranslationItem($"{t.FileName}:{k.Key}", k.Value))) - //.Where(k => k.Value.IndexOf("{{") != -1) + .SelectMany(t => t.Translations.Select(k => new TranslationItem($"{t.FileName}:{k.Key}", k.Value))) + //.Where(k => k.Value.IndexOf("{{") != -1) .Select(t => new { t.Key, @@ -654,12 +655,12 @@ public class LocalesTest var i = 0; var errorsCount = 0; - foreach (var enKeyWithVariables in enWithVariables) - { - foreach (var lng in otherLanguagesWithVariables) - { - var lngKey = lng.TranslationsWithVariables - .Where(t => t.Key == enKeyWithVariables.Key) + foreach (var enKeyWithVariables in enWithVariables) + { + foreach (var lng in otherLanguagesWithVariables) + { + var lngKey = lng.TranslationsWithVariables + .Where(t => t.Key == enKeyWithVariables.Key) .FirstOrDefault(); if (lngKey == null) @@ -671,8 +672,8 @@ public class LocalesTest } if (enKeyWithVariables.Variables.Count != lngKey.Variables.Count) - { - // wrong + { + // wrong message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has less variables then 'en' language have " + $"(en={enKeyWithVariables.Variables.Count}|{lng.Language}={lngKey.Variables.Count})\r\n" + $"'en': '{enKeyWithVariables.Value}'\r\n'{lng.Language}': '{lngKey.Value}'\r\n\r\n"; @@ -680,10 +681,10 @@ public class LocalesTest } if (!lngKey.Variables.All(v => enKeyWithVariables.Variables.Contains(v))) - { - // wrong - message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has not equals variables of 'en' language have \r\n" + - $"'{enKeyWithVariables.Value}' Variables=[{string.Join(",", enKeyWithVariables.Variables)}]\r\n" + + { + // wrong + message += $"{++i}. lng='{lng.Language}' key='{lngKey.Key}' has not equals variables of 'en' language have \r\n" + + $"'{enKeyWithVariables.Value}' Variables=[{string.Join(",", enKeyWithVariables.Variables)}]\r\n" + $"'{lngKey.Value}' Variables=[{string.Join(",", lngKey.Variables)}]\r\n\r\n"; errorsCount++; } @@ -708,8 +709,8 @@ public class LocalesTest { Language = g.Key, TranslationsWithTags = g.ToList() - .SelectMany(t => t.Translations) - //.Where(k => k.Value.IndexOf("<") != -1) + .SelectMany(t => t.Translations) + //.Where(k => k.Value.IndexOf("<") != -1) .Select(t => new { t.Key, @@ -735,22 +736,22 @@ public class LocalesTest var i = 0; var errorsCount = 0; - foreach (var enKeyWithTags in enWithTags) - { - foreach (var lng in otherLanguagesWithTags) - { - var lngKey = lng.TranslationsWithTags - .Where(t => t.Key == enKeyWithTags.Key) - .FirstOrDefault(); - - if (lngKey == null) - { + foreach (var enKeyWithTags in enWithTags) + { + foreach (var lng in otherLanguagesWithTags) + { + var lngKey = lng.TranslationsWithTags + .Where(t => t.Key == enKeyWithTags.Key) + .FirstOrDefault(); + + if (lngKey == null) + { // wrong //message += $"{++i}. lng='{lng.Language}' key='{enKeyWithTags.Key}' not found\r\n\r\n"; //errorsCount++; - continue; - } - + continue; + } + if (enKeyWithTags.Tags.Count != lngKey.Tags.Count) { // wrong @@ -758,8 +759,8 @@ public class LocalesTest $"(en={enKeyWithTags.Tags.Count}|{lng.Language}={lngKey.Tags.Count})\r\n" + $"'en': '{enKeyWithTags.Value}'\r\n'{lng.Language}': '{lngKey.Value}'\r\n\r\n"; errorsCount++; - } - + } + if (!lngKey.Tags.All(v => enKeyWithTags.Tags.Contains(v))) { // wrong @@ -767,9 +768,9 @@ public class LocalesTest $"'{enKeyWithTags.Value}' Tags=[{string.Join(",", enKeyWithTags.Tags)}]\r\n" + $"'{lngKey.Value}' Tags=[{string.Join(",", lngKey.Tags)}]\r\n\r\n"; errorsCount++; - } - } - + } + } + } /*foreach (var lng in otherLanguagesWithTags) @@ -809,19 +810,18 @@ public class LocalesTest }*/ Assert.AreEqual(0, errorsCount, message); - } - + } + [Test, Order(13)] [Category("Locales")] public void ForbiddenValueElementsTest() { - var message = $"Next keys have forbidden values `{string.Join(",", ForbiddenElements)}`:\r\n\r\n"; - - + var message = $"Next keys have forbidden values `{string.Join(",", ForbiddenElements)}`:\r\n\r\n"; + var exists = false; - var i = 0; - + var i = 0; + foreach (var module in ModuleFolders) { if (module.AvailableLanguages == null) @@ -844,38 +844,41 @@ public class LocalesTest message += string.Join("\r\n", keys) + "\r\n\r\n"; } - } + } + foreach (var lng in CommonTranslations) { - var translationItems = lng.Translations.Where(f => ForbiddenElements.Any(elem => f.Value.ToUpper().Contains(elem))).ToList(); - - if (!translationItems.Any()) - continue; - - exists = true; - - message += $"{++i}. Language '{lng.Language}' (Count: {translationItems.Count}). Path '{lng.Path}' " + - $"Keys:\r\n\r\n"; - - var keys = translationItems.Select(t => t.Key).ToList(); - + var translationItems = lng.Translations + .Where(elem => !SkipForbiddenKeys.Exists(k => k == elem.Key)) + .Where(f => ForbiddenElements.Any(elem => f.Value.ToUpper().Contains(elem))) + .ToList(); + + if (!translationItems.Any()) + continue; + + exists = true; + + message += $"{++i}. Language '{lng.Language}' (Count: {translationItems.Count}). Path '{lng.Path}' " + + $"Keys:\r\n\r\n"; + + var keys = translationItems.Select(t => t.Key).ToList(); + message += string.Join("\r\n", keys) + "\r\n\r\n"; } Assert.AreEqual(false, exists, message); - } - + } + [Test, Order(14)] - [Category("Locales")] + [Category("Locales")] public void ForbiddenKeysElementsTest() { - var message = $"Next keys have forbidden elements in names `{string.Join(",", ForbiddenElements)}`:\r\n\r\n"; - - + var message = $"Next keys have forbidden elements in names `{string.Join(",", ForbiddenElements)}`:\r\n\r\n"; + var exists = false; - var i = 0; - + var i = 0; + foreach (var module in ModuleFolders) { if (module.AvailableLanguages == null) @@ -883,9 +886,8 @@ public class LocalesTest foreach (var lng in module.AvailableLanguages) { - var translationItems = lng.Translations.Where(f => ForbiddenElements.Any(elem => f.Key.ToUpper().Contains(elem))).ToList(); - - + var translationItems = lng.Translations.Where(f => ForbiddenElements.Any(elem => f.Key.ToUpper().Contains(elem))).ToList(); + if (!translationItems.Any()) continue; @@ -899,28 +901,31 @@ public class LocalesTest message += string.Join("\r\n", keys) + "\r\n\r\n"; } - } - + } + foreach (var lng in CommonTranslations) - { - var translationItems = lng.Translations.Where(f => ForbiddenElements.Any(elem => f.Key.ToUpper().Contains(elem))).ToList(); - - if (!translationItems.Any()) - continue; - - exists = true; - - message += $"{++i}. Language '{lng.Language}' (Count: {translationItems.Count}). Path '{lng.Path}' " + - $"Keys:\r\n\r\n"; - - var keys = translationItems.Select(t => t.Key).ToList(); - + { + var translationItems = lng.Translations + .Where(elem => !SkipForbiddenKeys.Exists(k => k == elem.Key)) + .Where(f => ForbiddenElements.Any(elem => f.Key.ToUpper().Contains(elem))) + .ToList(); + + if (!translationItems.Any()) + continue; + + exists = true; + + message += $"{++i}. Language '{lng.Language}' (Count: {translationItems.Count}). Path '{lng.Path}' " + + $"Keys:\r\n\r\n"; + + var keys = translationItems.Select(t => t.Key).ToList(); + message += string.Join("\r\n", keys) + "\r\n\r\n"; } Assert.AreEqual(false, exists, message); - } - + } + [Test, Order(15)] [Category("Locales")] public void EmptyValueKeysTest() @@ -1023,8 +1028,8 @@ public class LocalesTest } Assert.AreEqual(false, exists, message); - } - + } + [Test, Order(16)] [Category("Locales")] public void NotTranslatedKeysTest() @@ -1070,8 +1075,8 @@ public class LocalesTest } Assert.AreEqual(false, exists, message); - } - + } + [Test, Order(17)] [Category("Locales")] public void NotTranslatedCommonKeysTest() @@ -1113,7 +1118,7 @@ public class LocalesTest [Test, Order(18)] [Category("Locales")] public void NotAllLanguageTranslatedTest() - { + { var groupedByLng = TranslationFiles .GroupBy(t => t.Language) .Select(grp => new { Lng = grp.Key, Count = grp.Count(), Files = grp.ToList() }) @@ -1165,8 +1170,8 @@ public class LocalesTest } Assert.AreEqual(0, incompleteList.Count, message); - } - + } + [Test, Order(19)] [Category("SpellCheck")] public void SpellCheckTest() @@ -1207,43 +1212,43 @@ public class LocalesTest if (result.HasProblems) { - var incorrectWords = result.SpellIssues - .Where(t => !SpellCheckCommonExcludes - .Exists(e => e.Equals(t.Word, StringComparison.InvariantCultureIgnoreCase))) - .Select(issue => $"'{issue.Word}' " + + var incorrectWords = result.SpellIssues + .Where(t => !SpellCheckCommonExcludes + .Exists(e => e.Equals(t.Word, StringComparison.InvariantCultureIgnoreCase))) + .Select(issue => $"'{issue.Word}' " + $"Suggestion: '{issue.Suggestions.FirstOrDefault()}'") .ToList(); if (!incorrectWords.Any()) continue; - message += $"{++i}. lng='{group.Language}' file='{g.FilePath}'\r\nkey='{item.Key}' " + - $"value='{item.Value}'\r\nIncorrect words:\r\n" + + message += $"{++i}. lng='{group.Language}' file='{g.FilePath}'\r\nkey='{item.Key}' " + + $"value='{item.Value}'\r\nIncorrect words:\r\n" + $"{string.Join("\r\n", incorrectWords)}\r\n\r\n"; errorsCount++; - if (Save) - { + if (Save) + { foreach (var word in result.SpellIssues .Where(issue => issue.Suggestions.Any()) - .Select(issue => issue.Word)) - { - if (!spellCheckExclude.Excludes.Contains(word)) - { - spellCheckExclude.Excludes.Add(word); - } - } + .Select(issue => issue.Word)) + { + if (!spellCheckExclude.Excludes.Contains(word)) + { + spellCheckExclude.Excludes.Add(word); + } + } } } } } } - if (Save) - { - spellCheckExclude.Excludes.Sort(); - - list.Add(spellCheckExclude); + if (Save) + { + spellCheckExclude.Excludes.Sort(); + + list.Add(spellCheckExclude); } } catch (NotSupportedException) @@ -1253,135 +1258,135 @@ public class LocalesTest } } - if (Save) - { - string json = JsonConvert.SerializeObject(list, Formatting.Indented); - File.WriteAllText(_spellCheckExcludesPath, json, Encoding.UTF8); - TestContext.Progress.WriteLine($"File spellcheck-excludes.json has been saved to '{_spellCheckExcludesPath}'"); + if (Save) + { + string json = JsonConvert.SerializeObject(list, Formatting.Indented); + File.WriteAllText(_spellCheckExcludesPath, json, Encoding.UTF8); + TestContext.Progress.WriteLine($"File spellcheck-excludes.json has been saved to '{_spellCheckExcludesPath}'"); } Assert.AreEqual(0, errorsCount, message); - } - - /* [Test, Order(17)] - [Category("Locales")] - public void UselessModuleTranslationKeysTest() - { - var notFoundi18nKeys = new List>>(); - - var message = $"Some i18n-keys are not found in Module or Common translations: \r\nKeys: \r\n\r\n"; - - var index = 0; - - for (int i = 0; i < ModuleFolders.Count; i++) - { - var module = ModuleFolders[i]; - - if (module.AppliedJsTranslationKeys == null && module.AvailableLanguages != null) - { - message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' NOT USED\r\n"; - - var list = module.AvailableLanguages - .SelectMany(l => l.Translations.Select(t => t.Key).ToList()) - .ToList(); - - notFoundi18nKeys.Add(new KeyValuePair>("ANY LANGUAGES", list)); - - continue; - } - - var exepts = new List { "Error", "Done", "Warning", "Alert", "Info" }; - - var notCommonKeys = module.AppliedJsTranslationKeys - .Except(exepts) - .Where(k => !k.StartsWith("Common:")) - .OrderBy(t => t) - .ToList(); - - var onlyCommonKeys = module.AppliedJsTranslationKeys - .Except(notCommonKeys) - .Select(k => k.Replace("Common:", "")) - .OrderBy(t => t) - .ToList(); - - notCommonKeys = notCommonKeys.Select(k => k.Substring(k.IndexOf(":") + 1)).ToList(); - - if (onlyCommonKeys.Any()) - { - foreach (var lng in CommonTranslations) - { - var list = onlyCommonKeys - .Except(lng.Translations.Select(t => t.Key)) - .ToList(); - - if (!list.Any()) - continue; - - message += $"{++index}. '{lng.Language}' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; - - notFoundi18nKeys.Add(new KeyValuePair>(lng.Language, list)); - } - } - - if (module.AvailableLanguages == null) - { - if (notCommonKeys.Any()) - { - var commonEnKeys = CommonTranslations.First(c => c.Language == "en").Translations.Select(t => t.Key).ToList(); - - var list = notCommonKeys - .Except(commonEnKeys.Select(k => k)) - .ToList(); - - if (list.Any()) - { - message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; - notFoundi18nKeys.Add(new KeyValuePair>("ANY LANGUAGES", list)); - } - } - - continue; - } - - foreach (var lng in module.AvailableLanguages) - { - var list = lng.Translations - .Select(t => t.Key) - .Except(notCommonKeys) - .ToList(); - - if (!list.Any()) - continue; - - message += $"{++index}. '{lng.Language}' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; - - notFoundi18nKeys.Add(new KeyValuePair>(lng.Language, list)); - } - } - - Assert.AreEqual(0, notFoundi18nKeys.Count, message); - }*/ - - //[Test] - //[Category("Locales")] - //public void TranslationsEncodingTest() - //{ - // /*//Convert to UTF-8 - // foreach (var issue in WrongEncodingJsonErrors) - // { - // if (issue.DetectionDetail.Encoding == null) - // continue; - - // ConvertFileEncoding(issue.Path, issue.Path, issue.DetectionDetail.Encoding, Encoding.UTF8); - // }*/ - - // var message = $"Next files have encoding issues:\r\n\r\n"; - - // Assert.AreEqual(0, WrongEncodingJsonErrors.Count, - // message + string.Join("\r\n", WrongEncodingJsonErrors - // .Select(e => $"File path = '{e.Path}' potentially wrong file encoding: {e.DetectionDetail.EncodingName}"))); - //} - + } + + /* [Test, Order(17)] + [Category("Locales")] + public void UselessModuleTranslationKeysTest() + { + var notFoundi18nKeys = new List>>(); + + var message = $"Some i18n-keys are not found in Module or Common translations: \r\nKeys: \r\n\r\n"; + + var index = 0; + + for (int i = 0; i < ModuleFolders.Count; i++) + { + var module = ModuleFolders[i]; + + if (module.AppliedJsTranslationKeys == null && module.AvailableLanguages != null) + { + message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' NOT USED\r\n"; + + var list = module.AvailableLanguages + .SelectMany(l => l.Translations.Select(t => t.Key).ToList()) + .ToList(); + + notFoundi18nKeys.Add(new KeyValuePair>("ANY LANGUAGES", list)); + + continue; + } + + var exepts = new List { "Error", "Done", "Warning", "Alert", "Info" }; + + var notCommonKeys = module.AppliedJsTranslationKeys + .Except(exepts) + .Where(k => !k.StartsWith("Common:")) + .OrderBy(t => t) + .ToList(); + + var onlyCommonKeys = module.AppliedJsTranslationKeys + .Except(notCommonKeys) + .Select(k => k.Replace("Common:", "")) + .OrderBy(t => t) + .ToList(); + + notCommonKeys = notCommonKeys.Select(k => k.Substring(k.IndexOf(":") + 1)).ToList(); + + if (onlyCommonKeys.Any()) + { + foreach (var lng in CommonTranslations) + { + var list = onlyCommonKeys + .Except(lng.Translations.Select(t => t.Key)) + .ToList(); + + if (!list.Any()) + continue; + + message += $"{++index}. '{lng.Language}' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; + + notFoundi18nKeys.Add(new KeyValuePair>(lng.Language, list)); + } + } + + if (module.AvailableLanguages == null) + { + if (notCommonKeys.Any()) + { + var commonEnKeys = CommonTranslations.First(c => c.Language == "en").Translations.Select(t => t.Key).ToList(); + + var list = notCommonKeys + .Except(commonEnKeys.Select(k => k)) + .ToList(); + + if (list.Any()) + { + message += $"{++index}. 'ANY LANGUAGES' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; + notFoundi18nKeys.Add(new KeyValuePair>("ANY LANGUAGES", list)); + } + } + + continue; + } + + foreach (var lng in module.AvailableLanguages) + { + var list = lng.Translations + .Select(t => t.Key) + .Except(notCommonKeys) + .ToList(); + + if (!list.Any()) + continue; + + message += $"{++index}. '{lng.Language}' '{module.Path}' \r\n {string.Join("\r\n", list)} \r\n"; + + notFoundi18nKeys.Add(new KeyValuePair>(lng.Language, list)); + } + } + + Assert.AreEqual(0, notFoundi18nKeys.Count, message); + }*/ + + //[Test] + //[Category("Locales")] + //public void TranslationsEncodingTest() + //{ + // /*//Convert to UTF-8 + // foreach (var issue in WrongEncodingJsonErrors) + // { + // if (issue.DetectionDetail.Encoding == null) + // continue; + + // ConvertFileEncoding(issue.Path, issue.Path, issue.DetectionDetail.Encoding, Encoding.UTF8); + // }*/ + + // var message = $"Next files have encoding issues:\r\n\r\n"; + + // Assert.AreEqual(0, WrongEncodingJsonErrors.Count, + // message + string.Join("\r\n", WrongEncodingJsonErrors + // .Select(e => $"File path = '{e.Path}' potentially wrong file encoding: {e.DetectionDetail.EncodingName}"))); + //} + /*[Test] public void TempTest() { @@ -1468,8 +1473,8 @@ public class LocalesTest UpdateKeys(lng.Path, newKeys); } - }*/ - + }*/ + public static void SaveNotFoundKeys(string pathToJson, List newKeys) { if (!File.Exists(pathToJson)) @@ -1488,8 +1493,8 @@ public class LocalesTest var sortedJsonString = JsonConvert.SerializeObject(result, Formatting.Indented); File.WriteAllText(pathToJson, sortedJsonString, Encoding.UTF8); - } - + } + public static void SaveNotFoundLanguage(string existJsonPath, string notExistJsonPath) { if (!File.Exists(existJsonPath) || File.Exists(notExistJsonPath)) @@ -1513,8 +1518,8 @@ public class LocalesTest Directory.CreateDirectory(fullPathOnly); File.WriteAllText(notExistJsonPath, sortedJsonString, Encoding.UTF8); - } - + } + public static void UpdateKeys(string pathToJson, List newKeys) { if (!File.Exists(pathToJson) || !newKeys.Any()) @@ -1608,8 +1613,8 @@ public class LocalesTest var sortedJsonString = JsonConvert.SerializeObject(result, Formatting.Indented); File.WriteAllText(pathToJson, sortedJsonString, Encoding.UTF8); - } - + } + public static Tuple getPaths(string language) { const string dictionariesPath = @"../../../dictionaries"; @@ -1630,84 +1635,84 @@ public class LocalesTest var affPath = Utils.ConvertPathToOS(Path.Combine(path, language, $"{language}.aff")); return new Tuple(dicPath, affPath); - } + } - public static void ConvertFileEncoding(string sourcePath, string destPath, Encoding sourceEncoding, Encoding destEncoding) - { - // If the destination's parent doesn't exist, create it. - var parent = Path.GetDirectoryName(Path.GetFullPath(destPath)); - if (!Directory.Exists(parent)) - { - Directory.CreateDirectory(parent); - } - // If the source and destination encodings are the same, just copy the file. - if (sourceEncoding == destEncoding) - { - File.Copy(sourcePath, destPath, true); - return; - } - // Convert the file. - string tempName = null; - try - { - tempName = Path.GetTempFileName(); - using (StreamReader sr = new StreamReader(sourcePath, sourceEncoding, false)) - { - using (StreamWriter sw = new StreamWriter(tempName, false, destEncoding)) - { - int charsRead; - char[] buffer = new char[128 * 1024]; - while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0) - { - sw.Write(buffer, 0, charsRead); - } - } - } - File.Delete(destPath); - File.Move(tempName, destPath); - } - finally - { - File.Delete(tempName); - } + public static void ConvertFileEncoding(string sourcePath, string destPath, Encoding sourceEncoding, Encoding destEncoding) + { + // If the destination's parent doesn't exist, create it. + var parent = Path.GetDirectoryName(Path.GetFullPath(destPath)); + if (!Directory.Exists(parent)) + { + Directory.CreateDirectory(parent); + } + // If the source and destination encodings are the same, just copy the file. + if (sourceEncoding == destEncoding) + { + File.Copy(sourcePath, destPath, true); + return; + } + // Convert the file. + string tempName = null; + try + { + tempName = Path.GetTempFileName(); + using (StreamReader sr = new StreamReader(sourcePath, sourceEncoding, false)) + { + using (StreamWriter sw = new StreamWriter(tempName, false, destEncoding)) + { + int charsRead; + char[] buffer = new char[128 * 1024]; + while ((charsRead = sr.ReadBlock(buffer, 0, buffer.Length)) > 0) + { + sw.Write(buffer, 0, charsRead); + } + } + } + File.Delete(destPath); + File.Move(tempName, destPath); + } + finally + { + File.Delete(tempName); + } } /* [Test] - public void MoveKeysToCommon() - { - var findKeys = new List { + public void MoveKeysToCommon() + { + var findKeys = new List { "SharingPanel:CustomFilter", "SharingPanel:ReadOnly", "SharingPanel:DenyAccess", "SharingPanel:Comment", - "SharingPanel:ShareVia" - }; - - //var findKeys = new List { - // "Translations:DownloadApps", - //}; - - foreach (var findKey in findKeys) - { - var splitted = findKey.Split(":"); - var file = splitted[0]; - var key = splitted[1]; - - var tFiles = TranslationFiles.Where(t => t.FileName.Equals($"{file}.json", StringComparison.InvariantCultureIgnoreCase)); - - foreach (var tFile in tFiles) - { - var tKeys = tFile.Translations.Where(t => t.Key == key); - - foreach (var tKey in tKeys) - { - var commonPath = Utils.ConvertPathToOS(Path.Combine(BasePath, "public/locales", tFile.Language, "Common.json")); - - AddKeyValue(commonPath, tKey.Key, tKey.Value); - - RemoveKey(tFile.FilePath, key); - } - } - } + "SharingPanel:ShareVia" + }; + + //var findKeys = new List { + // "Translations:DownloadApps", + //}; + + foreach (var findKey in findKeys) + { + var splitted = findKey.Split(":"); + var file = splitted[0]; + var key = splitted[1]; + + var tFiles = TranslationFiles.Where(t => t.FileName.Equals($"{file}.json", StringComparison.InvariantCultureIgnoreCase)); + + foreach (var tFile in tFiles) + { + var tKeys = tFile.Translations.Where(t => t.Key == key); + + foreach (var tKey in tKeys) + { + var commonPath = Utils.ConvertPathToOS(Path.Combine(BasePath, "public/locales", tFile.Language, "Common.json")); + + AddKeyValue(commonPath, tKey.Key, tKey.Value); + + RemoveKey(tFile.FilePath, key); + } + } + } } */ } \ No newline at end of file From 1e47593fee9076389ac0ca9d513c0c64c284c7e4 Mon Sep 17 00:00:00 2001 From: DmitrySychugov Date: Fri, 19 Jul 2024 16:12:42 +0500 Subject: [PATCH 08/22] Shared: fixed thirdparty logo in dark theme --- packages/shared/components/tag/Tag.styled.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/shared/components/tag/Tag.styled.ts b/packages/shared/components/tag/Tag.styled.ts index d8b3a48a28..caf20a51cd 100644 --- a/packages/shared/components/tag/Tag.styled.ts +++ b/packages/shared/components/tag/Tag.styled.ts @@ -104,6 +104,20 @@ const StyledTag = styled.div<{ padding: 2px 0px; width: 16px; height: 16px; + + ${(props) => + !props.theme.isBase && + css` + svg { + path[fill] { + fill: #fff; + } + + path[stroke] { + stroke: #fff; + } + `} + } } ${(props) => From 4dca95bb824158edb1aa7b44ffc6ba852beef62a Mon Sep 17 00:00:00 2001 From: Andrey Savihin Date: Fri, 19 Jul 2024 15:06:42 +0300 Subject: [PATCH 09/22] images: added regional logos --- public/images/logo/zh-cn/aboutpage.svg | 26 ++++++++++++++++++ public/images/logo/zh-cn/dark_aboutpage.svg | 26 ++++++++++++++++++ public/images/logo/zh-cn/dark_leftmenu.svg | 5 ++++ public/images/logo/zh-cn/dark_lightsmall.svg | 19 +++++++++++++ public/images/logo/zh-cn/dark_loginpage.svg | 26 ++++++++++++++++++ public/images/logo/zh-cn/docseditor.svg | 27 +++++++++++++++++++ public/images/logo/zh-cn/docseditorembed.svg | 27 +++++++++++++++++++ public/images/logo/zh-cn/favicon.ico | Bin 0 -> 147237 bytes public/images/logo/zh-cn/leftmenu.svg | 5 ++++ public/images/logo/zh-cn/lightsmall.svg | 19 +++++++++++++ public/images/logo/zh-cn/loginpage.svg | 26 ++++++++++++++++++ 11 files changed, 206 insertions(+) create mode 100644 public/images/logo/zh-cn/aboutpage.svg create mode 100644 public/images/logo/zh-cn/dark_aboutpage.svg create mode 100644 public/images/logo/zh-cn/dark_leftmenu.svg create mode 100644 public/images/logo/zh-cn/dark_lightsmall.svg create mode 100644 public/images/logo/zh-cn/dark_loginpage.svg create mode 100644 public/images/logo/zh-cn/docseditor.svg create mode 100644 public/images/logo/zh-cn/docseditorembed.svg create mode 100644 public/images/logo/zh-cn/favicon.ico create mode 100644 public/images/logo/zh-cn/leftmenu.svg create mode 100644 public/images/logo/zh-cn/lightsmall.svg create mode 100644 public/images/logo/zh-cn/loginpage.svg diff --git a/public/images/logo/zh-cn/aboutpage.svg b/public/images/logo/zh-cn/aboutpage.svg new file mode 100644 index 0000000000..5ab9b62734 --- /dev/null +++ b/public/images/logo/zh-cn/aboutpage.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/dark_aboutpage.svg b/public/images/logo/zh-cn/dark_aboutpage.svg new file mode 100644 index 0000000000..1520d1ed29 --- /dev/null +++ b/public/images/logo/zh-cn/dark_aboutpage.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/dark_leftmenu.svg b/public/images/logo/zh-cn/dark_leftmenu.svg new file mode 100644 index 0000000000..e3d7dee1cf --- /dev/null +++ b/public/images/logo/zh-cn/dark_leftmenu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/images/logo/zh-cn/dark_lightsmall.svg b/public/images/logo/zh-cn/dark_lightsmall.svg new file mode 100644 index 0000000000..1625842d0f --- /dev/null +++ b/public/images/logo/zh-cn/dark_lightsmall.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/dark_loginpage.svg b/public/images/logo/zh-cn/dark_loginpage.svg new file mode 100644 index 0000000000..1520d1ed29 --- /dev/null +++ b/public/images/logo/zh-cn/dark_loginpage.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/docseditor.svg b/public/images/logo/zh-cn/docseditor.svg new file mode 100644 index 0000000000..cf18297bdd --- /dev/null +++ b/public/images/logo/zh-cn/docseditor.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/docseditorembed.svg b/public/images/logo/zh-cn/docseditorembed.svg new file mode 100644 index 0000000000..e98c69bcc4 --- /dev/null +++ b/public/images/logo/zh-cn/docseditorembed.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/favicon.ico b/public/images/logo/zh-cn/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dc87d1a88394e3aec8f283642442d2a85fb7bec1 GIT binary patch literal 147237 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 WZWFiWO#}mI$b@lIEH7G6w*DWe&UJwR literal 0 HcmV?d00001 diff --git a/public/images/logo/zh-cn/leftmenu.svg b/public/images/logo/zh-cn/leftmenu.svg new file mode 100644 index 0000000000..e3d7dee1cf --- /dev/null +++ b/public/images/logo/zh-cn/leftmenu.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/images/logo/zh-cn/lightsmall.svg b/public/images/logo/zh-cn/lightsmall.svg new file mode 100644 index 0000000000..0e0fda0e98 --- /dev/null +++ b/public/images/logo/zh-cn/lightsmall.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/public/images/logo/zh-cn/loginpage.svg b/public/images/logo/zh-cn/loginpage.svg new file mode 100644 index 0000000000..5ab9b62734 --- /dev/null +++ b/public/images/logo/zh-cn/loginpage.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + From e82fedc10d09e6b58d6dcb7e310b5f04c34e2023 Mon Sep 17 00:00:00 2001 From: gopienkonikita Date: Fri, 19 Jul 2024 15:10:45 +0300 Subject: [PATCH 10/22] Bug 69255 - Files.Uploads. Request failed with status code 429 --- packages/client/src/store/FilesSettingsStore.js | 7 ++++++- packages/client/src/store/UploadDataStore.js | 13 ++++++------- packages/shared/api/files/types.ts | 3 ++- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/client/src/store/FilesSettingsStore.js b/packages/client/src/store/FilesSettingsStore.js index e37a324c00..f13fb75904 100644 --- a/packages/client/src/store/FilesSettingsStore.js +++ b/packages/client/src/store/FilesSettingsStore.js @@ -69,7 +69,8 @@ class FilesSettingsStore { openEditorInSameTab = null; thumbnails1280x720 = window.ClientConfig?.thumbnails1280x720 || false; chunkUploadSize = 1024 * 1023; // 1024 * 1023; //~0.999mb - chunkUploadCount = 5; + maxUploadThreadCount = 15; + maxUploadFilesCount = 5; settingsIsLoaded = false; @@ -122,6 +123,10 @@ class FilesSettingsStore { this.settingsIsLoaded = isLoaded; }; + get uploadThreadCount() { + return this.maxUploadThreadCount / this.maxUploadFilesCount; + } + get isLoadedSettingsTree() { return ( this.confirmDelete !== null && diff --git a/packages/client/src/store/UploadDataStore.js b/packages/client/src/store/UploadDataStore.js index 4afea04396..eb37d92ebc 100644 --- a/packages/client/src/store/UploadDataStore.js +++ b/packages/client/src/store/UploadDataStore.js @@ -1173,7 +1173,7 @@ class UploadDataStore { operationId, toFolderId, ) => { - const { chunkUploadCount: asyncChunkUploadCount } = this.filesSettingsStore; + const { uploadThreadCount } = this.filesSettingsStore; const length = requestsDataArray.length; const isThirdPartyFolder = typeof toFolderId === "string"; @@ -1204,8 +1204,7 @@ class UploadDataStore { } const promise = new Promise((resolve, reject) => { - let i = - length <= asyncChunkUploadCount ? length : asyncChunkUploadCount; + let i = length <= uploadThreadCount ? length : uploadThreadCount; while (i !== 0) { this.asyncUpload( t, @@ -1269,15 +1268,15 @@ class UploadDataStore { // console.log("IS PARALLEL"); const notUploadedFiles = this.files.filter((f) => !f.inAction); - const { chunkUploadCount } = this.filesSettingsStore; + const { maxUploadFilesCount } = this.filesSettingsStore; const countFiles = - notUploadedFiles.length >= chunkUploadCount - ? chunkUploadCount + notUploadedFiles.length >= maxUploadFilesCount + ? maxUploadFilesCount : notUploadedFiles.length; for (let i = 0; i < countFiles; i++) { - if (this.currentUploadNumber <= chunkUploadCount) { + if (this.currentUploadNumber <= maxUploadFilesCount) { const fileIndex = this.files.findIndex( (f) => f.uniqueId === notUploadedFiles[i].uniqueId, ); diff --git a/packages/shared/api/files/types.ts b/packages/shared/api/files/types.ts index 30d033c2a7..e1b979b28e 100644 --- a/packages/shared/api/files/types.ts +++ b/packages/shared/api/files/types.ts @@ -240,7 +240,8 @@ export type TFilesSettings = { }; canSearchByContent: boolean; chunkUploadSize: number; - chunkUploadCount: number; + maxUploadThreadCount: number; + maxUploadFilesCount: number; confirmDelete: boolean; convertNotify: boolean; defaultOrder: { is_asc: boolean; property: 1 }; From 912e16c3f4454c6e9693cb7fd6bcf83f41260e2b Mon Sep 17 00:00:00 2001 From: Viktor Fomin Date: Fri, 19 Jul 2024 16:08:09 +0300 Subject: [PATCH 11/22] Fix Bug 69323 When opening file from Upload panel in the same tab no Close button in Editor --- .../src/components/panels/UploadPanel/FileRow.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/panels/UploadPanel/FileRow.js b/packages/client/src/components/panels/UploadPanel/FileRow.js index 378a47d527..c79c245ddb 100644 --- a/packages/client/src/components/panels/UploadPanel/FileRow.js +++ b/packages/client/src/components/panels/UploadPanel/FileRow.js @@ -323,6 +323,11 @@ class FileRow extends Component { const onMediaClick = () => this.onMediaClick(item.fileId); + const onFileClick = (url) => { + if (!url) return; + window.open(url, downloadInCurrentTab ? "_self" : "_blank"); + }; + return ( <> + onFileClick(item.fileInfo ? item.fileInfo.webUrl : "") + } fontWeight="600" color={item.error && "#A3A9AE"} truncate - href={item.fileInfo ? item.fileInfo.webUrl : ""} - target={downloadInCurrentTab ? "_self" : "_blank"} + // href={item.fileInfo ? item.fileInfo.webUrl : ""} + // target={downloadInCurrentTab ? "_self" : "_blank"} > {name} {fileExtension} From b091424f5d2fea36eec3590256948a4b214fa739 Mon Sep 17 00:00:00 2001 From: Alexey Safronov Date: Fri, 19 Jul 2024 17:50:33 +0400 Subject: [PATCH 12/22] Whitelabel: Fix hide skeletons on logoTextWhiteLabel equals empty string --- .../categories/common/Branding/whitelabel.js | 14 ++++++-------- packages/client/src/store/CommonStore.js | 7 +++++++ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/client/src/pages/PortalSettings/categories/common/Branding/whitelabel.js b/packages/client/src/pages/PortalSettings/categories/common/Branding/whitelabel.js index b7e950b285..ce16de94cd 100644 --- a/packages/client/src/pages/PortalSettings/categories/common/Branding/whitelabel.js +++ b/packages/client/src/pages/PortalSettings/categories/common/Branding/whitelabel.js @@ -74,11 +74,12 @@ const WhiteLabel = (props) => { resetIsInit, standalone, theme, + + isWhitelableLoaded, } = props; const navigate = useNavigate(); const location = useLocation(); - const [isLoadedData, setIsLoadedData] = useState(false); const [logoTextWhiteLabel, setLogoTextWhiteLabel] = useState(""); const [isSaving, setIsSaving] = useState(false); @@ -135,12 +136,6 @@ const WhiteLabel = (props) => { } }, [logoText]); - useEffect(() => { - if (logoTextWhiteLabel && logoUrlsWhiteLabel.length && !isLoadedData) { - setIsLoadedData(true); - } - }, [isLoadedData, logoTextWhiteLabel, logoUrlsWhiteLabel]); - const onResetCompanyName = async () => { const whlText = await getWhiteLabelLogoText(); saveToSessionStorage("companyName", whlText); @@ -265,7 +260,7 @@ const WhiteLabel = (props) => { const isEqualText = defaultLogoTextWhiteLabel === logoTextWhiteLabel; const saveButtonDisabled = isEqualLogo && isEqualText; - return !isLoadedData ? ( + return !isWhitelableLoaded ? ( ) : ( @@ -563,6 +558,7 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => { defaultLogoTextWhiteLabel, enableRestoreButton, resetIsInit, + isWhitelableLoaded, } = common; const { @@ -590,5 +586,7 @@ export default inject(({ settingsStore, common, currentQuotaStore }) => { deviceType, resetIsInit, standalone, + + isWhitelableLoaded, }; })(withTranslation(["Settings", "Profile", "Common"])(observer(WhiteLabel))); diff --git a/packages/client/src/store/CommonStore.js b/packages/client/src/store/CommonStore.js index 591209f825..2b599ff796 100644 --- a/packages/client/src/store/CommonStore.js +++ b/packages/client/src/store/CommonStore.js @@ -211,6 +211,13 @@ class CommonStore { this.applyNewLogos(logos); }; + get isWhitelableLoaded() { + return ( + this.logoUrlsWhiteLabel.length > 0 && + this.whiteLabelLogoText !== undefined + ); + } + getGreetingSettingsIsDefault = async () => { const isDefault = await api.settings.getGreetingSettingsIsDefault(); runInAction(() => { From ea46b0496ccfb4e9eb204996c0e6a15facbfb61a Mon Sep 17 00:00:00 2001 From: Ilya Date: Fri, 19 Jul 2024 17:14:44 +0300 Subject: [PATCH 13/22] Add translations for ZH --- i18next/client.babel | 1503 +---------------- i18next/common.babel | 496 +----- i18next/editor.babel | 22 +- i18next/login.babel | 46 +- i18next/management.babel | 25 +- .../public/locales/en/FillPDFDialog.json | 2 +- .../locales/zh-CN/ChangePortalOwner.json | 7 + .../locales/zh-CN/ChangeUserStatusDialog.json | 6 +- .../locales/zh-CN/ChangeUserTypeDialog.json | 1 + .../client/public/locales/zh-CN/Confirm.json | 9 + .../locales/zh-CN/CreateEditRoomDialog.json | 7 +- .../public/locales/zh-CN/DeleteDialog.json | 2 + .../zh-CN/DeleteProfileEverDialog.json | 3 + .../zh-CN/DeleteSelfProfileDialog.json | 1 + .../locales/zh-CN/DowngradePlanDialog.json | 1 + .../public/locales/zh-CN/EmbeddingPanel.json | 7 + .../public/locales/zh-CN/EmptyView.json | 26 +- .../client/public/locales/zh-CN/Errors.json | 1 + .../client/public/locales/zh-CN/Files.json | 11 + .../public/locales/zh-CN/FilesSettings.json | 1 + .../public/locales/zh-CN/FillPDFDialog.json | 10 +- .../public/locales/zh-CN/HotkeysPanel.json | 1 + .../public/locales/zh-CN/InfoPanel.json | 34 + .../public/locales/zh-CN/InviteDialog.json | 4 + .../public/locales/zh-CN/JavascriptSdk.json | 18 + .../client/public/locales/zh-CN/Ldap.json | 75 +- .../client/public/locales/zh-CN/MainBar.json | 5 + .../public/locales/zh-CN/Notifications.json | 6 +- .../public/locales/zh-CN/PDFFormDialog.json | 8 +- .../client/public/locales/zh-CN/Payments.json | 8 + .../locales/zh-CN/PaymentsEnterprise.json | 4 + .../locales/zh-CN/PeopleTranslations.json | 4 + .../locales/zh-CN/PortalUnavailable.json | 5 +- .../locales/zh-CN/PreparationPortal.json | 5 +- .../client/public/locales/zh-CN/Profile.json | 2 + .../client/public/locales/zh-CN/Settings.json | 47 + .../public/locales/zh-CN/SingleSignOn.json | 1 + .../public/locales/zh-CN/Translations.json | 1 + .../public/locales/zh-CN/WebPlugins.json | 5 +- .../client/public/locales/zh-CN/Webhooks.json | 4 +- .../client/public/locales/zh-CN/Wizard.json | 4 +- .../public/locales/zh-CN/CompletedForm.json | 9 +- .../login/public/locales/zh-CN/Login.json | 7 +- .../public/locales/zh-CN/Management.json | 5 + public/locales/zh-CN/Common.json | 36 + 45 files changed, 388 insertions(+), 2097 deletions(-) diff --git a/i18next/client.babel b/i18next/client.babel index bf85847edd..302e72939d 100644 --- a/i18next/client.babel +++ b/i18next/client.babel @@ -1,5 +1,5 @@ - +