Merge branch 'release/v2.5.0' into feature/sdk-codeblock-redesign

This commit is contained in:
Ilya Oleshko 2024-04-10 14:00:46 +03:00
commit 14840653de
380 changed files with 3779 additions and 2735 deletions

View File

@ -14,16 +14,9 @@
-->
<link
id="favicon"
rel="shortcut icon"
sizes="any"
href="/storage/whitelabel/root/favicon.png"
onerror="this.onerror=null;this.href='favicon.ico';"
/>
<link
id="favicon-icon"
rel="icon"
href="/storage/whitelabel/root/favicon.png"
onerror="this.onerror=null;this.href='favicon.ico';"
type="image/x-icon"
href="/logo.ashx?logotype=3"
/>
<link rel="manifest" href="/manifest.json" />
@ -31,17 +24,6 @@
<!-- <meta name="mobile-web-app-capable" content="yes" /> -->
<!-- Tell iOS it's a PWA -->
<!-- <meta name="apple-mobile-web-app-capable" content="yes" /> -->
<!-- <link rel="apple-touch-icon" href="../../../public/appIcon-180.png" /> -->
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<meta name="react-apple-itunes-app" content="app-id=944896972" />
<meta
@ -49,17 +31,6 @@
content="app-id=com.onlyoffice.documents"
/>
<link
rel="apple-touch-icon"
href="/storage/whitelabel/root/favicon.png"
onerror="this.onerror=null;this.href='favicon.ico';"
/>
<link
rel="android-touch-icon"
href="/storage/whitelabel/root/favicon.png"
onerror="this.onerror=null;this.href='favicon.ico';"
/>
<!-- <%= htmlWebpackPlugin.options.custom %> -->
<style type="text/css">

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "وضع علامة كإصدار",
"MarkedAsFavorite": "تمت الإضافة إلى المفضلة",
"MarkRead": "ضع إشارة مقروء",
"MaximumNumberOfExternalLinksCreated": "تم إنشاء الحد الأقصى من الروابط الخارجية",
"Media": "الوسائط",
"MoveItem": "تم نقل <strong> {{title}} </strong>",
"MoveItems": "تم نقل العناصر <strong> {{qty}} </strong>",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Versiya kimi qeyd edin",
"MarkedAsFavorite": "Çox istifadə olunan siyahısına əlavə olundu",
"MarkRead": "Oxunmuş kimi işarələ",
"MaximumNumberOfExternalLinksCreated": "Yaradılan xarici keçidlərin maksimum sayı",
"Media": "Media",
"MoveItem": "<strong>{{title}}</strong> yerdəyişdirildi",
"MoveItems": "<strong>{{qty}}</strong> elementlərin yeri dəyişdirildi",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Маркирай като версия",
"MarkedAsFavorite": "Добавен в любими",
"MarkRead": "Маркирай като прочетено",
"MaximumNumberOfExternalLinksCreated": "Максимален брой създадени външни линкове",
"Media": "Медия",
"MoveItem": "<strong>{{title}}</strong> е преместен",
"MoveItems": "<strong>{{qty}}</strong> елемента бяха преместени",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Označit jako verzi",
"MarkedAsFavorite": "Přidáno k oblíbeným",
"MarkRead": "Označit jako přečtené",
"MaximumNumberOfExternalLinksCreated": "Maximální počet vytvořených externích odkazů",
"Media": "Média",
"MoveItem": "<strong>{{title}}</strong> přesunuty",
"MoveItems": "Prvky <strong>{{qty}}</strong> byly přesunuty",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Als Version markieren",
"MarkedAsFavorite": "Zu Favoriten hinzugefügt",
"MarkRead": "Als gelesen kennzeichnen",
"MaximumNumberOfExternalLinksCreated": "Maximale Anzahl der erstellten externen Links",
"Media": "Medien",
"MoveItem": "<strong>{{title}}</strong> verschoben",
"MoveItems": "Elemente verschoben: <strong>{{qty}}</strong>",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "Die Formular-Galerie ist momentan nicht verfügbar",
"SelectForm": "Formular auswählen",
"SubmitToGalleryDialogGuideInfo": "Erfahren Sie in unserem <1>Leitfaden</1>, wie Sie perfekte Formulare erstellen und Ihre Chancen auf eine Genehmigung erhöhen können.",
"GuideLink": "https://www.onlyoffice.com/blog/de/2022/07/wenn-design-wichtig-ist-erstellung-schoner-formulare",
"SubmitToGalleryDialogMainInfo": "Reichen Sie Ihr Formular in der öffentlichen Galerie ein, damit andere es für ihre Arbeit verwenden können. Sobald das Formular die Moderation bestanden hat, werden Sie benachrichtigt und für Ihren Beitrag belohnt.",
"SuggestChanges": "Änderungen vorschlagen",
"TemplateInfo": "Informationen zur Vorlage",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Επισήμανση ως έκδοση",
"MarkedAsFavorite": "Προστέθηκε στα αγαπημένα",
"MarkRead": "Σήμανση ως αναγνωσμένου",
"MaximumNumberOfExternalLinksCreated": "Δημιουργήθηκε ο μέγιστος αριθμός εξωτερικών συνδέσμων",
"Media": "Πολυμέσα",
"MoveItem": "Το <strong>{{title}}</strong> μετακινήθηκε",
"MoveItems": "<strong>{{qty}}</strong> στοιχεία έχουν μετακινηθεί",

View File

@ -14,5 +14,9 @@
"MoveToTrashTitle": "Move to Trash?",
"UnsubscribeButton": "Unsubscribe",
"UnsubscribeNote": "Are you sure you want to unsubscribe from the selected items from the list?",
"UnsubscribeTitle": "Unsubscribe confirmation"
"UnsubscribeTitle": "Unsubscribe confirmation",
"DeleteGroupTitle": "Delete group",
"DeleteAllGroupsTitle": "Delete groups",
"DeleteGroupDescription": "Group {{groupName}} will be deleted. Users in the group will not be removed from DocSpace. Are you sure you want to continue?",
"DeleteAllGroupDescription": "The selected groups will be deleted. Users in the groups will not be removed from DocSpace. Are you sure you want to continue?"
}

View File

@ -105,7 +105,6 @@
"MarkAsVersion": "Mark as version",
"MarkedAsFavorite": "Added to favorites",
"MarkRead": "Mark as read",
"MaximumNumberOfExternalLinksCreated": "Maximum number of external links created",
"Media": "Media",
"MoveItem": "<strong>{{title}}</strong> moved",
"MoveItems": "<strong>{{qty}}</strong> elements have been moved",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "Form gallery is temporarily unavailable",
"SelectForm": "Select Form",
"SubmitToGalleryDialogGuideInfo": "Learn how to create perfect forms and increase your chance to get approval in our <1>guide</1>.",
"GuideLink": "https://www.onlyoffice.com/blog/2022/07/when-design-matters-how-to-create-beautiful-forms-with-oforms",
"SubmitToGalleryDialogMainInfo": "Submit your form to the public gallery to let others use it in their work. Once the form passes moderation, you will be notified and rewarded for your contribution.",
"SuggestChanges": "Suggest changes",
"TemplateInfo": "Template info",

View File

@ -65,7 +65,7 @@
"LimitByTime": "Limit by time period",
"LinkSettings": "This link is protected with a {{parameter}}. To configure the link,",
"LinkSettings2": "A {{parameter1}} and {{parameter2}} is set for this link. To configure it,",
"LinkSettings3": "A {{parameter1}}, {{parameter2}}, and {{parameter2}} is set for this link. To configure it,",
"LinkSettings3": "A {{parameter1}}, {{parameter2}}, and {{parameter3}} is set for this link. To configure it,",
"Logo": "Logo",
"MainElementParameter": "Main element parameter",
"ManagerSearchBlockDescription": "You can disable the search, filter and sort options.",

View File

