From 716b9351770fa5c1316b9797e9d9b0912357d08b Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 23 Jan 2025 01:12:14 +0530 Subject: [PATCH 1/7] (feat:documents) formatting date --- frontend/src/utils/dateTimeUtils.ts | 49 ++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/frontend/src/utils/dateTimeUtils.ts b/frontend/src/utils/dateTimeUtils.ts index 7f89007c..7815f123 100644 --- a/frontend/src/utils/dateTimeUtils.ts +++ b/frontend/src/utils/dateTimeUtils.ts @@ -1,20 +1,39 @@ export function formatDate(dateString: string): string { - if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(dateString)) { - const dateTime = new Date(dateString); - return dateTime.toLocaleTimeString([], { - hour: '2-digit', - minute: '2-digit', - }); - } else if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}$/.test(dateString)) { - const dateTime = new Date(dateString); - return dateTime.toLocaleTimeString([], { - hour: '2-digit', - minute: '2-digit', - }); - } else if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) { + try { const date = new Date(dateString); - return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }); - } else { + + if (isNaN(date.getTime())) { + throw new Error('Invalid date'); + } + + const userLocale = navigator.language || 'en-US'; + const userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; + + const weekday = date.toLocaleDateString(userLocale, { + weekday: 'short', + timeZone: userTimezone, + }); + + const monthDay = date.toLocaleDateString(userLocale, { + day: '2-digit', + month: 'short', + year: 'numeric', + timeZone: userTimezone, + }); + + const time = date + .toLocaleTimeString(userLocale, { + hour: 'numeric', + minute: '2-digit', + second: '2-digit', + hour12: true, + timeZone: userTimezone, + }) + .replace(/am|pm/i, (match) => match.toUpperCase()); + + return `${weekday}, ${monthDay} ${time}`; + } catch (error) { + console.error('Error formatting date:', error); return dateString; } } From 34eb25b0ba3f5f9a0080b1a53ac9b75bee0096eb Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 23 Jan 2025 01:15:01 +0530 Subject: [PATCH 2/7] (feat:documents) design perfection --- frontend/src/locale/en.json | 1 + frontend/src/locale/es.json | 1 + frontend/src/locale/ru.json | 1 + frontend/src/locale/zh-TW.json | 1 + frontend/src/locale/zh.json | 5 +- frontend/src/settings/Documents.tsx | 353 +++++++++++++--------------- 6 files changed, 174 insertions(+), 188 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 8502cf36..8a8d645b 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -53,6 +53,7 @@ "default": "Default" }, "documents": { + "title": "This table contains all the documents that are available to you and those you have uploaded", "label": "Documents", "name": "Document Name", "date": "Vector Date", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index c5b0fa17..41b8fd96 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -53,6 +53,7 @@ "default": "Predeterminado" }, "documents": { + "title": "Esta tabla contiene todos los documentos que están disponibles para ti y los que has subido", "label": "Documentos", "name": "Nombre del Documento", "date": "Fecha de Vector", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index 69897452..cd9f2f44 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -53,6 +53,7 @@ "default": "По умолчанию" }, "documents": { + "title": "Эта таблица содержит все документы, которые доступны вам и те, которые вы загрузили", "label": "Документы", "name": "Название документа", "date": "Дата вектора", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index 3699afde..eb7ab9ef 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -53,6 +53,7 @@ "default": "預設" }, "documents": { + "title": "此表格包含所有可供您使用的文件以及您上傳的文件", "label": "文件", "name": "文件名稱", "date": "向量日期", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 9936350d..b73a8c54 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -53,7 +53,8 @@ "default": "默认" }, "documents": { - "label": "文件", + "title": "此表格包含所有可供您使用的文档以及您上传的文档", + "label": "文档", "name": "文件名称", "date": "向量日期", "type": "类型", @@ -111,7 +112,7 @@ "searchPlaceholder": "搜索...", "addTool": "添加工具", "noToolsFound": "未找到工具", - "selectToolSetup": "选择要设置的工具" , + "selectToolSetup": "选择要设置的工具", "settingsIconAlt": "设置图标", "configureToolAria": "配置 {toolName}", "toggleToolAria": "切换 {toolName}" diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index ee04d121..ee52b377 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -16,6 +16,7 @@ import { getDocs, getDocsWithPagination } from '../preferences/preferenceApi'; import { setSourceDocs } from '../preferences/preferenceSlice'; import { setPaginatedDocuments } from '../preferences/preferenceSlice'; import { truncate } from '../utils/stringUtils'; +import { formatDate } from '../utils/dateTimeUtils'; // Utility function to format numbers const formatTokens = (tokens: number): string => { @@ -85,6 +86,7 @@ const Documents: React.FC = ({ setSortField(newSortField); setSortOrder(newSortOrder); } + setLoading(true); getDocsWithPagination( newSortField, @@ -110,7 +112,6 @@ const Documents: React.FC = ({ userService .manageSync({ source_id: doc.id, sync_frequency }) .then(() => { - // First, fetch the updated source docs return getDocs(); }) .then((data) => { @@ -136,206 +137,186 @@ const Documents: React.FC = ({ useEffect(() => { if (modalState === 'INACTIVE') { - refreshDocs(sortField, currentPage, rowsPerPage); + refreshDocs(undefined, currentPage, rowsPerPage); } }, [modalState]); useEffect(() => { - // undefine to prevent reset the sort order refreshDocs(undefined, 1, rowsPerPage); }, [searchTerm]); return (
-
-
-
- - { - setSearchTerm(e.target.value); - setCurrentPage(1); - }} - /> -
- -
- {loading ? ( - - ) : ( -
-
-
- - - - - - - {/*} - - */} - - - - - {!currentDocuments?.length && ( - - - - )} - {Array.isArray(currentDocuments) && - currentDocuments.map((document, index) => ( - - - - - {/*} - - */} - - - ))} - -
- {t('settings.documents.name')} - -
- {t('settings.documents.date')} - refreshDocs('date')} - src={caretSort} - alt="sort" - /> -
-
-
- {t('settings.documents.tokenUsage')} - refreshDocs('tokens')} - src={caretSort} - alt="sort" - /> -
-
-
- {t('settings.documents.type')} -
-
- {t('settings.documents.actions')} -
- {t('settings.documents.noData')} -
- {truncate(document.name, 50)} - - {document.date} - - {document.tokens - ? formatTokens(+document.tokens) - : ''} - - {document.type === 'remote' - ? 'Pre-loaded' - : 'Private'} - -
- {document.type !== 'remote' && ( - {t('convTile.delete')} { - event.stopPropagation(); - handleDeleteDocument(index, document); - }} - /> - )} - {document.syncFrequency && ( -
- { - handleManageSync(document, value); - }} - defaultValue={document.syncFrequency} - icon={SyncIcon} - /> -
- )} -
-
-
-
-
- )} +
+

