@power-maverick/tool-erd-generator 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +118 -359
  2. package/index.html +18 -1
  3. package/package.json +13 -27
  4. package/tsconfig.json +20 -15
  5. package/{webview/vite.config.ts → vite.config.ts} +1 -1
  6. package/CONVERSION_SUMMARY.md +0 -288
  7. package/REFACTORING_COMPLETE.md +0 -352
  8. package/TYPESCRIPT_NOTES.md +0 -57
  9. package/dist/src/components/ERDGenerator.d.ts +0 -44
  10. package/dist/src/components/ERDGenerator.d.ts.map +0 -1
  11. package/dist/src/components/ERDGenerator.js +0 -232
  12. package/dist/src/components/ERDGenerator.js.map +0 -1
  13. package/dist/src/dvdtIntegration/integration.d.ts +0 -47
  14. package/dist/src/dvdtIntegration/integration.d.ts.map +0 -1
  15. package/dist/src/dvdtIntegration/integration.js +0 -223
  16. package/dist/src/dvdtIntegration/integration.js.map +0 -1
  17. package/dist/src/index.d.ts +0 -6
  18. package/dist/src/index.d.ts.map +0 -1
  19. package/dist/src/index.js +0 -26
  20. package/dist/src/index.js.map +0 -1
  21. package/dist/src/models/interfaces.d.ts +0 -84
  22. package/dist/src/models/interfaces.d.ts.map +0 -1
  23. package/dist/src/models/interfaces.js +0 -3
  24. package/dist/src/models/interfaces.js.map +0 -1
  25. package/dist/src/models/platformApi.d.ts +0 -92
  26. package/dist/src/models/platformApi.d.ts.map +0 -1
  27. package/dist/src/models/platformApi.js +0 -213
  28. package/dist/src/models/platformApi.js.map +0 -1
  29. package/dist/src/utils/Constants.d.ts +0 -3
  30. package/dist/src/utils/Constants.d.ts.map +0 -1
  31. package/dist/src/utils/Constants.js +0 -6
  32. package/dist/src/utils/Constants.js.map +0 -1
  33. package/dist/src/utils/DataverseClient.d.ts +0 -53
  34. package/dist/src/utils/DataverseClient.d.ts.map +0 -1
  35. package/dist/src/utils/DataverseClient.js +0 -236
  36. package/dist/src/utils/DataverseClient.js.map +0 -1
  37. package/dist/webview/index.css +0 -1
  38. package/dist/webview/index.html +0 -13
  39. package/dist/webview/index.js +0 -49
  40. package/tsconfig.webview.json +0 -24
  41. package/ui/test.html +0 -326
  42. package/webview/App.tsx +0 -412
  43. package/webview/index.html +0 -12
  44. package/webview/main.tsx +0 -10
  45. package/webview/styles.css +0 -288
  46. package/webview/tsconfig.json +0 -35
  47. /package/{webview/tsconfig.node.json → tsconfig.node.json} +0 -0
