This commit is contained in:
Krishav Raj Singh 2025-08-28 04:57:46 +05:30
parent 077b60fb3b
commit cf507c521e
5 changed files with 52 additions and 119 deletions

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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
}
}

View File

@ -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>;