@ -54,7 +54,9 @@
"BrandingSubtitle": "Use this option to provide on-brand experience to users.",
"BreakpointSmallText": "Your window is too small to display all page contents",
"BreakpointSmallTextPrompt": "Please resize the window or enable full-screen mode",
"BreakpointMobileWarningText": "This section is unavailable in mobile version",
"BreakpointWarningText": "This section is only available in the desktop version",
"BreakpointMobileWarningTextPrompt": "Please use the desktop or tablet to access the <1>{{sectionName}}</1>.",
"BreakpointWarningTextPrompt": "Please use the desktop site to access <1>{{sectionName}}</1> settings.",
"BruteForceProtection": "Brute Force Protection",
"BruteForceProtectionDescription": "Set up the limit of unsuccessful login attempts by the user to protect the space against brute-force attacks. When the limit is reached, attempts coming from the associated IP address will be banned for specified period of time, or captcha will be requested if enabled.",
@ -122,6 +124,7 @@
"EnterTime": "Enter time",
"EnterTitle": "Enter title",
"ErrorMessageBruteForceProtection": "Specified argument was out of the range of valid values.",
"ErrorOccuredDownloadLog": "Errors occurred during data import. Download the log to check them.",
"ErrorsWereFound": "{{errors}} errors were found",
"ExistingAccount": "Existing account",
"ForcePathStyle": "Force Path Style",
@ -171,6 +174,7 @@
"NewColorScheme": "New color scheme",
"NextStep": "Next step",
"NoEmail": "NO EMAIL",
"NoUsersInBackup": "No users found. Try again or upload other backup files.",
"NumberOfActiveEmployees": "Number of active employees: {{count}}",
"NumberOfAttempts": "Number of attempts",
"PasswordMinLenght": "Minimal password length",
@ -304,4 +308,4 @@
"WithoutEmailHint": "You dont have users without emails. Please proceed to the next step.",
"YouHaveUnsavedChanges": "You have unsaved changes",
"YourCurrentDomain": "Your current domain"
}
}

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Marcar como versión",
"MarkedAsFavorite": "Agregado a los favoritos",
"MarkRead": "Marcar como leído",
"MaximumNumberOfExternalLinksCreated": "Número máximo de enlaces externos creados",
"Media": "Multimedia",
"MoveItem": "<strong>{{title}}</strong> movido",
"MoveItems": "<strong>{{qty}}</strong> elementos se han movido",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "La galería de formularios no está disponible temporalmente ",
"SelectForm": "Seleccionar formulario",
"SubmitToGalleryDialogGuideInfo": "Aprenda a crear formularios perfectos y a aumentar sus posibilidades de obtener la aprobación en nuestra <1>guía</1>.",
"GuideLink": "https://www.onlyoffice.com/blog/es/2022/07/como-crear-formularios-bonitos-con-oforms",
"SubmitToGalleryDialogMainInfo": "Envíe su formulario a la galería pública para que otros puedan utilizarlo en su trabajo. Una vez que el formulario pase la moderación, recibirá una notificación y una recompensa por su contribución.",
"SuggestChanges": "Sugerir cambios",
"TemplateInfo": "Información sobre la plantilla",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Merkitse versioksi",
"MarkedAsFavorite": "Lisätty suosikkeihin",
"MarkRead": "Merkitse luetuksi",
"MaximumNumberOfExternalLinksCreated": "Enimmäismäärä ulkoisia linkkejä luotu",
"Media": "Media",
"MoveItem": "<strong> {{title}} </strong> siirretty",
"MoveItems": "<strong> {{qty}} </strong> elementtiä on siirretty",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Marquer comme version",
"MarkedAsFavorite": "Ajouté aux favoris",
"MarkRead": "Marquer comme lu(s)",
"MaximumNumberOfExternalLinksCreated": "Nombre maximum de liens externes créés",
"Media": "Média",
"MoveItem": "<strong>{{title}}</strong> déplacé",
"MoveItems": "<strong>{{qty}}</strong> éléments ont été déplacés",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "La galerie de formulaires est temporairement indisponible",
"SelectForm": "Sélectionner un formulaire",
"SubmitToGalleryDialogGuideInfo": "Apprenez à créer des formulaires parfaits et augmentez vos chances d'obtenir une approbation dans notre <1>guide</1>.",
"GuideLink": "https://www.onlyoffice.com/blog/fr/2022/07/creer-beaux-formulaires-avec-oforms",
"SubmitToGalleryDialogMainInfo": "Soumettez votre formulaire à la galerie publique pour permettre à d'autres personnes de l'utiliser dans leur travail. Une fois le formulaire modéré, vous serez informé et récompensé pour votre contribution.",
"SuggestChanges": "Proposer des modifications",
"TemplateInfo": "Informations sur le modèle",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Նշել որպես տարբերակ",
"MarkedAsFavorite": "Ավելացվեց ընտրյալների մեջ",
"MarkRead": "Նշել որպես ընթերցված",
"MaximumNumberOfExternalLinksCreated": "Ստեղծված արտաքին հղումների առավելագույն քանակը",
"Media": "Մեդիա",
"MoveItem": "<strong>{{title}}</strong> տեղափոխել է",
"MoveItems": "<strong>{{qty}}</strong> տարրերը տեղափոխվել են",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Contrassegna come versione",
"MarkedAsFavorite": "Aggiungi ai favoriti",
"MarkRead": "Segnare come letto",
"MaximumNumberOfExternalLinksCreated": "Numero massimo di link esterni creati",
"Media": "Multimedia",
"MoveItem": "<strong>{{title}}</strong> spostato",
"MoveItems": "I seguenti elementi sono stati spostati: <strong>{{qty}}</strong>",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "La galleria dei moduli è temporaneamente non disponibile",
"SelectForm": "Seleziona modulo",
"SubmitToGalleryDialogGuideInfo": "Scopri come creare moduli perfetti e aumentare le tue possibilità di ottenere l'approvazione nella nostra <1>guida</1>.",
"GuideLink": "https://www.onlyoffice.com/blog/it/2022/07/2022-07-come-creare-bellissimi-moduli-con-oform",
"SubmitToGalleryDialogMainInfo": "Invia il tuo modulo alla galleria pubblica per consentire ad altri di utilizzarlo nel loro lavoro. Una volta che il modulo avrà superato la moderazione, riceverai una notifica e sarai ricompensato per il tuo contributo.",
"SuggestChanges": "Suggerire modifiche",
"TemplateInfo": "Informazioni sul modello",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "バージョンとしてマークする",
"MarkedAsFavorite": "お気に入りに追加",
"MarkRead": "既読にする",
"MaximumNumberOfExternalLinksCreated": "作成される外部リンクの最大数",
"Media": "メディア",
"MoveItem": "<strong>{{title}}</strong>を移動した",
"MoveItems": "<strong>{{qty}}</strong>の要素が移動しました",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "フォームギャラリーは一時的に利用できません",
"SelectForm": "フォームの選択",
"SubmitToGalleryDialogGuideInfo": "<1>ガイド</1>で、完璧なフォームを作成し、承認を得るチャンスを増やす方法を学びましょう。",
"GuideLink": "https://www.onlyoffice.com/blog/ja/2022/07/when-design-matters-how-to-create-beautiful-forms-with-oforms",
"SubmitToGalleryDialogMainInfo": "あなたのフォームを公開ギャラリーに投稿して、他の人に使ってもらいましょう。フォームがモデレーションを通過すると、あなたに通知され、あなたの貢献に対して報酬が与えられます。",
"SuggestChanges": "変更点のご提案",
"TemplateInfo": "テンプレート情報",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "버전으로 표시",
"MarkedAsFavorite": "즐겨 찾기에 추가되었습니다",
"MarkRead": "읽은 것으로 표시",
"MaximumNumberOfExternalLinksCreated": "생성된 외부 링크의 최대 갯수",
"Media": "미디어",
"MoveItem": "<strong>{{title}}</strong> 이동 완료",
"MoveItems": "<strong>{{qty}}</strong> 요소 이동 완료",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Atzīmēt kā versiju",
"MarkedAsFavorite": "Pievienots izlasei",
"MarkRead": "Atzīmēt kā lasītu",
"MaximumNumberOfExternalLinksCreated": "Maksimālais izveidoto ārējo saišu skaits",
"Media": "Multivide",
"MoveItem": "<strong>{{title}}</strong> pārvietots",
"MoveItems": "<strong>{{qty}}</strong> elementi ir pārvietoti",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Markeren als versie",
"MarkedAsFavorite": "Toegevoegd aan favorieten",
"MarkRead": "Markeer als gelezen",
"MaximumNumberOfExternalLinksCreated": "Maximum aantal gemaakte externe links",
"Media": "Media",
"MoveItem": "<strong>{{title}}</strong> verplaatst",
"MoveItems": "<strong>{{qty}}</strong> elementen zijn verplaatst",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Oznacz jako wersję",
"MarkedAsFavorite": "Dodano do ulubionych",
"MarkRead": "Oznacz jako przeczytane",
"MaximumNumberOfExternalLinksCreated": "Utworzono maksymalną liczbę linków zewnętrznych",
"Media": "Media",
"MoveItem": "Przeniesiono <strong>{{title}}</strong>",
"MoveItems": "Przeniesiono <strong>{{qty}}</strong> element(y/ów)",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Marcar como versão",
"MarkedAsFavorite": "Adicionado aos favoritos",
"MarkRead": "Marcar como lido",
"MaximumNumberOfExternalLinksCreated": "Número máximo de links externos criados",
"Media": "Média",
"MoveItem": "<strong>{{title}}</strong> movido",
"MoveItems": "<strong>{{qty}}</strong> elementos foram movidos",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "A galeria de formulários está temporariamente indisponível",
"SelectForm": "Selecione o formulário",
"SubmitToGalleryDialogGuideInfo": "Aprenda como criar formulários perfeitos e aumente suas chances de obter aprovação em nosso <1>guide</1>.",
"GuideLink": "https://www.onlyoffice.com/blog/es/2022/07/como-crear-formularios-bonitos-con-oforms",
"SubmitToGalleryDialogMainInfo": "Envie seu formulário para a galeria pública para permitir que outras pessoas o utilizem em seus trabalhos. Assim que o formulário for aprovado na moderação, você será notificado e recompensado por sua contribuição.",
"SuggestChanges": "Sugerir alterações",
"TemplateInfo": "Informações do modelo",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Marcar como versão",
"MarkedAsFavorite": "Adicionar ao favoritos",
"MarkRead": "Marcar como lido",
"MaximumNumberOfExternalLinksCreated": "Número máximo de links externos criados",
"Media": "Multimédia",
"MoveItem": "<strong>{{title}}</strong> movido",
"MoveItems": "<strong>{{qty}}</strong> elementos foram movidos",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Marcare ca versiune",
"MarkedAsFavorite": "Adăugat la preferințe",
"MarkRead": "Marchează ca citit",
"MaximumNumberOfExternalLinksCreated": "Numărul maxim permis de link-uri externe a fost depășit",
"Media": "Media",
"MoveItem": "<strong>{{title}}</strong> deplasat",
"MoveItems": "<strong>{{qty}}</strong> elemente au fost deplasate",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Отметить как версию",
"MarkedAsFavorite": "Добавлено в избранное",
"MarkRead": "Пометить прочтённым",
"MaximumNumberOfExternalLinksCreated": "Максимальное количество созданных внешних ссылок",
"Media": "Медиа",
"MoveItem": "<strong>{{title}}</strong> перемещен",
"MoveItems": "Перемещено элементов: <strong>{{qty}}</strong>",

View File

@ -6,7 +6,7 @@
"AccessRightsChangeOwnerConfirmText": "Изменения будут применены после подтверждения по электронной почте.",
"AccessRightsProductUsersCan": "В модуле {{category}} участники портала со статусом Пользователи могут",
"AccessRightsUsersFromList": "Участников со статусом {{users}} из списка",
"AccountsWithoutEmails": "Мы нашли <1>{{users}} пользователей</1> без электронной почты. На следующем шаге вы можете добавить необходимые данные в их учетные записи.",
"AccountsWithoutEmails": "Мы нашли <1>{{users}} пользователей</1> без электронной почты. Вы можете заполнить их электронные почты или продолжить без этого действия.",
"AddAllowedIP": "Добавить разрешенный IP-адрес",
"AddEmails": "Добавьте адреса электронной почты в незавершенные аккаунты",
"AdditionalResources": "Дополнительные ресурсы",
@ -279,4 +279,4 @@
"WhiteLabelTooltip": "Размеры указаны для дисплеев Retina. Для дисплеев со стандартным разрешением ширина и высота логотипа будут соответственно изменены при загрузке.",
"YouHaveUnsavedChanges": "Имеются несохраненные изменения",
"YourCurrentDomain": "Ваш текущий домен"
}
}

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Označiť ako verziu",
"MarkedAsFavorite": "Pridané k obľúbeným",
"MarkRead": "Označiť ako prečítané",
"MaximumNumberOfExternalLinksCreated": "Maximálny počet vytvorených externých odkazov",
"Media": "Médiá",
"MoveItem": "<strong> {{title}} </strong> bolo presunuté",
"MoveItems": "<strong>{{qty}}</strong> prvkov bolo presunutých",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Označi kot verzijo",
"MarkedAsFavorite": "Dodano med priljubljene",
"MarkRead": "Označi kot prebrano",
"MaximumNumberOfExternalLinksCreated": "Maksimalno število ustvarjenih zunanjih povezav",
"Media": "Medij",
"MoveItem": "<strong>{{title}}</strong> premaknjen",
"MoveItems": "<strong>{{qty}}</strong> elementov je bilo premaknjenih",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Sürüm olarak işaretle",
"MarkedAsFavorite": "Favorilere eklendi",
"MarkRead": "Okundu olarak işaretle",
"MaximumNumberOfExternalLinksCreated": "Maksimum sayıda harici bağlantı oluşturuldu",
"Media": "Medya",
"MoveItem": "<strong>{{title}}</strong> taşındı",
"MoveItems": "<strong>{{qty}}</strong> öğeler taşındı",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Позначити як версію",
"MarkedAsFavorite": "Додано до вподобань",
"MarkRead": "Позначити як прочитані",
"MaximumNumberOfExternalLinksCreated": "Максимальна кількість створених зовнішніх посилань",
"Media": "Медіа",
"MoveItem": "<strong>{{title}}</strong> переміщено",
"MoveItems": "<strong>{{qty}}</strong> елемент. переміщено",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "Đánh dấu là phiên bản",
"MarkedAsFavorite": "Đã thêm vào mục yêu thích",
"MarkRead": "Đánh dấu là đã đọc",
"MaximumNumberOfExternalLinksCreated": "Số lượng liên kết bên ngoài tối đa đã được tạo",
"Media": "Phương tiện",
"MoveItem": "<strong>{{title}}</strong> đã được chuyển ",
"MoveItems": "<strong>{{qty}}</strong> thành phần đã được chuyển ",

View File

@ -87,7 +87,6 @@
"MarkAsVersion": "标记为版本",
"MarkedAsFavorite": "已添加至收藏",
"MarkRead": "标记为已读",
"MaximumNumberOfExternalLinksCreated": "创建外部链接的最大数量",
"Media": "媒体",
"MoveItem": "<strong>{{title}}</strong>已移动",
"MoveItems": "<strong>{{qty}}</strong>元素已移动",

View File

