mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-12-01 09:33:14 +00:00
feat(i18n): settings static content
This commit is contained in:
@@ -9,13 +9,14 @@ import {
|
||||
import { selectSourceDocs } from '../preferences/preferenceSlice';
|
||||
import Exit from '../assets/exit.svg';
|
||||
import Trash from '../assets/trash.svg';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
|
||||
const embeddingsName =
|
||||
import.meta.env.VITE_EMBEDDINGS_NAME ||
|
||||
'huggingface_sentence-transformers/all-mpnet-base-v2';
|
||||
|
||||
const APIKeys: React.FC = () => {
|
||||
const { t } = useTranslation();
|
||||
const [isCreateModalOpen, setCreateModal] = React.useState(false);
|
||||
const [isSaveKeyModalOpen, setSaveKeyModal] = React.useState(false);
|
||||
const [newKey, setNewKey] = React.useState('');
|
||||
@@ -97,7 +98,7 @@ const APIKeys: React.FC = () => {
|
||||
onClick={() => setCreateModal(true)}
|
||||
className="rounded-full bg-purple-30 px-4 py-3 text-white hover:bg-[#6F3FD1]"
|
||||
>
|
||||
Create new
|
||||
{t('settings.apiKeys.createNew')}
|
||||
</button>
|
||||
</div>
|
||||
{isCreateModalOpen && (
|
||||
@@ -117,11 +118,15 @@ const APIKeys: React.FC = () => {
|
||||
<table className="block w-max table-auto content-center justify-center rounded-xl border text-center dark:border-chinese-silver dark:text-bright-gray">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border-r p-4 md:w-[244px]">Name</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
Source document
|
||||
<th className="border-r p-4 md:w-[244px]">
|
||||
{t('settings.apiKeys.name')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
{t('settings.apiKeys.sourceDoc')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
{t('settings.apiKeys.key')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">API Key</th>
|
||||
<th className="px-4 py-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { DocumentsProps } from '../models/misc';
|
||||
import Trash from '../assets/trash.svg';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const Documents: React.FC<DocumentsProps> = ({
|
||||
documents,
|
||||
handleDeleteDocument,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="mt-8">
|
||||
<div className="flex flex-col">
|
||||
@@ -12,10 +14,18 @@ const Documents: React.FC<DocumentsProps> = ({
|
||||
<table className="block w-max table-auto content-center justify-center rounded-xl border text-center dark:border-chinese-silver dark:text-bright-gray">
|
||||
<thead>
|
||||
<tr>
|
||||
<th className="border-r p-4 md:w-[244px]">Document Name</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">Vector Date</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">Token usage</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">Type</th>
|
||||
<th className="border-r p-4 md:w-[244px]">
|
||||
{t('settings.documents.name')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
{t('settings.documents.date')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
{t('settings.documents.tokenUsage')}
|
||||
</th>
|
||||
<th className="w-[244px] border-r px-4 py-2">
|
||||
{t('settings.documents.type')}
|
||||
</th>
|
||||
<th className="px-4 py-2"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
import Prompts from './Prompts';
|
||||
import { useDarkTheme } from '../hooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import Dropdown from '../components/Dropdown';
|
||||
import {
|
||||
selectPrompt,
|
||||
@@ -14,8 +15,22 @@ import {
|
||||
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
|
||||
|
||||
const General: React.FC = () => {
|
||||
const themes = ['Light', 'Dark'];
|
||||
const languages = ['English'];
|
||||
const {
|
||||
t,
|
||||
i18n: { changeLanguage, language },
|
||||
} = useTranslation();
|
||||
const themes = [t('settings.general.light'), t('settings.general.dark')];
|
||||
|
||||
const languageOptions = [
|
||||
{
|
||||
label: 'English',
|
||||
value: 'en',
|
||||
},
|
||||
{
|
||||
label: 'Spanish',
|
||||
value: 'es',
|
||||
},
|
||||
];
|
||||
const chunks = ['0', '2', '4', '6', '8', '10'];
|
||||
const [prompts, setPrompts] = React.useState<
|
||||
{ name: string; id: string; type: string }[]
|
||||
@@ -23,12 +38,18 @@ const General: React.FC = () => {
|
||||
const selectedChunks = useSelector(selectChunks);
|
||||
const [isDarkTheme, toggleTheme] = useDarkTheme();
|
||||
const [selectedTheme, setSelectedTheme] = React.useState(
|
||||
isDarkTheme ? 'Dark' : 'Light',
|
||||
isDarkTheme ? t('settings.general.dark') : t('settings.general.light'),
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
const [selectedLanguage, setSelectedLanguage] = React.useState(languages[0]);
|
||||
const locale = localStorage.getItem('docsgpt-locale');
|
||||
const [selectedLanguage, setSelectedLanguage] = React.useState(
|
||||
locale ? languageOptions.find((option) => option.value === locale) : 'en',
|
||||
);
|
||||
const selectedPrompt = useSelector(selectPrompt);
|
||||
|
||||
useEffect(() => {
|
||||
console.log(selectedLanguage);
|
||||
console.log(language);
|
||||
}, [selectedLanguage]);
|
||||
React.useEffect(() => {
|
||||
const fetchPrompts = async () => {
|
||||
try {
|
||||
@@ -48,7 +69,9 @@ const General: React.FC = () => {
|
||||
return (
|
||||
<div className="mt-[59px]">
|
||||
<div className="mb-5">
|
||||
<p className="font-bold text-jet dark:text-bright-gray">Select Theme</p>
|
||||
<p className="font-bold text-jet dark:text-bright-gray">
|
||||
{t('settings.general.selectTheme')}
|
||||
</p>
|
||||
<Dropdown
|
||||
options={themes}
|
||||
selectedValue={selectedTheme}
|
||||
@@ -63,12 +86,16 @@ const General: React.FC = () => {
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<p className="font-bold text-jet dark:text-bright-gray">
|
||||
Select Language
|
||||
{t('settings.general.selectLanguage')}
|
||||
</p>
|
||||
<Dropdown
|
||||
options={languages}
|
||||
selectedValue={selectedLanguage}
|
||||
onSelect={setSelectedLanguage}
|
||||
options={languageOptions}
|
||||
selectedValue={selectedLanguage ?? languageOptions[0]}
|
||||
onSelect={(selectedOption: { label: string; value: string }) => {
|
||||
setSelectedLanguage(selectedOption);
|
||||
changeLanguage(selectedOption.value);
|
||||
localStorage.setItem('docsgpt-locale', selectedOption.value);
|
||||
}}
|
||||
size="w-56"
|
||||
rounded="3xl"
|
||||
border="border"
|
||||
@@ -76,7 +103,7 @@ const General: React.FC = () => {
|
||||
</div>
|
||||
<div className="mb-5">
|
||||
<p className="font-bold text-jet dark:text-bright-gray">
|
||||
Chunks processed per query
|
||||
{t('settings.general.chunks')}
|
||||
</p>
|
||||
<Dropdown
|
||||
options={chunks}
|
||||
@@ -100,13 +127,15 @@ const General: React.FC = () => {
|
||||
</div>
|
||||
<div className="w-56">
|
||||
<p className="font-bold text-jet dark:text-bright-gray">
|
||||
Delete all conversations
|
||||
{t('settings.general.deleteAllLabel')}
|
||||
</p>
|
||||
<button
|
||||
className="mt-2 flex w-full cursor-pointer items-center justify-between rounded-3xl border border-solid border-red-500 px-5 py-3 text-red-500 hover:bg-red-500 hover:text-white"
|
||||
onClick={() => dispatch(setModalStateDeleteConv('ACTIVE'))}
|
||||
>
|
||||
<span className="overflow-hidden text-ellipsis ">Delete all</span>
|
||||
<span className="overflow-hidden text-ellipsis ">
|
||||
{t('settings.general.deleteAllBtn')}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,8 @@ import React from 'react';
|
||||
import { PromptProps, ActiveState } from '../models/misc';
|
||||
import Dropdown from '../components/Dropdown';
|
||||
import PromptsModal from '../preferences/PromptsModal';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
|
||||
|
||||
const Prompts: React.FC<PromptProps> = ({
|
||||
prompts,
|
||||
selectedPrompt,
|
||||
@@ -34,7 +33,10 @@ const Prompts: React.FC<PromptProps> = ({
|
||||
});
|
||||
const [modalType, setModalType] = React.useState<'ADD' | 'EDIT'>('ADD');
|
||||
const [modalState, setModalState] = React.useState<ActiveState>('INACTIVE');
|
||||
|
||||
const {
|
||||
t,
|
||||
i18n: { changeLanguage, language },
|
||||
} = useTranslation();
|
||||
const handleAddPrompt = async () => {
|
||||
try {
|
||||
const response = await fetch(`${apiHost}/api/create_prompt`, {
|
||||
@@ -158,7 +160,9 @@ const Prompts: React.FC<PromptProps> = ({
|
||||
<div>
|
||||
<div className="flex flex-row items-center gap-8">
|
||||
<div>
|
||||
<p className="font-semibold dark:text-bright-gray">Active Prompt</p>
|
||||
<p className="font-semibold dark:text-bright-gray">
|
||||
{t('settings.general.prompt')}
|
||||
</p>
|
||||
<Dropdown
|
||||
options={prompts}
|
||||
selectedValue={selectedPrompt.name}
|
||||
@@ -193,7 +197,7 @@ const Prompts: React.FC<PromptProps> = ({
|
||||
setModalState('ACTIVE');
|
||||
}}
|
||||
>
|
||||
Add new
|
||||
{t('settings.general.addNew')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,12 +11,18 @@ import {
|
||||
import { Doc } from '../preferences/preferenceApi';
|
||||
import ArrowLeft from '../assets/arrow-left.svg';
|
||||
import ArrowRight from '../assets/arrow-right.svg';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
const dispatch = useDispatch();
|
||||
const tabs = ['General', 'Documents', 'API Keys'];
|
||||
const { t } = useTranslation();
|
||||
const tabs = [
|
||||
t('settings.general.label'),
|
||||
t('settings.documents.label'),
|
||||
t('settings.apiKeys.label'),
|
||||
];
|
||||
const [activeTab, setActiveTab] = React.useState('General');
|
||||
const [widgetScreenshot, setWidgetScreenshot] = React.useState<File | null>(
|
||||
null,
|
||||
@@ -45,7 +51,7 @@ const Settings: React.FC = () => {
|
||||
return (
|
||||
<div className="wa p-4 pt-20 md:p-12">
|
||||
<p className="text-2xl font-bold text-eerie-black dark:text-bright-gray">
|
||||
Settings
|
||||
{t('settings.label')}
|
||||
</p>
|
||||
<div className="mt-6 flex flex-row items-center space-x-4 overflow-x-auto md:space-x-8 ">
|
||||
<div className="md:hidden">
|
||||
@@ -100,9 +106,9 @@ const Settings: React.FC = () => {
|
||||
|
||||
function renderActiveTab() {
|
||||
switch (activeTab) {
|
||||
case 'General':
|
||||
case t('settings.general.label'):
|
||||
return <General />;
|
||||
case 'Documents':
|
||||
case t('settings.documents.label'):
|
||||
return (
|
||||
<Documents
|
||||
documents={documents}
|
||||
@@ -116,7 +122,7 @@ const Settings: React.FC = () => {
|
||||
onWidgetScreenshotChange={updateWidgetScreenshot} // Add this line
|
||||
/>
|
||||
);
|
||||
case 'API Keys':
|
||||
case t('settings.apiKeys.label'):
|
||||
return <APIKeys />;
|
||||
default:
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user