mirror of https://github.com/kortix-ai/suna.git
refactor
This commit is contained in:
parent
077b60fb3b
commit
cf507c521e
|
@ -21,7 +21,7 @@ import {
|
|||
DropdownMenuTrigger,
|
||||
} from '@/components/ui/dropdown-menu';
|
||||
import { constructHtmlPreviewUrl } from '@/lib/utils/url';
|
||||
import { downloadPresentationAsPDF, downloadPresentationAsPPTX } from '../utils/presentation-utils';
|
||||
import { downloadPresentation, DownloadFormat } from '../utils/presentation-utils';
|
||||
|
||||
interface SlideMetadata {
|
||||
title: string;
|
||||
|
@ -427,11 +427,11 @@ export function FullScreenPresentationViewer({
|
|||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-32">
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => downloadPresentationAsPDF(sandboxUrl, `/workspace/presentations/${presentationName}`, presentationName)} disabled={isDownloadingPDF}>
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => downloadPresentation(DownloadFormat.PDF, sandboxUrl, `/workspace/presentations/${presentationName}`, presentationName)} disabled={isDownloadingPDF}>
|
||||
<FileText className="h-4 w-4 mr-2" />
|
||||
PDF
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => downloadPresentationAsPPTX(sandboxUrl, `/workspace/presentations/${presentationName}`, presentationName)} disabled={isDownloadingPPTX}>
|
||||
<DropdownMenuItem className="cursor-pointer" onClick={() => downloadPresentation(DownloadFormat.PPTX, sandboxUrl, `/workspace/presentations/${presentationName}`, presentationName)} disabled={isDownloadingPPTX}>
|
||||
<Presentation className="h-4 w-4 mr-2" />
|
||||
PPTX
|
||||
</DropdownMenuItem>
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
getToolTitle,
|
||||
extractToolData,
|
||||
} from '../utils';
|
||||
import { downloadPresentationAsPDF, downloadPresentationAsPPTX } from '../utils/presentation-utils';
|
||||
import { downloadPresentation, DownloadFormat } from '../utils/presentation-utils';
|
||||
import { toast } from 'sonner';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
|
@ -75,45 +75,25 @@ export function PresentPresentationToolView({
|
|||
};
|
||||
|
||||
// Download state
|
||||
const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
|
||||
const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
|
||||
// Download handlers
|
||||
const handlePDFDownload = async () => {
|
||||
const handleDownload = async (format: DownloadFormat) => {
|
||||
if (!project?.sandbox?.sandbox_url || !presentationName) return;
|
||||
|
||||
setIsDownloadingPDF(true);
|
||||
setIsDownloading(true);
|
||||
try {
|
||||
await downloadPresentationAsPDF(
|
||||
await downloadPresentation(format,
|
||||
project.sandbox.sandbox_url,
|
||||
`/workspace/${presentationPath}`,
|
||||
presentationName
|
||||
);
|
||||
toast.success('PDF downloaded successfully');
|
||||
toast.success(`${format} downloaded successfully`);
|
||||
} catch (error) {
|
||||
console.error('Error downloading PDF:', error);
|
||||
toast.error(`Failed to download PDF: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
console.error(`Error downloading ${format}:`, error);
|
||||
toast.error(`Failed to download ${format}: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
} finally {
|
||||
setIsDownloadingPDF(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePPTXDownload = async () => {
|
||||
if (!project?.sandbox?.sandbox_url || !presentationName) return;
|
||||
|
||||
setIsDownloadingPPTX(true);
|
||||
try {
|
||||
await downloadPresentationAsPPTX(
|
||||
project.sandbox.sandbox_url,
|
||||
`/workspace/${presentationPath}`,
|
||||
presentationName
|
||||
);
|
||||
toast.success('PPTX downloaded successfully');
|
||||
} catch (error) {
|
||||
console.error('Error downloading PPTX:', error);
|
||||
toast.error(`Failed to download PPTX: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
||||
} finally {
|
||||
setIsDownloadingPPTX(false);
|
||||
setIsDownloading(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -216,10 +196,10 @@ export function PresentPresentationToolView({
|
|||
variant="outline"
|
||||
size="sm"
|
||||
className="border-gray-300 text-gray-700 hover:bg-gray-50 dark:border-gray-600 dark:text-gray-300 dark:hover:bg-gray-950"
|
||||
disabled={isDownloadingPDF || isDownloadingPPTX}
|
||||
disabled={isDownloading}
|
||||
title="Download presentation as PDF or PPTX"
|
||||
>
|
||||
{(isDownloadingPDF || isDownloadingPPTX) ? (
|
||||
{isDownloading ? (
|
||||
<Loader2 className="h-4 w-4 mr-2 animate-spin" />
|
||||
) : (
|
||||
<Download className="h-4 w-4 mr-2" />
|
||||
|
@ -229,17 +209,17 @@ export function PresentPresentationToolView({
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-32">
|
||||
<DropdownMenuItem
|
||||
onClick={() => handlePDFDownload()}
|
||||
onClick={() => handleDownload(DownloadFormat.PDF)}
|
||||
className="cursor-pointer"
|
||||
disabled={isDownloadingPDF}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
<FileText className="h-4 w-4 mr-2" />
|
||||
PDF
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handlePPTXDownload()}
|
||||
onClick={() => handleDownload(DownloadFormat.PPTX)}
|
||||
className="cursor-pointer"
|
||||
disabled={isDownloadingPPTX}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
<Presentation className="h-4 w-4 mr-2" />
|
||||
PPTX
|
||||
|
|
|
@ -30,12 +30,13 @@ import {
|
|||
} from 'lucide-react';
|
||||
import { ToolViewProps } from '../types';
|
||||
import { formatTimestamp, extractToolData, getToolTitle } from '../utils';
|
||||
import { downloadPresentationAsPDF, downloadPresentationAsPPTX } from '../utils/presentation-utils';
|
||||
import { downloadPresentation } from '../utils/presentation-utils';
|
||||
import { constructHtmlPreviewUrl } from '@/lib/utils/url';
|
||||
import { CodeBlockCode } from '@/components/ui/code-block';
|
||||
import { LoadingState } from '../shared/LoadingState';
|
||||
import { FullScreenPresentationViewer } from './FullScreenPresentationViewer';
|
||||
import { toast } from 'sonner';
|
||||
import { DownloadFormat } from '../utils/presentation-utils';
|
||||
|
||||
interface SlideMetadata {
|
||||
title: string;
|
||||
|
@ -79,8 +80,7 @@ export function PresentationViewer({
|
|||
const [visibleSlide, setVisibleSlide] = useState<number | null>(null);
|
||||
const [isFullScreenOpen, setIsFullScreenOpen] = useState(false);
|
||||
const [fullScreenInitialSlide, setFullScreenInitialSlide] = useState<number | null>(null);
|
||||
const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
|
||||
const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
|
||||
// Extract presentation info from tool data
|
||||
const { toolResult } = extractToolData(toolContent);
|
||||
|
@ -476,34 +476,22 @@ export function PresentationViewer({
|
|||
return <SlideIframe slide={slide} />;
|
||||
}, [SlideIframe]);
|
||||
|
||||
|
||||
|
||||
|
||||
const handlePDFDownload = useCallback(async (setIsDownloadingPDF: (isDownloading: boolean) => void) => {
|
||||
const handleDownload = useCallback(async (setIsDownloading: (isDownloading: boolean) => void, format: DownloadFormat) => {
|
||||
|
||||
if (!project?.sandbox?.sandbox_url || !extractedPresentationName) return;
|
||||
|
||||
setIsDownloadingPDF(true);
|
||||
setIsDownloading(true);
|
||||
try{
|
||||
await downloadPresentationAsPDF(project.sandbox.sandbox_url, `/workspace/presentations/${extractedPresentationName}`, extractedPresentationName);
|
||||
if (format === DownloadFormat.GOOGLE_SLIDES){
|
||||
// TODO: Implement Google Slides download
|
||||
console.log('Downloading Google Slides');
|
||||
} else{
|
||||
await downloadPresentation(format, project.sandbox.sandbox_url, `/workspace/presentations/${extractedPresentationName}`, extractedPresentationName);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error downloading PDF:', error);
|
||||
} finally {
|
||||
setIsDownloadingPDF(false);
|
||||
}
|
||||
}, [project?.sandbox?.sandbox_url, extractedPresentationName]);
|
||||
|
||||
const handlePPTXDownload = useCallback(async (setIsDownloadingPPTX: (isDownloading: boolean) => void) => {
|
||||
|
||||
if (!project?.sandbox?.sandbox_url || !extractedPresentationName) return;
|
||||
|
||||
setIsDownloadingPPTX(true);
|
||||
try{
|
||||
await downloadPresentationAsPPTX(project.sandbox.sandbox_url, `/workspace/presentations/${extractedPresentationName}`, extractedPresentationName);
|
||||
} catch (error) {
|
||||
console.error('Error downloading PPTX:', error);
|
||||
} finally {
|
||||
setIsDownloadingPPTX(false);
|
||||
setIsDownloading(false);
|
||||
}
|
||||
}, [project?.sandbox?.sandbox_url, extractedPresentationName]);
|
||||
|
||||
|
@ -546,9 +534,9 @@ export function PresentationViewer({
|
|||
size="sm"
|
||||
className="h-8 w-8 p-0"
|
||||
title="Export presentation"
|
||||
disabled={isDownloadingPDF || isDownloadingPPTX}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
{(isDownloadingPDF || isDownloadingPPTX) ? (
|
||||
{isDownloading ? (
|
||||
<Loader2 className="h-3.5 w-3.5 animate-spin" />
|
||||
) : (
|
||||
<Download className="h-3.5 w-3.5" />
|
||||
|
@ -557,28 +545,25 @@ export function PresentationViewer({
|
|||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-32">
|
||||
<DropdownMenuItem
|
||||
onClick={() => handlePDFDownload(setIsDownloadingPDF)}
|
||||
onClick={() => handleDownload(setIsDownloading, DownloadFormat.PDF)}
|
||||
className="cursor-pointer"
|
||||
disabled={isDownloadingPDF}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
<FileText className="h-4 w-4 mr-2" />
|
||||
PDF
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => handlePPTXDownload(setIsDownloadingPPTX)}
|
||||
onClick={() => handleDownload(setIsDownloading, DownloadFormat.PPTX)}
|
||||
className="cursor-pointer"
|
||||
disabled={isDownloadingPPTX}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
<Presentation className="h-4 w-4 mr-2" />
|
||||
PPTX
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
// TODO: Implement Google Slides export
|
||||
console.log('Export to Google Slides');
|
||||
}}
|
||||
onClick={() => handleDownload(setIsDownloading, DownloadFormat.GOOGLE_SLIDES)}
|
||||
className="cursor-pointer"
|
||||
disabled={isDownloadingPDF || isDownloadingPPTX}
|
||||
disabled={isDownloading}
|
||||
>
|
||||
<ExternalLink className="h-4 w-4 mr-2" />
|
||||
Google Slides
|
||||
|
|
|
@ -1,3 +1,9 @@
|
|||
export enum DownloadFormat {
|
||||
PDF = 'pdf',
|
||||
PPTX = 'pptx',
|
||||
GOOGLE_SLIDES = 'google-slides',
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility functions for handling presentation slide file paths
|
||||
*/
|
||||
|
@ -63,13 +69,14 @@ export function createPresentationViewerToolContent(
|
|||
* @param presentationName - The name of the presentation for the downloaded file
|
||||
* @returns Promise that resolves when download is complete
|
||||
*/
|
||||
export async function downloadPresentationAsPDF(
|
||||
export async function downloadPresentation(
|
||||
format: DownloadFormat,
|
||||
sandboxUrl: string,
|
||||
presentationPath: string,
|
||||
presentationName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${sandboxUrl}/presentation/convert-to-pdf`, {
|
||||
const response = await fetch(`${sandboxUrl}/presentation/convert-to-${format}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
|
@ -81,59 +88,18 @@ export async function downloadPresentationAsPDF(
|
|||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to download PDF');
|
||||
throw new Error(`Failed to download ${format}`);
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${presentationName}.pdf`;
|
||||
a.download = `${presentationName}.${format}`;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Error downloading PDF:', error);
|
||||
throw error; // Re-throw to allow calling code to handle
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a presentation as PPTX
|
||||
* @param sandboxUrl - The sandbox URL for the API endpoint
|
||||
* @param presentationPath - The path to the presentation in the workspace
|
||||
* @param presentationName - The name of the presentation for the downloaded file
|
||||
* @returns Promise that resolves when download is complete
|
||||
*/
|
||||
export async function downloadPresentationAsPPTX(
|
||||
sandboxUrl: string,
|
||||
presentationPath: string,
|
||||
presentationName: string
|
||||
): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${sandboxUrl}/presentation/convert-to-pptx`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
presentation_path: presentationPath,
|
||||
download: true
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to download PPTX');
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `${presentationName}.pptx`;
|
||||
a.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
} catch (error) {
|
||||
console.error('Error downloading PPTX:', error);
|
||||
console.error(`Error downloading ${format}:`, error);
|
||||
throw error; // Re-throw to allow calling code to handle
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,8 @@ import CreateAgentWorkflowToolView from '../create-agent-workflow/create-agent-w
|
|||
import ActivateAgentWorkflowToolView from '../activate-agent-workflow/activate-agent-workflow';
|
||||
import CreateAgentScheduledTriggerToolView from '../create-agent-scheduled-trigger/create-agent-scheduled-trigger';
|
||||
import ListAgentWorkflowsToolView from '../list-agent-workflows/list-agent-workflows';
|
||||
import { createPresentationViewerToolContent, parsePresentationSlidePath } from '../utils/presentation-utils';
|
||||
import { extractToolData } from '../utils';
|
||||
|
||||
|
||||
export type ToolViewComponent = React.ComponentType<ToolViewProps>;
|
||||
|
|
Loading…
Reference in New Issue