Compare commits

...

26 Commits

Author SHA1 Message Date
Ruben Talstra
97a6074edc Merge branch 'dev' into feat/multi-lang-Terms-of-service 2025-07-04 11:01:33 +02:00
Ruben Talstra
126b1fe412 Merge branch 'dev' into feat/multi-lang-Terms-of-service 2025-05-29 17:06:50 +02:00
Ruben Talstra
8053ef32bf Merge remote-tracking branch 'origin/feat/multi-lang-Terms-of-service' into feat/multi-lang-Terms-of-service 2025-05-29 17:06:33 +02:00
Ruben Talstra
a80c1dd2ce 🔧 chore: Update version to 0.7.82 in package.json and package-lock.json 2025-05-29 17:06:15 +02:00
Ruben Talstra
9962ec318c Merge branch 'dev' into feat/multi-lang-Terms-of-service 2025-05-16 10:02:25 +02:00
Ruben Talstra
1dd644b72e Merge branch 'dev' into feat/multi-lang-Terms-of-service 2025-05-15 17:09:30 +02:00
Ruben Talstra
c925f9f39c 🚀 feat: Add Cloudflare Turnstile support (#5987)
* 🚀 feat: Add @marsidev/react-turnstile dependency to package.json and package-lock.json

* 🚀 feat: Integrate Cloudflare Turnstile configuration support in AppService and add schema validation

* 🚀 feat: Implemented Cloudflare Turnstile integration in Login and Registration forms

* 🚀 feat: Enhance AppService tests with additional mocks and configuration setups

* 🚀 feat: Comment out outdated config version warning tests in AppService.spec.js

* 🚀 feat: Remove outdated warning tests and add new checks for environment variables and API health

* 🔧 test: Update AppService.spec.js to use expect.anything() for paths validation

* 🔧 test: Refactor AppService.spec.js to streamline mocks and enhance clarity

* 🔧 chore: removed not needed test

* Potential fix for code scanning alert no. 5638: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5629: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5642: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Update turnstile.js

* Potential fix for code scanning alert no. 5634: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5646: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

* Potential fix for code scanning alert no. 5647: Ensure code is properly formatted, use insertion, deletion, or replacement to obtain desired formatting.

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2025-05-15 09:38:58 -04:00
matt burnett
71effb1a66 🔃 refactor: AgentFooter to conditionally render buttons based on activePanel (#7306) 2025-05-15 09:37:14 -04:00
andresgit
e3acd18c07 🎨 feat: add copy-tex to improve copying KaTeX (#7308)
When selecting equations and using copy paste, uses the correct latex code.

Co-authored-by: Ruben Talstra <RubenTalstra1211@outlook.com>
2025-05-15 09:35:48 -04:00
Ruben Talstra
c371491e71 🔧 chore: Bump version to 0.7.821 in package.json and package-lock.json 2025-05-14 19:59:28 +02:00
Ruben Talstra
122773a2be 🔧 refactor: Remove unused hooks from Root.tsx 2025-05-14 19:55:16 +02:00
Ruben Talstra
fcc1eb45f4 Merge branch 'main' into feat/multi-lang-Terms-of-service 2025-05-14 19:52:56 +02:00
Ruben Talstra
f434ddc125 🔧 chore: Update version to 0.7.789 in package.json and package-lock.json 2025-05-14 19:50:17 +02:00
Ruben Talstra
5a9dcef1bc 🔧 chore: Bump version to 0.7.7891 in package.json and package-lock.json 2025-04-05 15:10:30 +02:00
Ruben Talstra
7c0324695a Merge branch 'main' into feat/multi-lang-Terms-of-service 2025-04-05 15:09:43 +02:00
Ruben Talstra
17c09e6e89 🚀 feat: Update version to 0.7.789 in package.json 2025-04-05 15:09:27 +02:00
Ruben Talstra
e488dab5db 🚀 feat: Bump version to 0.7.79 in package.json and package-lock.json 2025-04-05 15:07:48 +02:00
Ruben Talstra
4b75890d1f 🚀 feat: Update version to 0.7.75 and revise terms and conditions in German, English, and French 2025-03-24 18:00:44 +01:00
Ruben Talstra
4e82eab01c Merge branch 'main' into feat/multi-lang-Terms-of-service 2025-03-24 17:53:36 +01:00
Marco Beretta
f4c50ed25b 🔧 refactor(TermsAndConditions): Enhanced UI, accessibility, and updated to use new dialog and components 2025-03-23 02:43:03 +01:00
Ruben Talstra
9885982233 Merge branch 'main' into feat/multi-lang-Terms-of-service 2025-03-20 14:18:17 +01:00
Ruben Talstra
6b60ee4df8 🔧 test: Update Jest configuration to include additional test roots and add markdown file mock 2025-03-19 13:40:22 +01:00
Ruben Talstra
b170a57482 Merge branch 'main' into feat/multi-lang-Terms-of-service 2025-03-19 13:30:26 +01:00
Ruben Talstra
bb6a69e98a 🔧 chore: update package-lock.json 2025-03-19 13:30:10 +01:00
Ruben Talstra
a88e99dcfb 🌍 i18n: Refactor terms content structure and update paths for multi-language support 2025-03-10 18:27:13 +01:00
Ruben Talstra
b7a6d7caa6 🌍 i18n: Add multi-language support for Terms of Service and update modal content 2025-03-10 09:28:28 +01:00
13 changed files with 265 additions and 84 deletions

View File

@@ -1,5 +1,5 @@
module.exports = {
roots: ['<rootDir>/src'],
roots: ['<rootDir>/src', '<rootDir>/../terms'],
testEnvironment: 'jsdom',
testEnvironmentOptions: {
url: 'http://localhost:3080',
@@ -29,6 +29,7 @@ module.exports = {
'^test/(.*)$': '<rootDir>/test/$1',
'^~/(.*)$': '<rootDir>/src/$1',
'^librechat-data-provider/react-query$': '<rootDir>/../node_modules/librechat-data-provider/src/react-query',
'^.+\\.md\\?raw$': '<rootDir>/test/rawFileMock.js',
},
restoreMocks: true,
testResultsProcessor: 'jest-junit',

View File

@@ -1,12 +1,20 @@
import { useMemo } from 'react';
import type { TTermsOfService } from 'librechat-data-provider';
import React from 'react';
import MarkdownLite from '~/components/Chat/Messages/Content/MarkdownLite';
import DialogTemplate from '~/components/ui/DialogTemplate';
import OGDialogTemplate from '~/components/ui/OGDialogTemplate';
import { useAcceptTermsMutation } from '~/data-provider';
import { OGDialog, Button, Spinner } from '~/components';
import { useToastContext } from '~/Providers';
import { OGDialog } from '~/components/ui';
import { useLocalize } from '~/hooks';
interface TermsModalProps {
open: boolean;
onOpenChange: (isOpen: boolean) => void;
onAccept: () => void;
onDecline: () => void;
title?: string;
modalContent?: string;
}
const TermsAndConditionsModal = ({
open,
onOpenChange,
@@ -14,17 +22,10 @@ const TermsAndConditionsModal = ({
onDecline,
title,
modalContent,
}: {
open: boolean;
onOpenChange: (isOpen: boolean) => void;
onAccept: () => void;
onDecline: () => void;
title?: string;
contentUrl?: string;
modalContent?: TTermsOfService['modalContent'];
}) => {
}: TermsModalProps) => {
const localize = useLocalize();
const { showToast } = useToastContext();
const acceptTermsMutation = useAcceptTermsMutation({
onSuccess: () => {
onAccept();
@@ -35,6 +36,8 @@ const TermsAndConditionsModal = ({
},
});
const isLoading = acceptTermsMutation.isLoading;
const handleAccept = () => {
acceptTermsMutation.mutate();
};
@@ -51,36 +54,22 @@ const TermsAndConditionsModal = ({
onOpenChange(isOpen);
};
const content = useMemo(() => {
if (typeof modalContent === 'string') {
return modalContent;
}
if (Array.isArray(modalContent)) {
return modalContent.join('\n');
}
return '';
}, [modalContent]);
return (
<OGDialog open={open} onOpenChange={handleOpenChange}>
<DialogTemplate
<OGDialogTemplate
title={title ?? localize('com_ui_terms_and_conditions')}
className="w-11/12 max-w-3xl sm:w-3/4 md:w-1/2 lg:w-2/5"
showCloseButton={false}
showCancelButton={false}
main={
<section
// Motivation: This is a dialog, so its content should be focusable
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
tabIndex={0}
className="max-h-[60vh] overflow-y-auto p-4"
aria-label={localize('com_ui_terms_and_conditions')}
>
<div className="prose dark:prose-invert w-full max-w-none !text-text-primary">
{content !== '' ? (
<MarkdownLite content={content} />
<div className="prose dark:prose-invert w-full max-w-none text-text-primary">
{modalContent ? (
<MarkdownLite content={modalContent} />
) : (
<p>{localize('com_ui_no_terms_content')}</p>
)}
@@ -89,18 +78,12 @@ const TermsAndConditionsModal = ({
}
buttons={
<>
<button
onClick={handleDecline}
className="inline-flex h-10 items-center justify-center rounded-lg border border-border-heavy bg-surface-secondary px-4 py-2 text-sm text-text-primary hover:bg-surface-active"
>
<Button onClick={handleDecline} variant="destructive" disabled={isLoading}>
{localize('com_ui_decline')}
</button>
<button
onClick={handleAccept}
className="inline-flex h-10 items-center justify-center rounded-lg border border-border-heavy bg-surface-secondary px-4 py-2 text-sm text-text-primary hover:bg-green-500 hover:text-white focus:bg-green-500 focus:text-white dark:hover:bg-green-600 dark:focus:bg-green-600"
>
{localize('com_ui_accept')}
</button>
</Button>
<Button onClick={handleAccept} variant="submit" disabled={isLoading}>
{isLoading ? <Spinner /> : localize('com_ui_accept')}
</Button>
</>
}
/>

View File

@@ -14,11 +14,14 @@ import {
FileMapContext,
SetConvoProvider,
} from '~/Providers';
import TermsAndConditionsModal from '~/components/ui/TermsAndConditionsModal';
import TermsAndConditionsModal from '~/components/Chat/TermsAndConditionsModal';
import { useUserTermsQuery, useGetStartupConfig } from '~/data-provider';
import { Nav, MobileNav } from '~/components/Nav';
import { useHealthCheck } from '~/data-provider';
import { Banner } from '~/components/Banners';
import { getTermsMarkdown } from '~/utils';
import { useRecoilValue } from 'recoil';
import store from '~/store';
export default function Root() {
const [showTerms, setShowTerms] = useState(false);
@@ -37,6 +40,9 @@ export default function Root() {
const agentsMap = useAgentsMap({ isAuthenticated });
const fileMap = useFileMap({ isAuthenticated });
const lang = useRecoilValue(store.lang);
const modalContent = getTermsMarkdown(lang);
const { data: config } = useGetStartupConfig();
const { data: termsData } = useUserTermsQuery({
enabled: isAuthenticated && config?.interface?.termsOfService?.modalAcceptance === true,
@@ -86,7 +92,7 @@ export default function Root() {
onAccept={handleAcceptTerms}
onDecline={handleDeclineTerms}
title={config.interface.termsOfService.modalTitle}
modalContent={config.interface.termsOfService.modalContent}
modalContent={modalContent}
/>
)}
</AssistantsMapContext.Provider>

View File

@@ -15,6 +15,7 @@ export * from './languages';
export * from './endpoints';
export * from './localStorage';
export * from './promptGroups';
export * from './termsContent';
export { default as cn } from './cn';
export { default as logger } from './logger';
export { default as buildTree } from './buildTree';

View File

@@ -0,0 +1,45 @@
import terms_en from '../../../terms/terms_en.md?raw';
import terms_de from '../../../terms/terms_de.md?raw';
import terms_fr from '../../../terms/terms_fr.md?raw';
/**
* A mapping of language codes to their respective terms markdown content.
*
* You can add both base language codes (e.g. 'en') and full codes (e.g. 'pt-BR') if needed.
*
* @type {Record<string, string>}
*/
const markdownMap: Record<string, string> = {
en: terms_en,
de: terms_de,
fr: terms_fr,
// For example, to support Brazilian Portuguese, you could add:
// 'pt-BR': terms_ptBR,
};
/**
* Retrieves the terms markdown content for the specified language.
*
* The function first checks if an exact language code match exists in the markdown map.
* If not, it attempts to extract the base language (e.g., 'pt' from 'pt-BR') and checks again.
* If no match is found, it falls back to English.
*
* @param {string} lang - The language code, which may include a region (e.g., 'pt-BR', 'en-US').
* @returns {string} The markdown content corresponding to the language,
* or the English version if no matching language is found.
*/
export function getTermsMarkdown(lang: string): string {
// Check for exact language code match (e.g., 'pt-BR').
if (lang in markdownMap) {
return markdownMap[lang];
}
// Extract the base language (e.g., 'pt' from 'pt-BR') and check again.
const baseLang = lang.split('-')[0];
if (baseLang in markdownMap) {
return markdownMap[baseLang];
}
// Fall back to English if no match is found.
return markdownMap['en'];
}

View File

@@ -0,0 +1 @@
module.exports = 'MOCK_MARKDOWN_CONTENT';

View File

@@ -13,7 +13,7 @@ services:
- rag_api
restart: always
extra_hosts:
- "host.docker.internal:host-gateway"
- "host.docker.internal:host-gateway"
env_file:
- .env
environment:
@@ -30,7 +30,7 @@ services:
- ./images:/app/client/public/images
- ./uploads:/app/uploads
- ./logs:/app/api/logs
- ./terms:/app/terms
client:
image: nginx:1.27.0-alpine
container_name: LibreChat-NGINX

View File

@@ -27,6 +27,7 @@ services:
- ./images:/app/client/public/images
- ./uploads:/app/uploads
- ./logs:/app/api/logs
- ./terms:/app/terms
mongodb:
container_name: chat-mongodb
image: mongo

View File

@@ -27,42 +27,6 @@ interface:
openNewTab: true
modalAcceptance: true
modalTitle: "Terms of Service for LibreChat"
modalContent: |
# Terms and Conditions for LibreChat
*Effective Date: February 18, 2024*
Welcome to LibreChat, the informational website for the open-source AI chat platform, available at https://librechat.ai. These Terms of Service ("Terms") govern your use of our website and the services we offer. By accessing or using the Website, you agree to be bound by these Terms and our Privacy Policy, accessible at https://librechat.ai//privacy.
## 1. Ownership
Upon purchasing a package from LibreChat, you are granted the right to download and use the code for accessing an admin panel for LibreChat. While you own the downloaded code, you are expressly prohibited from reselling, redistributing, or otherwise transferring the code to third parties without explicit permission from LibreChat.
## 2. User Data
We collect personal data, such as your name, email address, and payment information, as described in our Privacy Policy. This information is collected to provide and improve our services, process transactions, and communicate with you.
## 3. Non-Personal Data Collection
The Website uses cookies to enhance user experience, analyze site usage, and facilitate certain functionalities. By using the Website, you consent to the use of cookies in accordance with our Privacy Policy.
## 4. Use of the Website
You agree to use the Website only for lawful purposes and in a manner that does not infringe the rights of, restrict, or inhibit anyone else's use and enjoyment of the Website. Prohibited behavior includes harassing or causing distress or inconvenience to any person, transmitting obscene or offensive content, or disrupting the normal flow of dialogue within the Website.
## 5. Governing Law
These Terms shall be governed by and construed in accordance with the laws of the United States, without giving effect to any principles of conflicts of law.
## 6. Changes to the Terms
We reserve the right to modify these Terms at any time. We will notify users of any changes by email. Your continued use of the Website after such changes have been notified will constitute your consent to such changes.
## 7. Contact Information
If you have any questions about these Terms, please contact us at contact@librechat.ai.
By using the Website, you acknowledge that you have read these Terms of Service and agree to be bound by them.
endpointsMenu: true
modelSelect: true

View File

@@ -477,7 +477,6 @@ const termsOfServiceSchema = z.object({
openNewTab: z.boolean().optional(),
modalAcceptance: z.boolean().optional(),
modalTitle: z.string().optional(),
modalContent: z.string().or(z.array(z.string())).optional(),
});
export type TTermsOfService = z.infer<typeof termsOfServiceSchema>;

60
terms/terms_de.md Normal file
View File

@@ -0,0 +1,60 @@
# Allgemeine Geschäftsbedingungen für [Ihr Unternehmen/Produktname]
*Gültigkeitsdatum: [Datum einfügen]*
Willkommen bei [Ihre Webseite], erreichbar unter [URL einfügen]. Diese Allgemeinen Geschäftsbedingungen („AGB“) regeln Ihre Nutzung unserer Website und Dienstleistungen. Durch den Zugriff auf oder die Nutzung unserer Website stimmen Sie diesen Bedingungen und unserer Datenschutzerklärung zu, die unter [URL zur Datenschutzerklärung einfügen] verfügbar ist.
## Inhaltsverzeichnis
1. **Akzeptanz der Bedingungen**
- Zustimmung durch Nutzung
2. **Eigentum und Lizenz**
- Gewährte Rechte
- Einschränkungen bei Weitergabe oder Weiterverkauf
3. **Benutzerkonten** (falls zutreffend)
- Erstellung und Sicherheit des Kontos
- Verantwortlichkeiten des Benutzers
4. **Benutzerdaten**
- Erhebung und Nutzung personenbezogener Daten
- Hinweis auf Datenschutzerklärung
5. **Cookies und nicht-personenbezogene Daten**
- Nutzung und Zustimmung
6. **Richtlinien zur akzeptablen Nutzung**
- Zulässige und verbotene Aktivitäten
- Konsequenzen bei Verstößen
7. **Links und Dienste Dritter**
- Haftungsausschluss für Inhalte Dritter
8. **Rechte am geistigen Eigentum**
- Eigentum am Inhalt
- Einschränkungen der Nutzung geistigen Eigentums
9. **Gewährleistungsausschluss**
- Haftungsbeschränkungen
10. **Freistellung**
- Verpflichtungen des Nutzers zur Freistellung des Unternehmens
11. **Haftungsbeschränkung**
- Begrenzung der Haftung und Ausschlüsse
12. **Kündigung**
- Gründe für eine Kündigung
- Auswirkungen einer Kündigung
13. **Geltendes Recht und Gerichtsstand**
- Anwendbares Recht und Gerichtsstand
14. **Änderungen dieser Bedingungen**
- Benachrichtigung und Zustimmung zu Änderungen
15. **Kontaktinformationen**
- Kontaktmöglichkeiten bei Fragen
Durch den Zugriff auf und die Nutzung von [Ihre Webseite/Dienstleistung] erkennen Sie an, dass Sie diese Allgemeinen Geschäftsbedingungen gelesen und verstanden haben und ihnen zustimmen.

60
terms/terms_en.md Normal file
View File

@@ -0,0 +1,60 @@
# Terms and Conditions for [Your Company/Product Name]
*Effective Date: [Insert Effective Date]*
Welcome to [Your Website], accessible at [Insert URL]. These Terms and Conditions ("Terms") govern your use of our website and services. By accessing or using our Website, you agree to comply with these Terms and our Privacy Policy, accessible at [Insert URL to Privacy Policy].
## Table of Contents
1. **Acceptance of Terms**
- Agreement to terms upon use
2. **Ownership and License**
- Rights granted
- Restrictions on redistribution or resale
3. **User Accounts** (if applicable)
- Account creation and security
- Responsibilities of the user
4. **User Data**
- Collection and use of personal data
- Reference to Privacy Policy
5. **Cookies and Non-Personal Data**
- Usage and consent
6. **Acceptable Use Policy**
- Permitted and prohibited activities
- Consequences of violations
7. **Third-Party Links and Services**
- Disclaimer for third-party content
8. **Intellectual Property Rights**
- Ownership of content
- Restrictions on use of intellectual property
9. **Disclaimer of Warranties**
- Limitations on liability
10. **Indemnification**
- User obligations to indemnify the company
11. **Limitation of Liability**
- Cap on liability and exclusions
12. **Termination**
- Grounds for termination
- Effects of termination
13. **Governing Law and Jurisdiction**
- Applicable laws and legal jurisdiction
14. **Changes to These Terms**
- Notification and acceptance of changes
15. **Contact Information**
- How users can reach you with questions
By accessing and using [Your Website/Service], you acknowledge that you have read, understood, and agree to be bound by these Terms and Conditions.

60
terms/terms_fr.md Normal file
View File

@@ -0,0 +1,60 @@
# Conditions Générales pour [Votre Entreprise/Nom du Produit]
*Date d'entrée en vigueur : [Insérer la date]*
Bienvenue sur [Votre site web], accessible à l'adresse [Insérer URL]. Ces Conditions Générales (« CG ») régissent votre utilisation de notre site web et de nos services. En accédant ou en utilisant notre site web, vous acceptez ces conditions ainsi que notre Politique de confidentialité disponible à l'adresse [Insérer URL vers la Politique de confidentialité].
## Table des matières
1. **Acceptation des conditions**
- Accord des conditions par utilisation
2. **Propriété et Licence**
- Droits accordés
- Restrictions sur la redistribution ou la revente
3. **Comptes utilisateur** (le cas échéant)
- Création et sécurité du compte
- Responsabilités de l'utilisateur
4. **Données Utilisateur**
- Collecte et utilisation des données personnelles
- Référence à la Politique de confidentialité
5. **Cookies et données non personnelles**
- Utilisation et consentement
6. **Politique d'utilisation acceptable**
- Activités autorisées et interdites
- Conséquences en cas de violations
7. **Liens et services tiers**
- Exclusion de responsabilité pour les contenus tiers
8. **Droits de propriété intellectuelle**
- Propriété du contenu
- Restrictions sur l'utilisation de la propriété intellectuelle
9. **Exclusion de garanties**
- Limitations de responsabilité
10. **Indemnisation**
- Obligations de l'utilisateur à indemniser l'entreprise
11. **Limitation de responsabilité**
- Plafond de responsabilité et exclusions
12. **Résiliation**
- Motifs de résiliation
- Effets de la résiliation
13. **Loi applicable et juridiction compétente**
- Lois applicables et juridiction
14. **Modifications des présentes conditions**
- Notification et acceptation des modifications
15. **Informations de contact**
- Comment nous contacter en cas de questions
En accédant et en utilisant [Votre site web/service], vous reconnaissez avoir lu, compris et accepté d'être lié par ces Conditions Générales.