diff --git a/apps/client/index.html b/apps/client/index.html index c96058cb..28679e40 100644 --- a/apps/client/index.html +++ b/apps/client/index.html @@ -2,10 +2,18 @@ - - - + + + Docmost + + + + + + + + diff --git a/apps/client/package.json b/apps/client/package.json index 78306af7..031646e8 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -1,7 +1,7 @@ { "name": "client", "private": true, - "version": "0.22.2", + "version": "0.23.1", "scripts": { "dev": "vite", "build": "tsc && vite build", @@ -40,7 +40,7 @@ "katex": "0.16.22", "lowlight": "^3.3.0", "mantine-form-zod-resolver": "^1.3.0", - "mermaid": "^11.6.0", + "mermaid": "^11.11.0", "mitt": "^3.0.1", "posthog-js": "^1.255.1", "react": "^18.3.1", diff --git a/apps/client/public/favicon-16x16.png b/apps/client/public/favicon-16x16.png deleted file mode 100644 index 6298fe8a..00000000 Binary files a/apps/client/public/favicon-16x16.png and /dev/null differ diff --git a/apps/client/public/favicon-32x32.png b/apps/client/public/favicon-32x32.png deleted file mode 100644 index 40d6a30e..00000000 Binary files a/apps/client/public/favicon-32x32.png and /dev/null differ diff --git a/apps/client/public/icons/app-icon-192x192.png b/apps/client/public/icons/app-icon-192x192.png new file mode 100644 index 00000000..46bce9e5 Binary files /dev/null and b/apps/client/public/icons/app-icon-192x192.png differ diff --git a/apps/client/public/icons/app-icon-512x512.png b/apps/client/public/icons/app-icon-512x512.png new file mode 100644 index 00000000..65b91ed0 Binary files /dev/null and b/apps/client/public/icons/app-icon-512x512.png differ diff --git a/apps/client/public/icons/favicon-16x16.png b/apps/client/public/icons/favicon-16x16.png new file mode 100644 index 00000000..c8d2d56f Binary files /dev/null and b/apps/client/public/icons/favicon-16x16.png differ diff --git a/apps/client/public/icons/favicon-32x32.png b/apps/client/public/icons/favicon-32x32.png new file mode 100644 index 00000000..3ccc0fb0 Binary files /dev/null and b/apps/client/public/icons/favicon-32x32.png differ diff --git a/apps/client/public/locales/de-DE/translation.json b/apps/client/public/locales/de-DE/translation.json index 0199a502..bc1bd1f2 100644 --- a/apps/client/public/locales/de-DE/translation.json +++ b/apps/client/public/locales/de-DE/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "z.B. Bereich für das Produktteam", "e.g Space for sales team to collaborate": "z.B. Bereich für das Vertriebsteam zur Zusammenarbeit", "Edit": "Bearbeiten", + "Read": "Lesen", "Edit group": "Gruppe bearbeiten", "Email": "E-Mail", "Enter a strong password": "Geben Sie ein starkes Passwort ein", @@ -495,5 +496,36 @@ "Page restored successfully": "Seite erfolgreich wiederhergestellt", "Deleted by": "Gelöscht von", "Deleted at": "Gelöscht am", - "Preview": "Vorschau" + "Preview": "Vorschau", + "Subpages": "Unterseiten", + "Failed to load subpages": "Fehler beim Laden von Unterseiten", + "No subpages": "Keine Unterseiten", + "Subpages (Child pages)": "Unterseiten (Untergeordnete Seiten)", + "List all subpages of the current page": "Alle Unterseiten der aktuellen Seite auflisten", + "Attachments": "Anhänge", + "All spaces": "Alle Bereiche", + "Unknown": "Unbekannt", + "Find a space": "Einen Bereich finden", + "Search in all your spaces": "In all deinen Bereichen suchen", + "Type": "Art", + "Enterprise": "Unternehmen", + "Download attachment": "Anhang herunterladen", + "Allowed email domains": "Erlaubte E-Mail-Domains", + "Only users with email addresses from these domains can signup via SSO.": "Nur Benutzer mit E-Mail-Adressen aus diesen Domains können sich über SSO registrieren.", + "Enter valid domain names separated by comma or space": "Geben Sie gültige Domainnamen ein, durch Kommas oder Leerzeichen getrennt", + "Enforce two-factor authentication": "Erzwingen der Zwei-Faktor-Authentifizierung", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Sobald es erzwungen wird, müssen alle Mitglieder die Zwei-Faktor-Authentifizierung aktivieren, um auf den Arbeitsbereich zugreifen zu können.", + "Toggle MFA enforcement": "Umschalten der MFA-Erzwingung", + "Display name": "Anzeigename", + "Allow signup": "Registrierung erlauben", + "Enabled": "Aktiviert", + "Advanced Settings": "Erweiterte Einstellungen", + "Enable TLS/SSL": "TLS/SSL aktivieren", + "Use secure connection to LDAP server": "Sichere Verbindung zum LDAP-Server verwenden", + "Group sync": "Gruppensynchronisation", + "No SSO providers found.": "Keine SSO-Anbieter gefunden.", + "Delete SSO provider": "SSO-Anbieter löschen", + "Are you sure you want to delete this SSO provider?": "Sind Sie sicher, dass Sie diesen SSO-Anbieter löschen möchten?", + "Action": "Aktion", + "{{ssoProviderType}} configuration": "{{ssoProviderType}}-Konfiguration" } diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index 4b4a2158..7fbded98 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "e.g Space for product team", "e.g Space for sales team to collaborate": "e.g Space for sales team to collaborate", "Edit": "Edit", + "Read": "Read", "Edit group": "Edit group", "Email": "Email", "Enter a strong password": "Enter a strong password", @@ -497,5 +498,42 @@ "Page restored successfully": "Page restored successfully", "Deleted by": "Deleted by", "Deleted at": "Deleted at", - "Preview": "Preview" + "Preview": "Preview", + "Subpages": "Subpages", + "Failed to load subpages": "Failed to load subpages", + "No subpages": "No subpages", + "Subpages (Child pages)": "Subpages (Child pages)", + "List all subpages of the current page": "List all subpages of the current page", + "Attachments": "Attachments", + "All spaces": "All spaces", + "Unknown": "Unknown", + "Find a space": "Find a space", + "Search in all your spaces": "Search in all your spaces", + "Type": "Type", + "Enterprise": "Enterprise", + "Download attachment": "Download attachment", + "Allowed email domains": "Allowed email domains", + "Only users with email addresses from these domains can signup via SSO.": "Only users with email addresses from these domains can signup via SSO.", + "Enter valid domain names separated by comma or space": "Enter valid domain names separated by comma or space", + "Enforce two-factor authentication": "Enforce two-factor authentication", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Once enforced, all members must enable two-factor authentication to access the workspace.", + "Toggle MFA enforcement": "Toggle MFA enforcement", + "Display name": "Display name", + "Allow signup": "Allow signup", + "Enabled": "Enabled", + "Advanced Settings": "Advanced Settings", + "Enable TLS/SSL": "Enable TLS/SSL", + "Use secure connection to LDAP server": "Use secure connection to LDAP server", + "Group sync": "Group sync", + "No SSO providers found.": "No SSO providers found.", + "Delete SSO provider": "Delete SSO provider", + "Are you sure you want to delete this SSO provider?": "Are you sure you want to delete this SSO provider?", + "Action": "Action", + "{{ssoProviderType}} configuration": "{{ssoProviderType}} configuration", + "Icon": "Icon", + "Upload image": "Upload image", + "Remove image": "Remove image", + "Failed to remove image": "Failed to remove image", + "Image exceeds 10MB limit.": "Image exceeds 10MB limit.", + "Image removed successfully": "Image removed successfully" } diff --git a/apps/client/public/locales/es-ES/translation.json b/apps/client/public/locales/es-ES/translation.json index 407b9f14..3450f27d 100644 --- a/apps/client/public/locales/es-ES/translation.json +++ b/apps/client/public/locales/es-ES/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "ej: Espacio para el equipo de producto", "e.g Space for sales team to collaborate": "ej: Espacio para que el equipo de ventas colabore", "Edit": "Editar", + "Read": "Leer", "Edit group": "Editar grupo", "Email": "Correo electrónico", "Enter a strong password": "Introduce una contraseña fuerte", @@ -495,5 +496,36 @@ "Page restored successfully": "Página restaurada con éxito", "Deleted by": "Eliminado por", "Deleted at": "Eliminado en", - "Preview": "Vista previa" + "Preview": "Vista previa", + "Subpages": "Subpáginas", + "Failed to load subpages": "Error al cargar subpáginas", + "No subpages": "Sin subpáginas", + "Subpages (Child pages)": "Subpáginas (Páginas hijas)", + "List all subpages of the current page": "Listar todas las subpáginas de la página actual", + "Attachments": "Adjuntos", + "All spaces": "Todos los espacios", + "Unknown": "Desconocido", + "Find a space": "Encontrar un espacio", + "Search in all your spaces": "Buscar en todos tus espacios", + "Type": "Tipo", + "Enterprise": "Empresa", + "Download attachment": "Descargar adjunto", + "Allowed email domains": "Dominios de correo electrónico permitidos", + "Only users with email addresses from these domains can signup via SSO.": "Solo los usuarios con direcciones de correo electrónico de estos dominios pueden registrarse a través de SSO.", + "Enter valid domain names separated by comma or space": "Introduce nombres de dominio válidos separados por coma o espacio", + "Enforce two-factor authentication": "Aplicar autenticación de dos factores", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Una vez aplicada, todos los miembros deben habilitar la autenticación de dos factores para acceder al espacio de trabajo.", + "Toggle MFA enforcement": "Alternar la aplicación de MFA", + "Display name": "Nombre para mostrar", + "Allow signup": "Permitir registro", + "Enabled": "Habilitado", + "Advanced Settings": "Configuración avanzada", + "Enable TLS/SSL": "Habilitar TLS/SSL", + "Use secure connection to LDAP server": "Usar conexión segura al servidor LDAP", + "Group sync": "Sincronización de grupos", + "No SSO providers found.": "No se encontraron proveedores de SSO.", + "Delete SSO provider": "Eliminar proveedor de SSO", + "Are you sure you want to delete this SSO provider?": "¿Está seguro de que desea eliminar este proveedor de SSO?", + "Action": "Acción", + "{{ssoProviderType}} configuration": "Configuración de {{ssoProviderType}}" } diff --git a/apps/client/public/locales/fr-FR/translation.json b/apps/client/public/locales/fr-FR/translation.json index a502af11..0dbd62ac 100644 --- a/apps/client/public/locales/fr-FR/translation.json +++ b/apps/client/public/locales/fr-FR/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "par ex. Espace pour l'équipe produit", "e.g Space for sales team to collaborate": "par ex. Espace pour l'équipe de vente pour collaborer", "Edit": "Modifier", + "Read": "Lire", "Edit group": "Modifier groupe", "Email": "Email", "Enter a strong password": "Entrez un mot de passe fort", @@ -495,5 +496,36 @@ "Page restored successfully": "Page restaurée avec succès", "Deleted by": "Supprimé par", "Deleted at": "Supprimé à", - "Preview": "Aperçu" + "Preview": "Aperçu", + "Subpages": "Sous-pages", + "Failed to load subpages": "Échec du chargement des sous-pages", + "No subpages": "Pas de sous-pages", + "Subpages (Child pages)": "Sous-pages (Pages enfants)", + "List all subpages of the current page": "Lister toutes les sous-pages de la page actuelle", + "Attachments": "Pièces jointes", + "All spaces": "Tous les espaces", + "Unknown": "Inconnu", + "Find a space": "Trouver un espace", + "Search in all your spaces": "Rechercher dans tous vos espaces", + "Type": "Type", + "Enterprise": "Entreprise", + "Download attachment": "Télécharger la pièce jointe", + "Allowed email domains": "Domaines de messagerie autorisés", + "Only users with email addresses from these domains can signup via SSO.": "Seuls les utilisateurs possédant des adresses e-mail provenant de ces domaines peuvent s'inscrire via SSO.", + "Enter valid domain names separated by comma or space": "Entrez des noms de domaine valides séparés par une virgule ou un espace", + "Enforce two-factor authentication": "Imposer l'authentification à deux facteurs", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Une fois appliquée, tous les membres doivent activer l'authentification à deux facteurs pour accéder à l'espace de travail.", + "Toggle MFA enforcement": "Basculer l'application de l'AMF", + "Display name": "Nom d'affichage", + "Allow signup": "Autoriser l'inscription", + "Enabled": "Activé", + "Advanced Settings": "Paramètres avancés", + "Enable TLS/SSL": "Activer TLS/SSL", + "Use secure connection to LDAP server": "Utiliser une connexion sécurisée au serveur LDAP", + "Group sync": "Synchronisation de groupe", + "No SSO providers found.": "Aucun fournisseur SSO trouvé.", + "Delete SSO provider": "Supprimer le fournisseur SSO", + "Are you sure you want to delete this SSO provider?": "Êtes-vous sûr de vouloir supprimer ce fournisseur SSO ?", + "Action": "Action", + "{{ssoProviderType}} configuration": "Configuration {{ssoProviderType}}" } diff --git a/apps/client/public/locales/it-IT/translation.json b/apps/client/public/locales/it-IT/translation.json index f72c58c7..8ed1f2c8 100644 --- a/apps/client/public/locales/it-IT/translation.json +++ b/apps/client/public/locales/it-IT/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "es. Spazio per il team di prodotto", "e.g Space for sales team to collaborate": "es. Spazio per la collaborazione del team di vendita", "Edit": "Modifica", + "Read": "Leggi", "Edit group": "Modifica gruppo", "Email": "Email", "Enter a strong password": "Inserisci una password sicura", @@ -495,5 +496,36 @@ "Page restored successfully": "Pagina ripristinata con successo", "Deleted by": "Eliminato da", "Deleted at": "Eliminato il", - "Preview": "Anteprima" + "Preview": "Anteprima", + "Subpages": "Sottopagine", + "Failed to load subpages": "Caricamento delle sottopagine non riuscito", + "No subpages": "Nessuna sottopagina", + "Subpages (Child pages)": "Sottopagine (Pagine figlie)", + "List all subpages of the current page": "Elenca tutte le sottopagine della pagina corrente", + "Attachments": "Allegati", + "All spaces": "Tutti gli spazi", + "Unknown": "Sconosciuto", + "Find a space": "Trova uno spazio", + "Search in all your spaces": "Cerca in tutti i tuoi spazi", + "Type": "Tipo", + "Enterprise": "Impresa", + "Download attachment": "Scarica allegato", + "Allowed email domains": "Domini email consentiti", + "Only users with email addresses from these domains can signup via SSO.": "Solo gli utenti con indirizzi email provenienti da questi domini possono registrarsi tramite SSO.", + "Enter valid domain names separated by comma or space": "Inserisci nomi di dominio validi separati da virgole o spazi", + "Enforce two-factor authentication": "Imponi l'autenticazione a due fattori", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Una volta impostata, tutti i membri devono abilitare l'autenticazione a due fattori per accedere all'area di lavoro.", + "Toggle MFA enforcement": "Attiva disattiva l'applicazione MFA", + "Display name": "Nome visualizzato", + "Allow signup": "Consenti iscrizione", + "Enabled": "Abilitato", + "Advanced Settings": "Impostazioni avanzate", + "Enable TLS/SSL": "Abilita TLS/SSL", + "Use secure connection to LDAP server": "Usa connessione sicura al server LDAP", + "Group sync": "Sincronizzazione gruppi", + "No SSO providers found.": "Nessun provider SSO trovato.", + "Delete SSO provider": "Elimina provider SSO", + "Are you sure you want to delete this SSO provider?": "Sei sicuro di voler eliminare questo provider SSO?", + "Action": "Azione", + "{{ssoProviderType}} configuration": "Configurazione {{ssoProviderType}}" } diff --git a/apps/client/public/locales/ja-JP/translation.json b/apps/client/public/locales/ja-JP/translation.json index 3e7950db..4e1811f3 100644 --- a/apps/client/public/locales/ja-JP/translation.json +++ b/apps/client/public/locales/ja-JP/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "例: 製品チームのスペース", "e.g Space for sales team to collaborate": "例: 営業チーム連携用スペース", "Edit": "編集", + "Read": "読む", "Edit group": "グループを編集", "Email": "メールアドレス", "Enter a strong password": "強力なパスワードを入力してください", @@ -495,5 +496,36 @@ "Page restored successfully": "ページが正常に復元されました", "Deleted by": "削除者", "Deleted at": "削除日時", - "Preview": "プレビュー" + "Preview": "プレビュー", + "Subpages": "サブページ", + "Failed to load subpages": "サブページの読み込みに失敗しました", + "No subpages": "サブページがありません", + "Subpages (Child pages)": "サブページ(子ページ)", + "List all subpages of the current page": "現在のページのすべてのサブページをリスト", + "Attachments": "添付ファイル", + "All spaces": "すべてのスペース", + "Unknown": "不明", + "Find a space": "スペースを探す", + "Search in all your spaces": "あなたのすべてのスペースで検索", + "Type": "タイプ", + "Enterprise": "エンタープライズ", + "Download attachment": "添付ファイルをダウンロード", + "Allowed email domains": "許可されたメールドメイン", + "Only users with email addresses from these domains can signup via SSO.": "これらのドメインからのメールアドレスを持つユーザーのみがSSOで登録できます。", + "Enter valid domain names separated by comma or space": "コンマまたはスペースで区切って有効なドメイン名を入力してください", + "Enforce two-factor authentication": "二要素認証を強制する", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "一度強制されると、すべてのメンバーはワークスペースにアクセスするために二要素認証を有効にする必要があります。", + "Toggle MFA enforcement": "MFAの強制を切り替える", + "Display name": "表示名", + "Allow signup": "登録を許可する", + "Enabled": "有効", + "Advanced Settings": "詳細設定", + "Enable TLS/SSL": "TLS/SSLを有効にする", + "Use secure connection to LDAP server": "LDAPサーバーへの安全な接続を使用する", + "Group sync": "グループ同期", + "No SSO providers found.": "SSOプロバイダーが見つかりませんでした。", + "Delete SSO provider": "SSOプロバイダーを削除する", + "Are you sure you want to delete this SSO provider?": "このSSOプロバイダーを削除してもよろしいですか?", + "Action": "アクション", + "{{ssoProviderType}} configuration": "{{ssoProviderType}}の構成" } diff --git a/apps/client/public/locales/ko-KR/translation.json b/apps/client/public/locales/ko-KR/translation.json index fdf35b72..c6e3dc88 100644 --- a/apps/client/public/locales/ko-KR/translation.json +++ b/apps/client/public/locales/ko-KR/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "예: 제품 팀을 위한 Space", "e.g Space for sales team to collaborate": "예: 영업 팀의 Space", "Edit": "편집", + "Read": "읽기", "Edit group": "팀 편집", "Email": "이메일", "Enter a strong password": "강력한 비밀번호를 입력하세요", @@ -495,5 +496,36 @@ "Page restored successfully": "페이지가 성공적으로 복구되었습니다", "Deleted by": "삭제자", "Deleted at": "삭제 시간", - "Preview": "미리보기" + "Preview": "미리보기", + "Subpages": "하위 페이지", + "Failed to load subpages": "하위 페이지 로드 실패", + "No subpages": "하위 페이지 없음", + "Subpages (Child pages)": "하위 페이지 (자식 페이지)", + "List all subpages of the current page": "현재 페이지의 모든 하위 페이지 목록", + "Attachments": "첨부 파일", + "All spaces": "전체 공간", + "Unknown": "알 수 없음", + "Find a space": "공간 찾기", + "Search in all your spaces": "모든 공간에서 검색", + "Type": "유형", + "Enterprise": "기업", + "Download attachment": "첨부 파일 다운로드", + "Allowed email domains": "허용된 이메일 도메인", + "Only users with email addresses from these domains can signup via SSO.": "이 도메인의 이메일 주소를 가진 사용자만 SSO를 통해 가입할 수 있습니다.", + "Enter valid domain names separated by comma or space": "콤마 또는 공백으로 구분하여 유효한 도메인 이름 입력", + "Enforce two-factor authentication": "이중 인증 시행", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "시행되면 모든 멤버가 작업 공간에 액세스하기 위해 이중 인증을 활성화해야 합니다.", + "Toggle MFA enforcement": "MFA 시행 전환", + "Display name": "표시 이름", + "Allow signup": "가입 허용", + "Enabled": "활성화됨", + "Advanced Settings": "고급 설정", + "Enable TLS/SSL": "TLS\\/SSL 활성화", + "Use secure connection to LDAP server": "LDAP 서버에 안전한 연결 사용", + "Group sync": "그룹 동기화", + "No SSO providers found.": "SSO 제공자를 찾을 수 없습니다.", + "Delete SSO provider": "SSO 제공자 삭제", + "Are you sure you want to delete this SSO provider?": "이 SSO 제공자를 삭제하시겠습니까?", + "Action": "작업", + "{{ssoProviderType}} configuration": "{{ssoProviderType}} 구성" } diff --git a/apps/client/public/locales/nl-NL/translation.json b/apps/client/public/locales/nl-NL/translation.json index 1757f92e..7429bfe1 100644 --- a/apps/client/public/locales/nl-NL/translation.json +++ b/apps/client/public/locales/nl-NL/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "bijv. Ruimte voor productteam", "e.g Space for sales team to collaborate": "bijv. Ruimte voor verkoopteam om samen te werken", "Edit": "Bewerken", + "Read": "Lezen", "Edit group": "Groep bewerken", "Email": "E-mailadres", "Enter a strong password": "Voer een sterk wachtwoord in", @@ -495,5 +496,36 @@ "Page restored successfully": "Pagina succesvol hersteld", "Deleted by": "Verwijderd door", "Deleted at": "Verwijderd op", - "Preview": "Voorbeeld" + "Preview": "Voorbeeld", + "Subpages": "Subpagina's", + "Failed to load subpages": "Laden van subpagina's mislukt", + "No subpages": "Geen subpagina's", + "Subpages (Child pages)": "Subpagina's (Kindpagina's)", + "List all subpages of the current page": "Lijst van alle subpagina's van de huidige pagina", + "Attachments": "Bijlagen", + "All spaces": "Alle ruimtes", + "Unknown": "Onbekend", + "Find a space": "Vind een ruimte", + "Search in all your spaces": "Zoek in al je ruimtes", + "Type": "Type", + "Enterprise": "Onderneming", + "Download attachment": "Bijlage downloaden", + "Allowed email domains": "Toegestane e-maildomeinen", + "Only users with email addresses from these domains can signup via SSO.": "Alleen gebruikers met e-mailadressen van deze domeinen kunnen zich aanmelden via SSO.", + "Enter valid domain names separated by comma or space": "Voer geldige domeinnamen in, gescheiden door komma of spatie", + "Enforce two-factor authentication": "Handhaaf tweefactorauthenticatie", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Na handhaving moeten alle leden tweefactorauthenticatie inschakelen om toegang te krijgen tot de werkomgeving.", + "Toggle MFA enforcement": "Schakel MFA-handhaving in of uit", + "Display name": "Weergavenaam", + "Allow signup": "Aanmelden toestaan", + "Enabled": "Ingeschakeld", + "Advanced Settings": "Geavanceerde instellingen", + "Enable TLS/SSL": "TLS/SSL inschakelen", + "Use secure connection to LDAP server": "Gebruik een beveiligde verbinding met de LDAP-server", + "Group sync": "Groepssynchronisatie", + "No SSO providers found.": "Geen SSO-providers gevonden.", + "Delete SSO provider": "Verwijder SSO-provider", + "Are you sure you want to delete this SSO provider?": "Weet u zeker dat u deze SSO-provider wilt verwijderen?", + "Action": "Actie", + "{{ssoProviderType}} configuration": "{{ssoProviderType}} configuratie" } diff --git a/apps/client/public/locales/pt-BR/translation.json b/apps/client/public/locales/pt-BR/translation.json index 1ed2c6e5..c4564830 100644 --- a/apps/client/public/locales/pt-BR/translation.json +++ b/apps/client/public/locales/pt-BR/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "ex.: Espaço para a equipe de produto", "e.g Space for sales team to collaborate": "ex.: Espaço para a equipe de vendas colaborar", "Edit": "Editar", + "Read": "Ler", "Edit group": "Editar grupo", "Email": "Email", "Enter a strong password": "Insira uma senha forte", @@ -495,5 +496,36 @@ "Page restored successfully": "Página restaurada com sucesso", "Deleted by": "Excluído por", "Deleted at": "Excluído em", - "Preview": "Visualização" + "Preview": "Visualização", + "Subpages": "Subpáginas", + "Failed to load subpages": "Falha ao carregar subpáginas", + "No subpages": "Sem subpáginas", + "Subpages (Child pages)": "Subpáginas (Páginas filhas)", + "List all subpages of the current page": "Listar todas as subpáginas da página atual", + "Attachments": "Anexos", + "All spaces": "Todos os espaços", + "Unknown": "Desconhecido", + "Find a space": "Encontrar um espaço", + "Search in all your spaces": "Pesquisar em todos os seus espaços", + "Type": "Tipo", + "Enterprise": "Empresa", + "Download attachment": "Baixar anexo", + "Allowed email domains": "Domínios de email permitidos", + "Only users with email addresses from these domains can signup via SSO.": "Apenas usuários com endereços de email desses domínios podem se inscrever via SSO.", + "Enter valid domain names separated by comma or space": "Insira nomes de domínio válidos separados por vírgula ou espaço", + "Enforce two-factor authentication": "Impor autenticação de dois fatores", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Uma vez imposto, todos os membros devem habilitar a autenticação de dois fatores para acessar o espaço de trabalho.", + "Toggle MFA enforcement": "Alternar imposição de MFA", + "Display name": "Nome de exibição", + "Allow signup": "Permitir inscrição", + "Enabled": "Habilitado", + "Advanced Settings": "Configurações Avançadas", + "Enable TLS/SSL": "Habilitar TLS/SSL", + "Use secure connection to LDAP server": "Usar conexão segura com o servidor LDAP", + "Group sync": "Sincronização de grupo", + "No SSO providers found.": "Nenhum provedor de SSO encontrado.", + "Delete SSO provider": "Excluir provedor de SSO", + "Are you sure you want to delete this SSO provider?": "Tem certeza de que deseja excluir este provedor de SSO?", + "Action": "Ação", + "{{ssoProviderType}} configuration": "Configuração de {{ssoProviderType}}" } diff --git a/apps/client/public/locales/ru-RU/translation.json b/apps/client/public/locales/ru-RU/translation.json index 3ad0607f..fab5389e 100644 --- a/apps/client/public/locales/ru-RU/translation.json +++ b/apps/client/public/locales/ru-RU/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "например, Пространство для продуктовой команды", "e.g Space for sales team to collaborate": "например, Пространство для совместной работы команды продаж", "Edit": "Редактировать", + "Read": "Читать", "Edit group": "Редактировать группу", "Email": "Электронная почта", "Enter a strong password": "Введите надёжный пароль", @@ -495,5 +496,36 @@ "Page restored successfully": "Страница успешно восстановлена", "Deleted by": "Удалено пользователем", "Deleted at": "Удалено в", - "Preview": "Предпросмотр" + "Preview": "Предпросмотр", + "Subpages": "Подстраницы", + "Failed to load subpages": "Не удалось загрузить подстраницы", + "No subpages": "Нет подстраниц", + "Subpages (Child pages)": "Подстраницы (вложенные страницы)", + "List all subpages of the current page": "Показать все подстраницы текущей страницы", + "Attachments": "Вложения", + "All spaces": "Все пространства", + "Unknown": "Неизвестно", + "Find a space": "Найти пространство", + "Search in all your spaces": "Поиск во всех ваших пространствах", + "Type": "Тип", + "Enterprise": "Предприятие", + "Download attachment": "Скачать вложение", + "Allowed email domains": "Разрешенные домены электронной почты", + "Only users with email addresses from these domains can signup via SSO.": "Только пользователи с электронными адресами из этих доменов могут зарегистрироваться через SSO.", + "Enter valid domain names separated by comma or space": "Введите допустимые доменные имена, разделённые запятыми или пробелами", + "Enforce two-factor authentication": "Обязательная двухфакторная аутентификация", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "После введения обязательности все участники должны будут включить двухфакторную аутентификацию для доступа к рабочему пространству.", + "Toggle MFA enforcement": "Переключить обязательность MFA", + "Display name": "Отображаемое имя", + "Allow signup": "Разрешить регистрацию", + "Enabled": "Включено", + "Advanced Settings": "Расширенные настройки", + "Enable TLS/SSL": "Включить TLS/SSL", + "Use secure connection to LDAP server": "Использовать защищённое соединение с сервером LDAP", + "Group sync": "Синхронизация группы", + "No SSO providers found.": "Поставщики SSO не найдены.", + "Delete SSO provider": "Удалить поставщика SSO", + "Are you sure you want to delete this SSO provider?": "Вы уверены, что хотите удалить этого поставщика SSO?", + "Action": "Действие", + "{{ssoProviderType}} configuration": "Настройка {{ssoProviderType}}" } diff --git a/apps/client/public/locales/uk-UA/translation.json b/apps/client/public/locales/uk-UA/translation.json index e3f359a3..e6d5427f 100644 --- a/apps/client/public/locales/uk-UA/translation.json +++ b/apps/client/public/locales/uk-UA/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "наприклад, Простір для продуктової команди", "e.g Space for sales team to collaborate": "наприклад, Простір для спільної роботи команди продажів", "Edit": "Редагувати", + "Read": "Читати", "Edit group": "Редагувати групу", "Email": "Електронна пошта", "Enter a strong password": "Введіть надійний пароль", @@ -495,5 +496,36 @@ "Page restored successfully": "Сторінку успішно відновлено", "Deleted by": "Видалено", "Deleted at": "Видалено о", - "Preview": "Попередній перегляд" + "Preview": "Попередній перегляд", + "Subpages": "Підсторінки", + "Failed to load subpages": "Не вдалося завантажити підсторінки", + "No subpages": "Немає підсторінок", + "Subpages (Child pages)": "Підсторінки (дочірні сторінки)", + "List all subpages of the current page": "Перелік всіх підсторінок поточної сторінки", + "Attachments": "Вкладення", + "All spaces": "Усі простори", + "Unknown": "Невідомо", + "Find a space": "Знайти простір", + "Search in all your spaces": "Шукати у всіх ваших просторах", + "Type": "Тип", + "Enterprise": "Підприємство", + "Download attachment": "Завантажити вкладення", + "Allowed email domains": "Дозволені домени електронної пошти", + "Only users with email addresses from these domains can signup via SSO.": "Лише користувачі з адресами електронної пошти з цих доменів можуть реєструватися через SSO.", + "Enter valid domain names separated by comma or space": "Введіть дійсні доменні імена, розділені комою або пробілом", + "Enforce two-factor authentication": "Вимагати двофакторну автентифікацію", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "Після увімкнення всі учасники повинні ввімкнути двофакторну автентифікацію для доступу до робочого простору.", + "Toggle MFA enforcement": "Перемикання вимоги MFA", + "Display name": "Відображуване ім'я", + "Allow signup": "Дозволити реєстрацію", + "Enabled": "Увімкнено", + "Advanced Settings": "Розширені налаштування", + "Enable TLS/SSL": "Увімкнути TLS/SSL", + "Use secure connection to LDAP server": "Використовувати захищене з'єднання з сервером LDAP", + "Group sync": "Синхронізація групи", + "No SSO providers found.": "Постачальників SSO не знайдено.", + "Delete SSO provider": "Видалити постачальника SSO", + "Are you sure you want to delete this SSO provider?": "Ви впевнені, що хочете видалити цього постачальника SSO?", + "Action": "Дія", + "{{ssoProviderType}} configuration": "Конфігурація {{ssoProviderType}}" } diff --git a/apps/client/public/locales/zh-CN/translation.json b/apps/client/public/locales/zh-CN/translation.json index 56c7ec85..33373155 100644 --- a/apps/client/public/locales/zh-CN/translation.json +++ b/apps/client/public/locales/zh-CN/translation.json @@ -53,6 +53,7 @@ "e.g Space for product team": "例如:产品团队的空间", "e.g Space for sales team to collaborate": "例如:销售团队协作的空间", "Edit": "编辑", + "Read": "阅读", "Edit group": "编辑群组", "Email": "电子邮箱", "Enter a strong password": "输入一个强密码", @@ -495,5 +496,36 @@ "Page restored successfully": "页面恢复成功", "Deleted by": "删除人", "Deleted at": "删除时间", - "Preview": "预览" + "Preview": "预览", + "Subpages": "子页面", + "Failed to load subpages": "加载子页面失败", + "No subpages": "没有子页面", + "Subpages (Child pages)": "子页面(子页面)", + "List all subpages of the current page": "列出当前页面的所有子页面", + "Attachments": "附件", + "All spaces": "所有空间", + "Unknown": "未知", + "Find a space": "查找空间", + "Search in all your spaces": "在您的所有空间中搜索", + "Type": "类型", + "Enterprise": "企业", + "Download attachment": "下载附件", + "Allowed email domains": "允许的电子邮件域", + "Only users with email addresses from these domains can signup via SSO.": "只有来自这些域的电子邮件地址的用户才能通过SSO注册。", + "Enter valid domain names separated by comma or space": "输入用逗号或空格分隔的有效域名", + "Enforce two-factor authentication": "强制实施双因素认证", + "Once enforced, all members must enable two-factor authentication to access the workspace.": "一旦实施,所有成员必须启用双因素认证才能访问工作区。", + "Toggle MFA enforcement": "切换多因素认证实施", + "Display name": "显示名称", + "Allow signup": "允许注册", + "Enabled": "已启用", + "Advanced Settings": "高级设置", + "Enable TLS/SSL": "启用TLS/SSL", + "Use secure connection to LDAP server": "使用安全连接到LDAP服务器", + "Group sync": "组同步", + "No SSO providers found.": "未找到SSO提供商。", + "Delete SSO provider": "删除SSO提供商", + "Are you sure you want to delete this SSO provider?": "您确定要删除此SSO提供商吗?", + "Action": "操作", + "{{ssoProviderType}} configuration": "{{ssoProviderType}} 配置" } diff --git a/apps/client/public/manifest.json b/apps/client/public/manifest.json new file mode 100644 index 00000000..3e4b35dd --- /dev/null +++ b/apps/client/public/manifest.json @@ -0,0 +1,30 @@ +{ + "name": "Docmost", + "short_name": "Docmost", + "start_url": "/", + "display": "standalone", + "background_color": "#222", + "theme_color": "#222", + "icons": [ + { + "src": "icons/favicon-16x16.png", + "type": "image/png", + "sizes": "16x16" + }, + { + "src": "icons/favicon-32x32.png", + "type": "image/png", + "sizes": "32x32" + }, + { + "src": "icons/app-icon-192x192.png", + "type": "image/png", + "sizes": "180x180 192x192" + }, + { + "src": "icons/app-icon-512x512.png", + "type": "image/png", + "sizes": "512x512" + } + ] +} diff --git a/apps/client/src/components/common/avatar-uploader.tsx b/apps/client/src/components/common/avatar-uploader.tsx new file mode 100644 index 00000000..0c83411c --- /dev/null +++ b/apps/client/src/components/common/avatar-uploader.tsx @@ -0,0 +1,165 @@ +import React, { useRef } from "react"; +import { Menu, Box, Loader } from "@mantine/core"; +import { useTranslation } from "react-i18next"; +import { IconTrash, IconUpload } from "@tabler/icons-react"; +import { CustomAvatar } from "@/components/ui/custom-avatar.tsx"; +import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts"; +import { notifications } from "@mantine/notifications"; + +interface AvatarUploaderProps { + currentImageUrl?: string | null; + fallbackName?: string; + radius?: string | number; + size?: string | number; + variant?: string; + type: AvatarIconType; + onUpload: (file: File) => Promise; + onRemove: () => Promise; + isLoading?: boolean; + disabled?: boolean; +} + +export default function AvatarUploader({ + currentImageUrl, + fallbackName, + radius, + variant, + size, + type, + onUpload, + onRemove, + isLoading = false, + disabled = false, +}: AvatarUploaderProps) { + const { t } = useTranslation(); + const fileInputRef = useRef(null); + + const handleFileInputChange = async ( + event: React.ChangeEvent, + ) => { + const file = event.target.files?.[0]; + if (!file || disabled) { + return; + } + + // Validate file size (max 10MB) + const maxSizeInBytes = 10 * 1024 * 1024; + if (file.size > maxSizeInBytes) { + notifications.show({ + message: t("Image exceeds 10MB limit."), + color: "red", + }); + // Reset the input + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + return; + } + + try { + await onUpload(file); + } catch (error) { + console.error(error); + notifications.show({ + message: t("Failed to upload image"), + color: "red", + }); + } + + // Reset the input so the same file can be selected again + if (fileInputRef.current) { + fileInputRef.current.value = ""; + } + }; + + const handleUploadClick = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } else { + console.error("File input ref is null!"); + } + }; + + const handleRemove = async () => { + if (disabled) return; + + try { + await onRemove(); + notifications.show({ + message: t("Image removed successfully"), + }); + } catch (error) { + console.error(error); + notifications.show({ + message: t("Failed to remove image"), + color: "red", + }); + } + }; + + return ( + + + + + + + + {isLoading && ( + + + + )} + + + + + } + disabled={isLoading || disabled} + onClick={handleUploadClick} + > + {t("Upload image")} + + + {currentImageUrl && ( + } + color="red" + onClick={handleRemove} + disabled={isLoading || disabled} + > + {t("Remove image")} + + )} + + + + ); +} diff --git a/apps/client/src/components/layouts/global/app-header.tsx b/apps/client/src/components/layouts/global/app-header.tsx index 09b95539..eb1ca74f 100644 --- a/apps/client/src/components/layouts/global/app-header.tsx +++ b/apps/client/src/components/layouts/global/app-header.tsx @@ -14,6 +14,14 @@ import SidebarToggle from "@/components/ui/sidebar-toggle-button.tsx"; import { useTranslation } from "react-i18next"; import useTrial from "@/ee/hooks/use-trial.tsx"; import { isCloud } from "@/lib/config.ts"; +import { + SearchControl, + SearchMobileControl, +} from "@/features/search/components/search-control.tsx"; +import { + searchSpotlight, + shareSearchSpotlight, +} from "@/features/search/constants.ts"; const links = [{ link: APP_ROUTE.HOME, label: "Home" }]; @@ -79,6 +87,15 @@ export function AppHeader() { +
+ + + + + + +
+ {isCloud() && isTrial && trialDaysLeft !== 0 && ( {isCloud() && } + ); } diff --git a/apps/client/src/components/layouts/global/top-menu.tsx b/apps/client/src/components/layouts/global/top-menu.tsx index d3a89ecc..84925080 100644 --- a/apps/client/src/components/layouts/global/top-menu.tsx +++ b/apps/client/src/components/layouts/global/top-menu.tsx @@ -1,8 +1,8 @@ import { Group, Menu, - UnstyledButton, Text, + UnstyledButton, useMantineColorScheme, } from "@mantine/core"; import { @@ -10,7 +10,6 @@ import { IconBrush, IconCheck, IconChevronDown, - IconChevronRight, IconDeviceDesktop, IconLogout, IconMoon, @@ -26,6 +25,7 @@ import APP_ROUTE from "@/lib/app-route.ts"; import useAuth from "@/features/auth/hooks/use-auth.ts"; import { CustomAvatar } from "@/components/ui/custom-avatar.tsx"; import { useTranslation } from "react-i18next"; +import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts"; export default function TopMenu() { const { t } = useTranslation(); @@ -50,6 +50,7 @@ export default function TopMenu() { name={workspace?.name} variant="filled" size="sm" + type={AvatarIconType.WORKSPACE_ICON} /> {workspace?.name} diff --git a/apps/client/src/components/settings/app-version.tsx b/apps/client/src/components/settings/app-version.tsx index cb332478..5ba9ce2a 100644 --- a/apps/client/src/components/settings/app-version.tsx +++ b/apps/client/src/components/settings/app-version.tsx @@ -50,7 +50,7 @@ export default function AppVersion() { href="https://github.com/docmost/docmost/releases" target="_blank" > - v{APP_VERSION} + {appVersion?.currentVersion && <>v{appVersion?.currentVersion}} diff --git a/apps/client/src/components/ui/custom-avatar.tsx b/apps/client/src/components/ui/custom-avatar.tsx index de4456e5..54730127 100644 --- a/apps/client/src/components/ui/custom-avatar.tsx +++ b/apps/client/src/components/ui/custom-avatar.tsx @@ -1,6 +1,7 @@ import React from "react"; import { Avatar } from "@mantine/core"; import { getAvatarUrl } from "@/lib/config.ts"; +import { AvatarIconType } from "@/features/attachments/types/attachment.types.ts"; interface CustomAvatarProps { avatarUrl: string; @@ -11,13 +12,15 @@ interface CustomAvatarProps { variant?: string; style?: any; component?: any; + type?: AvatarIconType; + mt?: string | number; } export const CustomAvatar = React.forwardRef< HTMLInputElement, CustomAvatarProps ->(({ avatarUrl, name, ...props }: CustomAvatarProps, ref) => { - const avatarLink = getAvatarUrl(avatarUrl); +>(({ avatarUrl, name, type, ...props }: CustomAvatarProps, ref) => { + const avatarLink = getAvatarUrl(avatarUrl, type); return ( void; readOnly: boolean; + actionIconProps?: { + size?: string; + variant?: string; + c?: string; + }; } function EmojiPicker({ @@ -22,6 +27,7 @@ function EmojiPicker({ icon, removeEmojiAction, readOnly, + actionIconProps, }: EmojiPickerInterface) { const { t } = useTranslation(); const [opened, handlers] = useDisclosure(false); @@ -64,7 +70,12 @@ function EmojiPicker({ closeOnEscape={true} > - + {icon} diff --git a/apps/client/src/components/ui/responsive-settings-row.tsx b/apps/client/src/components/ui/responsive-settings-row.tsx new file mode 100644 index 00000000..ec3f65f7 --- /dev/null +++ b/apps/client/src/components/ui/responsive-settings-row.tsx @@ -0,0 +1,47 @@ +import { Box } from "@mantine/core"; +import React from "react"; + +interface ResponsiveSettingsRowProps { + children: React.ReactNode; +} + +export function ResponsiveSettingsRow({ children }: ResponsiveSettingsRowProps) { + return ( + + {children} + + ); +} + +interface ResponsiveSettingsContentProps { + children: React.ReactNode; +} + +export function ResponsiveSettingsContent({ children }: ResponsiveSettingsContentProps) { + return ( + + {children} + + ); +} + +interface ResponsiveSettingsControlProps { + children: React.ReactNode; +} + +export function ResponsiveSettingsControl({ children }: ResponsiveSettingsControlProps) { + return ( + + {children} + + ); +} diff --git a/apps/client/src/ee/components/ldap-login-modal.tsx b/apps/client/src/ee/components/ldap-login-modal.tsx new file mode 100644 index 00000000..9360651d --- /dev/null +++ b/apps/client/src/ee/components/ldap-login-modal.tsx @@ -0,0 +1,124 @@ +import React, { useState } from "react"; +import { Modal, TextInput, PasswordInput, Button, Stack } from "@mantine/core"; +import { useForm } from "@mantine/form"; +import { zodResolver } from "mantine-form-zod-resolver"; +import { z } from "zod"; +import { notifications } from "@mantine/notifications"; +import { useNavigate } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { IAuthProvider } from "@/ee/security/types/security.types"; +import APP_ROUTE from "@/lib/app-route"; +import { ldapLogin } from "@/ee/security/services/ldap-auth-service"; + +const formSchema = z.object({ + username: z.string().min(1, { message: "Username is required" }), + password: z.string().min(1, { message: "Password is required" }), +}); + +interface LdapLoginModalProps { + opened: boolean; + onClose: () => void; + provider: IAuthProvider; + workspaceId: string; +} + +export function LdapLoginModal({ + opened, + onClose, + provider, + workspaceId, +}: LdapLoginModalProps) { + const { t } = useTranslation(); + const navigate = useNavigate(); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(null); + + const form = useForm({ + validate: zodResolver(formSchema), + initialValues: { + username: "", + password: "", + }, + }); + + const handleSubmit = async (values: { + username: string; + password: string; + }) => { + setIsLoading(true); + setError(null); + + try { + const response = await ldapLogin({ + username: values.username, + password: values.password, + providerId: provider.id, + workspaceId, + }); + + // Handle MFA like the regular login + if (response?.userHasMfa) { + onClose(); + navigate(APP_ROUTE.AUTH.MFA_CHALLENGE); + } else if (response?.requiresMfaSetup) { + onClose(); + navigate(APP_ROUTE.AUTH.MFA_SETUP_REQUIRED); + } else { + onClose(); + navigate(APP_ROUTE.HOME); + } + } catch (err: any) { + setIsLoading(false); + const errorMessage = + err.response?.data?.message || "Authentication failed"; + setError(errorMessage); + + notifications.show({ + message: errorMessage, + color: "red", + }); + } + }; + + const handleClose = () => { + form.reset(); + setError(null); + onClose(); + }; + + return ( + +
+ + + + + + + +
+
+ ); +} diff --git a/apps/client/src/ee/components/sso-login.tsx b/apps/client/src/ee/components/sso-login.tsx index 8de93c29..8c96d9c5 100644 --- a/apps/client/src/ee/components/sso-login.tsx +++ b/apps/client/src/ee/components/sso-login.tsx @@ -1,29 +1,62 @@ +import { useState } from "react"; import { useWorkspacePublicDataQuery } from "@/features/workspace/queries/workspace-query.ts"; import { Button, Divider, Stack } from "@mantine/core"; -import { IconLock } from "@tabler/icons-react"; +import { IconLock, IconServer } from "@tabler/icons-react"; import { IAuthProvider } from "@/ee/security/types/security.types.ts"; import { buildSsoLoginUrl } from "@/ee/security/sso.utils.ts"; import { SSO_PROVIDER } from "@/ee/security/contants.ts"; import { GoogleIcon } from "@/components/icons/google-icon.tsx"; import { isCloud } from "@/lib/config.ts"; +import { LdapLoginModal } from "@/ee/components/ldap-login-modal.tsx"; export default function SsoLogin() { const { data, isLoading } = useWorkspacePublicDataQuery(); + const [ldapModalOpened, setLdapModalOpened] = useState(false); + const [selectedLdapProvider, setSelectedLdapProvider] = useState(null); if (!data?.authProviders || data?.authProviders?.length === 0) { return null; } const handleSsoLogin = (provider: IAuthProvider) => { - window.location.href = buildSsoLoginUrl({ - providerId: provider.id, - type: provider.type, - workspaceId: data.id, - }); + if (provider.type === SSO_PROVIDER.LDAP) { + // Open modal for LDAP instead of redirecting + setSelectedLdapProvider(provider); + setLdapModalOpened(true); + } else { + // Redirect for other SSO providers + window.location.href = buildSsoLoginUrl({ + providerId: provider.id, + type: provider.type, + workspaceId: data.id, + }); + } + }; + + const getProviderIcon = (provider: IAuthProvider) => { + if (provider.type === SSO_PROVIDER.GOOGLE) { + return ; + } else if (provider.type === SSO_PROVIDER.LDAP) { + return ; + } else { + return ; + } }; return ( <> + {selectedLdapProvider && ( + { + setLdapModalOpened(false); + setSelectedLdapProvider(null); + }} + provider={selectedLdapProvider} + workspaceId={data.id} + /> + )} + {(isCloud() || data.hasLicenseKey) && ( <> @@ -31,13 +64,7 @@ export default function SsoLogin() {
- - ) : ( - - - - - )} - + + + ) : ( + + + + + )} + + { const req = await api.post( "/mfa/generate-backup-codes", diff --git a/apps/client/src/ee/mfa/types/mfa.types.ts b/apps/client/src/ee/mfa/types/mfa.types.ts index ac032195..9f3bbe7c 100644 --- a/apps/client/src/ee/mfa/types/mfa.types.ts +++ b/apps/client/src/ee/mfa/types/mfa.types.ts @@ -46,7 +46,7 @@ export interface MfaEnableResponse { } export interface MfaDisableRequest { - confirmPassword: string; + confirmPassword?: string; } export interface MfaBackupCodesResponse { diff --git a/apps/client/src/ee/security/components/allowed-domains.tsx b/apps/client/src/ee/security/components/allowed-domains.tsx index c50825fe..d1050975 100644 --- a/apps/client/src/ee/security/components/allowed-domains.tsx +++ b/apps/client/src/ee/security/components/allowed-domains.tsx @@ -1,6 +1,7 @@ import { useAtom } from "jotai"; import * as z from "zod"; -import { useForm, zodResolver } from "@mantine/form"; +import { useForm } from "@mantine/form"; +import { zodResolver } from "mantine-form-zod-resolver"; import { workspaceAtom } from "@/features/user/atoms/current-user-atom.ts"; import React, { useState } from "react"; import { Button, Text, TagsInput } from "@mantine/core"; @@ -54,9 +55,11 @@ export default function AllowedDomains() { return ( <>
- Allowed email domains + {t("Allowed email domains")} - Only users with email addresses from these domains can signup via SSO. + {t( + "Only users with email addresses from these domains can signup via SSO.", + )}
diff --git a/apps/client/src/ee/security/components/create-sso-provider.tsx b/apps/client/src/ee/security/components/create-sso-provider.tsx index 8a6162e9..3f213bb9 100644 --- a/apps/client/src/ee/security/components/create-sso-provider.tsx +++ b/apps/client/src/ee/security/components/create-sso-provider.tsx @@ -1,7 +1,7 @@ import React, { useState } from "react"; import { useDisclosure } from "@mantine/hooks"; import { Button, Menu, Group } from "@mantine/core"; -import { IconChevronDown, IconLock } from "@tabler/icons-react"; +import { IconChevronDown, IconLock, IconServer } from "@tabler/icons-react"; import { useCreateSsoProviderMutation } from "@/ee/security/queries/security-query.ts"; import { SSO_PROVIDER } from "@/ee/security/contants.ts"; import { IAuthProvider } from "@/ee/security/types/security.types.ts"; @@ -40,6 +40,19 @@ export default function CreateSsoProvider() { } }; + const handleCreateLDAP = async () => { + try { + const newProvider = await createSsoProviderMutation.mutateAsync({ + type: SSO_PROVIDER.LDAP, + name: "LDAP", + }); + setProvider(newProvider); + open(); + } catch (error) { + console.error("Failed to create LDAP provider", error); + } + }; + return ( <> @@ -71,6 +84,13 @@ export default function CreateSsoProvider() { > OpenID (OIDC) + + } + > + LDAP / Active Directory + diff --git a/apps/client/src/ee/security/components/sso-google-form.tsx b/apps/client/src/ee/security/components/sso-google-form.tsx index 97a39a3b..ddd14b0f 100644 --- a/apps/client/src/ee/security/components/sso-google-form.tsx +++ b/apps/client/src/ee/security/components/sso-google-form.tsx @@ -1,6 +1,7 @@ import React from "react"; import { z } from "zod"; -import { useForm, zodResolver } from "@mantine/form"; +import { useForm } from "@mantine/form"; +import { zodResolver } from "mantine-form-zod-resolver"; import { Box, Button, Group, Stack, Switch, TextInput } from "@mantine/core"; import classes from "@/ee/security/components/sso.module.css"; import { IAuthProvider } from "@/ee/security/types/security.types.ts"; diff --git a/apps/client/src/ee/security/components/sso-ldap-form.tsx b/apps/client/src/ee/security/components/sso-ldap-form.tsx new file mode 100644 index 00000000..662e8458 --- /dev/null +++ b/apps/client/src/ee/security/components/sso-ldap-form.tsx @@ -0,0 +1,228 @@ +import React from "react"; +import { z } from "zod"; +import { useForm } from "@mantine/form"; +import { zodResolver } from "mantine-form-zod-resolver"; +import { + Box, + Button, + Group, + Stack, + Switch, + TextInput, + Textarea, + Text, + Accordion, +} from "@mantine/core"; +import classes from "@/ee/security/components/sso.module.css"; +import { IAuthProvider } from "@/ee/security/types/security.types.ts"; +import { useTranslation } from "react-i18next"; +import { useUpdateSsoProviderMutation } from "@/ee/security/queries/security-query.ts"; +import { IconInfoCircle } from "@tabler/icons-react"; + +const ssoSchema = z.object({ + name: z.string().min(1, "Display name is required"), + ldapUrl: z.string().url().startsWith("ldap", "Must be an LDAP URL"), + ldapBindDn: z.string().min(1, "Bind DN is required"), + ldapBindPassword: z.string().min(1, "Bind password is required"), + ldapBaseDn: z.string().min(1, "Base DN is required"), + ldapUserSearchFilter: z.string().optional(), + ldapTlsEnabled: z.boolean(), + ldapTlsCaCert: z.string().optional(), + isEnabled: z.boolean(), + allowSignup: z.boolean(), + groupSync: z.boolean(), +}); + +type SSOFormValues = z.infer; + +interface SsoFormProps { + provider: IAuthProvider; + onClose?: () => void; +} + +export function SsoLDAPForm({ provider, onClose }: SsoFormProps) { + const { t } = useTranslation(); + const updateSsoProviderMutation = useUpdateSsoProviderMutation(); + + const form = useForm({ + initialValues: { + name: provider.name || "", + ldapUrl: provider.ldapUrl || "", + ldapBindDn: provider.ldapBindDn || "", + ldapBindPassword: provider.ldapBindPassword || "", + ldapBaseDn: provider.ldapBaseDn || "", + ldapUserSearchFilter: + provider.ldapUserSearchFilter || "(mail={{username}})", + ldapTlsEnabled: provider.ldapTlsEnabled || false, + ldapTlsCaCert: provider.ldapTlsCaCert || "", + isEnabled: provider.isEnabled, + allowSignup: provider.allowSignup, + groupSync: provider.groupSync || false, + }, + validate: zodResolver(ssoSchema), + }); + + const handleSubmit = async (values: SSOFormValues) => { + const ssoData: Partial = { + providerId: provider.id, + }; + if (form.isDirty("name")) { + ssoData.name = values.name; + } + if (form.isDirty("ldapUrl")) { + ssoData.ldapUrl = values.ldapUrl; + } + if (form.isDirty("ldapBindDn")) { + ssoData.ldapBindDn = values.ldapBindDn; + } + if (form.isDirty("ldapBindPassword")) { + ssoData.ldapBindPassword = values.ldapBindPassword; + } + if (form.isDirty("ldapBaseDn")) { + ssoData.ldapBaseDn = values.ldapBaseDn; + } + if (form.isDirty("ldapUserSearchFilter")) { + ssoData.ldapUserSearchFilter = values.ldapUserSearchFilter; + } + if (form.isDirty("ldapTlsEnabled")) { + ssoData.ldapTlsEnabled = values.ldapTlsEnabled; + } + if (form.isDirty("ldapTlsCaCert")) { + ssoData.ldapTlsCaCert = values.ldapTlsCaCert; + } + if (form.isDirty("isEnabled")) { + ssoData.isEnabled = values.isEnabled; + } + if (form.isDirty("allowSignup")) { + ssoData.allowSignup = values.allowSignup; + } + if (form.isDirty("groupSync")) { + ssoData.groupSync = values.groupSync; + } + + await updateSsoProviderMutation.mutateAsync(ssoData); + form.resetDirty(); + onClose(); + }; + + return ( + + + + + + + + + + + + + + + + + + }> + {t("Advanced Settings")} + + + + +
+ {t("Enable TLS/SSL")} + + Use secure connection to LDAP server + +
+ +
+ + {form.values.ldapTlsEnabled && ( +