Skip to content

Commit 4bf41f8

Browse files
committed
Remove react dialog
1 parent cee7797 commit 4bf41f8

1 file changed

Lines changed: 0 additions & 358 deletions

File tree

src/views/ChartifactDialog.tsx

Lines changed: 0 additions & 358 deletions
Original file line numberDiff line numberDiff line change
@@ -1,368 +1,10 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4-
import React, { FC, useState, useEffect, useRef } from 'react';
5-
import {
6-
Dialog,
7-
DialogTitle,
8-
DialogContent,
9-
DialogActions,
10-
Button,
11-
Typography,
12-
TextField,
13-
Box,
14-
} from '@mui/material';
154
import { Chart, DictTable, FieldItem } from '../components/ComponentType';
165
import { assembleVegaChart, prepVisTable, exportTableToDsv } from '../app/utils';
176
import { ClientConfig } from '../app/dfSlice';
187

19-
// Chartifact library type declarations
20-
interface SpecReview<T> {
21-
pluginName: string;
22-
containerId: string;
23-
approvedSpec: T;
24-
blockedSpec?: T;
25-
reason?: string;
26-
}
27-
28-
interface SandboxedPreHydrateMessage {
29-
type: 'sandboxedPreHydrate';
30-
transactionId: number;
31-
specs: SpecReview<{}>[];
32-
}
33-
34-
interface SandboxOptions {
35-
onReady?: () => void;
36-
onError?: (error: Error) => void;
37-
onApprove: (message: SandboxedPreHydrateMessage) => SpecReview<{}>[];
38-
}
39-
40-
interface ChartifactSandbox {
41-
options: SandboxOptions;
42-
element: HTMLElement;
43-
iframe: HTMLIFrameElement;
44-
destroy(): void;
45-
send(markdown: string): void;
46-
}
47-
48-
interface ChartifactHtmlWrapper {
49-
htmlMarkdownWrapper: (title: string, markdown: string) => string;
50-
htmlJsonWrapper: (title: string, json: string) => string;
51-
}
52-
53-
const chartifactScripts = [
54-
'https://microsoft.github.io/chartifact/dist/v1/chartifact.sandbox.umd.js',
55-
'https://microsoft.github.io/chartifact/dist/v1/chartifact.html-wrapper.umd.js'
56-
];
57-
58-
// Type declarations for Chartifact global
59-
declare global {
60-
interface Window {
61-
Chartifact?: {
62-
sandbox: {
63-
Sandbox: new (
64-
elementOrSelector: string | HTMLElement,
65-
markdown: string,
66-
options: SandboxOptions
67-
) => ChartifactSandbox;
68-
};
69-
htmlWrapper: ChartifactHtmlWrapper;
70-
};
71-
}
72-
}
73-
74-
interface ChartifactDialogProps {
75-
open: boolean;
76-
onClose: () => void;
77-
reportContent: string;
78-
reportStyle: string;
79-
charts: Chart[];
80-
tables: DictTable[];
81-
conceptShelfItems: FieldItem[];
82-
config: ClientConfig;
83-
}
84-
85-
export const ChartifactDialog: FC<ChartifactDialogProps> = ({
86-
open,
87-
onClose,
88-
reportContent,
89-
reportStyle,
90-
charts,
91-
tables,
92-
conceptShelfItems,
93-
config
94-
}) => {
95-
const [source, setSource] = useState('');
96-
const [isConverting, setIsConverting] = useState(false);
97-
const [chartifactLoaded, setChartifactLoaded] = useState(false);
98-
const [sandboxReady, setSandboxReady] = useState(false);
99-
const [parentElement, setParentElement] = useState<HTMLDivElement | null>(null);
100-
const sandboxRef = useRef<ChartifactSandbox | null>(null);
101-
102-
// Load Chartifact scripts
103-
const loadChartifactScripts = async (): Promise<void> => {
104-
// Check if Chartifact is already loaded
105-
if (window.Chartifact?.sandbox && window.Chartifact?.htmlWrapper) {
106-
setChartifactLoaded(true);
107-
return;
108-
}
109-
110-
try {
111-
for (const src of chartifactScripts) {
112-
await new Promise<void>((resolve, reject) => {
113-
const script = document.createElement('script');
114-
script.src = src;
115-
script.onload = () => resolve();
116-
script.onerror = () => reject(new Error(`Failed to load ${src}`));
117-
document.head.appendChild(script);
118-
});
119-
}
120-
121-
// Verify that Chartifact was loaded correctly
122-
if (window.Chartifact?.sandbox && window.Chartifact?.htmlWrapper) {
123-
setChartifactLoaded(true);
124-
} else {
125-
throw new Error('Chartifact namespace not found after loading scripts');
126-
}
127-
} catch (error) {
128-
console.error('Error loading Chartifact scripts:', error);
129-
throw error;
130-
}
131-
};
132-
133-
// Initialize Chartifact sandbox
134-
const initializeSandbox = () => {
135-
if (!chartifactLoaded || !parentElement || !source) {
136-
return;
137-
}
138-
139-
try {
140-
sandboxRef.current = new window.Chartifact!.sandbox.Sandbox(parentElement, source, {
141-
onReady: () => {
142-
setSandboxReady(true);
143-
},
144-
onError: (error: any) => {
145-
console.error('Sandbox error:', error);
146-
},
147-
onApprove: (message: any) => {
148-
//TODO policy to approve unapproved on localhost
149-
const { specs } = message;
150-
return specs;
151-
},
152-
});
153-
} catch (error) {
154-
console.error('Error initializing Chartifact sandbox:', error);
155-
}
156-
};
157-
158-
// Check if sandbox is functional
159-
const isSandboxFunctional = (): boolean => {
160-
if (!sandboxRef.current || !sandboxRef.current.iframe) {
161-
return false;
162-
}
163-
164-
const iframe = sandboxRef.current.iframe;
165-
const contentWindow = iframe.contentWindow;
166-
167-
// Only recreate if we have clear evidence of a broken iframe
168-
// Missing contentWindow is a clear sign of tombstoning
169-
if (!contentWindow) {
170-
return false;
171-
}
172-
173-
// Missing or invalid src indicates a problem
174-
if (!iframe.src || iframe.src === 'about:blank') {
175-
return false;
176-
}
177-
178-
// For normal cases (including blob URLs), assume functional to preserve user state
179-
// Only the clear failures above will trigger recreation
180-
return true;
181-
}; // Load scripts when dialog opens
182-
useEffect(() => {
183-
if (open && !chartifactLoaded) {
184-
loadChartifactScripts();
185-
}
186-
}, [open, chartifactLoaded]);
187-
188-
// Initialize sandbox when dialog opens with all requirements ready
189-
useEffect(() => {
190-
if (open && chartifactLoaded && source && parentElement) {
191-
if (!isSandboxFunctional() || !sandboxReady) {
192-
// Destroy existing sandbox before creating new one
193-
if (sandboxRef.current) {
194-
if (sandboxRef.current.destroy) {
195-
sandboxRef.current.destroy();
196-
}
197-
sandboxRef.current = null;
198-
setSandboxReady(false);
199-
}
200-
initializeSandbox();
201-
} else if (sandboxRef.current) {
202-
sandboxRef.current.send(source);
203-
}
204-
}
205-
206-
// Cleanup function runs when dialog closes or component unmounts
207-
return () => {
208-
if (!open && sandboxRef.current) {
209-
if (sandboxRef.current.destroy) {
210-
sandboxRef.current.destroy();
211-
}
212-
sandboxRef.current = null;
213-
setSandboxReady(false);
214-
}
215-
};
216-
}, [open, chartifactLoaded, source, parentElement, charts, tables, conceptShelfItems, config]);
217-
218-
// Convert report content when dialog opens
219-
useEffect(() => {
220-
if (open && reportContent) {
221-
setIsConverting(true);
222-
convertToChartifact(reportContent, reportStyle, charts, tables, conceptShelfItems, config)
223-
.then(chartifactMarkdown => {
224-
setSource(chartifactMarkdown);
225-
setIsConverting(false);
226-
})
227-
.catch(error => {
228-
console.error('Error converting to Chartifact:', error);
229-
setSource('Error converting report to Chartifact format');
230-
setIsConverting(false);
231-
});
232-
}
233-
}, [open, reportContent]);
234-
235-
return (
236-
<Dialog
237-
open={open}
238-
onClose={onClose}
239-
maxWidth="xl"
240-
fullWidth
241-
PaperProps={{
242-
sx: {
243-
minHeight: '90vh',
244-
maxHeight: '90vh',
245-
}
246-
}}
247-
>
248-
<DialogTitle>
249-
<Typography variant="h5" component="div">
250-
Chartifact Report
251-
</Typography>
252-
</DialogTitle>
253-
<DialogContent dividers sx={{ display: 'flex', flexDirection: 'row', gap: 2, p: 2, overflow: 'hidden' }}>
254-
<Box sx={{ flex: 1, display: 'flex', flexDirection: 'column', gap: 1, minHeight: 0 }}>
255-
<Typography variant="body2" color="text.secondary">
256-
Source
257-
</Typography>
258-
<TextField
259-
multiline
260-
fullWidth
261-
value={source}
262-
onChange={(e) => setSource(e.target.value)}
263-
placeholder={isConverting ? "Converting report to Chartifact format..." : "Enter the report source here..."}
264-
variant="outlined"
265-
disabled={isConverting}
266-
sx={{
267-
flex: 1,
268-
minHeight: 0,
269-
display: 'flex',
270-
flexDirection: 'column',
271-
'& .MuiInputBase-root': {
272-
height: '100%',
273-
alignItems: 'flex-start',
274-
overflow: 'hidden',
275-
},
276-
'& .MuiInputBase-input': {
277-
fontFamily: 'monospace',
278-
fontSize: '0.875rem',
279-
overflow: 'auto !important',
280-
height: '100% !important',
281-
}
282-
}}
283-
/>
284-
</Box>
285-
<Box
286-
sx={{
287-
flex: 1,
288-
display: 'flex',
289-
flexDirection: 'column',
290-
gap: 1,
291-
minHeight: 0
292-
}}
293-
>
294-
<Typography variant="body2" color="text.secondary">
295-
Preview
296-
</Typography>
297-
<Box
298-
ref={setParentElement}
299-
sx={{
300-
flex: 1,
301-
minHeight: 0,
302-
border: '1px solid',
303-
borderColor: 'divider',
304-
borderRadius: 1,
305-
overflow: 'auto',
306-
position: 'relative',
307-
'& > iframe': {
308-
position: 'absolute',
309-
top: 0,
310-
left: 0,
311-
width: '100%',
312-
height: '100%',
313-
border: 'none',
314-
}
315-
}}
316-
/>
317-
</Box>
318-
</DialogContent>
319-
<DialogActions sx={{ justifyContent: 'space-between', px: 3, py: 2 }}>
320-
<Typography variant="caption" sx={{ color: 'text.secondary', fontSize: '0.75rem' }}>
321-
<a href="https://microsoft.github.io/chartifact/" target="_blank" rel="noopener noreferrer">
322-
Learn more about Chartifact
323-
</a>
324-
</Typography>
325-
<Box sx={{ display: 'flex', gap: 1 }}>
326-
<Button
327-
onClick={() => {
328-
const blob = new Blob([source], { type: 'text/markdown' });
329-
const url = URL.createObjectURL(blob);
330-
const a = document.createElement('a');
331-
a.href = url;
332-
a.download = 'chartifact-report.idoc.md';
333-
a.click();
334-
URL.revokeObjectURL(url);
335-
}}
336-
disabled={!source}
337-
>
338-
Download Markdown
339-
</Button>
340-
<Button
341-
onClick={() => {
342-
if (window.Chartifact?.htmlWrapper) {
343-
const html = window.Chartifact.htmlWrapper.htmlMarkdownWrapper('Chartifact Report', source);
344-
const blob = new Blob([html], { type: 'text/html' });
345-
const url = URL.createObjectURL(blob);
346-
const a = document.createElement('a');
347-
a.href = url;
348-
a.download = 'chartifact-report.html';
349-
a.click();
350-
URL.revokeObjectURL(url);
351-
}
352-
}}
353-
disabled={!source || !chartifactLoaded}
354-
>
355-
Download HTML
356-
</Button>
357-
<Button onClick={onClose} color="primary">
358-
Close
359-
</Button>
360-
</Box>
361-
</DialogActions>
362-
</Dialog>
363-
);
364-
};
365-
3668
// Function to generate CSS styling based on report type
3679
const generateStyleCSS = (style: string): string => {
36810
// Font families

0 commit comments

Comments
 (0)