package/webview/App.tsx DELETED
@@ -1,412 +0,0 @@
1
- import { useEffect, useState } from "react";
2
- import { ERDGenerator } from "../src/components/ERDGenerator";
3
- import { DataverseSolution } from "../src/models/interfaces";
4
- import { IPlatformAPI, PlatformAPIFactory, ToolContext } from "../src/models/platformApi";
5
- import "../src/types/pptb.d.ts";
6
- import { DataverseClient } from "../src/utils/DataverseClient";
7
-
8
- // Declare Mermaid library (loaded externally for visualization)
9
- declare global {
10
- interface Window {
11
- mermaid?: {
12
- initialize: (config: any) => void;
13
- init: (config: any, element: HTMLElement | null) => void;
14
- };
15
- }
16
- }
17
-
18
- interface Solution {
19
- uniqueName: string;
20
- displayName: string;
21
- version: string;
22
- }
23
-
24
- function App() {
25
- // Platform API - automatically detects PPTB or DVDT
26
- const [platformAPI, setPlatformAPI] = useState<IPlatformAPI | null>(null);
27
- const [platformName, setPlatformName] = useState<string>("");
28
-
29
- const [connectionUrl, setConnectionUrl] = useState<string>("");
30
- const [accessToken, setAccessToken] = useState<string>("");
31
- const [solutions, setSolutions] = useState<Solution[]>([]);
32
- const [selectedSolution, setSelectedSolution] = useState<string>("");
33
- const [selectedFormat, setSelectedFormat] = useState<'mermaid' | 'plantuml' | 'graphviz'>('mermaid');
34
- const [loading, setLoading] = useState<boolean>(true);
35
- const [error, setError] = useState<string>("");
36
- const [generatedDiagram, setGeneratedDiagram] = useState<string>("");
37
- const [viewMode, setViewMode] = useState<'visual' | 'text'>('visual');
38
-
39
- // Configuration options
40
- const [includeAttributes, setIncludeAttributes] = useState<boolean>(true);
41
- const [includeRelationships, setIncludeRelationships] = useState<boolean>(true);
42
- const [maxAttributesPerTable, setMaxAttributesPerTable] = useState<number>(10);
43
-
44
- // Initialize platform API and detect environment
45
- useEffect(() => {
46
- const initializePlatform = async () => {
47
- setLoading(true);
48
-
49
- // For PPTB: Listen for TOOLBOX_CONTEXT via postMessage
50
- if (PlatformAPIFactory.isPPTB()) {
51
- const handlePPTBMessage = (event: MessageEvent) => {
52
- if (event.data && event.data.type === 'TOOLBOX_CONTEXT') {
53
- window.TOOLBOX_CONTEXT = event.data.data;
54
- console.log('[App] Received TOOLBOX_CONTEXT:', window.TOOLBOX_CONTEXT);
55
-
56
- // Re-create platform API with updated context
57
- const api = PlatformAPIFactory.create();
58
- setPlatformAPI(api);
59
- setPlatformName(api.getPlatformName());
60
-
61
- // Load context
62
- loadPlatformContext(api);
63
- }
64
- };
65
-
66
- window.addEventListener('message', handlePPTBMessage);
67
-
68
- // Try to create API immediately (context might already be available)
69
- try {
70
- const api = PlatformAPIFactory.create();
71
- setPlatformAPI(api);
72
- setPlatformName(api.getPlatformName());
73
- await loadPlatformContext(api);
74
- } catch (error) {
75
- console.error('[App] Failed to create PPTB API:', error);
76
- }
77
-
78
- return () => {
79
- window.removeEventListener('message', handlePPTBMessage);
80
- };
81
- }
82
- // For DVDT: Listen for credentials message
83
- else {
84
- const handleDVDTMessage = (event: MessageEvent) => {
85
- const message = event.data;
86
- if (message.command === 'setCredentials') {
87
- console.log('[App] Received DVDT credentials');
88
-
89
- const context: ToolContext = {
90
- toolId: null,
91
- connectionUrl: message.environmentUrl,
92
- accessToken: message.accessToken,
93
- };
94
-
95
- const api = PlatformAPIFactory.create(context);
96
- setPlatformAPI(api);
97
- setPlatformName(api.getPlatformName());
98
-
99
- setConnectionUrl(message.environmentUrl);
100
- setAccessToken(message.accessToken);
101
- setLoading(false);
102
- }
103
- };
104
-
105
- window.addEventListener('message', handleDVDTMessage);
106
-
107
- // Signal to DVDT that we're ready
108
- console.log('[App] Running in DVDT mode, waiting for credentials...');
109
-
110
- return () => {
111
- window.removeEventListener('message', handleDVDTMessage);
112
- };
113
- }
114
- };
115
-
116
- initializePlatform();
117
- }, []);
118
-
119
- // Helper to load context from platform API
120
- const loadPlatformContext = async (api: IPlatformAPI) => {
121
- try {
122
- const context = await api.getToolContext();
123
- console.log('[App] Loaded platform context:', context);
124
-
125
- setConnectionUrl(context.connectionUrl || "");
126
- setAccessToken(context.accessToken || "");
127
- setLoading(false);
128
- } catch (error) {
129
- console.error('[App] Failed to load platform context:', error);
130
- showError('Failed to load connection context');
131
- setLoading(false);
132
- }
133
- };
134
-
135
- // Load solutions when credentials are available
136
- useEffect(() => {
137
- if (connectionUrl && accessToken) {
138
- loadSolutions();
139
- }
140
- }, [connectionUrl, accessToken]);
141
-
142
- const loadSolutions = async () => {
143
- try {
144
- const client = new DataverseClient({
145
- environmentUrl: connectionUrl,
146
- accessToken: accessToken
147
- });
148
-
149
- const solutionList = await client.listSolutions();
150
- setSolutions(solutionList);
151
- } catch (error: any) {
152
- showError(`Failed to load solutions: ${error.message}`);
153
- }
154
- };
155
-
156
- const showError = (message: string) => {
157
- setError(message);
158
- setTimeout(() => setError(""), 5000);
159
- };
160
-
161
- const showNotification = async (title: string, body: string, type: 'success' | 'error' | 'info') => {
162
- if (platformAPI) {
163
- await platformAPI.showNotification({ title, body, type });
164
- }
165
- };
166
-
167
- const handleGenerateERD = async () => {
168
- if (!selectedSolution) {
169
- showError('Please select a solution first');
170
- return;
171
- }
172
-
173
- try {
174
- setLoading(true);
175
-
176
- const client = new DataverseClient({
177
- environmentUrl: connectionUrl,
178
- accessToken: accessToken
179
- });
180
-
181
- const solution: DataverseSolution = await client.fetchSolution(selectedSolution);
182
-
183
- const generator = new ERDGenerator({
184
- format: selectedFormat,
185
- includeAttributes,
186
- includeRelationships,
187
- maxAttributesPerTable
188
- });
189
-
190
- const diagram = generator.generate(solution);
191
- setGeneratedDiagram(diagram);
192
-
193
- await showNotification('Success', 'ERD generated successfully', 'success');
194
- } catch (error: any) {
195
- showError(`Failed to generate ERD: ${error.message}`);
196
- } finally {
197
- setLoading(false);
198
- }
199
- };
200
-
201
- const handleDownload = async () => {
202
- if (!generatedDiagram || !platformAPI) return;
203
-
204
- const extensions: Record<string, string> = {
205
- 'mermaid': 'mmd',
206
- 'plantuml': 'puml',
207
- 'graphviz': 'dot'
208
- };
209
-
210
- const fileName = `${selectedSolution}-erd.${extensions[selectedFormat]}`;
211
-
212
- try {
213
- const savedPath = await platformAPI.saveFile(fileName, generatedDiagram);
214
- if (savedPath) {
215
- await showNotification('Success', 'File saved successfully', 'success');
216
- }
217
- } catch (error: any) {
218
- showError(`Failed to save file: ${error.message}`);
219
- }
220
- };
221
-
222
- const handleCopyToClipboard = async () => {
223
- if (!generatedDiagram || !platformAPI) return;
224
-
225
- try {
226
- await platformAPI.copyToClipboard(generatedDiagram);
227
- await showNotification('Success', 'Copied to clipboard', 'success');
228
- } catch (error: any) {
229
- showError(`Failed to copy: ${error.message}`);
230
- }
231
- };
232
-
233
- const renderDiagram = () => {
234
- if (!generatedDiagram) return null;
235
-
236
- if (viewMode === 'visual' && selectedFormat === 'mermaid') {
237
- // Render Mermaid diagram
238
- return (
239
- <div
240
- className="mermaid-container"
241
- dangerouslySetInnerHTML={{ __html: generatedDiagram }}
242
- ref={(el) => {
243
- if (el && window.mermaid) {
244
- try {
245
- window.mermaid.init(undefined, el);
246
- } catch (error) {
247
- console.error('Mermaid rendering error:', error);
248
- }
249
- }
250
- }}
251
- />
252
- );
253
- } else {
254
- // Show text view
255
- return (
256
- <pre className="diagram-text">
257
- {generatedDiagram}
258
- </pre>
259
- );
260
- }
261
- };
262
-
263
- if (loading) {
264
- return (
265
- <div className="container">
266
- <div className="loading">Loading...</div>
267
- </div>
268
- );
269
- }
270
-
271
- return (
272
- <div className="container">
273
- <header className="header">
274
- <h1>🗺️ Dataverse ERD Generator</h1>
275
- <p>Generate Entity Relationship Diagrams from your Dataverse solutions</p>
276
- </header>
277
-
278
- {error && (
279
- <div className="error">
280
- {error}
281
- </div>
282
- )}
283
-
284
- <div className="card">
285
- <div className="info-message">
286
- <strong>✓ Connected to Dataverse</strong><br />
287
- Environment: <span>{connectionUrl || "Not connected"}</span>
288
- </div>
289
-
290
- <div className="form-group">
291
- <label htmlFor="solutionSelect">Select a Solution</label>
292
- <select
293
- id="solutionSelect"
294
- value={selectedSolution}
295
- onChange={(e) => setSelectedSolution(e.target.value)}
296
- disabled={solutions.length === 0}
297
- >
298
- <option value="">-- Select a Solution --</option>
299
- {solutions.map((solution) => (
300
- <option key={solution.uniqueName} value={solution.uniqueName}>
301
- {solution.displayName} ({solution.version})
302
- </option>
303
- ))}
304
- </select>
305
- </div>
306
-
307
- <div className="generate-section">
308
- <h2>Generate ERD</h2>
309
- <div className="format-selector">
310
- <label style={{ fontWeight: 600, marginRight: '10px' }}>Output Format:</label>
311
- <button
312
- className={`format-btn ${selectedFormat === 'mermaid' ? 'active' : ''}`}
313
- onClick={() => setSelectedFormat('mermaid')}
314
- >
315
- Mermaid
316
- </button>
317
- <button
318
- className={`format-btn ${selectedFormat === 'plantuml' ? 'active' : ''}`}
319
- onClick={() => setSelectedFormat('plantuml')}
320
- >
321
- PlantUML
322
- </button>
323
- <button
324
- className={`format-btn ${selectedFormat === 'graphviz' ? 'active' : ''}`}
325
- onClick={() => setSelectedFormat('graphviz')}
326
- >
327
- Graphviz
328
- </button>
329
- </div>
330
-
331
- <div className="config-section">
332
- <h3>Configuration</h3>
333
-
334
- <div className="config-group">
335
- <label>
336
- <input
337
- type="checkbox"
338
- checked={includeAttributes}
339
- onChange={(e) => setIncludeAttributes(e.target.checked)}
340
- />
341
- <span>Include Attributes</span>
342
- </label>
343
- <div className="config-help">Show table columns/fields in the diagram</div>
344
- </div>
345
-
346
- <div className="config-group">
347
- <label>
348
- <input
349
- type="checkbox"
350
- checked={includeRelationships}
351
- onChange={(e) => setIncludeRelationships(e.target.checked)}
352
- />
353
- <span>Include Relationships</span>
354
- </label>
355
- <div className="config-help">Show relationships between tables</div>
356
- </div>
357
-
358
- <div className="config-group">
359
- <div className="config-label-group">
360
- <label htmlFor="maxAttributesInput">Max Attributes per Table:</label>
361
- <input
362
- type="number"
363
- id="maxAttributesInput"
364
- value={maxAttributesPerTable}
365
- onChange={(e) => setMaxAttributesPerTable(parseInt(e.target.value) || 0)}
366
- min="0"
367
- max="100"
368
- />
369
- </div>
370
- <div className="config-help">Maximum number of attributes to display per table (0 = show all)</div>
371
- </div>
372
- </div>
373
-
374
- <button
375
- className="btn btn-primary"
376
- onClick={handleGenerateERD}
377
- disabled={!selectedSolution || loading}
378
- >
379
- Generate ERD
380
- </button>
381
- </div>
382
- </div>
383
-
384
- {generatedDiagram && (
385
- <div className="card">
386
- <h2>Generated ERD</h2>
387
- <div className="diagram-controls">
388
- {selectedFormat === 'mermaid' && (
389
- <button
390
- className="btn btn-secondary"
391
- onClick={() => setViewMode(viewMode === 'visual' ? 'text' : 'visual')}
392
- >
393
- {viewMode === 'visual' ? '📝 Show Text' : '🎨 Show Visual'}
394
- </button>
395
- )}
396
- <button className="btn btn-secondary" onClick={handleDownload}>
397
- 📥 Download Source
398
- </button>
399
- <button className="btn btn-secondary" onClick={handleCopyToClipboard}>
400
- 📋 Copy to Clipboard
401
- </button>
402
- </div>
403
- <div className="diagram-container">
404
- {renderDiagram()}
405
- </div>
406
- </div>
407
- )}
408
- </div>
409
- );
410
- }
411
-
412
- export default App;
@@ -1,12 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Dataverse ERD Generator</title>
7
- </head>
8
- <body>
9
- <div id="root"></div>
10
- <script type="module" src="/main.tsx"></script>
11
- </body>
12
- </html>
package/webview/main.tsx DELETED
@@ -1,10 +0,0 @@
1
- import { StrictMode } from 'react';
2
- import { createRoot } from 'react-dom/client';
3
- import App from './App';
4
- import './styles.css';
5
-
6
- createRoot(document.getElementById('root')!).render(
7
- <StrictMode>
8
- <App />
9
- </StrictMode>
10
- );