CoolFace
Apppublic

admin08077/Githubgemini

sourceHugging Faceotherupdated 10mo agoView on Hugging Face
0likes
PrSummaryGenerator-BY4XKruc.js.map1 linesDownload Raw Back to assets
1{"version":3,"file":"PrSummaryGenerator-BY4XKruc.js","sources":["../../services/workspaceService.ts","../../components/features/AiPullRequestAssistant.tsx"],"sourcesContent":["\n\nimport { ensureGapiClient } from './googleApiService.ts';\nimport { logError } from './telemetryService.ts';\nimport type { SlideSummary } from '../types.ts';\n\ndeclare var gapi: any;\n\n// --- Docs Service ---\nexport const createDocument = async (title: string): Promise<{ documentId: string; webViewLink: string }> => {\n    try {\n        const isReady = await ensureGapiClient();\n        if (!isReady) throw new Error(\"Google API client not ready.\");\n        \n        await gapi.client.load('https://docs.googleapis.com/$discovery/rest?version=v1');\n\n        const response = await gapi.client.docs.documents.create({ title });\n        const doc = response.result;\n        return { documentId: doc.documentId, webViewLink: `https://docs.google.com/document/d/${doc.documentId}/edit` };\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'createDocument' });\n        throw error;\n    }\n};\n\nexport const insertText = async (documentId: string, text: string): Promise<void> => {\n     try {\n        const isReady = await ensureGapiClient();\n        if (!isReady) throw new Error(\"Google API client not ready.\");\n\n        await gapi.client.load('https://docs.googleapis.com/$discovery/rest?version=v1');\n\n        await gapi.client.docs.documents.batchUpdate({\n            documentId,\n            resource: {\n                requests: [{\n                    insertText: {\n                        text: text,\n                        location: { index: 1 }\n                    }\n                }]\n            }\n        });\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'insertText' });\n        throw error;\n    }\n};\n\n// --- Drive Service ---\n\nconst getDriveClient = async () => {\n    const isReady = await ensureGapiClient();\n    if (!isReady) throw new Error(\"Google API client not ready.\");\n    await gapi.client.load('https://www.googleapis.com/discovery/v1/apis/drive/v3/rest');\n    return gapi.client.drive;\n};\n\nexport const findOrCreateFolder = async (folderName: string): Promise<string> => {\n    try {\n        const drive = await getDriveClient();\n        const query = `mimeType='application/vnd.google-apps.folder' and name='${folderName}' and trashed=false`;\n        const response = await drive.files.list({ q: query, fields: 'files(id, name)' });\n        \n        if (response.result.files && response.result.files.length > 0) {\n            return response.result.files[0].id;\n        } else {\n            const fileMetadata = {\n                name: folderName,\n                mimeType: 'application/vnd.google-apps.folder'\n            };\n            const createResponse = await drive.files.create({ resource: fileMetadata, fields: 'id' });\n            return createResponse.result.id;\n        }\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'findOrCreateFolder' });\n        throw error;\n    }\n};\n\nexport const uploadFile = async (folderId: string, fileName: string, content: string, mimeType: string): Promise<any> => {\n    try {\n        await getDriveClient(); // Ensures client is loaded\n        \n        const metadata = {\n            name: fileName,\n            parents: [folderId],\n            mimeType,\n        };\n        \n        const form = new FormData();\n        form.append('metadata', new Blob([JSON.stringify(metadata)], { type: 'application/json' }));\n        form.append('file', new Blob([content], { type: mimeType }));\n\n        const token = sessionStorage.getItem('google_access_token');\n        if (!token) throw new Error(\"Not authenticated\");\n\n        const res = await fetch('https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart', {\n            method: 'POST',\n            headers: {\n                Authorization: `Bearer ${token}`\n            },\n            body: form\n        });\n        \n        if (!res.ok) {\n            const errorBody = await res.json();\n            throw new Error(`Failed to upload file: ${errorBody.error.message}`);\n        }\n\n        return await res.json();\n    } catch (error) {\n        logError(error as Error, { service: 'workspaceService', function: 'uploadFile' });\n        throw error;\n    }\n};\n\n// Stubs for other Workspace services\nexport const appendRowToSheet = async (sheetId: string, rowData: any[]) => { console.log('appendRowToSheet called', sheetId, rowData); };\nexport const createTask = async (listId: string, title: string, notes: string) => { console.log('createTask called', listId, title, notes); };\nexport const createCalendarEvent = async (title: string, description: string, date: string) => { console.log('createCalendarEvent called', title, description, date); };","\nimport React, { useState, useMemo, useCallback } from 'react';\nimport * as Diff from 'diff';\nimport { generatePrSummaryStructured, generateTechnicalSpecFromDiff, downloadFile } from '../../services/index.ts';\nimport { createDocument, insertText } from '../../services/workspaceService.ts';\nimport type { StructuredPrSummary } from '../../types.ts';\nimport { AiPullRequestAssistantIcon, DocumentIcon } from '../icons.tsx';\nimport { LoadingSpinner } from '../shared/index.tsx';\nimport { useNotification } from '../../contexts/NotificationContext.tsx';\nimport { useGlobalState } from '../../contexts/GlobalStateContext.tsx';\n\nconst exampleBefore = `function Greeter(props) {\n  return <h1>Hello, {props.name}!</h1>;\n}`;\nconst exampleAfter = `function Greeter({ name, enthusiasmLevel = 1 }) {\n  const punctuation = '!'.repeat(enthusiasmLevel);\n  return <h1>Hello, {name}{punctuation}</h1>;\n}`;\n\nexport const AiPullRequestAssistant: React.FC = () => {\n    const [beforeCode, setBeforeCode] = useState<string>(exampleBefore);\n    const [afterCode, setAfterCode] = useState<string>(exampleAfter);\n    const [isLoading, setIsLoading] = useState<boolean>(false);\n    const [isExporting, setIsExporting] = useState<boolean>(false);\n    const [error, setError] = useState<string>('');\n    const [summary, setSummary] = useState<StructuredPrSummary | null>(null);\n\n    const { addNotification } = useNotification();\n    const { state } = useGlobalState();\n    const { user } = state;\n\n    const diff = useMemo(() => Diff.createPatch('component.tsx', beforeCode, afterCode), [beforeCode, afterCode]);\n\n    const handleGenerateSummary = useCallback(async () => {\n        if (!beforeCode.trim() && !afterCode.trim()) {\n            setError('Please provide code to generate a summary.');\n            return;\n        }\n        setIsLoading(true);\n        setError('');\n        setSummary(null);\n        \n        try {\n            const result: StructuredPrSummary = await generatePrSummaryStructured(diff);\n            setSummary(result);\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            setError(`Failed to generate summary: ${errorMessage}`);\n        } finally {\n            setIsLoading(false);\n        }\n    }, [diff, beforeCode, afterCode]);\n\n    const handleExportToDocs = async () => {\n        if (!summary || !user) {\n            addNotification('Please generate a summary first and ensure you are signed in.', 'error');\n            return;\n        }\n        setIsExporting(true);\n        try {\n            const specContent = await generateTechnicalSpecFromDiff(diff, summary);\n            const doc = await createDocument(`Tech Spec: ${summary.title}`);\n            await insertText(doc.documentId, specContent);\n            addNotification('Successfully exported to Google Docs!', 'success');\n            window.open(doc.webViewLink, '_blank');\n        } catch (err) {\n            const errorMessage = err instanceof Error ? err.message : 'An unknown error occurred.';\n            addNotification(`Failed to export: ${errorMessage}`, 'error');\n        } finally {\n            setIsExporting(false);\n        }\n    };\n    \n    return (\n        <div className=\"h-full flex flex-col p-4 sm:p-6 lg:p-8 text-text-primary\">\n            <header className=\"mb-6\">\n                <h1 className=\"text-3xl font-bold flex items-center\">\n                    <AiPullRequestAssistantIcon />\n                    <span className=\"ml-3\">AI Pull Request Assistant</span>\n                </h1>\n                <p className=\"text-text-secondary mt-1\">Generate a PR summary from code changes and export a full tech spec.</p>\n            </header>\n            <div className=\"flex-grow grid grid-cols-1 lg:grid-cols-2 gap-6 min-h-0\">\n                {/* Left side: Inputs and Generator */}\n                <div className=\"flex flex-col gap-4 min-h-0\">\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"before-code\" className=\"text-sm font-medium text-text-secondary mb-2\">Before</label>\n                        <textarea id=\"before-code\" value={beforeCode} onChange={e => setBeforeCode(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\" />\n                    </div>\n                    <div className=\"flex flex-col flex-1 min-h-0\">\n                        <label htmlFor=\"after-code\" className=\"text-sm font-medium text-text-secondary mb-2\">After</label>\n                        <textarea id=\"after-code\" value={afterCode} onChange={e => setAfterCode(e.target.value)} className=\"flex-grow p-4 bg-surface border border-border rounded-md resize-none font-mono text-sm\" />\n                    </div>\n                    <button onClick={handleGenerateSummary} disabled={isLoading} className=\"btn-primary w-full flex items-center justify-center px-6 py-3\">\n                        {isLoading ? <LoadingSpinner /> : 'Generate Summary'}\n                    </button>\n                    {error && <p className=\"text-red-500 text-xs text-center\">{error}</p>}\n                </div>\n\n                {/* Right side: Summary and Export */}\n                <div className=\"flex flex-col gap-4 min-h-0\">\n                    <div className=\"flex flex-col bg-surface border border-border p-4 rounded-lg flex-grow min-h-0\">\n                        <h3 className=\"text-lg font-bold mb-2\">Generated Summary</h3>\n                        <div className=\"flex-grow overflow-y-auto pr-2 space-y-2\">\n                            {summary ? (\n                                <>\n                                    <input type=\"text\" readOnly value={summary.title} className=\"w-full font-bold p-2 bg-background rounded\"/>\n                                    <textarea readOnly value={summary.summary} className=\"w-full h-24 p-2 bg-background rounded resize-none\"/>\n                                    <div>\n                                        <h4 className=\"font-semibold\">Changes:</h4>\n                                        <ul className=\"list-disc list-inside text-sm\">\n                                            {summary.changes.map((c, i) => <li key={i}>{c}</li>)}\n                                        </ul>\n                                    </div>\n                                </>\n                            ) : (\n                                <div className=\"text-text-secondary h-full flex items-center justify-center\">\n                                    {isLoading ? <LoadingSpinner /> : 'PR summary will appear here.'}\n                                </div>\n                            )}\n                        </div>\n                         {summary && user && (\n                            <div className=\"mt-4 pt-4 border-t border-border\">\n                                <button onClick={handleExportToDocs} disabled={isExporting} className=\"w-full btn-primary bg-blue-600 flex items-center justify-center gap-2 py-2\">\n                                    {isExporting ? <LoadingSpinner /> : <><DocumentIcon /> Export to Google Docs</>}\n                                </button>\n                            </div>\n                         )}\n                    </div>\n                </div>\n            </div>\n        </div>\n    );\n};\n"],"names":["createDocument","title","ensureGapiClient","doc","error","logError","insertText","documentId","text","exampleBefore","exampleAfter","AiPullRequestAssistant","beforeCode","setBeforeCode","useState","afterCode","setAfterCode","isLoading","setIsLoading","isExporting","setIsExporting","setError","summary","setSummary","addNotification","useNotification","state","useGlobalState","user","diff","useMemo","Diff.createPatch","handleGenerateSummary","useCallback","result","generatePrSummaryStructured","err","errorMessage","handleExportToDocs","specContent","generateTechnicalSpecFromDiff","jsxs","jsx","AiPullRequestAssistantIcon","e","LoadingSpinner","Fragment","c","i","DocumentIcon"],"mappings":"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"}