@ -5,7 +5,6 @@
"ErrorViewHeader": "表单库暂时不可用",
"SelectForm": "选择表单",
"SubmitToGalleryDialogGuideInfo": "通过我们的<1>指南</1>,了解如何创建完备的表单,提高获得批准的机会。",
"GuideLink": "https://www.onlyoffice.com/blog/zh-hans/2024/02/when-design-matters-how-to-create-beautiful-forms-with-oforms",
"SubmitToGalleryDialogMainInfo": "将您的表单提交至公共表单库,让他人在工作中使用。表单通过审核,您就会收到通知、获得奖励。",
"SuggestChanges": "提出修改建议",
"TemplateInfo": "模板信息",

View File

@ -230,6 +230,7 @@ const Client = inject(
const { isInit: isInitPlugins, initPlugins } = pluginStore;
const { isVisible } = infoPanelStore;
const isProfile = window.location.pathname.includes("/profile");
return {
isDesktop: isDesktopClient,
@ -244,7 +245,7 @@ const Client = inject(
isLoaded: authStore.isLoaded && clientLoadingStore.isLoaded,
setIsLoaded: clientLoadingStore.setIsLoaded,
withMainButton,
isInfoPanelVisible: isVisible,
isInfoPanelVisible: isVisible && !isProfile,
setIsFilterLoading: setIsSectionFilterLoading,
setIsHeaderLoading: setIsSectionHeaderLoading,
isLoading,

View File

@ -31,7 +31,7 @@ import { combineUrl } from "@docspace/shared/utils/combineUrl";
import Badges from "../components/Badges";
import config from "PACKAGE_FILE";
import copy from "copy-to-clipboard";
import { copyShareLink } from "@docspace/shared/utils/copy";
import { toastr } from "@docspace/shared/components/toast";
import { isMobileOnly } from "react-device-detect";
@ -116,12 +116,10 @@ export default function withBadges(WrappedComponent) {
};
onCopyPrimaryLink = async () => {
if (isMobileOnly) return;
const { t, item, getPrimaryLink } = this.props;
const primaryLink = await getPrimaryLink(item.id);
if (primaryLink) {
copy(primaryLink.sharedTo.shareLink);
copyShareLink(primaryLink.sharedTo.shareLink);
toastr.success(t("Common:LinkSuccessfullyCopied"));
}
};

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import React from "react";
import { useCallback } from "react";
import { inject, observer } from "mobx-react";
import { useTranslation } from "react-i18next";
@ -41,6 +41,10 @@ export default function withContent(WrappedContent) {
deselectUser,
setBufferSelection,
selectRow,
singleContextMenuAction,
multipleContextMenuAction,
resetSelections,
openGroupAction,
theme,
getModel,
@ -50,26 +54,43 @@ export default function withContent(WrappedContent) {
const { mobilePhone, email, role, displayName, avatar } = item;
const onContentRowSelect = (checked, user) => {
setBufferSelection(null, false);
setBufferSelection(null);
checked ? selectUser(user) : deselectUser(user);
};
const onContentRowClick = (
checked,
user,
addToSelection = true,
isContextClick = true,
) => {
if (isContextClick) {
checked
? setBufferSelection(user, addToSelection)
: setBufferSelection(null);
const onContextClick = (item, isSingleMenu) => {
isSingleMenu
? singleContextMenuAction(item)
: multipleContextMenuAction(item);
};
const onContentRowClick = (e, user) => {
if (
e.target?.tagName === "A" ||
e.target.closest(".checkbox") ||
e.target.closest(".table-container_row-checkbox") ||
e.target.closest(".type-combobox") ||
e.target.closest(".groups-combobox") ||
e.target.closest(".paid-badge") ||
e.target.closest(".pending-badge") ||
e.target.closest(".disabled-badge") ||
e.target.closest(".dropdown-container") ||
e.detail === 0
) {
return;
}
selectRow(user);
};
const onOpenGroup = useCallback(
(groupId, withBackURL, tempTitle) => {
resetSelections();
openGroupAction(groupId, withBackURL, tempTitle);
},
[resetSelections, openGroupAction],
);
const checkedProps = { checked };
const element = (
@ -102,6 +123,7 @@ export default function withContent(WrappedContent) {
<WrappedContent
onContentRowSelect={onContentRowSelect}
onContentRowClick={onContentRowClick}
onUserContextClick={onContextClick}
onPhoneClick={onPhoneClick}
onEmailClick={onEmailClick}
groups={[]}
@ -109,6 +131,7 @@ export default function withContent(WrappedContent) {
element={element}
contextOptionsProps={contextOptionsProps}
value={value}
onOpenGroup={onOpenGroup}
{...props}
/>
);
@ -119,6 +142,7 @@ export default function withContent(WrappedContent) {
const { getTargetUser } = peopleStore.targetUserStore;
const { selectionStore, contextOptionsStore } = peopleStore;
const { openGroupAction } = peopleStore.groupsStore;
const { getModel } = contextOptionsStore;
@ -129,6 +153,9 @@ export default function withContent(WrappedContent) {
selectUser,
deselectUser,
selectRow,
singleContextMenuAction,
multipleContextMenuAction,
resetSelections,
} = selectionStore;
return {
@ -144,6 +171,10 @@ export default function withContent(WrappedContent) {
deselectUser,
getModel,
selectRow,
singleContextMenuAction,
multipleContextMenuAction,
resetSelections,
openGroupAction,
};
})(observer(WithContent));
}

View File

@ -27,8 +27,8 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { toastr } from "@docspace/shared/components/toast";
import { copyShareLink } from "@docspace/shared/utils/copy";
import QuickButtons from "../components/QuickButtons";
import copy from "copy-to-clipboard";
export default function withQuickButtons(WrappedComponent) {
class WithQuickButtons extends React.Component {
@ -83,7 +83,7 @@ export default function withQuickButtons(WrappedComponent) {
const { t, item, getPrimaryFileLink, setShareChanged } = this.props;
const primaryLink = await getPrimaryFileLink(item.id);
if (primaryLink) {
copy(primaryLink.sharedTo.shareLink);
copyShareLink(primaryLink.sharedTo.shareLink);
item.shared
? toastr.success(t("Common:LinkSuccessfullyCopied"))
: toastr.success(t("Files:LinkSuccessfullyCreatedAndCopied"));
@ -95,7 +95,7 @@ export default function withQuickButtons(WrappedComponent) {
const { t, item, getPrimaryLink } = this.props;
const primaryLink = await getPrimaryLink(item.id);
if (primaryLink) {
copy(primaryLink.sharedTo.shareLink);
copyShareLink(primaryLink.sharedTo.shareLink);
toastr.success(t("Common:LinkSuccessfullyCopied"));
}
};

View File

@ -33,7 +33,6 @@ import { useTranslation } from "react-i18next";
import { isMobile, isIOS, isFirefox } from "react-device-detect";
import { toast as toastify } from "react-toastify";
import { setFavicon } from "@docspace/shared/utils/favicon";
import { Portal } from "@docspace/shared/components/portal";
import { SnackBar } from "@docspace/shared/components/snackbar";
import { Toast, toastr } from "@docspace/shared/components/toast";
@ -78,7 +77,6 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
setSnackbarExist,
userTheme,
//user,
whiteLabelLogoUrls,
userId,
currentDeviceType,
timezone,
@ -130,11 +128,6 @@ const Shell = ({ items = [], page = "home", ...rest }) => {
moment.locale(language);
}, []);
useEffect(() => {
if (!whiteLabelLogoUrls) return;
setFavicon(whiteLabelLogoUrls);
}, [whiteLabelLogoUrls]);
useEffect(() => {
socketHelper.emit({
command: "subscribe",
@ -469,7 +462,6 @@ const ShellWrapper = inject(
setSnackbarExist,
socketHelper,
setTheme,
whiteLabelLogoUrls,
currentDeviceType,
isFrame,
frameConfig,
@ -521,7 +513,6 @@ const ShellWrapper = inject(
setSnackbarExist,
userTheme: isFrame ? frameConfig?.theme : userTheme,
userId: userStore?.user?.id,
whiteLabelLogoUrls,
currentDeviceType,
showArticleLoader: clientLoadingStore.showArticleLoader,
setPortalTariff,

View File

@ -31,6 +31,7 @@ import styled, { css } from "styled-components";
import { inject, observer } from "mobx-react";
import { mobile } from "@docspace/shared/utils";
import { isMobileOnly } from "react-device-detect";
import { MainButtonMobile } from "@docspace/shared/components/main-button-mobile";
@ -41,16 +42,21 @@ const StyledMainButtonMobile = styled(MainButtonMobile)`
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
left: 24px;
left: ${isMobileOnly
? "calc(16px + env(safe-area-inset-left))"
: "24px"};
`
: css`
right: 24px;
right: ${isMobileOnly
? "calc(16px + env(safe-area-inset-right))"
: "24px"};
`}
bottom: 24px;
@media ${mobile} {
position: absolute;
bottom: 16px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`

View File

@ -402,10 +402,14 @@ const ArticleMainButtonContent = (props) => {
action: EmployeeType.Guest,
key: "user",
},
{
isSeparator: true,
key: "invite-users-separator",
},
...(!isMobileArticle
? [
{
isSeparator: true,
key: "invite-users-separator",
},
]
: []),
{
id: "invite_again",
className: "main-button_drop-down",
@ -541,6 +545,7 @@ const ArticleMainButtonContent = (props) => {
onShowSelectFileDialog,
onUploadFileClick,
onUploadFolderClick,
isMobileArticle,
]);
const mainButtonText = t("Common:Actions");

View File

@ -88,7 +88,6 @@ export default inject<TStore>(
currentDeviceType,
standalone,
isBurgerLoading,
whiteLabelLogoUrls,
} = settingsStore;
const { isFreeTariff, isNonProfit, isTrial, currentTariffPlanTitle } =
@ -116,7 +115,6 @@ export default inject<TStore>(
showProgress,
isBurgerLoading,
whiteLabelLogoUrls,
isEnterprise,
isTrial,
isLicenseDateExpired,

View File

@ -38,13 +38,21 @@ const BreakpointWarning = ({
tReady,
theme,
isSmallWindow,
isMobileUnavailableOnly,
}) => {
const textHeader = isSmallWindow
? t("BreakpointSmallText")
: t("BreakpointWarningText");
: isMobileUnavailableOnly
? t("BreakpointMobileWarningText")
: t("BreakpointWarningText");
const textPrompt = isSmallWindow ? (
t("BreakpointSmallTextPrompt")
) : isMobileUnavailableOnly ? (
<Trans t={t} i18nKey="BreakpointMobileWarningTextPrompt" ns="Settings">
"Please use the desktop site to access the {{ sectionName }}
settings."
</Trans>
) : (
<Trans t={t} i18nKey="BreakpointWarningTextPrompt" ns="Settings">
"Please use the desktop site to access the {{ sectionName }}

View File

@ -29,16 +29,8 @@ import { inject, observer } from "mobx-react";
import DocspaceLogo from "@docspace/shared/components/docspace-logo/DocspaceLogo";
import type { DocspaceLogoProps } from "@docspace/shared/components/docspace-logo/DocspaceLogo.types";
const DocspaceLogoWrapper = ({
whiteLabelLogoUrls,
className,
}: Partial<DocspaceLogoProps>) => {
return (
<DocspaceLogo
whiteLabelLogoUrls={whiteLabelLogoUrls!}
className={className}
/>
);
const DocspaceLogoWrapper = ({ className }: Partial<DocspaceLogoProps>) => {
return <DocspaceLogo className={className} />;
};
export default inject<TStore>(({ settingsStore }) => {

View File

@ -34,12 +34,8 @@ const Error520Wrapper = (props: Error520Props) => {
};
export default inject<TStore>(({ authStore, settingsStore, userStore }) => {
const {
whiteLabelLogoUrls,
firebaseHelper,
currentDeviceType,
currentColorScheme,
} = settingsStore;
const { firebaseHelper, currentDeviceType, currentColorScheme } =
settingsStore;
const { user } = userStore;
const version = authStore.version;
@ -48,7 +44,6 @@ export default inject<TStore>(({ authStore, settingsStore, userStore }) => {
version,
firebaseHelper,
currentDeviceType,
whiteLabelLogoUrls,
currentColorScheme,
};
})(observer(Error520Wrapper));

View File

@ -34,12 +34,8 @@ const ErrorBoundaryWrapper = (props: ErrorBoundaryProps) => {
};
export default inject<TStore>(({ authStore, settingsStore, userStore }) => {
const {
whiteLabelLogoUrls,
firebaseHelper,
currentDeviceType,
currentColorScheme,
} = settingsStore;
const { firebaseHelper, currentDeviceType, currentColorScheme } =
settingsStore;
const { user } = userStore;
const version = authStore.version;
@ -49,7 +45,6 @@ export default inject<TStore>(({ authStore, settingsStore, userStore }) => {
version,
firebaseHelper,
currentDeviceType,
whiteLabelLogoUrls,
currentColorScheme,
};
})(observer(ErrorBoundaryWrapper));

View File

@ -34,6 +34,7 @@ export type FilesSelectorProps = {
isPanelVisible: boolean;
// withoutImmediatelyClose: boolean;
isThirdParty: boolean;
isSelectFolder: boolean;
rootThirdPartyId?: string;
isRoomsOnly: boolean;
isUserOnly: boolean;

View File

@ -62,6 +62,7 @@ const FilesSelectorWrapper = ({
isRoomsOnly = false,
isUserOnly = false,
isEditorDialog = false,
isSelectFolder = false,
rootThirdPartyId,
filterParam,
@ -273,7 +274,7 @@ const FilesSelectorWrapper = ({
isSelect,
filterParam,
isRestore,
isThirdParty,
isSelectFolder,
);
const defaultAcceptButtonLabel = getAcceptButtonLabel(
@ -285,6 +286,7 @@ const FilesSelectorWrapper = ({
isSelect,
filterParam,
isRestore,
isSelectFolder,
);
const getIsDisabledAction = (
@ -303,7 +305,7 @@ const FilesSelectorWrapper = ({
return getIsDisabled(
isFirstLoad,
isSelectedParentFolder,
fromFolderId === selectedItemId,
fromFolderId === Number(selectedItemId),
selectedItemType === "rooms",
isRoot,
isCopy,
@ -479,7 +481,7 @@ export default inject(
(rootFolderType === FolderType.Archive ||
rootFolderType === FolderType.TRASH
? undefined
: selectedId === selectionsWithoutEditing[0]?.id
: selectedId !== selectionsWithoutEditing[0]?.id
? parentId
: selectedId);

View File

@ -41,10 +41,10 @@ export const getHeaderLabel = (
isSelect?: boolean,
filterParam?: string,
isRestore?: boolean,
isThirdParty?: boolean,
isSelectFolder?: boolean,
) => {
if (isRestore) return t("Common:RestoreTo");
if (isThirdParty) return t("Common:SelectFolder");
if (isSelectFolder) return t("Common:SelectFolder");
if (isMove) return t("Common:MoveTo");
if (isCopy && !isEditorDialog) return t("Common:Copy");
if (isRestoreAll) return t("Common:Restore");
@ -68,12 +68,13 @@ export const getAcceptButtonLabel = (
isSelect?: boolean,
filterParam?: string,
isRestore?: boolean,
isSelectFolder?: boolean,
) => {
if (isRestore) return t("Common:RestoreHere");
if (isMove) return t("Common:MoveHere");
if (isCopy && !isEditorDialog) return t("Common:CopyHere");
if (isRestoreAll) return t("Common:RestoreHere");
if (isSelect) return t("Common:SelectAction");
if (isSelect || isSelectFolder) return t("Common:SelectAction");
if (filterParam === FilesSelectorFilterTypes.DOCX) return t("Common:Create");
// if (filterParam === FilesSelectorFilterTypes.DOCXF) return t("Common:SubmitToGallery");

View File

@ -39,6 +39,7 @@ const FilesSelectorInput = (props) => {
id,
isThirdParty,
isRoomsOnly,
isSelectFolder,
setNewPath,
newPath,
onSelectFolder: setSelectedFolder,
@ -126,6 +127,7 @@ const FilesSelectorInput = (props) => {
rootThirdPartyId={rootThirdPartyId}
isThirdParty={isThirdParty}
isRoomsOnly={isRoomsOnly}
isSelectFolder={isSelectFolder}
id={id}
onClose={onClose}
isPanelVisible={isPanelVisible}

View File

@ -26,6 +26,7 @@
import React, { useEffect, useCallback, useState } from "react";
import { inject, observer } from "mobx-react";
import { isMobile, isIOS } from "react-device-detect";
import { toastr } from "@docspace/shared/components/toast";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
@ -67,6 +68,7 @@ const Dialog = ({
useEffect(() => {
let input = document?.getElementById("create-text-input");
if (isMobile && isIOS) return;
if (input && value === startValue && !isChanged) input.select();
}, [visible, value]);

View File

@ -33,12 +33,17 @@ import { Link as LinkWithoutRedirect } from "react-router-dom";
import { isMobileOnly, isMobile } from "react-device-detect";
import { useLocation } from "react-router-dom";
import { useTranslation } from "react-i18next";
import { isDesktop, tablet, mobile } from "@docspace/shared/utils";
import {
isDesktop,
tablet,
mobile,
NoUserSelect,
getLogoUrl,
} from "@docspace/shared/utils";
import { WhiteLabelLogoType } from "@docspace/shared/enums";
import { combineUrl } from "@docspace/shared/utils/combineUrl";
import { NoUserSelect } from "@docspace/shared/utils";
import HeaderCatalogBurger from "./header-catalog-burger";
import { Base } from "@docspace/shared/themes";
import { getLogoFromPath } from "@docspace/shared/utils";
const Header = styled.header`
display: flex;
@ -231,9 +236,7 @@ const HeaderComponent = ({
return () => window.removeEventListener("resize", onResize);
});
const logo = getLogoFromPath(
!theme.isBase ? logoUrl?.path?.dark : logoUrl?.path?.light,
);
const logo = getLogoUrl(WhiteLabelLogoType.LightSmall, !theme.isBase);
return (
<>

View File

@ -29,8 +29,9 @@ import { Link } from "react-router-dom";
import PropTypes from "prop-types";
import styled from "styled-components";
import { inject, observer } from "mobx-react";
import { NoUserSelect } from "@docspace/shared/utils";
import { getLogoFromPath } from "@docspace/shared/utils";
import { NoUserSelect, getLogoUrl } from "@docspace/shared/utils";
import { WhiteLabelLogoType } from "@docspace/shared/enums";
const LogoItem = styled.div`
display: flex;
min-width: 48px;
@ -54,7 +55,10 @@ const NavLogoItem = (props) => {
return (
<LogoItem opened={props.opened}>
<Link className="nav-logo-wrapper" to="/" onClick={props.onClick}>
<img className="nav-logo-icon" src={getLogoFromPath(props.logoUrl)} />
<img
className="nav-logo-icon"
src={getLogoUrl(WhiteLabelLogoType.LightSmall)}
/>
</Link>
</LogoItem>
);

View File

@ -117,13 +117,8 @@ const QuickButtons = (props) => {
!isArchiveFolder &&
!isTile;
const onShare = () => {
if (isMobile()) return;
onClickShare();
};
return (
<div className="badges additional-badges badges__quickButtons">
<div className="badges additional-badges badges__quickButtons">
{isAvailableLockFile && (
<ColorTheme
themeId={ThemeId.IconButton}
@ -171,7 +166,7 @@ const QuickButtons = (props) => {
iconName={LinkReactSvgUrl}
className="badge copy-link icons-group"
size={sizeQuickButton}
onClick={onShare}
onClick={onClickShare}
color={colorShare}
isDisabled={isDisabled}
hoverColor={theme.filesQuickButtons.sharedColor}

View File

@ -38,6 +38,12 @@ const StyledBody = styled.div`
max-height: 32px;
}
.quota_checkbox {
svg {
margin-right: 8px;
}
}
.quota_value {
max-width: fit-content;
padding: 0;

View File

@ -225,6 +225,7 @@ const QuotaForm = ({
<Checkbox
label={checkboxLabel}
isChecked={isChecked}
className="quota_checkbox"
onChange={onChangeCheckbox}
isDisabled={isLoading || isDisabled}
/>

View File

@ -31,12 +31,14 @@ const StyledBody = styled.div`
overflow: hidden;
width: 100%;
max-width: max-content;
margin-left: 0px !important;
display: flex;
flex-wrap: nowrap;
height: 28px;
align-items: center;
p {
padding-top: 8px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;

View File

@ -60,7 +60,7 @@ const PureConnectDialogContainer = (props) => {
setIsConnectDialogReconnect,
saveAfterReconnectOAuth,
setSaveAfterReconnectOAuth,
setSelectedThirdPartyAccount,
setThirdPartyAccountsInfo,
} = props;
const { title, link, token, provider_id, provider_key, key } = item;
@ -169,9 +169,8 @@ const PureConnectDialogContainer = (props) => {
provider_key,
provider_id,
)
.then(() => {
onClose();
setSelectedThirdPartyAccount(null);
.then(async () => {
await setThirdPartyAccountsInfo();
})
.catch((err) => {
toastr.error(err);
@ -424,7 +423,7 @@ export default inject(
const { id, folders } = selectedFolderStore;
const {
selectedThirdPartyAccount: backupConnectionItem,
setSelectedThirdPartyAccount,
setThirdPartyAccountsInfo,
} = backup;
const {
connectDialogVisible: visible,
@ -455,12 +454,12 @@ export default inject(
openConnectWindow,
fetchThirdPartyProviders,
setConnectDialogVisible,
setSelectedThirdPartyAccount,
personal,
isConnectDialogReconnect,
saveAfterReconnectOAuth,
setSaveAfterReconnectOAuth,
setIsConnectDialogReconnect,
setThirdPartyAccountsInfo,
};
},
)(observer(ConnectDialog));

View File

@ -37,6 +37,8 @@ import SimulatePassword from "../../SimulatePassword";
import StyledComponent from "./StyledConvertPasswordDialog";
import config from "PACKAGE_FILE";
let _isMounted = false;
const ConvertPasswordDialogComponent = (props) => {
const {
t,

View File

@ -24,7 +24,7 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { useState } from "react";
import { useCallback } from "react";
import { useTranslation } from "react-i18next";
import { SelectorAddButton } from "@docspace/shared/components/selector-add-button";
import PlusSvgUrl from "PUBLIC_DIR/images/icons/16/button.plus.react.svg?url";
@ -32,13 +32,16 @@ import * as Styled from "./index.styled";
import SelectGroupMembersPanel from "./SelectGroupMembersPanel";
import GroupMemberRow from "../GroupMemberRow";
interface MembersParamProps {
groupManager: object | null;
groupMembers: object[] | null;
setGroupMembers: (groupMembers: object[]) => void;
onShowSelectMembersPanel: () => void;
interface GroupMember {
id: string;
}
interface MembersParamProps {
groupManager: GroupMember | null;
groupMembers: GroupMember[] | null;
setGroupMembers: (groupMembers: GroupMember[]) => void;
onShowSelectMembersPanel: () => void;
}
const MembersParam = ({
groupManager,
groupMembers,
@ -47,10 +50,13 @@ const MembersParam = ({
}: MembersParamProps) => {
const { t } = useTranslation(["Common", "PeopleTranslation"]);
const onRemoveUserById = (id: string) => {
const newGroupMembers = groupMembers?.filter((gm) => gm.id !== id);
setGroupMembers(newGroupMembers || []);
};
const onRemoveUserById = useCallback(
(id: string) => {
const newGroupMembers = groupMembers?.filter((gm) => gm.id !== id);
setGroupMembers(newGroupMembers || []);
},
[groupMembers, setGroupMembers],
);
return (
<div>
@ -61,16 +67,16 @@ const MembersParam = ({
<div className="label">{t("PeopleTranslations:AddMembers")}</div>
</Styled.AddMembersButton>
{groupMembers.map(
(member) =>
member.id !== groupManager?.id && (
{groupMembers &&
groupMembers
.filter((member) => member.id !== groupManager?.id)
.map((member) => (
<GroupMemberRow
key={member.id}
groupMember={member}
onClickRemove={() => onRemoveUserById(member.id)}
/>
),
)}
))}
</div>
);
};

View File

@ -85,7 +85,7 @@ const CreateRoomDialog = ({
const startRoomParams = {
type: undefined,
title: title,
title: title ?? "",
tags: [],
isPrivate: false,
storageLocation: {
@ -116,6 +116,9 @@ const CreateRoomDialog = ({
setRoomParams((prev) => ({
...prev,
type: newRoomType,
storageLocation: {
isThirdparty: false,
},
}));
};

View File

@ -72,7 +72,8 @@ const EditRoomDialog = ({
.join("|")
.toLowerCase() &&
((prevParams.icon.uploadedFile === "" &&
currentParams.icon.uploadedFile === null) ||
(currentParams.icon.uploadedFile === null ||
currentParams.icon.uploadedFile === undefined)) ||
prevParams.icon.uploadedFile === currentParams.icon.uploadedFile) &&
prevParams.quota === currentParams.quota
);

View File

@ -50,7 +50,7 @@ const ChangeRoomOwner = ({
<div className="change-owner-display">
<Avatar
className={"change-owner-display-avatar"}
size="base"
size="min"
role={""}
isDefaultSource={roomOwner.hasAvatar}
source={roomOwner.avatarSmall ?? roomOwner.avatar}

View File

@ -42,7 +42,7 @@ const DialogHeader = ({ t, isEdit, isChooseRoomType, onArrowClick }) => {
) : (
<div className="header-with-button">
<IconButton
size="15px"
size={17}
iconName={ArrowPathReactSvgUrl}
className="sharing_panel-arrow"
onClick={onArrowClick}

View File

@ -52,22 +52,30 @@ const StyledDropdownMobile = styled.div`
StyledDropdownMobile.defaultProps = { theme: Base };
const DropdownMobile = ({ t, open, onClose, chooseRoomType }) => {
const DropdownMobile = ({
t,
open,
onClose,
chooseRoomType,
forсeHideDropdown,
}) => {
return (
<>
<Backdrop visible={open} onClick={onClose} zIndex={450} />
<StyledDropdownMobile className="dropdown-mobile" isOpen={open}>
{RoomsTypeValues.map((roomType) => (
<RoomType
id={roomType}
t={t}
key={roomType}
roomType={roomType}
type="dropdownItem"
onClick={() => chooseRoomType(roomType)}
/>
))}
</StyledDropdownMobile>
{!forсeHideDropdown && (
<StyledDropdownMobile className="dropdown-mobile" isOpen={open}>
{RoomsTypeValues.map((roomType) => (
<RoomType
id={roomType}
t={t}
key={roomType}
roomType={roomType}
type="dropdownItem"
onClick={() => chooseRoomType(roomType)}
/>
))}
</StyledDropdownMobile>
)}
</>
);
};

View File

@ -25,7 +25,7 @@
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { isMobile } from "@docspace/shared/utils";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import styled from "styled-components";
import RoomType from "../RoomType";
import DropdownDesktop from "./DropdownDesktop";
@ -49,6 +49,7 @@ const RoomTypeDropdown = ({
setRoomType,
setIsScrollLocked,
isDisabled,
forсeHideDropdown,
}) => {
const [isOpen, setIsOpen] = useState(false);
@ -68,6 +69,14 @@ const RoomTypeDropdown = ({
setRoomType(roomType);
toggleDropdown();
};
useEffect(() => {
if (forсeHideDropdown) {
setIsScrollLocked(false);
setIsOpen(false);
}
}, [forсeHideDropdown]);
return (
<StyledRoomTypeDropdown isOpen={isOpen}>
<RoomType
@ -85,6 +94,7 @@ const RoomTypeDropdown = ({
open={isOpen}
onClose={toggleDropdown}
chooseRoomType={chooseRoomType}
forсeHideDropdown={forсeHideDropdown}
/>
) : (
<DropdownDesktop t={t} open={isOpen} chooseRoomType={chooseRoomType} />

View File

@ -103,6 +103,9 @@ const SetRoomParams = ({
useState(true);
const [disableImageRescaling, setDisableImageRescaling] = useState(isEdit);
const [forceHideRoomTypeDropdown, setForceHideRoomTypeDropdown] =
useState(false);
const isFormRoom = roomParams.type === RoomsType.FormRoom;
const isPublicRoom = roomParams.type === RoomsType.PublicRoom;
@ -155,6 +158,7 @@ const SetRoomParams = ({
setRoomType={setRoomType}
setIsScrollLocked={setIsScrollLocked}
isDisabled={isDisabled}
forсeHideDropdown={forceHideRoomTypeDropdown}
/>
)}
{isEdit && (
@ -176,6 +180,8 @@ const SetRoomParams = ({
isDisabled={isDisabled}
isValidTitle={isValidTitle}
isWrongTitle={isWrongTitle}
onFocus={() => setForceHideRoomTypeDropdown(true)}
onBlur={() => setForceHideRoomTypeDropdown(false)}
errorMessage={
isWrongTitle
? t("Files:ContainsSpecCharacter")
@ -184,11 +190,14 @@ const SetRoomParams = ({
onKeyUp={onKeyUp}
isAutoFocussed={true}
/>
<TagInput
t={t}
tagHandler={tagHandler}
setIsScrollLocked={setIsScrollLocked}
isDisabled={isDisabled}
onFocus={() => setForceHideRoomTypeDropdown(true)}
onBlur={() => setForceHideRoomTypeDropdown(false)}
/>
{/* //TODO: Uncomment when private rooms are done

View File

@ -52,7 +52,14 @@ const StyledTagInput = styled.div`
${({ hasTags }) => !hasTags && "margin-bottom: -8px"}
`;
const TagInput = ({ t, tagHandler, setIsScrollLocked, isDisabled }) => {
const TagInput = ({
t,
tagHandler,
setIsScrollLocked,
isDisabled,
onFocus,
onBlur,
}) => {
const inputRef = useRef();
const [tagInput, setTagInput] = useState("");
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
@ -69,13 +76,6 @@ const TagInput = ({ t, tagHandler, setIsScrollLocked, isDisabled }) => {
setTagInput(text);
};
const handleFocus = (event) => {
const text = event.target.value;
if (text.trim().length > 0) {
openDropdown();
}
};
const openDropdown = () => {
if (isDisabled) return;
setIsScrollLocked(true);
@ -87,6 +87,19 @@ const TagInput = ({ t, tagHandler, setIsScrollLocked, isDisabled }) => {
setIsDropdownOpen(false);
};
const handleFocus = (event) => {
const text = event.target.value;
if (text.trim().length > 0) {
openDropdown();
}
onFocus();
};
const handleBlur = () => {
closeDropdown();
onBlur();
};
const handleKeyDown = (event) => {
const keyCode = event.code;
@ -110,8 +123,8 @@ const TagInput = ({ t, tagHandler, setIsScrollLocked, isDisabled }) => {
placeholder={t("TagsPlaceholder")}
value={tagInput}
onChange={onTagInputChange}
onBlur={closeDropdown}
onFocus={handleFocus}
onBlur={handleBlur}
isDisabled={isDisabled}
onKeyDown={handleKeyDown}
/>

View File

@ -214,9 +214,9 @@ const FolderInput = ({
isPanelVisible={isDialogOpen}
onClose={onClose}
isThirdParty
isSelectFolder
onSelectTreeNode={setTreeNode}
passedFoldersTree={[thirdpartyAccount]}
acceptButtonLabel={t("Common:SelectAction")}
currentFolderId={treeNode ? treeNode.id : thirdpartyAccount.id}
/>
)}

View File

@ -24,102 +24,39 @@
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import ExpanderDownReactSvgUrl from "PUBLIC_DIR/images/expander-down.react.svg?url";
import React, { useEffect, useState, useRef } from "react";
import styled from "styled-components";
import { ReactSVG } from "react-svg";
import { StyledDropDown, StyledDropDownWrapper } from "../StyledDropdown";
import { isMobile as isMobileUtil, DomHelpers } from "@docspace/shared/utils";
import { isMobileOnly, isMobile } from "react-device-detect";
import { isMobile, DomHelpers } from "@docspace/shared/utils";
import { Text } from "@docspace/shared/components/text";
import { Button } from "@docspace/shared/components/button";
import { DropDownItem } from "@docspace/shared/components/drop-down-item";
import { connectedCloudsTypeTitleTranslation as ProviderKeyTranslation } from "@docspace/client/src/helpers/filesUtils";
import { Base } from "@docspace/shared/themes";
import { toastr } from "@docspace/shared/components/toast";
import { ComboBox } from "@docspace/shared/components/combobox";
const StyledStorageLocation = styled.div`
display: flex;
flex-direction: column;
.thirdparty-combobox {
padding: 0px;
.dropdown-container {
border: ${(props) =>
`1px solid ${props.theme.createEditRoomDialog.thirdpartyStorage.combobox.dropdownBorderColor}`};
}
.combo-button {
padding-left: 8px;
}
}
.set_room_params-thirdparty {
display: flex;
flex-direction: row;
gap: 8px;
&-combobox {
cursor: pointer;
width: 100%;
display: flex;
flex-direction: row;
justify-content: space-between;
padding: 5px 7px;
background: ${(props) =>
props.theme.createEditRoomDialog.thirdpartyStorage.combobox.background};
border-radius: 3px;
max-height: 32px;
border: ${(props) =>
`1px solid ${
props.isOpen
? props.theme.createEditRoomDialog.thirdpartyStorage.combobox
.isOpenDropdownBorderColor
: props.theme.createEditRoomDialog.thirdpartyStorage.combobox
.dropdownBorderColor
}`};
transition: all 0.2s ease;
&:hover {
border: ${(props) =>
`1px solid ${
props.isOpen
? props.theme.createEditRoomDialog.thirdpartyStorage.combobox
.isOpenDropdownBorderColor
: props.theme.createEditRoomDialog.thirdpartyStorage.combobox
.hoverDropdownBorderColor
}`};
}
&-text {
font-weight: 400;
font-size: ${(props) => props.theme.getCorrectFontSize("13px")};
line-height: 20px;
}
&-expander {
display: flex;
align-items: center;
justify-content: center;
width: 6.35px;
svg {
transform: ${(props) =>
props.isOpen ? "rotate(180deg)" : "rotate(0)"};
width: 6.35px;
height: auto;
path {
fill: ${(props) =>
props.theme.createEditRoomDialog.thirdpartyStorage.combobox
.arrowFill};
}
}
}
}
&-checkbox {
margin-top: 8px;
.checkbox {
${({ theme }) =>
theme.interfaceDirection === "rtl"
? `margin-left: 8px;`
: `margin-right: 8px;`}
}
.checkbox-text {
font-weight: 400;
font-size: ${(props) => props.theme.getCorrectFontSize("13px")};
line-height: 20px;
}
}
}
`;
@ -143,13 +80,10 @@ const ThirdPartyComboBox = ({
setConnectItem,
getOAuthToken,
setIsScrollLocked,
setIsOauthWindowOpen,
isDisabled,
}) => {
const dropdownRef = useRef(null);
const thirdparties = connectItems.map((item) => ({
...item,
title: item.category
@ -157,34 +91,8 @@ const ThirdPartyComboBox = ({
: ProviderKeyTranslation(item.providerKey, t),
}));
const [isOpen, setIsOpen] = useState(false);
const [dropdownDirection, setDropdownDirection] = useState("bottom");
const toggleIsOpen = () => {
if (isDisabled) return;
if (isOpen) setIsScrollLocked(false);
else {
setIsScrollLocked(true);
calculateDropdownDirection();
}
setIsOpen(!isOpen);
};
const setStorageLocaiton = (thirparty) => {
onChangeProvider(thirparty);
setIsOpen(false);
setIsScrollLocked(false);
};
const calculateDropdownDirection = () => {
const { top: offsetTop } = DomHelpers.getOffset(dropdownRef.current);
const offsetBottom = window.innerHeight - offsetTop;
const neededHeightDesktop = Math.min(thirdparties.length * 32 + 16, 404);
const neededHeightMobile = Math.min(thirdparties.length * 32 + 16, 180);
const neededheight = isMobile() ? neededHeightMobile : neededHeightDesktop;
setDropdownDirection(neededheight > offsetBottom ? "top" : "bottom");
};
const onShowService = async () => {
@ -244,24 +152,51 @@ const ThirdPartyComboBox = ({
setSaveThirdpartyResponse(null);
}, [saveThirdpartyResponse]);
return (
<StyledStorageLocation isOpen={isOpen}>
<div className="set_room_params-thirdparty">
<div
id="shared_third-party-storage_combobox"
className="set_room_params-thirdparty-combobox"
onClick={toggleIsOpen}
>
<Text className="set_room_params-thirdparty-combobox-text" noSelect>
{storageLocation?.provider?.title ||
t("ThirdPartyStorageComboBoxPlaceholder")}
</Text>
<ReactSVG
className="set_room_params-thirdparty-combobox-expander"
src={ExpanderDownReactSvgUrl}
/>
</div>
const options = thirdparties.map((item) => ({
label: item.title,
key: item?.category ?? item.id,
}));
const onSelect = (elem) => {
console.log("123a", elem);
console.log("thirdparties", thirdparties);
const thirdparty = thirdparties.find(
(t) => elem.key === t.id || elem.key === t.category,
);
console.log("thirdparty", thirdparty);
thirdparty && setStorageLocaiton(thirdparty);
};
return (
<StyledStorageLocation>
<div className="set_room_params-thirdparty">
<ComboBox
className="thirdparty-combobox"
selectedOption={{
key: "length",
label:
storageLocation?.provider?.title ||
t("ThirdPartyStorageComboBoxPlaceholder"),
}}
options={options}
scaled
withBackdrop={isMobile}
size="content"
title={t("Common:Role")}
manualWidth={"fit-content"}
isMobileView={isMobileOnly}
directionY="both"
displaySelectedOption
noBorder={false}
fixedDirection
isDefaultMode={false}
hideMobileView={false}
forceCloseClickOutside
scaledOptions
onSelect={onSelect}
/>
<Button
id="shared_third-party-storage_connect"
isDisabled={
@ -275,34 +210,6 @@ const ThirdPartyComboBox = ({
onClick={onShowService}
/>
</div>
<StyledDropDownWrapper
className="dropdown-content-wrapper"
ref={dropdownRef}
>
<StyledDropDown
className="dropdown-content"
open={isOpen}
forwardedRef={dropdownRef}
clickOutsideAction={toggleIsOpen}
maxHeight={isMobile() ? 158 : 382}
directionY={dropdownDirection}
marginTop={dropdownDirection === "bottom" ? "4px" : "-36px"}
hasItems={isOpen}
>
{thirdparties.map((thirdparty) => (
<DropDownItem
id={thirdparty.id}
className={`dropdown-item ${thirdparty.className ?? ""}`}
label={thirdparty.title}
key={thirdparty.id}
height={32}
heightTablet={32}
onClick={() => setStorageLocaiton(thirdparty)}
/>
))}
</StyledDropDown>
</StyledDropDownWrapper>
</StyledStorageLocation>
);
};

View File

@ -137,6 +137,13 @@ const DeleteDialogComponent = (props) => {
};
const onClose = () => {
if (
selection.length === 1 &&
selection[0].isArchive &&
selection[0].isRootFolder === false
) {
setSelected("none");
}
setBufferSelection(null);
setRemoveMediaItem(null);
setIsRoomDelete(false);
@ -209,7 +216,7 @@ const DeleteDialogComponent = (props) => {
<>
<>{t("DeleteFolder")} </>
<>{t("DeleteSharedNote")} </>
<>{t("FolderPermanentlyDeleted")} </>
{!isThirdParty && <>{t("FolderPermanentlyDeleted")} </>}
<>{t("Common:WantToContinue")}</>
</>
) : (

View File

@ -0,0 +1,137 @@
// (c) Copyright Ascensio System SIA 2009-2024
//
// This program is a free software product.
// You can redistribute it and/or modify it under the terms
// of the GNU Affero General Public License (AGPL) version 3 as published by the Free Software
// Foundation. In accordance with Section 7(a) of the GNU AGPL its Section 15 shall be amended
// to the effect that Ascensio System SIA expressly excludes the warranty of non-infringement of
// any third-party rights.
//
// This program is distributed WITHOUT ANY WARRANTY, without even the implied warranty
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For details, see
// the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
//
// You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia, EU, LV-1021.
//
// The interactive user interfaces in modified source and object code versions of the Program must
// display Appropriate Legal Notices, as required under Section 5 of the GNU AGPL version 3.
//
// Pursuant to Section 7(b) of the License you must retain the original Product logo when
// distributing the program. Pursuant to Section 7(e) we decline to grant you any rights under
// trademark law for use of our trademarks.
//
// All the Product's GUI elements, including illustrations and icon sets, as well as technical writing
// content are licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0
// International. See the License terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
import { useEffect } from "react";
import { inject, observer } from "mobx-react";
import { withTranslation } from "react-i18next";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
import { Button } from "@docspace/shared/components/button";
import { Text } from "@docspace/shared/components/text";
import { toastr } from "@docspace/shared/components/toast";
import ModalDialogContainer from "../ModalDialogContainer";
const DeleteGroupDialog = (props) => {
const {
t,
visible,
onClose,
selection,
bufferSelection,
groupName,
onDeleteGroup,
onDeleteAllGroups,
isLoading,
} = props;
useEffect(() => {
document.addEventListener("keyup", onKeyUp, false);
return () => {
document.removeEventListener("keyup", onKeyUp, false);
};
}, []);
const onKeyUp = (e) => {
if (e.keyCode === 27) onClose();
if (e.keyCode === 13 || e.which === 13) onDeleteAction();
};
const hasMoreGroups = selection.length > 1;
const onDeleteAction = () => {
try {
if (hasMoreGroups) {
onDeleteAllGroups(t);
} else {
onDeleteGroup(t, bufferSelection?.id || selection[0].id);
}
} catch (err) {
toastr.error(err.message);
console.error(err);
}
};
return (
<ModalDialogContainer
visible={visible}
onClose={onClose}
displayType="modal"
>
<ModalDialog.Header>
{hasMoreGroups
? t("DeleteDialog:DeleteAllGroupsTitle")
: t("DeleteDialog:DeleteGroupTitle")}
</ModalDialog.Header>
<ModalDialog.Body>
<Text>
{hasMoreGroups
? t("DeleteDialog:DeleteAllGroupDescription")
: t("DeleteDialog:DeleteGroupDescription", { groupName })}
</Text>
</ModalDialog.Body>
<ModalDialog.Footer>
<Button
id="group-modal_delete"
key="Delete"
label={t("Common:Delete")}
size="normal"
primary
scale
onClick={onDeleteAction}
isLoading={isLoading}
/>
<Button
id="group-modal_cancel"
key="CancelButton"
label={t("Common:CancelButton")}
size="normal"
scale
onClick={onClose}
/>
</ModalDialog.Footer>
</ModalDialogContainer>
);
};
export default inject(({ peopleStore }) => {
const {
selection,
bufferSelection,
groupName,
onDeleteGroup,
onDeleteAllGroups,
isLoading,
} = peopleStore.groupsStore;
return {
selection,
bufferSelection,
groupName,
onDeleteGroup,
onDeleteAllGroups,
isLoading,
};
})(withTranslation(["Common", "DeleteDialog"])(observer(DeleteGroupDialog)));

View File

@ -50,6 +50,7 @@ const DeleteThirdPartyDialog = (props) => {
setDeleteThirdPartyDialogVisible,
isConnectionViaBackupModule,
updateInfo,
setConnectedThirdPartyAccount,
} = props;
const [isLoading, setIsLoading] = useState(false);
@ -60,10 +61,13 @@ const DeleteThirdPartyDialog = (props) => {
const onClose = () => setDeleteThirdPartyDialogVisible(false);
const onDeleteThirdParty = () => {
setIsLoading(true);
if (isConnectionViaBackupModule) {
deleteThirdParty(+removeItem.provider_id)
.catch((err) => toastr.error(err))
.finally(() => {
setConnectedThirdPartyAccount(null);
updateInfo && updateInfo();
setIsLoading(false);
onClose();
@ -76,7 +80,6 @@ const DeleteThirdPartyDialog = (props) => {
(x) => x.provider_id !== removeItem.id,
);
setIsLoading(true);
deleteThirdParty(+removeItem.id)
.then(() => {
setThirdPartyProviders(newProviders);
@ -145,7 +148,10 @@ export default inject(
const { providers, setThirdPartyProviders, deleteThirdParty } =
filesSettingsStore.thirdPartyStore;
const { setIsLoading } = filesStore;
const { selectedThirdPartyAccount: backupConnectionItem } = backup;
const {
selectedThirdPartyAccount: backupConnectionItem,
setConnectedThirdPartyAccount,
} = backup;
const {
deleteThirdPartyDialogVisible: visible,
setDeleteThirdPartyDialogVisible,
@ -168,6 +174,7 @@ export default inject(
setThirdPartyProviders,
deleteThirdParty,
setDeleteThirdPartyDialogVisible,
setConnectedThirdPartyAccount,
};
},
)(

View File

@ -41,6 +41,7 @@ import { updateRoomMemberRole } from "@docspace/shared/api/rooms";
import { toastr } from "@docspace/shared/components/toast";
import { useState } from "react";
import { HelpButton } from "@docspace/shared/components/help-button";
import { getUserRoleOptions } from "@docspace/shared/utils/room-members/getUserRoleOptions";
interface GroupMemberProps {
t: any;
@ -56,23 +57,23 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
infoPanelSelection.roomType,
false,
);
const selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
t,
user.userAccess || user.groupAccess,
);
let selectedUserRoleCBOption;
if (user.isOwner)
selectedUserRoleCBOption = getUserRoleOptions(t).docSpaceAdmin;
else if (user.isRoomAdmin)
selectedUserRoleCBOption = getUserRoleOptions(t).roomAdmin;
else
selectedUserRoleCBOption = getUserRoleOptionsByUserAccess(
t,
user.userAccess || user.groupAccess,
);
const availableUserRoleCBOptions = filterUserRoleOptions(
fullRoomRoleOptions,
user,
);
console.log(
"GroupMember",
user,
selectedUserRoleCBOption,
availableUserRoleCBOptions,
fullRoomRoleOptions,
);
const onChangeRole = async (userRoleOption) => {
setIsLoading(true);
updateRoomMemberRole(infoPanelSelection.id, {
@ -85,6 +86,8 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
.finally(() => setIsLoading(false));
};
console.log(user);
return (
<Styled.GroupMember isExpect={user.isExpect} key={user.id}>
<Avatar
@ -117,6 +120,7 @@ const GroupMember = ({ t, user, infoPanelSelection }: GroupMemberProps) => {
<HelpButton
place="left"
offsetRight={0}
openOnClick={false}
tooltipContent={
<Text fontSize="12px" fontWeight={600}>
{t("PeopleTranslations:IndividualRights")}

View File

@ -40,6 +40,7 @@ const LeaveRoomDialog = (props) => {
setChangeRoomOwnerIsVisible,
isOwner,
onLeaveRoomAction,
updateInfoPanelSelection,
} = props;
const [isLoading, setIsLoading] = useState(false);
@ -65,6 +66,7 @@ const LeaveRoomDialog = (props) => {
setIsLoading(true);
await onLeaveRoomAction(t, isOwner);
setIsLoading(false);
updateInfoPanelSelection();
onClose();
}
};
@ -113,6 +115,7 @@ export default inject(
filesStore,
selectedFolderStore,
filesActionsStore,
infoPanelStore,
}) => {
const {
leaveRoomDialogVisible: visible,
@ -121,6 +124,7 @@ export default inject(
} = dialogsStore;
const { user } = userStore;
const { selection, bufferSelection } = filesStore;
const { updateInfoPanelSelection } = infoPanelStore;
const selections = selection.length ? selection : [bufferSelection];
const folderItem = selections[0] ? selections[0] : selectedFolderStore;
@ -133,6 +137,7 @@ export default inject(
setChangeRoomOwnerIsVisible,
isOwner: isRoomOwner,
onLeaveRoomAction: filesActionsStore.onLeaveRoom,
updateInfoPanelSelection,
};
},
)(observer(withTranslation(["Common", "Files"])(LeaveRoomDialog)));

View File

@ -27,7 +27,7 @@
import { Link } from "@docspace/shared/components/link";
import { ModalDialog } from "@docspace/shared/components/modal-dialog";
import { Button } from "@docspace/shared/components/button";
import { useState, useRef } from "react";
import { useState, useRef, useEffect } from "react";
import { observer, inject } from "mobx-react";
import { Trans, withTranslation } from "react-i18next";
import { ReactSVG } from "react-svg";
@ -49,9 +49,12 @@ const SubmitToFormGallery = ({
currentColorScheme,
canSubmitToFormGallery,
submitToFormGallery,
fetchGuideLink,
}) => {
const [isSubmitting, setIsSubmitting] = useState(false);
const [guideLink, setGuideLink] = useState(null);
const abortControllerRef = useRef(new AbortController());
let formItemIsSet = !!formItem;
@ -118,6 +121,13 @@ const SubmitToFormGallery = ({
onClose();
};
useEffect(() => {
(async () => {
const fetchedGuideLink = await fetchGuideLink();
setGuideLink(fetchedGuideLink);
})();
}, []);
if (!canSubmitToFormGallery()) return null;
if (isSelectingForm)
@ -153,7 +163,7 @@ const SubmitToFormGallery = ({
approval in our
<Link
color={currentColorScheme.main?.accent}
href={t("FormGallery:GuideLink")}
href={guideLink || "#"}
type={"page"}
target={"_blank"}
isBold
@ -233,5 +243,6 @@ export default inject(
currentColorScheme: settingsStore.currentColorScheme,
canSubmitToFormGallery: accessRightsStore.canSubmitToFormGallery,
submitToFormGallery: oformsStore.submitToFormGallery,
fetchGuideLink: oformsStore.fetchGuideLink,
}),
)(withTranslation("Common", "FormGallery")(observer(SubmitToFormGallery)));

View File

@ -68,6 +68,7 @@ import DeletePluginDialog from "./DeletePluginDialog";
import ShareFolderDialog from "./ShareFolderDialog";
import EditGroupMembersDialog from "./EditGroupMembersDialog";
import ChangeStorageQuotaDialog from "./ChangeStorageQuotaDialog";
import DeleteGroupDialog from "./DeleteGroupDialog";
export {
EmptyTrashDialog,
@ -114,4 +115,5 @@ export {
EditGroupMembersDialog,
ChangeQuotaDialog,
ChangeStorageQuotaDialog,
DeleteGroupDialog,
};

View File

@ -26,21 +26,23 @@
import { useTheme } from "styled-components";
import { useTranslation } from "react-i18next";
import { useState, useEffect, useCallback, useRef } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import DefaultUserPhoto from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
import EmptyScreenPersonsSvgUrl from "PUBLIC_DIR/images/empty_screen_persons.svg?url";
import CatalogAccountsReactSvgUrl from "PUBLIC_DIR/images/catalog.accounts.react.svg?url";
import EmptyScreenPersonsSvgDarkUrl from "PUBLIC_DIR/images/empty_screen_persons_dark.svg?url";
import { Aside } from "@docspace/shared/components/aside";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { Selector, TSelectorItem } from "@docspace/shared/components/selector";
import {
Selector,
SelectorAccessRightsMode,
TSelectorItem,
} from "@docspace/shared/components/selector";
import {
TAccessRight,
TSelectorAccessRights,
TSelectorCancelButton,
TSelectorSelectAll,
TWithTabs,
} from "@docspace/shared/components/selector/Selector.types";
import { toastr } from "@docspace/shared/components/toast";
@ -92,6 +94,7 @@ const toListItem = (
const userAvatar = hasAvatar ? avatar : DefaultUserPhoto;
const isInvited = invitedUsers?.includes(id) || (isRoom && shared);
const isDisabled =
disableDisabledUsers && status === EmployeeStatus.Disabled;
@ -122,9 +125,10 @@ const toListItem = (
isGroup,
name: groupName,
shared,
} = item;
const isInvited = invitedUsers?.includes(id);
const isInvited = invitedUsers?.includes(id) || (isRoom && shared);
const disabledText = isInvited ? t("Common:Invited") : "";
const userAvatar = "";
@ -199,6 +203,35 @@ const AddUsersPanel = ({
const [isInit, setIsInit] = useState(true);
const [isLoading, setIsLoading] = useLoadingWithTimeout<boolean>(0, true);
const [activeTabId, setActiveTabId] = useState<string>(PEOPLE_TAB_ID);
const [selectedItems, setSelectedItems] = useState<TSelectorItem[]>([]);
const [itemsList, setItemsList] = useState<TSelectorItem[]>([]);
const [searchValue, setSearchValue] = useState("");
const [hasNextPage, setHasNextPage] = useState(true);
const [isNextPageLoading, setIsNextPageLoading] = useState(false);
const [total, setTotal] = useState(0);
const totalRef = useRef(0);
const onSelect = (
item: TSelectorItem,
isDoubleClick: boolean,
doubleClickCallback: () => void,
) => {
setSelectedItems((items) => {
const includeFile = items.find((el) => el.id === item.id);
if (includeFile)
return isMultiSelect
? items.filter((el) => el.id !== includeFile.id)
: [];
return isMultiSelect ? [...items, item] : [item];
});
if (isDoubleClick && !isMultiSelect) {
doubleClickCallback();
}
};
const accessRight =
defaultAccess ||
(isEncrypted ? ShareAccessRights.FullAccess : ShareAccessRights.ReadOnly);
@ -267,13 +300,6 @@ const AddUsersPanel = ({
(access) => access.access === accessRight,
)[0];
const [itemsList, setItemsList] = useState<TSelectorItem[]>([]);
const [searchValue, setSearchValue] = useState("");
const [hasNextPage, setHasNextPage] = useState(true);
const [isNextPageLoading, setIsNextPageLoading] = useState(false);
const [total, setTotal] = useState(0);
const totalRef = useRef(0);
const changeActiveTab = useCallback((tab: number | string) => {
setActiveTabId(`${tab}`);
isFirstLoad.current = true;
@ -393,7 +419,13 @@ const AddUsersPanel = ({
isGroup?: boolean,
) => {
return (
<div style={{ width: "100%" }}>
<div
style={{
width: "100%",
overflow: "hidden",
marginInlineEnd: "16px",
}}
>
<Text
className="label"
fontWeight={600}
@ -423,15 +455,6 @@ const AddUsersPanel = ({
);
};
const withSelectAllProps: TSelectorSelectAll = isMultiSelect
? {
withSelectAll: isMultiSelect,
selectAllLabel: t("Common:AllAccounts"),
selectAllIcon: CatalogAccountsReactSvgUrl,
onSelectAll: () => {},
}
: {};
const withAccessRightsProps: TSelectorAccessRights =
withAccessRights && isMultiSelect
? {
@ -439,6 +462,7 @@ const AddUsersPanel = ({
accessRights: accessOptions,
selectedAccessRight: selectedAccess,
onAccessRightsChange: () => {},
accessRightsMode: SelectorAccessRightsMode.Detailed,
}
: {};
@ -489,12 +513,14 @@ const AddUsersPanel = ({
>
<Selector
withHeader
alwaysShowFooter
headerProps={{
// Todo: Update groups empty screen texts when they are ready
headerLabel: t("Common:ListAccounts"),
withoutBackButton: false,
onBackClick,
}}
onSelect={onSelect}
renderCustomItem={renderCustomItem}
withSearch
searchPlaceholder={t("Common:Search")}
@ -505,8 +531,7 @@ const AddUsersPanel = ({
isMultiSelect={isMultiSelect}
submitButtonLabel={t("Common:AddButton")}
onSubmit={onUsersSelect}
disableSubmitButton={false}
{...withSelectAllProps}
disableSubmitButton={selectedItems.length === 0}
{...withAccessRightsProps}
{...withCancelButtonProps}
emptyScreenImage={emptyScreenImage}

View File

@ -56,6 +56,8 @@ const StyledChangeRoomOwner = styled.div`
}
.selector_footer-checkbox {
background-color: ${(props) =>
props.theme.filesPanels.aside.backgroundColor};
padding: 17px 0 1px 0;
}
`}

View File

@ -40,8 +40,7 @@ import CheckIcon from "PUBLIC_DIR/images/check.edit.react.svg";
import CrossIcon from "PUBLIC_DIR/images/cross.edit.react.svg";
import CrossIconMobile from "PUBLIC_DIR/images/cross.react.svg";
import DeleteIcon from "PUBLIC_DIR/images/mobile.actions.remove.react.svg";
import { isMobile, desktop } from "@docspace/shared/utils";
import { isMobile, desktop, commonInputStyles } from "@docspace/shared/utils";
import Base from "@docspace/shared/themes/base";
const fillAvailableWidth = css`
@ -235,6 +234,31 @@ const StyledInviteInput = styled.div`
height: 30px;
}
}
display: flex;
border: 1px solid rgb(208, 213, 218);
border-radius: 3px;
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-results-button,
input[type="search"]::-webkit-search-results-decoration {
-webkit-appearance: none;
appearance: none;
}
.append {
display: ${(props) => (props.isShowCross ? "flex" : "none")};
align-items: center;
padding-right: 8px;
cursor: default;
}
${commonInputStyles}
:focus-within {
border-color: ${(props) => props.theme.inputBlock.borderColor};
}
`;
const StyledAccessSelector = styled.div`
@ -498,12 +522,16 @@ const StyledInviteLanguage = styled.div`
padding-left: 6px;
padding-right: 6px;
}
.combo-button-label {
.combo-buttons_arrow-icon {
margin-left: 0px;
}
.combo-button_closed:not(:hover) .combo-button-label {
color: ${(props) =>
props.theme.createEditRoomDialog.commonParam.descriptionColor};
}
.combo-buttons_arrow-icon {
margin-left: 0px;
.combo-button_closed:not(:hover) .combo-buttons_arrow-icon {
svg {
path {
fill: ${(props) =>

View File

@ -315,6 +315,8 @@ const InvitePanel = ({
addInfoPanelMembers(t, result.members);
}
console.log(result);
onClose();
toastr.success(t("Common:UsersInvited"));
@ -410,28 +412,27 @@ const InvitePanel = ({
) : (
bodyInvitePanel
)}
{hasInvitedUsers && (
<StyledButtons>
<Button
className="send-invitation"
scale={true}
size={"normal"}
isDisabled={hasErrors}
primary
onClick={onClickSend}
label={t("SendInvitation")}
isLoading={isLoading}
/>
<Button
className="cancel-button"
scale={true}
size={"normal"}
onClick={onClose}
label={t("Common:CancelButton")}
isDisabled={isLoading}
/>
</StyledButtons>
)}
<StyledButtons>
<Button
className="send-invitation"
scale={true}
size={"normal"}
isDisabled={hasErrors || !hasInvitedUsers}
primary
onClick={onClickSend}
label={t("SendInvitation")}
isLoading={isLoading}
/>
<Button
className="cancel-button"
scale={true}
size={"normal"}
onClick={onClose}
label={t("Common:CancelButton")}
isDisabled={isLoading}
/>
</StyledButtons>
</>
)}
</>

View File

@ -63,6 +63,7 @@ import {
StyledDescription,
StyledInviteLanguage,
ResetLink,
StyledCrossIcon,
} from "../StyledInvitePanel";
import AtReactSvgUrl from "PUBLIC_DIR/images/@.react.svg?url";
@ -90,6 +91,7 @@ const InviteInput = ({
cultureNames,
i18n,
setCultureKey,
standalone,
}) => {
const isPublicRoomType = roomType === RoomsType.PublicRoom;
@ -184,6 +186,10 @@ const InviteInput = ({
const onChange = (e) => {
const value = e.target.value;
onChangeInput(value);
};
const onChangeInput = (value) => {
const clearValue = value.trim();
setInputValue(value);
@ -362,7 +368,14 @@ const InviteInput = ({
</DropDownItem>
);
const accessOptions = getAccessOptions(t, roomType);
const accessOptions = getAccessOptions(
t,
roomType,
false,
true,
isOwner,
standalone,
);
const onSelectAccess = (item) => {
setSelectedAccess(item.access);
@ -486,7 +499,7 @@ const InviteInput = ({
)}
<StyledInviteInputContainer ref={inputsRef}>
<StyledInviteInput ref={searchRef}>
<StyledInviteInput ref={searchRef} isShowCross={!!inputValue}>
<TextInput
className="invite-input"
scale
@ -500,7 +513,12 @@ const InviteInput = ({
isAutoFocussed={true}
onKeyDown={onKeyDown}
type="search"
withBorder={false}
/>
<div className="append" onClick={() => onChangeInput("")}>
<StyledCrossIcon />
</div>
</StyledInviteInput>
{isAddEmailPanelBlocked ? (
<></>
@ -566,8 +584,10 @@ export default inject(({ settingsStore, dialogsStore, userStore }) => {
culture,
} = dialogsStore;
const { culture: language, standalone } = settingsStore;
return {
language: settingsStore.culture,
language,
setInviteLanguage,
setInviteItems,
inviteItems,
@ -576,6 +596,7 @@ export default inject(({ settingsStore, dialogsStore, userStore }) => {
hideSelector: invitePanelOptions.hideSelector,
defaultAccess: invitePanelOptions.defaultAccess,
isOwner,
standalone,
};
})(
withCultureNames(

View File

@ -216,6 +216,7 @@ const Item = ({
displayType="auto"
offsetRight={0}
tooltipContent={t("EmailErrorMessage")}
openOnClick={false}
size={16}
color="#F21C0E"
/>

View File

@ -27,14 +27,14 @@
import React from "react";
import { inject, observer } from "mobx-react";
import { Text } from "@docspace/shared/components/text";
import { NoUserSelect, tablet } from "@docspace/shared/utils";
import { NoUserSelect, tablet, getLogoUrl } from "@docspace/shared/utils";
import { WhiteLabelLogoType } from "@docspace/shared/enums";
import { useTranslation } from "react-i18next";
import styled from "styled-components";
import { ReactSVG } from "react-svg";
import { ColorTheme, ThemeId } from "@docspace/shared/components/color-theme";
import logoPersonalAboutUrl from "PUBLIC_DIR/images/logo_personal_about.svg?url";
import { getLogoFromPath } from "@docspace/shared/utils";
const StyledAboutBody = styled.div`
width: 100%;
@ -109,7 +109,6 @@ const AboutContent = (props) => {
theme,
companyInfoSettingsData,
previewData,
whiteLabelLogoUrls,
} = props;
const { t } = useTranslation("About");
const license = "AGPL-3.0";
@ -134,11 +133,7 @@ const AboutContent = (props) => {
? previewData.address
: companyInfoSettingsData?.address;
const logo = getLogoFromPath(
!theme.isBase
? whiteLabelLogoUrls[6]?.path.dark
: whiteLabelLogoUrls[6]?.path.light,
);
const logo = getLogoUrl(WhiteLabelLogoType.AboutPage, !theme.isBase);
return (
companyInfoSettingsData && (
@ -289,11 +284,10 @@ const AboutContent = (props) => {
};
export default inject(({ settingsStore }) => {
const { theme, companyInfoSettingsData, whiteLabelLogoUrls } = settingsStore;
const { theme, companyInfoSettingsData } = settingsStore;
return {
theme,
companyInfoSettingsData,
whiteLabelLogoUrls,
};
})(observer(AboutContent));

View File

@ -58,7 +58,7 @@ const CategoryFilterDesktop = ({
tabIndex={1}
className={"combobox"}
opened={isOpen}
onClick={onToggleDropdownIsOpen}
onToggle={onToggleDropdownIsOpen}
onSelect={onCloseDropdown}
isDisabled={false}
showDisabledItems={true}

View File

@ -33,7 +33,6 @@ import { inject, observer } from "mobx-react";
import { flagsIcons } from "@docspace/shared/utils/image-flags";
import { convertToCulture } from "@docspace/shared/utils/common";
import { Backdrop } from "@docspace/shared/components/backdrop";
import { isMobile } from "@docspace/shared/utils";
import { RectangleSkeleton } from "@docspace/shared/skeletons";
@ -73,12 +72,6 @@ const LanguageFilter = ({
return (
<Styled.LanguageFilter>
<Backdrop
visible={isOpen}
withBackground={isMobile()}
onClick={onCloseDropdown}
withoutBlur={!isMobile()}
/>
<Styled.LanguangeComboBox
id="comboBoxLanguage"
tabIndex={1}
@ -99,6 +92,7 @@ const LanguageFilter = ({
fixedDirection={true}
advancedOptionsCount={5}
fillIcon={false}
withBlur={isMobile()}
options={[]}
selectedOption={{}}
advancedOptions={

View File

@ -83,7 +83,7 @@ export const LanguageFilterSelectedItem = styled(DropDownItem)`
margin: 0;
width: 16px;
height: 16px;
& > div {
div {
display: flex;
align-items: center;
justify-content: center;

View File

@ -77,6 +77,11 @@ const Tile = ({
const getContextModel = () => getFormGalleryContextOptions(item, t, navigate);
const contextMenuHeader = {
icon: getIcon(32, ".docxf"),
title: item?.attributes?.name_form,
};
const getOptions = () =>
getFormGalleryContextOptions(item, t, navigate).map((item) => item.key);
@ -142,6 +147,7 @@ const Tile = ({
<StyledContextMenu
ignoreChangeView={isMobile()}
getContextModel={getContextModel}
header={contextMenuHeader}
ref={cm}
withBackdrop={true}
/>

View File

@ -109,7 +109,6 @@ const StyledAccountsItemTitle = styled.div`
}
.context-button {
padding-top: 24px;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
@ -186,10 +185,12 @@ const StyledAccountContent = styled.div`
}
.info_field_groups {
margin-top: 8px;
height: 100%;
}
.info_groups {
margin-top: 4px;
display: flex;
flex-direction: column;
align-items: start;

View File

@ -66,7 +66,8 @@ export const GroupsContent = styled.div<{}>`
.email {
max-width: 180px;
color: #a3a9ae;
font-size: ${({ theme }) => theme.getCorrectFontSize("10px")};
font-size: ${({ theme }) => theme.getCorrectFontSize("12px")};
line-height: 16px;
font-style: normal;
font-weight: 400;
overflow: hidden;

View File

@ -30,7 +30,7 @@ import { withTranslation } from "react-i18next";
import { Text } from "@docspace/shared/components/text";
import DefaultUserPhoto from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
import { ContextMenuButton } from "@docspace/shared/components/context-menu-button";
import { Avatar } from "@docspace/shared/components/avatar";
import { Avatar, AvatarSize } from "@docspace/shared/components/avatar";
import { Badge } from "@docspace/shared/components/badge";
import Badges from "@docspace/client/src/pages/Home/Section/AccountsBody/Badges";
import { StyledAccountsItemTitle } from "../../styles/accounts";
@ -79,7 +79,7 @@ const AccountsItemTitle = ({
<Avatar
className="avatar"
role={infoPanelSelection.role ? infoPanelSelection.role : "user"}
size={"big"}
size={AvatarSize.big}
source={userAvatar}
/>
<div className="info-panel__info-text">

View File

@ -30,7 +30,7 @@ import { withTranslation } from "react-i18next";
import { Text } from "@docspace/shared/components/text";
import DefaultUserPhoto from "PUBLIC_DIR/images/default_user_photo_size_82-82.png";
import { ContextMenuButton } from "@docspace/shared/components/context-menu-button";
import { Avatar } from "@docspace/shared/components/avatar";
import { Avatar, AvatarSize } from "@docspace/shared/components/avatar";
import { StyledAccountsItemTitle } from "../../styles/accounts";
import { decode } from "he";
@ -56,7 +56,7 @@ const GroupsItemTitle = ({
<StyledAccountsItemTitle ref={itemTitleRef}>
<Avatar
className="avatar"
size={"big"}
size={AvatarSize.big}
userName={infoPanelSelection.name}
isGroup={true}
/>

View File

@ -52,7 +52,7 @@ const RoomsItemHeader = ({
setInviteUsersWarningDialogVisible,
isPublicRoomType,
roomsView,
setSelected,
setSelection,
setBufferSelection,
isArchive,
hasLinks,
@ -76,7 +76,7 @@ const RoomsItemHeader = ({
const isRoomMembersPanel = selection?.isRoom && roomsView === "info_members";
const onSelectItem = () => {
setSelected("none");
setSelection([]);
setBufferSelection(selection);
};
@ -188,7 +188,7 @@ export default inject(
(selectedFolderStore.roomType ??
infoPanelStore.infoPanelSelection?.roomType) === RoomsType.PublicRoom,
setSelected: filesStore.setSelected,
setSelection: filesStore.setSelection,
setBufferSelection: filesStore.setBufferSelection,
isArchive,
hasLinks: externalLinks.length,

View File

@ -272,7 +272,7 @@ const Accounts = (props) => {
{infoPanelSelection?.groups?.length && (
<>
<Text
className={"info_field info_field_groups"}
className={`info_field info_field_groups`}
noSelect
title={t("Common:Group")}
>

Some files were not shown because too many files have changed in this diff Show More