+ {t('settings.documents.title')} +

+
+
+
+ + { + setSearchTerm(e.target.value); + setCurrentPage(1); + }} + /> +
+
- {/* outside scrollable area */} - { - setCurrentPage(page); - refreshDocs(undefined, page, rowsPerPage); - }} - onRowsPerPageChange={(rows) => { - setRowsPerPage(rows); - setCurrentPage(1); - refreshDocs(undefined, 1, rows); - }} - /> - {/* Conditionally render the Upload modal based on modalState */} - {modalState === 'ACTIVE' && ( -
-
- {/* Your Upload component */} - setModalState('INACTIVE')} - /> -
+ {loading ? ( + + ) : ( +
+ + + + + + + + + + + {!currentDocuments?.length && ( + + + + )} + {Array.isArray(currentDocuments) && + currentDocuments.map((document, index) => ( + + + + + + + ))} + +
+ {t('settings.documents.name')} + +
+ {t('settings.documents.date')} + refreshDocs('date')} + src={caretSort} + alt="sort" + /> +
+
+
+ + {t('settings.documents.tokenUsage')} + + + {t('settings.documents.tokenUsage')} + + refreshDocs('tokens')} + src={caretSort} + alt="sort" + /> +
+
+ + {t('settings.documents.actions')} + +
+ {t('settings.documents.noData')} +
+
+ {truncate(document.name, 50)} +
+
+ {document.date ? formatDate(document.date) : ''} + + {document.tokens ? formatTokens(+document.tokens) : ''} + +
+ {/* For non-remote documents, adding empty space holder */} + {!document.syncFrequency && ( +
+ )} + {document.syncFrequency && ( + { + handleManageSync(document, value); + }} + defaultValue={document.syncFrequency} + icon={SyncIcon} + /> + )} + +
+
)}
+ { + setCurrentPage(page); + refreshDocs(undefined, page, rowsPerPage); + }} + onRowsPerPageChange={(rows) => { + setRowsPerPage(rows); + setCurrentPage(1); + refreshDocs(undefined, 1, rows); + }} + /> + {modalState === 'ACTIVE' && ( + setModalState('INACTIVE')} + /> + )}
); }; From 9d475001ee0ae001bf3bf4c9cfd5e76e5370b1b0 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 23 Jan 2025 02:50:24 +0530 Subject: [PATCH 3/7] (feat:chatbots) confirm before deletion --- frontend/src/locale/en.json | 3 ++- frontend/src/locale/es.json | 3 ++- frontend/src/locale/jp.json | 5 +++-- frontend/src/locale/ru.json | 3 ++- frontend/src/locale/zh-TW.json | 5 +++-- frontend/src/locale/zh.json | 3 ++- frontend/src/settings/APIKeys.tsx | 25 ++++++++++++++++++++++++- 7 files changed, 38 insertions(+), 9 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 8a8d645b..2f6d2617 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -79,7 +79,8 @@ "key": "API Key", "sourceDoc": "Source Document", "createNew": "Create New", - "noData": "No existing Chatbots" + "noData": "No existing Chatbots", + "deleteConfirmation": "Are you sure you want to delete the API key '{{name}}'?" }, "analytics": { "label": "Analytics", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 41b8fd96..6437dead 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -79,7 +79,8 @@ "key": "Clave de API", "sourceDoc": "Documento Fuente", "createNew": "Crear Nuevo", - "noData": "No hay chatbots existentes" + "noData": "No hay chatbots existentes", + "deleteConfirmation": "¿Estás seguro de que quieres eliminar la clave API '{{name}}'?" }, "analytics": { "label": "Analítica", diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 0098807a..199f83e8 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -73,12 +73,13 @@ "actions": "アクション" }, "apiKeys": { - "label": "APIキー", + "label": "チャットボット", "name": "名前", "key": "APIキー", "sourceDoc": "ソースドキュメント", "createNew": "新規作成", - "noData": "既存のAPIキーがありません" + "noData": "既存のチャットボットはありません", + "deleteConfirmation": "APIキー '{{name}}' を削除してもよろしいですか?" }, "analytics": { "label": "分析", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index cd9f2f44..3621aafc 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -79,7 +79,8 @@ "key": "API ключ", "sourceDoc": "Источник документа", "createNew": "Создать новый", - "noData": "Нет существующих API ключей" + "noData": "Нет существующих чатботов", + "deleteConfirmation": "Вы уверены, что хотите удалить API ключ '{{name}}'?" }, "analytics": { "label": "Аналитика", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index eb7ab9ef..8dbd550d 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -78,8 +78,9 @@ "name": "名稱", "key": "API 金鑰", "sourceDoc": "來源文件", - "createNew": "新增", - "noData": "沒有現有的聊天機器人" + "createNew": "建立新的", + "noData": "沒有現有的聊天機器人", + "deleteConfirmation": "您確定要刪除 API 金鑰 '{{name}}' 嗎?" }, "analytics": { "label": "分析", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index b73a8c54..0e53a257 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -79,7 +79,8 @@ "key": "API 密钥", "sourceDoc": "源文档", "createNew": "创建新的", - "noData": "没有现有的聊天机器人" + "noData": "没有现有的聊天机器人", + "deleteConfirmation": "您确定要删除 API 密钥 '{{name}}' 吗?" }, "analytics": { "label": "分析", diff --git a/frontend/src/settings/APIKeys.tsx b/frontend/src/settings/APIKeys.tsx index 038e4bbb..44242cda 100644 --- a/frontend/src/settings/APIKeys.tsx +++ b/frontend/src/settings/APIKeys.tsx @@ -5,6 +5,7 @@ import userService from '../api/services/userService'; import Trash from '../assets/trash.svg'; import CreateAPIKeyModal from '../modals/CreateAPIKeyModal'; import SaveAPIKeyModal from '../modals/SaveAPIKeyModal'; +import ConfirmationModal from '../modals/ConfirmationModal'; import { APIKeyData } from './types'; import SkeletonLoader from '../components/SkeletonLoader'; @@ -15,6 +16,10 @@ export default function APIKeys() { const [newKey, setNewKey] = React.useState(''); const [apiKeys, setApiKeys] = React.useState([]); const [loading, setLoading] = useState(true); + const [keyToDelete, setKeyToDelete] = useState<{ + id: string; + name: string; + } | null>(null); const handleFetchKeys = async () => { setLoading(true); @@ -44,6 +49,7 @@ export default function APIKeys() { .then((data) => { data.success === true && setApiKeys((previous) => previous.filter((elem) => elem.id !== id)); + setKeyToDelete(null); }) .catch((error) => { console.error(error); @@ -104,6 +110,18 @@ export default function APIKeys() { close={() => setSaveKeyModal(false)} /> )} + {keyToDelete && ( + setKeyToDelete(null)} + submitLabel={t('modals.deleteConv.delete')} + handleSubmit={() => handleDeleteKey(keyToDelete.id)} + handleCancel={() => setKeyToDelete(null)} + /> + )}
{loading ? ( @@ -157,7 +175,12 @@ export default function APIKeys() { alt={`Delete ${element.name}`} className="h-4 w-4 cursor-pointer hover:opacity-50" id={`img-${index}`} - onClick={() => handleDeleteKey(element.id)} + onClick={() => + setKeyToDelete({ + id: element.id, + name: element.name, + }) + } /> From fe4657b122ceea7658851b716cab6c1d06bd7320 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Fri, 24 Jan 2025 02:46:31 +0530 Subject: [PATCH 4/7] (fix:analytics) updated to show feedback --- application/api/user/routes.py | 175 ++++++++++----------------------- 1 file changed, 50 insertions(+), 125 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 06b60a25..10b141c0 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -1478,90 +1478,17 @@ class GetFeedbackAnalytics(Resource): ) except Exception as err: return make_response(jsonify({"success": False, "error": str(err)}), 400) + end_date = datetime.datetime.now(datetime.timezone.utc) if filter_option == "last_hour": start_date = end_date - datetime.timedelta(hours=1) group_format = "%Y-%m-%d %H:%M:00" - group_stage_1 = { - "$group": { - "_id": { - "minute": { - "$dateToString": { - "format": group_format, - "date": "$timestamp", - } - }, - "feedback": "$feedback", - }, - "count": {"$sum": 1}, - } - } - group_stage_2 = { - "$group": { - "_id": "$_id.minute", - "likes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "LIKE"]}, - "$count", - 0, - ] - } - }, - "dislikes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "DISLIKE"]}, - "$count", - 0, - ] - } - }, - } - } - + date_field = {"$dateToString": {"format": group_format, "date": "$date"}} elif filter_option == "last_24_hour": start_date = end_date - datetime.timedelta(hours=24) group_format = "%Y-%m-%d %H:00" - group_stage_1 = { - "$group": { - "_id": { - "hour": { - "$dateToString": { - "format": group_format, - "date": "$timestamp", - } - }, - "feedback": "$feedback", - }, - "count": {"$sum": 1}, - } - } - group_stage_2 = { - "$group": { - "_id": "$_id.hour", - "likes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "LIKE"]}, - "$count", - 0, - ] - } - }, - "dislikes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "DISLIKE"]}, - "$count", - 0, - ] - } - }, - } - } - + date_field = {"$dateToString": {"format": group_format, "date": "$date"}} else: if filter_option in ["last_7_days", "last_15_days", "last_30_days"]: filter_days = ( @@ -1579,61 +1506,59 @@ class GetFeedbackAnalytics(Resource): hour=23, minute=59, second=59, microsecond=999999 ) group_format = "%Y-%m-%d" - group_stage_1 = { - "$group": { - "_id": { - "day": { - "$dateToString": { - "format": group_format, - "date": "$timestamp", - } - }, - "feedback": "$feedback", - }, - "count": {"$sum": 1}, - } - } - group_stage_2 = { - "$group": { - "_id": "$_id.day", - "likes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "LIKE"]}, - "$count", - 0, - ] - } - }, - "dislikes": { - "$sum": { - "$cond": [ - {"$eq": ["$_id.feedback", "DISLIKE"]}, - "$count", - 0, - ] - } - }, - } - } + date_field = {"$dateToString": {"format": group_format, "date": "$date"}} try: match_stage = { "$match": { - "timestamp": {"$gte": start_date, "$lte": end_date}, + "date": {"$gte": start_date, "$lte": end_date}, + "queries": {"$exists": True, "$ne": []}, } } if api_key: match_stage["$match"]["api_key"] = api_key - feedback_data = feedback_collection.aggregate( - [ - match_stage, - group_stage_1, - group_stage_2, - {"$sort": {"_id": 1}}, - ] - ) + # Unwind the queries array to process each query separately + pipeline = [ + match_stage, + {"$unwind": "$queries"}, + {"$match": {"queries.feedback": {"$exists": True}}}, + { + "$group": { + "_id": { + "time": date_field, + "feedback": "$queries.feedback" + }, + "count": {"$sum": 1} + } + }, + { + "$group": { + "_id": "$_id.time", + "positive": { + "$sum": { + "$cond": [ + {"$eq": ["$_id.feedback", "LIKE"]}, + "$count", + 0 + ] + } + }, + "negative": { + "$sum": { + "$cond": [ + {"$eq": ["$_id.feedback", "DISLIKE"]}, + "$count", + 0 + ] + } + } + } + }, + {"$sort": {"_id": 1}} + ] + + feedback_data = conversations_collection.aggregate(pipeline) if filter_option == "last_hour": intervals = generate_minute_range(start_date, end_date) @@ -1648,8 +1573,8 @@ class GetFeedbackAnalytics(Resource): for entry in feedback_data: daily_feedback[entry["_id"]] = { - "positive": entry["likes"], - "negative": entry["dislikes"], + "positive": entry["positive"], + "negative": entry["negative"] } except Exception as err: @@ -2105,4 +2030,4 @@ class DeleteTool(Resource): except Exception as err: return {"success": False, "error": str(err)}, 400 - return {"success": True}, 200 \ No newline at end of file + return {"success": True}, 200 From 16608370a6c03e9beac666eafb8791fae9a4c0f9 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Mon, 27 Jan 2025 03:01:39 +0530 Subject: [PATCH 5/7] (feat:settings)docs table design perfection --- frontend/src/settings/Documents.tsx | 242 ++++++++++++++-------------- 1 file changed, 124 insertions(+), 118 deletions(-) diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index ee52b377..e33a5214 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -15,7 +15,6 @@ import { Doc, DocumentsProps, ActiveState } from '../models/misc'; // Ensure Act import { getDocs, getDocsWithPagination } from '../preferences/preferenceApi'; import { setSourceDocs } from '../preferences/preferenceSlice'; import { setPaginatedDocuments } from '../preferences/preferenceSlice'; -import { truncate } from '../utils/stringUtils'; import { formatDate } from '../utils/dateTimeUtils'; // Utility function to format numbers @@ -146,8 +145,8 @@ const Documents: React.FC = ({ }, [searchTerm]); return ( -
-
+
+

{t('settings.documents.title')} @@ -186,128 +185,135 @@ const Documents: React.FC = ({ {loading ? ( ) : ( -
- - - - - - + + + + + + )) + )} + +
- {t('settings.documents.name')} - -
- {t('settings.documents.date')} - refreshDocs('date')} - src={caretSort} - alt="sort" - /> -
-
-
- - {t('settings.documents.tokenUsage')} +
+ {' '} + {/* Removed overflow-auto */} +
+ + + + + + + - - - - - {!currentDocuments?.length && ( - - + - )} - {Array.isArray(currentDocuments) && - currentDocuments.map((document, index) => ( - - - - - + {!currentDocuments?.length ? ( + + - ))} - -
+ {t('settings.documents.name')} + +
+ {t('settings.documents.date')} + refreshDocs('date')} + src={caretSort} + alt="sort" + /> +
+
+
+ + {t('settings.documents.tokenUsage')} + + + {t('settings.documents.tokenUsage')} + + refreshDocs('tokens')} + src={caretSort} + alt="sort" + /> +
+
+ + {t('settings.documents.actions')} - - {t('settings.documents.tokenUsage')} - - refreshDocs('tokens')} - src={caretSort} - alt="sort" - /> - - - - {t('settings.documents.actions')} - -
- {t('settings.documents.noData')} -
-
- {truncate(document.name, 50)} -
-
- {document.date ? formatDate(document.date) : ''} - - {document.tokens ? formatTokens(+document.tokens) : ''} - -
- {/* For non-remote documents, adding empty space holder */} - {!document.syncFrequency && ( -
- )} - {document.syncFrequency && ( - { - handleManageSync(document, value); - }} - defaultValue={document.syncFrequency} - icon={SyncIcon} - /> - )} - -
+ +
+ {t('settings.documents.noData')}
+ ) : ( + currentDocuments.map((document, index) => ( +
+ {document.name} + + {document.date ? formatDate(document.date) : ''} + + {document.tokens + ? formatTokens(+document.tokens) + : ''} + +
+ {!document.syncFrequency && ( +
+ )} + {document.syncFrequency && ( + { + handleManageSync(document, value); + }} + defaultValue={document.syncFrequency} + icon={SyncIcon} + /> + )} + +
+
+

)}
- { - setCurrentPage(page); - refreshDocs(undefined, page, rowsPerPage); - }} - onRowsPerPageChange={(rows) => { - setRowsPerPage(rows); - setCurrentPage(1); - refreshDocs(undefined, 1, rows); - }} - /> + +
+ { + setCurrentPage(page); + refreshDocs(undefined, page, rowsPerPage); + }} + onRowsPerPageChange={(rows) => { + setRowsPerPage(rows); + setCurrentPage(1); + refreshDocs(undefined, 1, rows); + }} + /> +
+ {modalState === 'ACTIVE' && ( Date: Mon, 27 Jan 2025 03:32:32 +0530 Subject: [PATCH 6/7] (fix:settings/docs) avoid refresh on modal close --- frontend/src/settings/Documents.tsx | 9 +-- frontend/src/upload/Upload.tsx | 113 +++++++++++++++------------- 2 files changed, 65 insertions(+), 57 deletions(-) diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index e33a5214..a11b125f 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -134,12 +134,6 @@ const Documents: React.FC = ({ }); }; - useEffect(() => { - if (modalState === 'INACTIVE') { - refreshDocs(undefined, currentPage, rowsPerPage); - } - }, [modalState]); - useEffect(() => { refreshDocs(undefined, 1, rowsPerPage); }, [searchTerm]); @@ -321,6 +315,9 @@ const Documents: React.FC = ({ isOnboarding={isOnboarding} renderTab={null} close={() => setModalState('INACTIVE')} + onSuccessfulUpload={() => + refreshDocs(undefined, currentPage, rowsPerPage) + } /> )}
diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 59a2bf93..02aa2318 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -23,12 +23,14 @@ function Upload({ isOnboarding, renderTab = null, close, + onSuccessfulUpload, }: { receivedFile: File[]; setModalState: (state: ActiveState) => void; isOnboarding: boolean; renderTab: string | null; close: () => void; + onSuccessfulUpload: () => void; }) { const [docName, setDocName] = useState(receivedFile[0]?.name); const [urlName, setUrlName] = useState(''); @@ -218,6 +220,7 @@ function Upload({ setfiles([]); setProgress(undefined); setModalState('INACTIVE'); + onSuccessfulUpload(); } } else if (data.status == 'PROGRESS') { setProgress( @@ -424,20 +427,26 @@ function Upload({

{t('modals.uploadDoc.info')}

-
+

{t('modals.uploadDoc.uploadedFiles')}

- {files.map((file) => ( -

- {file.name} -

- ))} - {files.length === 0 && ( -

- {t('none')} -

- )} +
+ {files.map((file) => ( +

+ {file.name} +

+ ))} + {files.length === 0 && ( +

+ {t('none')} +

+ )} +
)} @@ -597,47 +606,49 @@ function Upload({ {t('modals.uploadDoc.back')} )} - + className={`rounded-3xl px-4 py-2 font-medium ${ + (activeTab === 'file' && (!files.length || !docName)) || + (activeTab === 'remote' && + ((urlType.label !== 'Reddit' && + urlType.label !== 'GitHub' && + (!url || !urlName)) || + (urlType.label === 'GitHub' && !repoUrl) || + (urlType.label === 'Reddit' && + (!redditData.client_id || + !redditData.client_secret || + !redditData.user_agent || + !redditData.search_queries || + !redditData.number_posts)))) + ? 'cursor-not-allowed bg-gray-300 text-gray-500' + : 'cursor-pointer bg-purple-30 text-white hover:bg-purple-40' + }`} + > + {t('modals.uploadDoc.train')} + + )}
); From 83e4023c19455f88577ec23d5d1815c791cd132d Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 28 Jan 2025 04:50:28 +0530 Subject: [PATCH 7/7] (feat:settings/docs) confirm on delete --- frontend/src/locale/en.json | 3 +- frontend/src/locale/es.json | 3 +- frontend/src/locale/jp.json | 3 +- frontend/src/locale/ru.json | 3 +- frontend/src/locale/zh-TW.json | 3 +- frontend/src/locale/zh.json | 3 +- frontend/src/settings/Documents.tsx | 57 ++++++++++++++++++++++++----- frontend/src/upload/Upload.tsx | 6 +-- 8 files changed, 62 insertions(+), 19 deletions(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 2f6d2617..35058be0 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -71,7 +71,8 @@ "weekly": "Weekly", "monthly": "Monthly" }, - "actions": "Actions" + "actions": "Actions", + "deleteWarning": "Are you sure you want to delete \"{{name}}\"?" }, "apiKeys": { "label": "Chatbots", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 6437dead..d0b47874 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -71,7 +71,8 @@ "weekly": "Semanal", "monthly": "Mensual" }, - "actions": "Acciones" + "actions": "Acciones", + "deleteWarning": "¿Estás seguro de que deseas eliminar \"{{name}}\"?" }, "apiKeys": { "label": "Chatbots", diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 199f83e8..2fdc2c61 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -70,7 +70,8 @@ "weekly": "毎週", "monthly": "毎月" }, - "actions": "アクション" + "actions": "アクション", + "deleteWarning": "\"{{name}}\"を削除してもよろしいですか?" }, "apiKeys": { "label": "チャットボット", diff --git a/frontend/src/locale/ru.json b/frontend/src/locale/ru.json index 3621aafc..087b8dfd 100644 --- a/frontend/src/locale/ru.json +++ b/frontend/src/locale/ru.json @@ -71,7 +71,8 @@ "weekly": "Еженедельно", "monthly": "Ежемесячно" }, - "actions": "Действия" + "actions": "Действия", + "deleteWarning": "Вы уверены, что хотите удалить \"{{name}}\"?" }, "apiKeys": { "label": "API ключи", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index 8dbd550d..f2abf1e5 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -71,7 +71,8 @@ "weekly": "每週", "monthly": "每月" }, - "actions": "操作" + "actions": "操作", + "deleteWarning": "您確定要刪除 \"{{name}}\" 嗎?" }, "apiKeys": { "label": "聊天機器人", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 0e53a257..56c8fbb1 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -71,7 +71,8 @@ "weekly": "每周", "monthly": "每月" }, - "actions": "操作" + "actions": "操作", + "deleteWarning": "您确定要删除 \"{{name}}\" 吗?" }, "apiKeys": { "label": "聊天机器人", diff --git a/frontend/src/settings/Documents.tsx b/frontend/src/settings/Documents.tsx index a11b125f..88590165 100644 --- a/frontend/src/settings/Documents.tsx +++ b/frontend/src/settings/Documents.tsx @@ -16,6 +16,7 @@ import { getDocs, getDocsWithPagination } from '../preferences/preferenceApi'; import { setSourceDocs } from '../preferences/preferenceSlice'; import { setPaginatedDocuments } from '../preferences/preferenceSlice'; import { formatDate } from '../utils/dateTimeUtils'; +import ConfirmationModal from '../modals/ConfirmationModal'; // Utility function to format numbers const formatTokens = (tokens: number): string => { @@ -134,6 +135,26 @@ const Documents: React.FC = ({ }); }; + const [documentToDelete, setDocumentToDelete] = useState<{ + index: number; + document: Doc; + } | null>(null); + const [deleteModalState, setDeleteModalState] = + useState('INACTIVE'); + + const handleDeleteConfirmation = (index: number, document: Doc) => { + setDocumentToDelete({ index, document }); + setDeleteModalState('ACTIVE'); + }; + + const handleConfirmedDelete = () => { + if (documentToDelete) { + handleDeleteDocument(documentToDelete.index, documentToDelete.document); + setDeleteModalState('INACTIVE'); + setDocumentToDelete(null); + } + }; + useEffect(() => { refreshDocs(undefined, 1, rowsPerPage); }, [searchTerm]); @@ -182,10 +203,10 @@ const Documents: React.FC = ({
{' '} {/* Removed overflow-auto */} -
+
- + @@ -223,34 +244,34 @@ const Documents: React.FC = ({ - + {!currentDocuments?.length ? ( ) : ( currentDocuments.map((document, index) => ( - + - - -
{t('settings.documents.name')}
{t('settings.documents.noData')}
{document.name} + {document.date ? formatDate(document.date) : ''} + {document.tokens ? formatTokens(+document.tokens) : ''} +
{!document.syncFrequency && (
@@ -269,7 +290,7 @@ const Documents: React.FC = ({
); }; diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 02aa2318..b1c45156 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -23,14 +23,14 @@ function Upload({ isOnboarding, renderTab = null, close, - onSuccessfulUpload, + onSuccessfulUpload = () => undefined, }: { receivedFile: File[]; setModalState: (state: ActiveState) => void; isOnboarding: boolean; renderTab: string | null; close: () => void; - onSuccessfulUpload: () => void; + onSuccessfulUpload?: () => void; }) { const [docName, setDocName] = useState(receivedFile[0]?.name); const [urlName, setUrlName] = useState(''); @@ -220,7 +220,7 @@ function Upload({ setfiles([]); setProgress(undefined); setModalState('INACTIVE'); - onSuccessfulUpload(); + onSuccessfulUpload?.(); } } else if (data.status == 'PROGRESS') { setProgress(