233 lines
8.9 KiB
TypeScript
233 lines
8.9 KiB
TypeScript
import { PluginID, PluginKey } from '@/types/plugin';
|
|
import { IconKey } from '@tabler/icons-react';
|
|
import { FC, KeyboardEvent, useEffect, useRef, useState } from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { SidebarButton } from '../Sidebar/SidebarButton';
|
|
|
|
interface Props {
|
|
pluginKeys: PluginKey[];
|
|
onPluginKeyChange: (pluginKey: PluginKey) => void;
|
|
onClearPluginKey: (pluginKey: PluginKey) => void;
|
|
}
|
|
|
|
export const PluginKeys: FC<Props> = ({
|
|
pluginKeys,
|
|
onPluginKeyChange,
|
|
onClearPluginKey,
|
|
}) => {
|
|
const { t } = useTranslation('sidebar');
|
|
|
|
const [isChanging, setIsChanging] = useState(false);
|
|
|
|
const modalRef = useRef<HTMLDivElement>(null);
|
|
|
|
const handleEnter = (e: KeyboardEvent<HTMLDivElement>) => {
|
|
if (e.key === 'Enter' && !e.shiftKey) {
|
|
e.preventDefault();
|
|
setIsChanging(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
const handleMouseDown = (e: MouseEvent) => {
|
|
if (modalRef.current && !modalRef.current.contains(e.target as Node)) {
|
|
window.addEventListener('mouseup', handleMouseUp);
|
|
}
|
|
};
|
|
|
|
const handleMouseUp = (e: MouseEvent) => {
|
|
window.removeEventListener('mouseup', handleMouseUp);
|
|
setIsChanging(false);
|
|
};
|
|
|
|
window.addEventListener('mousedown', handleMouseDown);
|
|
|
|
return () => {
|
|
window.removeEventListener('mousedown', handleMouseDown);
|
|
};
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<SidebarButton
|
|
text={t('Plugin Keys')}
|
|
icon={<IconKey size={18} />}
|
|
onClick={() => setIsChanging(true)}
|
|
/>
|
|
|
|
{isChanging && (
|
|
<div
|
|
className="z-100 fixed inset-0 flex items-center justify-center bg-black bg-opacity-50"
|
|
onKeyDown={handleEnter}
|
|
>
|
|
<div className="fixed inset-0 z-10 overflow-y-auto">
|
|
<div className="flex min-h-screen items-center justify-center px-4 pt-4 pb-20 text-center sm:block sm:p-0">
|
|
<div
|
|
className="hidden sm:inline-block sm:h-screen sm:align-middle"
|
|
aria-hidden="true"
|
|
/>
|
|
|
|
<div
|
|
ref={modalRef}
|
|
className="dark:border-netural-400 inline-block max-h-[400px] transform overflow-hidden rounded-lg border border-gray-300 bg-white px-4 pt-5 pb-4 text-left align-bottom shadow-xl transition-all dark:bg-[#202123] sm:my-8 sm:max-h-[600px] sm:w-full sm:max-w-lg sm:p-6 sm:align-middle"
|
|
role="dialog"
|
|
>
|
|
<div className="mb-10 text-4xl">Plugin Keys</div>
|
|
|
|
<div className="mt-6 rounded border p-4">
|
|
<div className="text-xl font-bold">Google Search Plugin</div>
|
|
<div className="mt-4 italic">
|
|
Please enter your Google API Key and Google CSE ID to enable
|
|
the Google Search Plugin.
|
|
</div>
|
|
|
|
<div className="mt-6 text-sm font-bold text-black dark:text-neutral-200">
|
|
Google API Key
|
|
</div>
|
|
<input
|
|
className="mt-2 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-[#40414F] dark:text-neutral-100"
|
|
type="password"
|
|
value={
|
|
pluginKeys
|
|
.find((p) => p.pluginId === PluginID.GOOGLE_SEARCH)
|
|
?.requiredKeys.find((k) => k.key === 'GOOGLE_API_KEY')
|
|
?.value
|
|
}
|
|
onChange={(e) => {
|
|
const pluginKey = pluginKeys.find(
|
|
(p) => p.pluginId === PluginID.GOOGLE_SEARCH,
|
|
);
|
|
|
|
if (pluginKey) {
|
|
const requiredKey = pluginKey.requiredKeys.find(
|
|
(k) => k.key === 'GOOGLE_API_KEY',
|
|
);
|
|
|
|
if (requiredKey) {
|
|
const updatedPluginKey = {
|
|
...pluginKey,
|
|
requiredKeys: pluginKey.requiredKeys.map((k) => {
|
|
if (k.key === 'GOOGLE_API_KEY') {
|
|
return {
|
|
...k,
|
|
value: e.target.value,
|
|
};
|
|
}
|
|
|
|
return k;
|
|
}),
|
|
};
|
|
|
|
onPluginKeyChange(updatedPluginKey);
|
|
}
|
|
} else {
|
|
const newPluginKey: PluginKey = {
|
|
pluginId: PluginID.GOOGLE_SEARCH,
|
|
requiredKeys: [
|
|
{
|
|
key: 'GOOGLE_API_KEY',
|
|
value: e.target.value,
|
|
},
|
|
{
|
|
key: 'GOOGLE_CSE_ID',
|
|
value: '',
|
|
},
|
|
],
|
|
};
|
|
|
|
onPluginKeyChange(newPluginKey);
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<div className="mt-6 text-sm font-bold text-black dark:text-neutral-200">
|
|
Google CSE ID
|
|
</div>
|
|
<input
|
|
className="mt-2 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-[#40414F] dark:text-neutral-100"
|
|
type="password"
|
|
value={
|
|
pluginKeys
|
|
.find((p) => p.pluginId === PluginID.GOOGLE_SEARCH)
|
|
?.requiredKeys.find((k) => k.key === 'GOOGLE_CSE_ID')
|
|
?.value
|
|
}
|
|
onChange={(e) => {
|
|
const pluginKey = pluginKeys.find(
|
|
(p) => p.pluginId === PluginID.GOOGLE_SEARCH,
|
|
);
|
|
|
|
if (pluginKey) {
|
|
const requiredKey = pluginKey.requiredKeys.find(
|
|
(k) => k.key === 'GOOGLE_CSE_ID',
|
|
);
|
|
|
|
if (requiredKey) {
|
|
const updatedPluginKey = {
|
|
...pluginKey,
|
|
requiredKeys: pluginKey.requiredKeys.map((k) => {
|
|
if (k.key === 'GOOGLE_CSE_ID') {
|
|
return {
|
|
...k,
|
|
value: e.target.value,
|
|
};
|
|
}
|
|
|
|
return k;
|
|
}),
|
|
};
|
|
|
|
onPluginKeyChange(updatedPluginKey);
|
|
}
|
|
} else {
|
|
const newPluginKey: PluginKey = {
|
|
pluginId: PluginID.GOOGLE_SEARCH,
|
|
requiredKeys: [
|
|
{
|
|
key: 'GOOGLE_API_KEY',
|
|
value: '',
|
|
},
|
|
{
|
|
key: 'GOOGLE_CSE_ID',
|
|
value: e.target.value,
|
|
},
|
|
],
|
|
};
|
|
|
|
onPluginKeyChange(newPluginKey);
|
|
}
|
|
}}
|
|
/>
|
|
|
|
<button
|
|
className="mt-6 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow hover:bg-neutral-100 focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-white dark:text-black dark:hover:bg-neutral-300"
|
|
onClick={() => {
|
|
const pluginKey = pluginKeys.find(
|
|
(p) => p.pluginId === PluginID.GOOGLE_SEARCH,
|
|
);
|
|
|
|
if (pluginKey) {
|
|
onClearPluginKey(pluginKey);
|
|
}
|
|
}}
|
|
>
|
|
Clear Google Search Plugin Keys
|
|
</button>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
className="mt-6 w-full rounded-lg border border-neutral-500 px-4 py-2 text-neutral-900 shadow hover:bg-neutral-100 focus:outline-none dark:border-neutral-800 dark:border-opacity-50 dark:bg-white dark:text-black dark:hover:bg-neutral-300"
|
|
onClick={() => setIsChanging(false)}
|
|
>
|
|
{t('Save')}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</>
|
|
);
|
|
};
|