mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-12-03 02:23:14 +00:00
Chore: deleted unused files, dead code; minor fixes (#2059)
* (feat:pause-stream) generator exit * (feat:pause-stream) close request * (feat:pause-stream) finally close; google anthropic * (feat:task_status)communicate failure * (clean:connector) unused routes * (feat:file-table) missing skeletons * (chore:fe) purge unused * (fix:apiKeys) build err * (chore:settings) clean unused * merge from main * (chore:purge) unused fe assets * (clean:check_docs) unused logic * (feat:selectedDocs) replace null type --------- Co-authored-by: GH Action - Upstream Sync <action@github.com>
This commit is contained in:
@@ -1,233 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import userService from '../api/services/userService';
|
||||
import Trash from '../assets/trash.svg';
|
||||
import SkeletonLoader from '../components/SkeletonLoader';
|
||||
import { useLoaderState } from '../hooks';
|
||||
import ConfirmationModal from '../modals/ConfirmationModal';
|
||||
import CreateAPIKeyModal from '../modals/CreateAPIKeyModal';
|
||||
import SaveAPIKeyModal from '../modals/SaveAPIKeyModal';
|
||||
import { selectToken } from '../preferences/preferenceSlice';
|
||||
import { APIKeyData } from './types';
|
||||
|
||||
export default function APIKeys() {
|
||||
const { t } = useTranslation();
|
||||
const token = useSelector(selectToken);
|
||||
const [isCreateModalOpen, setCreateModal] = useState(false);
|
||||
const [isSaveKeyModalOpen, setSaveKeyModal] = useState(false);
|
||||
const [newKey, setNewKey] = useState('');
|
||||
const [apiKeys, setApiKeys] = useState<APIKeyData[]>([]);
|
||||
const [loading, setLoading] = useLoaderState(true);
|
||||
const [keyToDelete, setKeyToDelete] = useState<{
|
||||
id: string;
|
||||
name: string;
|
||||
} | null>(null);
|
||||
|
||||
const handleFetchKeys = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const response = await userService.getAPIKeys(token);
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch API Keys');
|
||||
}
|
||||
const apiKeys = await response.json();
|
||||
setApiKeys(apiKeys);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDeleteKey = (id: string) => {
|
||||
setLoading(true);
|
||||
userService
|
||||
.deleteAPIKey({ id }, token)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to delete API Key');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
if (data.success === true) {
|
||||
setApiKeys((previous) => previous.filter((elem) => elem.id !== id));
|
||||
}
|
||||
setKeyToDelete(null);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
const handleCreateKey = (payload: {
|
||||
name: string;
|
||||
source?: string;
|
||||
retriever?: string;
|
||||
prompt_id: string;
|
||||
chunks: string;
|
||||
}) => {
|
||||
setLoading(true);
|
||||
userService
|
||||
.createAPIKey(payload, token)
|
||||
.then((response) => {
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to create API Key');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then((data) => {
|
||||
setApiKeys([...apiKeys, data]);
|
||||
setCreateModal(false);
|
||||
setNewKey(data.key);
|
||||
setSaveKeyModal(true);
|
||||
handleFetchKeys();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
})
|
||||
.finally(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
handleFetchKeys();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="mt-8 flex w-full max-w-full flex-col overflow-hidden">
|
||||
<div className="relative flex grow flex-col">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-sonic-silver text-base font-medium">
|
||||
{t('settings.apiKeys.description')}
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="mb-6 flex flex-col items-start justify-end gap-3 sm:flex-row sm:items-center">
|
||||
<button
|
||||
onClick={() => setCreateModal(true)}
|
||||
className="bg-purple-30 hover:bg-violets-are-blue flex h-[30px] w-[108px] items-center justify-center rounded-full text-sm text-white"
|
||||
title={t('settings.apiKeys.createNew')}
|
||||
>
|
||||
{t('settings.apiKeys.createNew')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="relative w-full">
|
||||
<div className="dark:border-silver/40 overflow-hidden rounded-md border border-gray-300">
|
||||
<div className="table-scroll overflow-x-auto">
|
||||
<table className="w-full table-auto">
|
||||
<thead>
|
||||
<tr className="dark:border-silver/40 border-b border-gray-300">
|
||||
<th className="text-sonic-silver w-[35%] px-4 py-3 text-left text-xs font-medium">
|
||||
{t('settings.apiKeys.name')}
|
||||
</th>
|
||||
<th className="text-sonic-silver w-[35%] px-4 py-3 text-left text-xs font-medium">
|
||||
{t('settings.apiKeys.sourceDoc')}
|
||||
</th>
|
||||
<th className="text-sonic-silver w-[25%] px-4 py-3 text-left text-xs font-medium">
|
||||
<span className="hidden sm:inline">
|
||||
{t('settings.apiKeys.key')}
|
||||
</span>
|
||||
<span className="sm:hidden">
|
||||
{t('settings.apiKeys.key')}
|
||||
</span>
|
||||
</th>
|
||||
<th className="w-[5%] px-4 py-3 text-right text-xs font-medium text-gray-700 dark:text-[#E0E0E0]">
|
||||
<span className="sr-only">Actions</span>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="dark:divide-silver/40 divide-y divide-gray-300">
|
||||
{loading ? (
|
||||
<SkeletonLoader component="fileTable" />
|
||||
) : !apiKeys?.length ? (
|
||||
<tr>
|
||||
<td
|
||||
colSpan={4}
|
||||
className="bg-transparent py-4 text-center text-gray-700 dark:text-neutral-200"
|
||||
>
|
||||
{t('settings.apiKeys.noData')}
|
||||
</td>
|
||||
</tr>
|
||||
) : (
|
||||
Array.isArray(apiKeys) &&
|
||||
apiKeys.map((element) => (
|
||||
<tr
|
||||
key={element.id}
|
||||
className="group transition-colors hover:bg-gray-50 dark:hover:bg-gray-800/50"
|
||||
>
|
||||
<td className="w-[35%] max-w-0 min-w-48 px-4 py-4 text-sm font-semibold text-gray-700 dark:text-[#E0E0E0]">
|
||||
<div className="truncate" title={element.name}>
|
||||
{element.name}
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[35%] max-w-0 min-w-48 px-4 py-4 text-sm text-gray-700 dark:text-[#E0E0E0]">
|
||||
<div className="truncate" title={element.source}>
|
||||
{element.source}
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[25%] px-4 py-4 font-mono text-sm text-gray-700 dark:text-[#E0E0E0]">
|
||||
<div className="truncate" title={element.key}>
|
||||
{element.key}
|
||||
</div>
|
||||
</td>
|
||||
<td className="w-[5%] px-4 py-4 text-right">
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
onClick={() =>
|
||||
setKeyToDelete({
|
||||
id: element.id,
|
||||
name: element.name,
|
||||
})
|
||||
}
|
||||
className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-full transition-colors hover:bg-gray-100 dark:hover:bg-gray-700"
|
||||
>
|
||||
<img
|
||||
src={Trash}
|
||||
alt={t('convTile.delete')}
|
||||
className="h-4 w-4 opacity-60 hover:opacity-100"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{isCreateModalOpen && (
|
||||
<CreateAPIKeyModal
|
||||
createAPIKey={handleCreateKey}
|
||||
close={() => setCreateModal(false)}
|
||||
/>
|
||||
)}
|
||||
{isSaveKeyModalOpen && (
|
||||
<SaveAPIKeyModal apiKey={newKey} close={() => setSaveKeyModal(false)} />
|
||||
)}
|
||||
{keyToDelete && (
|
||||
<ConfirmationModal
|
||||
message={t('settings.apiKeys.deleteConfirmation', {
|
||||
name: keyToDelete.name,
|
||||
})}
|
||||
modalState="ACTIVE"
|
||||
setModalState={() => setKeyToDelete(null)}
|
||||
submitLabel={t('modals.deleteConv.delete')}
|
||||
handleSubmit={() => handleDeleteKey(keyToDelete.id)}
|
||||
handleCancel={() => setKeyToDelete(null)}
|
||||
variant="danger"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
import React from 'react';
|
||||
import Dropdown from '../components/Dropdown';
|
||||
|
||||
const Widgets: React.FC<{
|
||||
widgetScreenshot: File | null;
|
||||
onWidgetScreenshotChange: (screenshot: File | null) => void;
|
||||
}> = ({ widgetScreenshot, onWidgetScreenshotChange }) => {
|
||||
const widgetSources = ['Source 1', 'Source 2', 'Source 3'];
|
||||
const widgetMethods = ['Method 1', 'Method 2', 'Method 3'];
|
||||
const widgetTypes = ['Type 1', 'Type 2', 'Type 3'];
|
||||
|
||||
const [selectedWidgetSource, setSelectedWidgetSource] = React.useState(
|
||||
widgetSources[0],
|
||||
);
|
||||
const [selectedWidgetMethod, setSelectedWidgetMethod] = React.useState(
|
||||
widgetMethods[0],
|
||||
);
|
||||
const [selectedWidgetType, setSelectedWidgetType] = React.useState(
|
||||
widgetTypes[0],
|
||||
);
|
||||
|
||||
// const [widgetScreenshot, setWidgetScreenshot] = useState<File | null>(null);
|
||||
const [widgetCode, setWidgetCode] = React.useState<string>(''); // Your widget code state
|
||||
|
||||
const handleScreenshotChange = (
|
||||
event: React.ChangeEvent<HTMLInputElement>,
|
||||
) => {
|
||||
const files = event.target.files;
|
||||
|
||||
if (files && files.length > 0) {
|
||||
const selectedScreenshot = files[0];
|
||||
onWidgetScreenshotChange(selectedScreenshot); // Update the screenshot in the parent component
|
||||
}
|
||||
};
|
||||
|
||||
const handleCopyToClipboard = () => {
|
||||
// Create a new textarea element to select the text
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.value = widgetCode;
|
||||
document.body.appendChild(textArea);
|
||||
|
||||
// Select and copy the text
|
||||
textArea.select();
|
||||
document.execCommand('copy');
|
||||
|
||||
// Clean up the textarea element
|
||||
document.body.removeChild(textArea);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="mt-[59px]">
|
||||
<p className="text-jet font-bold">Widget Source</p>
|
||||
<Dropdown
|
||||
options={widgetSources}
|
||||
selectedValue={selectedWidgetSource}
|
||||
onSelect={setSelectedWidgetSource}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<p className="text-jet font-bold">Widget Method</p>
|
||||
<Dropdown
|
||||
options={widgetMethods}
|
||||
selectedValue={selectedWidgetMethod}
|
||||
onSelect={setSelectedWidgetMethod}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-5">
|
||||
<p className="text-jet font-bold">Widget Type</p>
|
||||
<Dropdown
|
||||
options={widgetTypes}
|
||||
selectedValue={selectedWidgetType}
|
||||
onSelect={setSelectedWidgetType}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<p className="text-jet font-bold">Widget Code Snippet</p>
|
||||
<textarea
|
||||
rows={4}
|
||||
value={widgetCode}
|
||||
onChange={(e) => setWidgetCode(e.target.value)}
|
||||
className="mt-3 w-full rounded-lg border-2 p-2"
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-1">
|
||||
<button
|
||||
onClick={handleCopyToClipboard}
|
||||
className="rounded-lg bg-blue-400 px-2 py-2 font-bold text-white transition-all hover:bg-blue-600"
|
||||
>
|
||||
Copy
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="mt-4">
|
||||
<p className="text-lg font-semibold">Widget Screenshot</p>
|
||||
<input type="file" accept="image/*" onChange={handleScreenshotChange} />
|
||||
</div>
|
||||
|
||||
{widgetScreenshot && (
|
||||
<div className="mt-4">
|
||||
<img
|
||||
src={URL.createObjectURL(widgetScreenshot)}
|
||||
alt="Widget Screenshot"
|
||||
className="max-w-full rounded-lg border border-gray-300"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Widgets;
|
||||
@@ -25,16 +25,12 @@ import Sources from './Sources';
|
||||
import General from './General';
|
||||
import Logs from './Logs';
|
||||
import Tools from './Tools';
|
||||
import Widgets from './Widgets';
|
||||
|
||||
export default function Settings() {
|
||||
const dispatch = useDispatch();
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const [widgetScreenshot, setWidgetScreenshot] = React.useState<File | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const getActiveTabFromPath = () => {
|
||||
const path = location.pathname;
|
||||
@@ -43,7 +39,6 @@ export default function Settings() {
|
||||
return t('settings.analytics.label');
|
||||
if (path.includes('/settings/logs')) return t('settings.logs.label');
|
||||
if (path.includes('/settings/tools')) return t('settings.tools.label');
|
||||
if (path.includes('/settings/widgets')) return 'Widgets';
|
||||
return t('settings.general.label');
|
||||
};
|
||||
|
||||
@@ -57,7 +52,6 @@ export default function Settings() {
|
||||
navigate('/settings/analytics');
|
||||
else if (tab === t('settings.logs.label')) navigate('/settings/logs');
|
||||
else if (tab === t('settings.tools.label')) navigate('/settings/tools');
|
||||
else if (tab === 'Widgets') navigate('/settings/widgets');
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
@@ -72,9 +66,6 @@ export default function Settings() {
|
||||
const token = useSelector(selectToken);
|
||||
const documents = useSelector(selectSourceDocs);
|
||||
const paginatedDocuments = useSelector(selectPaginatedDocuments);
|
||||
const updateWidgetScreenshot = (screenshot: File | null) => {
|
||||
setWidgetScreenshot(screenshot);
|
||||
};
|
||||
|
||||
const updateDocumentsList = (documents: Doc[], index: number) => [
|
||||
...documents.slice(0, index),
|
||||
@@ -122,15 +113,6 @@ export default function Settings() {
|
||||
<Route path="analytics" element={<Analytics />} />
|
||||
<Route path="logs" element={<Logs />} />
|
||||
<Route path="tools" element={<Tools />} />
|
||||
<Route
|
||||
path="widgets"
|
||||
element={
|
||||
<Widgets
|
||||
widgetScreenshot={widgetScreenshot}
|
||||
onWidgetScreenshotChange={updateWidgetScreenshot}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate to="/settings" replace />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user