Merge pull request #168 from danny-avila/feat-export-convo

fix: remove use-screenshot
This commit is contained in:
Danny Avila 2023-04-07 10:15:43 -04:00 committed by GitHub
commit 7ec90a3585
4 changed files with 81 additions and 58 deletions

View file

@ -68,7 +68,6 @@
"tailwindcss-animate": "^1.0.5", "tailwindcss-animate": "^1.0.5",
"tailwindcss-radix": "^2.8.0", "tailwindcss-radix": "^2.8.0",
"url": "^0.11.0", "url": "^0.11.0",
"use-react-screenshot": "github:danny-avila/use-react-screenshot#master",
"uuidv4": "^6.2.13" "uuidv4": "^6.2.13"
}, },
"devDependencies": { "devDependencies": {

View file

@ -23,7 +23,6 @@ export default function ExportModel({ open, onOpenChange }) {
const [includeOptions, setIncludeOptions] = useState(true); const [includeOptions, setIncludeOptions] = useState(true);
const [exportBranches, setExportBranches] = useState(false); const [exportBranches, setExportBranches] = useState(false);
const [exportBranchesSupport, setExportBranchesSupport] = useState(false);
const [recursive, setRecursive] = useState(true); const [recursive, setRecursive] = useState(true);
const conversation = useRecoilValue(store.conversation) || {}; const conversation = useRecoilValue(store.conversation) || {};
@ -37,30 +36,34 @@ export default function ExportModel({ open, onOpenChange }) {
[] []
); );
const typeOptions = ['text', 'markdown', 'csv', 'json', 'screenshot']; //,, 'webpage']; const typeOptions = [
{ value: 'text', display: 'text (.txt)' },
{ value: 'markdown', display: 'markdown (.md)' },
{ value: 'csv', display: 'csv (.csv)' },
{ value: 'json', display: 'json (.json)' },
{ value: 'screenshot', display: 'screenshot (.png)' }
]; //,, 'webpage'];
useEffect(() => { useEffect(() => {
setFileName( setFileName(filenamify(String(conversation?.title || 'file')));
filenamify(String(conversation?.title || 'file'))
);
setType('text'); setType('text');
setIncludeOptions(true); setIncludeOptions(true);
setExportBranches(false); setExportBranches(false);
setExportBranchesSupport(false);
setRecursive(true); setRecursive(true);
}, [open]); }, [open]);
const _setType = newType => { const _setType = newType => {
if (newType === 'json' || newType === 'csv' || newType === 'webpage') { const exportBranchesSupport = newType === 'json' || newType === 'csv' || newType === 'webpage';
setExportBranches(true); const exportOptionsSupport = newType !== 'csv' && newType !== 'screenshot';
setExportBranchesSupport(true);
} else { setExportBranches(exportBranchesSupport);
setExportBranches(false); setIncludeOptions(exportOptionsSupport);
setExportBranchesSupport(false);
}
setType(newType); setType(newType);
}; };
const exportBranchesSupport = type === 'json' || type === 'csv' || type === 'webpage';
const exportOptionsSupport = type !== 'csv' && type !== 'screenshot';
// return an object or an array based on branches and recursive option // return an object or an array based on branches and recursive option
// messageId is used to get siblindIdx from recoil snapshot // messageId is used to get siblindIdx from recoil snapshot
const buildMessageTree = async ({ messageId, message, messages, branches = false, recursive = false }) => { const buildMessageTree = async ({ messageId, message, messages, branches = false, recursive = false }) => {
@ -320,57 +323,54 @@ export default function ExportModel({ open, onOpenChange }) {
</div> </div>
</div> </div>
<div className="grid w-full gap-6 sm:grid-cols-2"> <div className="grid w-full gap-6 sm:grid-cols-2">
{type !== 'csv' && type !== 'screenshot' ? ( <div className="col-span-1 flex flex-col items-start justify-start gap-2">
<div className="col-span-1 flex flex-col items-start justify-start gap-2">
<div className="grid w-full items-center gap-2">
<Label
htmlFor="includeOptions"
className="text-left text-sm font-medium"
>
Include endpoint options
</Label>
<div className="flex h-[40px] w-full items-center space-x-3">
<Checkbox
id="includeOptions"
checked={includeOptions}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setIncludeOptions}
/>
<label
htmlFor="includeOptions"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
>
Enabled
</label>
</div>
</div>
</div>
) : null}
{type !== 'screenshot' ? (
<div className="grid w-full items-center gap-2"> <div className="grid w-full items-center gap-2">
<Label <Label
htmlFor="exportBranches" htmlFor="includeOptions"
className="text-left text-sm font-medium" className="text-left text-sm font-medium"
> >
Export all message branches Include endpoint options
</Label> </Label>
<div className="flex h-[40px] w-full items-center space-x-3"> <div className="flex h-[40px] w-full items-center space-x-3">
<Checkbox <Checkbox
id="exportBranches" id="includeOptions"
disabled={!exportBranchesSupport} disabled={!exportOptionsSupport}
checked={exportBranches} checked={includeOptions}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0" className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setExportBranches} onCheckedChange={setIncludeOptions}
/> />
<label <label
htmlFor="exportBranches" htmlFor="includeOptions"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50" className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
> >
{exportBranchesSupport ? 'Enabled' : 'Not Supported'} {exportOptionsSupport ? 'Enabled' : 'Not Supported'}
</label> </label>
</div> </div>
</div> </div>
) : null} </div>
<div className="grid w-full items-center gap-2">
<Label
htmlFor="exportBranches"
className="text-left text-sm font-medium"
>
Export all message branches
</Label>
<div className="flex h-[40px] w-full items-center space-x-3">
<Checkbox
id="exportBranches"
disabled={!exportBranchesSupport}
checked={exportBranches}
className="focus:ring-opacity-20 dark:border-gray-500 dark:bg-gray-700 dark:text-gray-50 dark:focus:ring-gray-600 dark:focus:ring-opacity-50 dark:focus:ring-offset-0"
onCheckedChange={setExportBranches}
/>
<label
htmlFor="exportBranches"
className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70 dark:text-gray-50"
>
{exportBranchesSupport ? 'Enabled' : 'Not Supported'}
</label>
</div>
</div>
{type === 'json' ? ( {type === 'json' ? (
<div className="grid w-full items-center gap-2"> <div className="grid w-full items-center gap-2">
<Label <Label

View file

@ -4,6 +4,7 @@ import { Listbox } from '@headlessui/react';
import { cn } from '~/utils/'; import { cn } from '~/utils/';
function Dropdown({ value, onChange, options, className, containerClassName }) { function Dropdown({ value, onChange, options, className, containerClassName }) {
const currentOption = options.find(element => element === value || element?.value === value) ?? value;
return ( return (
<div className={cn('flex items-center justify-center gap-2', containerClassName)}> <div className={cn('flex items-center justify-center gap-2', containerClassName)}>
<div className="relative w-full"> <div className="relative w-full">
@ -19,7 +20,7 @@ function Dropdown({ value, onChange, options, className, containerClassName }) {
> >
<span className="inline-flex w-full truncate"> <span className="inline-flex w-full truncate">
<span className="flex h-6 items-center gap-1 truncate text-sm text-black dark:text-white"> <span className="flex h-6 items-center gap-1 truncate text-sm text-black dark:text-white">
{value} {currentOption?.display ?? value}
</span> </span>
</span> </span>
<span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2"> <span className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
@ -43,19 +44,19 @@ function Dropdown({ value, onChange, options, className, containerClassName }) {
{options.map((item, i) => ( {options.map((item, i) => (
<Listbox.Option <Listbox.Option
key={i} key={i}
value={item} value={item?.value ?? item}
className="group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden border-b border-black/10 pl-3 pr-9 text-gray-900 last:border-0 hover:bg-[#ECECF1] dark:border-white/20 dark:text-white dark:hover:bg-gray-700" className="group relative flex h-[42px] cursor-pointer select-none items-center overflow-hidden border-b border-black/10 pl-3 pr-9 text-gray-900 last:border-0 hover:bg-[#ECECF1] dark:border-white/20 dark:text-white dark:hover:bg-gray-700"
> >
<span className="flex items-center gap-1.5 truncate"> <span className="flex items-center gap-1.5 truncate">
<span <span
className={cn( className={cn(
'flex h-6 items-center gap-1 text-gray-800 dark:text-gray-100', 'flex h-6 items-center gap-1 text-gray-800 dark:text-gray-100',
value === item ? 'font-semibold' : '' value === (item?.value ?? item) ? 'font-semibold' : ''
)} )}
> >
{item} {item?.display ?? item}
</span> </span>
{value === item && ( {value === (item?.value ?? item) && (
<span className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-800 dark:text-gray-100"> <span className="absolute inset-y-0 right-0 flex items-center pr-3 text-gray-800 dark:text-gray-100">
<CheckMark /> <CheckMark />
</span> </span>

View file

@ -1,14 +1,37 @@
import React, { createContext, useRef, useContext, useCallback } from 'react'; import React, { createContext, useRef, useContext, useCallback } from 'react';
import { useScreenshot as useScreenshot_ } from 'use-react-screenshot'; import html2canvas from 'html2canvas';
const ScreenshotContext = createContext({}); const ScreenshotContext = createContext({});
export const useScreenshot = () => { export const useScreenshot = () => {
const { ref } = useContext(ScreenshotContext); const { ref } = useContext(ScreenshotContext);
const [image, takeScreenshot] = useScreenshot_();
const takeScreenShot = node => {
if (!node) {
throw new Error('You should provide correct html node.');
}
return html2canvas(node).then(canvas => {
const croppedCanvas = document.createElement('canvas');
const croppedCanvasContext = croppedCanvas.getContext('2d');
// init data
const cropPositionTop = 0;
const cropPositionLeft = 0;
const cropWidth = canvas.width;
const cropHeight = canvas.height;
croppedCanvas.width = cropWidth;
croppedCanvas.height = cropHeight;
croppedCanvasContext.drawImage(canvas, cropPositionLeft, cropPositionTop);
const base64Image = croppedCanvas.toDataURL('image/png', 1);
return base64Image;
});
};
const captureScreenshot = () => { const captureScreenshot = () => {
return takeScreenshot(ref.current); return takeScreenShot(ref.current);
}; };
return { screenshotTargetRef: ref, captureScreenshot }; return { screenshotTargetRef: ref, captureScreenshot };