retold-facto 0.0.4

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 (92) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.dockerignore +8 -0
  3. package/.quackage.json +19 -0
  4. package/Dockerfile +26 -0
  5. package/bin/retold-facto.js +909 -0
  6. package/examples/facto-government-data.sqlite +0 -0
  7. package/examples/government-data-catalog.json +137 -0
  8. package/examples/government-data-loader.js +1432 -0
  9. package/package.json +91 -0
  10. package/scripts/facto-download.js +425 -0
  11. package/source/Retold-Facto.js +1042 -0
  12. package/source/services/Retold-Facto-BeaconProvider.js +511 -0
  13. package/source/services/Retold-Facto-CatalogManager.js +1252 -0
  14. package/source/services/Retold-Facto-DataLakeService.js +1642 -0
  15. package/source/services/Retold-Facto-DatasetManager.js +417 -0
  16. package/source/services/Retold-Facto-IngestEngine.js +1315 -0
  17. package/source/services/Retold-Facto-ProjectionEngine.js +3960 -0
  18. package/source/services/Retold-Facto-RecordManager.js +360 -0
  19. package/source/services/Retold-Facto-SchemaManager.js +1110 -0
  20. package/source/services/Retold-Facto-SourceFolderScanner.js +2243 -0
  21. package/source/services/Retold-Facto-SourceManager.js +730 -0
  22. package/source/services/Retold-Facto-StoreConnectionManager.js +441 -0
  23. package/source/services/Retold-Facto-ThroughputMonitor.js +478 -0
  24. package/source/services/web-app/codemirror-entry.js +7 -0
  25. package/source/services/web-app/pict-app/Pict-Application-Facto-Configuration.json +9 -0
  26. package/source/services/web-app/pict-app/Pict-Application-Facto.js +70 -0
  27. package/source/services/web-app/pict-app/Pict-Facto-Bundle.js +11 -0
  28. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto-UI.js +66 -0
  29. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto.js +69 -0
  30. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Catalog.js +93 -0
  31. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Connections.js +42 -0
  32. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Datasets.js +605 -0
  33. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Projections.js +188 -0
  34. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Scanner.js +80 -0
  35. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Schema.js +116 -0
  36. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Sources.js +104 -0
  37. package/source/services/web-app/pict-app/views/PictView-Facto-Catalog.js +526 -0
  38. package/source/services/web-app/pict-app/views/PictView-Facto-Datasets.js +173 -0
  39. package/source/services/web-app/pict-app/views/PictView-Facto-Ingest.js +259 -0
  40. package/source/services/web-app/pict-app/views/PictView-Facto-Layout.js +191 -0
  41. package/source/services/web-app/pict-app/views/PictView-Facto-Projections.js +231 -0
  42. package/source/services/web-app/pict-app/views/PictView-Facto-Records.js +326 -0
  43. package/source/services/web-app/pict-app/views/PictView-Facto-Scanner.js +624 -0
  44. package/source/services/web-app/pict-app/views/PictView-Facto-Sources.js +201 -0
  45. package/source/services/web-app/pict-app/views/PictView-Facto-Throughput.js +456 -0
  46. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full-Configuration.json +14 -0
  47. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full.js +391 -0
  48. package/source/services/web-app/pict-app-full/providers/PictRouter-Facto-Configuration.json +56 -0
  49. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-BottomBar.js +68 -0
  50. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Connections.js +340 -0
  51. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboard.js +149 -0
  52. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboards.js +819 -0
  53. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Datasets.js +178 -0
  54. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-IngestJobs.js +99 -0
  55. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Layout.js +62 -0
  56. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-MappingEditor.js +158 -0
  57. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-ProjectionDetail.js +1120 -0
  58. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Projections.js +172 -0
  59. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-QueryPanel.js +119 -0
  60. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-RecordViewer.js +663 -0
  61. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Records.js +648 -0
  62. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Scanner.js +1017 -0
  63. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDetail.js +1404 -0
  64. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDocEditor.js +1036 -0
  65. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaEditor.js +636 -0
  66. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaResearch.js +357 -0
  67. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceDetail.js +822 -0
  68. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceEditor.js +1036 -0
  69. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceResearch.js +487 -0
  70. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Sources.js +165 -0
  71. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Throughput.js +439 -0
  72. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-TopBar.js +335 -0
  73. package/source/services/web-app/pict-app-full/views/projections/Facto-Projections-Constants.js +71 -0
  74. package/source/services/web-app/web/chart.min.js +20 -0
  75. package/source/services/web-app/web/codemirror-bundle.js +30099 -0
  76. package/source/services/web-app/web/css/facto-themes.css +467 -0
  77. package/source/services/web-app/web/css/facto.css +502 -0
  78. package/source/services/web-app/web/index.html +28 -0
  79. package/source/services/web-app/web/retold-facto.js +12138 -0
  80. package/source/services/web-app/web/retold-facto.js.map +1 -0
  81. package/source/services/web-app/web/retold-facto.min.js +2 -0
  82. package/source/services/web-app/web/retold-facto.min.js.map +1 -0
  83. package/source/services/web-app/web/simple/index.html +17 -0
  84. package/test/Facto_Browser_Integration_tests.js +798 -0
  85. package/test/RetoldFacto_tests.js +4117 -0
  86. package/test/fixtures/weather-readings.csv +17 -0
  87. package/test/fixtures/weather-stations.csv +9 -0
  88. package/test/model/MeadowModel-Extended.json +8497 -0
  89. package/test/model/MeadowModel-PICT.json +1 -0
  90. package/test/model/MeadowModel.json +1355 -0
  91. package/test/model/ddl/Facto.ddl +225 -0
  92. package/test/model/fable-configuration.json +14 -0
@@ -0,0 +1,1404 @@
1
+ const libPictView = require('pict-view');
2
+ const libPictSectionContent = require('pict-section-content');
3
+
4
+ const _ViewConfiguration =
5
+ {
6
+ ViewIdentifier: "Facto-Full-SchemaDetail",
7
+
8
+ DefaultRenderable: "Facto-Full-SchemaDetail-Content",
9
+ DefaultDestinationAddress: "#Facto-Full-Content-Container",
10
+
11
+ AutoRender: false,
12
+
13
+ CSS: /*css*/`
14
+ .facto-schema-detail-back {
15
+ display: inline-flex;
16
+ align-items: center;
17
+ gap: 0.35em;
18
+ color: var(--facto-text-secondary);
19
+ cursor: pointer;
20
+ font-size: 0.85em;
21
+ margin-bottom: 0.75em;
22
+ transition: color 0.15s;
23
+ }
24
+ .facto-schema-detail-back:hover {
25
+ color: var(--facto-brand);
26
+ }
27
+
28
+ /* Schema definition display */
29
+ .facto-schema-ddl-wrap {
30
+ background: var(--facto-bg-input, #0d1117);
31
+ border: 1px solid var(--facto-border-subtle);
32
+ border-radius: 8px;
33
+ padding: 1em 1.25em;
34
+ margin-bottom: 1.5em;
35
+ font-family: 'SF Mono', Consolas, monospace;
36
+ font-size: 0.85em;
37
+ white-space: pre-wrap;
38
+ color: var(--facto-text);
39
+ max-height: 300px;
40
+ overflow-y: auto;
41
+ }
42
+ .facto-schema-ddl-empty {
43
+ color: var(--facto-text-tertiary);
44
+ font-style: italic;
45
+ }
46
+ .facto-schema-edit-section {
47
+ margin-bottom: 1.5em;
48
+ }
49
+ .facto-schema-edit-section textarea {
50
+ width: 100%;
51
+ min-height: 150px;
52
+ font-family: 'SF Mono', Consolas, monospace;
53
+ font-size: 0.85em;
54
+ margin-bottom: 0.5em;
55
+ }
56
+ .facto-schema-edit-actions {
57
+ display: flex;
58
+ gap: 0.5em;
59
+ align-items: center;
60
+ }
61
+
62
+ /* Version history */
63
+ .facto-version-history {
64
+ margin-top: 1.5em;
65
+ }
66
+ .facto-version-history h2 {
67
+ font-size: 1em;
68
+ margin: 0 0 0.75em;
69
+ color: var(--facto-text-secondary);
70
+ text-transform: uppercase;
71
+ letter-spacing: 0.05em;
72
+ }
73
+
74
+ /* Linked datasets */
75
+ .facto-linked-datasets {
76
+ margin-top: 1.5em;
77
+ }
78
+ .facto-linked-datasets h2 {
79
+ font-size: 1em;
80
+ margin: 0 0 0.75em;
81
+ color: var(--facto-text-secondary);
82
+ text-transform: uppercase;
83
+ letter-spacing: 0.05em;
84
+ }
85
+ .facto-link-dataset-row {
86
+ display: flex;
87
+ gap: 0.5em;
88
+ align-items: center;
89
+ margin-top: 0.75em;
90
+ }
91
+ .facto-link-dataset-row select {
92
+ width: 300px;
93
+ margin-bottom: 0;
94
+ }
95
+
96
+ /* Documentation section */
97
+ .facto-doc-section {
98
+ margin-top: 1.5em;
99
+ }
100
+ .facto-doc-section-header {
101
+ display: flex;
102
+ align-items: center;
103
+ gap: 0.75em;
104
+ margin-bottom: 0.75em;
105
+ }
106
+ .facto-doc-section-header h2 {
107
+ font-size: 1em;
108
+ margin: 0;
109
+ color: var(--facto-text-secondary);
110
+ text-transform: uppercase;
111
+ letter-spacing: 0.05em;
112
+ }
113
+ .facto-edit-toggle {
114
+ display: inline-flex;
115
+ align-items: center;
116
+ gap: 0.35em;
117
+ padding: 0.25em 0.6em;
118
+ font-size: 0.75em;
119
+ border-radius: 4px;
120
+ cursor: pointer;
121
+ transition: background 0.15s, color 0.15s;
122
+ border: 1px solid var(--facto-border-subtle);
123
+ background: transparent;
124
+ color: var(--facto-text-tertiary);
125
+ }
126
+ .facto-edit-toggle:hover {
127
+ border-color: var(--facto-brand);
128
+ color: var(--facto-brand);
129
+ }
130
+ .facto-edit-toggle.active {
131
+ background: var(--facto-brand-a15);
132
+ border-color: var(--facto-brand);
133
+ color: var(--facto-brand);
134
+ }
135
+
136
+ /* Doc content */
137
+ .facto-doc-content-wrap {
138
+ background: var(--facto-bg-elevated);
139
+ border: 1px solid var(--facto-border-subtle);
140
+ border-radius: 8px;
141
+ padding: 1.5em 2em;
142
+ min-height: 100px;
143
+ }
144
+ .facto-doc-content-wrap h1 { font-size: 1.75em; color: var(--facto-text-heading); border-bottom: 1px solid var(--facto-border-subtle); padding-bottom: 0.3em; margin-top: 0; }
145
+ .facto-doc-content-wrap h2 { font-size: 1.4em; color: var(--facto-text-heading); border-bottom: 1px solid var(--facto-border-subtle); padding-bottom: 0.25em; margin-top: 1.5em; }
146
+ .facto-doc-content-wrap h3 { font-size: 1.15em; color: var(--facto-text-heading); margin-top: 1.25em; }
147
+ .facto-doc-content-wrap p { line-height: 1.7; color: var(--facto-text-secondary); margin: 0.75em 0; }
148
+ .facto-doc-content-wrap a { color: var(--facto-brand); }
149
+ .facto-doc-content-wrap code { background: var(--facto-brand-a10); color: var(--facto-brand); padding: 0.15em 0.35em; border-radius: 3px; font-size: 0.9em; }
150
+ .facto-doc-content-wrap pre { background: var(--facto-bg-input); border: 1px solid var(--facto-border-subtle); border-radius: 6px; padding: 1em; overflow-x: auto; color: var(--facto-text-heading); }
151
+ .facto-doc-content-wrap pre code { background: transparent; padding: 0; color: inherit; }
152
+ .facto-doc-content-wrap blockquote { border-left: 3px solid var(--facto-brand); padding: 0.5em 1em; margin: 1em 0; color: var(--facto-text-tertiary); background: var(--facto-brand-a05); border-radius: 0 4px 4px 0; }
153
+ .facto-doc-content-wrap img { max-width: 100%; height: auto; border-radius: 4px; margin: 0.5em 0; }
154
+ .facto-doc-content-wrap ul, .facto-doc-content-wrap ol { color: var(--facto-text-secondary); padding-left: 1.5em; line-height: 1.7; }
155
+
156
+ .facto-doc-list {
157
+ display: flex;
158
+ flex-wrap: wrap;
159
+ gap: 0.5em;
160
+ margin-bottom: 1em;
161
+ }
162
+ .facto-doc-item {
163
+ padding: 0.4em 0.75em;
164
+ background: var(--facto-bg-elevated);
165
+ border: 1px solid var(--facto-border-subtle);
166
+ border-radius: 6px;
167
+ font-size: 0.85em;
168
+ cursor: pointer;
169
+ color: var(--facto-text-secondary);
170
+ transition: border-color 0.15s, color 0.15s;
171
+ }
172
+ .facto-doc-item:hover { border-color: var(--facto-brand); color: var(--facto-text-heading); }
173
+ .facto-doc-item.active { border-color: var(--facto-brand); color: var(--facto-brand); background: var(--facto-brand-a10); }
174
+ .facto-doc-new-input {
175
+ display: flex;
176
+ gap: 0.5em;
177
+ align-items: center;
178
+ }
179
+ .facto-doc-new-input input {
180
+ width: 240px;
181
+ margin-bottom: 0;
182
+ }
183
+
184
+ /* Analyze records panel */
185
+ .facto-schema-analyze-panel {
186
+ background: var(--facto-bg-card);
187
+ border: 1px solid var(--facto-border);
188
+ border-radius: 8px;
189
+ padding: 1.25em;
190
+ margin-bottom: 1.5em;
191
+ }
192
+ .facto-schema-analyze-panel h2 {
193
+ font-size: 1em;
194
+ margin: 0 0 0.75em;
195
+ color: var(--facto-text-secondary);
196
+ text-transform: uppercase;
197
+ letter-spacing: 0.05em;
198
+ }
199
+ .facto-schema-analyze-controls {
200
+ display: flex;
201
+ gap: 0.75em;
202
+ align-items: center;
203
+ flex-wrap: wrap;
204
+ margin-bottom: 0.75em;
205
+ }
206
+ .facto-schema-analyze-controls select,
207
+ .facto-schema-analyze-controls input {
208
+ margin-bottom: 0;
209
+ }
210
+ .facto-schema-analyze-controls select {
211
+ max-width: 300px;
212
+ }
213
+ .facto-schema-analyze-controls input[type="number"] {
214
+ width: 80px;
215
+ }
216
+ .facto-schema-fields-table {
217
+ width: 100%;
218
+ border-collapse: collapse;
219
+ font-size: 0.85em;
220
+ margin-top: 0.75em;
221
+ }
222
+ .facto-schema-fields-table th {
223
+ text-align: left;
224
+ padding: 0.5em 0.6em;
225
+ border-bottom: 2px solid var(--facto-border);
226
+ color: var(--facto-text-heading);
227
+ font-size: 0.8em;
228
+ text-transform: uppercase;
229
+ letter-spacing: 0.04em;
230
+ }
231
+ .facto-schema-fields-table td {
232
+ padding: 0.4em 0.6em;
233
+ border-bottom: 1px solid var(--facto-border-subtle);
234
+ vertical-align: middle;
235
+ }
236
+ .facto-schema-fields-table input[type="text"] {
237
+ width: 100%;
238
+ margin-bottom: 0;
239
+ padding: 0.25em 0.4em;
240
+ font-size: 0.95em;
241
+ }
242
+ .facto-schema-fields-table select {
243
+ margin-bottom: 0;
244
+ padding: 0.25em 0.3em;
245
+ font-size: 0.95em;
246
+ }
247
+ .facto-schema-fields-table .facto-field-addr {
248
+ font-family: 'SF Mono', Consolas, monospace;
249
+ font-size: 0.9em;
250
+ color: var(--facto-text);
251
+ }
252
+ .facto-schema-fields-table .facto-field-sample {
253
+ font-family: 'SF Mono', Consolas, monospace;
254
+ font-size: 0.85em;
255
+ color: var(--facto-text-tertiary);
256
+ max-width: 180px;
257
+ overflow: hidden;
258
+ text-overflow: ellipsis;
259
+ white-space: nowrap;
260
+ }
261
+ .facto-schema-fields-table .facto-field-freq {
262
+ text-align: center;
263
+ color: var(--facto-text-secondary);
264
+ }
265
+ .facto-schema-analyze-actions {
266
+ display: flex;
267
+ gap: 0.5em;
268
+ margin-top: 1em;
269
+ }
270
+ `,
271
+
272
+ Templates:
273
+ [
274
+ {
275
+ Hash: "Facto-Full-SchemaDetail-Template",
276
+ Template: /*html*/`
277
+ <div class="facto-content">
278
+ <div class="facto-schema-detail-back" onclick="{~P~}.views['Facto-Full-SchemaDetail'].goBack()">
279
+ &#8592; Back to Schema Research
280
+ </div>
281
+
282
+ <div class="facto-content-header">
283
+ <h1 id="Facto-SchemaDetail-Title">Schema</h1>
284
+ </div>
285
+
286
+ <div id="Facto-SchemaDetail-Loading" style="color:var(--facto-text-secondary);">Loading schema...</div>
287
+ <div id="Facto-SchemaDetail-Error" class="facto-status facto-status-error" style="display:none;"></div>
288
+
289
+ <div id="Facto-SchemaDetail-Container" style="display:none;">
290
+ <div class="facto-record-meta" id="Facto-SchemaDetail-Meta"></div>
291
+
292
+ <div id="Facto-SchemaDetail-DDLSection"></div>
293
+
294
+ <div class="facto-schema-analyze-panel">
295
+ <h2>Generate Schema from Records</h2>
296
+ <div class="facto-schema-analyze-controls">
297
+ <label style="font-size:0.85em; color:var(--facto-text-secondary);">Dataset:</label>
298
+ <select id="Facto-SchemaDetail-AnalyzeDataset"><option value="">Select dataset...</option></select>
299
+ <label style="font-size:0.85em; color:var(--facto-text-secondary);">Source:</label>
300
+ <select id="Facto-SchemaDetail-AnalyzeSource"><option value="">Any source</option></select>
301
+ <label style="font-size:0.85em; color:var(--facto-text-secondary);">Samples:</label>
302
+ <input type="number" id="Facto-SchemaDetail-AnalyzeSampleSize" value="50" min="1" max="200">
303
+ <button class="facto-btn facto-btn-primary" onclick="pict.views['Facto-Full-SchemaDetail'].analyzeRecords()">Analyze Records</button>
304
+ </div>
305
+ <div id="Facto-SchemaDetail-AnalyzeStatus" style="display:none;"></div>
306
+ <div id="Facto-SchemaDetail-AnalyzeResults"></div>
307
+ </div>
308
+
309
+ <div class="facto-linked-datasets" id="Facto-SchemaDetail-LinkedDatasets"></div>
310
+
311
+ <div class="facto-doc-section">
312
+ <div class="facto-doc-section-header">
313
+ <h2>Documentation</h2>
314
+ <button class="facto-edit-toggle" id="Facto-SchemaDetail-EditToggle" onclick="{~P~}.views['Facto-Full-SchemaDetail'].toggleEditMode()">
315
+ &#9998; Edit
316
+ </button>
317
+ </div>
318
+ <div id="Facto-SchemaDetail-DocListWrap"></div>
319
+ <div id="Facto-SchemaDetail-ContentWrap" style="display:none;">
320
+ <div class="facto-doc-content-wrap" id="Facto-SchemaDetail-ContentDisplay"></div>
321
+ </div>
322
+ <div id="Facto-SchemaDetail-EditorWrap" style="display:none;">
323
+ <div id="Facto-SchemaDetail-EditorContainer"></div>
324
+ </div>
325
+ </div>
326
+
327
+ <div class="facto-version-history" id="Facto-SchemaDetail-VersionHistory"></div>
328
+ </div>
329
+ </div>
330
+ `
331
+ }
332
+ ],
333
+
334
+ Renderables:
335
+ [
336
+ {
337
+ RenderableHash: "Facto-Full-SchemaDetail-Content",
338
+ TemplateHash: "Facto-Full-SchemaDetail-Template",
339
+ DestinationAddress: "#Facto-Full-Content-Container",
340
+ RenderMethod: "replace"
341
+ }
342
+ ]
343
+ };
344
+
345
+ class FactoFullSchemaDetailView extends libPictView
346
+ {
347
+ constructor(pFable, pOptions, pServiceHash)
348
+ {
349
+ super(pFable, pOptions, pServiceHash);
350
+
351
+ this._CurrentIDSchema = null;
352
+ this._CurrentIDDoc = null;
353
+ this._CurrentDocName = '';
354
+ this._CurrentDocContent = '';
355
+ this._Documentation = [];
356
+ this._Versions = [];
357
+ this._LinkedDatasets = [];
358
+ this._SchemaData = null;
359
+ this._EditMode = false;
360
+ this._DDLEditMode = false;
361
+ }
362
+
363
+ onBeforeInitialize()
364
+ {
365
+ super.onBeforeInitialize();
366
+
367
+ if (!this.pict.providers.PictContent)
368
+ {
369
+ this.pict.addProvider('PictContent', { ProviderIdentifier: 'PictContent' }, libPictSectionContent.PictContentProvider);
370
+ }
371
+
372
+ return true;
373
+ }
374
+
375
+ loadSchema(pIDSchema, pIDDoc)
376
+ {
377
+ this._CurrentIDSchema = pIDSchema;
378
+ this._CurrentIDDoc = pIDDoc || null;
379
+ this.render();
380
+ }
381
+
382
+ onAfterRender()
383
+ {
384
+ super.onAfterRender();
385
+
386
+ if (!this._CurrentIDSchema)
387
+ {
388
+ let tmpLoading = document.getElementById('Facto-SchemaDetail-Loading');
389
+ if (tmpLoading) tmpLoading.textContent = 'No schema selected.';
390
+ return;
391
+ }
392
+
393
+ this._fetchAndDisplaySchema();
394
+ }
395
+
396
+ _fetchAndDisplaySchema()
397
+ {
398
+ let tmpProvider = this.pict.providers.Facto;
399
+ let tmpLoadingEl = document.getElementById('Facto-SchemaDetail-Loading');
400
+ let tmpErrorEl = document.getElementById('Facto-SchemaDetail-Error');
401
+
402
+ let tmpSummary = null;
403
+ let tmpDocumentation = null;
404
+ let tmpVersions = null;
405
+
406
+ let tmpSummaryPromise = tmpProvider.loadSchemaSummary(this._CurrentIDSchema);
407
+ let tmpDocsPromise = tmpProvider.loadSchemaDocumentation(this._CurrentIDSchema);
408
+ let tmpVersionsPromise = tmpProvider.loadSchemaVersions(this._CurrentIDSchema);
409
+
410
+ tmpSummaryPromise.then(
411
+ (pResponse) =>
412
+ {
413
+ if (pResponse && pResponse.Error)
414
+ {
415
+ if (tmpLoadingEl) tmpLoadingEl.style.display = 'none';
416
+ if (tmpErrorEl)
417
+ {
418
+ tmpErrorEl.textContent = 'Error loading schema: ' + pResponse.Error;
419
+ tmpErrorEl.style.display = 'block';
420
+ }
421
+ return;
422
+ }
423
+ tmpSummary = pResponse;
424
+ });
425
+
426
+ tmpDocsPromise.then(
427
+ (pResponse) =>
428
+ {
429
+ tmpDocumentation = (pResponse && pResponse.Documentation) ? pResponse.Documentation : [];
430
+ });
431
+
432
+ tmpVersionsPromise.then(
433
+ (pResponse) =>
434
+ {
435
+ tmpVersions = (pResponse && pResponse.Versions) ? pResponse.Versions : [];
436
+ });
437
+
438
+ Promise.all([tmpSummaryPromise, tmpDocsPromise, tmpVersionsPromise]).then(
439
+ () =>
440
+ {
441
+ if (!tmpSummary || !tmpSummary.Schema)
442
+ {
443
+ if (tmpLoadingEl) tmpLoadingEl.style.display = 'none';
444
+ if (tmpErrorEl)
445
+ {
446
+ tmpErrorEl.textContent = 'Schema not found';
447
+ tmpErrorEl.style.display = 'block';
448
+ }
449
+ return;
450
+ }
451
+
452
+ this._renderSchemaDetail(tmpSummary, tmpDocumentation, tmpVersions);
453
+ }).catch(
454
+ (pError) =>
455
+ {
456
+ if (tmpLoadingEl) tmpLoadingEl.style.display = 'none';
457
+ if (tmpErrorEl)
458
+ {
459
+ tmpErrorEl.textContent = 'Error loading schema: ' + (pError.message || pError);
460
+ tmpErrorEl.style.display = 'block';
461
+ }
462
+ });
463
+ }
464
+
465
+ _renderSchemaDetail(pSummary, pDocumentation, pVersions)
466
+ {
467
+ let tmpLoadingEl = document.getElementById('Facto-SchemaDetail-Loading');
468
+ let tmpContainer = document.getElementById('Facto-SchemaDetail-Container');
469
+ let tmpTitleEl = document.getElementById('Facto-SchemaDetail-Title');
470
+
471
+ if (tmpLoadingEl) tmpLoadingEl.style.display = 'none';
472
+ if (tmpContainer) tmpContainer.style.display = 'block';
473
+
474
+ let tmpSchema = pSummary.Schema;
475
+ this._SchemaData = tmpSchema;
476
+
477
+ if (tmpTitleEl)
478
+ {
479
+ tmpTitleEl.textContent = tmpSchema.Name || ('Schema #' + tmpSchema.IDSchema);
480
+ }
481
+
482
+ // Metadata cards
483
+ let tmpMetaEl = document.getElementById('Facto-SchemaDetail-Meta');
484
+ if (tmpMetaEl)
485
+ {
486
+ tmpMetaEl.innerHTML = this._buildMetaCards(tmpSchema, pSummary);
487
+ }
488
+
489
+ // Schema definition section
490
+ this._renderDDLSection(tmpSchema);
491
+
492
+ // Populate analyze dropdowns
493
+ this._populateAnalyzeDropdowns();
494
+
495
+ // Linked datasets
496
+ this._LinkedDatasets = pSummary.LinkedDatasets || [];
497
+ this._renderLinkedDatasets();
498
+
499
+ // Documentation
500
+ this._Documentation = pDocumentation;
501
+ this._renderDocList();
502
+
503
+ // Version history
504
+ this._Versions = pVersions;
505
+ this._renderVersionHistory();
506
+
507
+ // Auto-open document if specified
508
+ if (this._CurrentIDDoc)
509
+ {
510
+ this.selectDocument(this._CurrentIDDoc);
511
+ }
512
+ }
513
+
514
+ _buildMetaCards(pSchema, pSummary)
515
+ {
516
+ let tmpGUID = (pSchema.GUIDSchema || '').substring(0, 8) + '\u2026' + (pSchema.GUIDSchema || '').substring((pSchema.GUIDSchema || '').length - 4);
517
+ let tmpActive = pSchema.Active
518
+ ? '<span class="facto-badge facto-badge-success">Active</span>'
519
+ : '<span class="facto-badge facto-badge-muted">Inactive</span>';
520
+
521
+ let tmpHtml = '';
522
+
523
+ // Identity card
524
+ tmpHtml += '<div class="facto-record-meta-card">';
525
+ tmpHtml += '<h3>Schema Identity</h3>';
526
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">ID</span><span class="facto-record-meta-value">' + pSchema.IDSchema + '</span></div>';
527
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">GUID</span><span class="facto-record-meta-value">' + tmpGUID + '</span></div>';
528
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Hash</span><span class="facto-record-meta-value facto-hash-value">' + (pSchema.Hash || '\u2014') + '</span></div>';
529
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Status</span><span class="facto-record-meta-value">' + tmpActive + '</span></div>';
530
+ tmpHtml += '</div>';
531
+
532
+ // Schema info card
533
+ tmpHtml += '<div class="facto-record-meta-card">';
534
+ tmpHtml += '<h3>Schema Info</h3>';
535
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Type</span><span class="facto-record-meta-value"><span class="facto-badge facto-badge-primary">' + (pSchema.Type || '\u2014') + '</span></span></div>';
536
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Version</span><span class="facto-record-meta-value">' + (pSchema.Version || 0) + '</span></div>';
537
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Schema Hash</span><span class="facto-record-meta-value"><code style="font-size:0.8em;">' + (pSchema.SchemaHash || '\u2014') + '</code></span></div>';
538
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Description</span><span class="facto-record-meta-value">' + (pSchema.Description || '\u2014') + '</span></div>';
539
+ tmpHtml += '</div>';
540
+
541
+ // Statistics card
542
+ tmpHtml += '<div class="facto-record-meta-card">';
543
+ tmpHtml += '<h3>Statistics</h3>';
544
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Documents</span><span class="facto-record-meta-value">' + (pSummary.DocumentationCount || 0) + '</span></div>';
545
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Versions</span><span class="facto-record-meta-value">' + (pSummary.VersionCount || 0) + '</span></div>';
546
+ tmpHtml += '<div class="facto-record-meta-row"><span class="facto-record-meta-label">Linked Datasets</span><span class="facto-record-meta-value">' + (pSummary.LinkedDatasetCount || 0) + '</span></div>';
547
+ tmpHtml += '</div>';
548
+
549
+ return tmpHtml;
550
+ }
551
+
552
+ // ------------------------------------------------------------------
553
+ // Schema Definition Section
554
+ // ------------------------------------------------------------------
555
+
556
+ _renderDDLSection(pSchema)
557
+ {
558
+ let tmpEl = document.getElementById('Facto-SchemaDetail-DDLSection');
559
+ if (!tmpEl) return;
560
+
561
+ let tmpDDL = pSchema.SchemaDefinition || '';
562
+ let tmpHtml = '<div class="facto-schema-edit-section">';
563
+ tmpHtml += '<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.5em;">';
564
+ tmpHtml += '<h2 style="font-size:1em; margin:0; color:var(--facto-text-secondary); text-transform:uppercase; letter-spacing:0.05em;">Schema Definition (MicroDDL)</h2>';
565
+ tmpHtml += '<button class="facto-edit-toggle" id="Facto-SchemaDetail-DDLEditToggle" onclick="pict.views[\'Facto-Full-SchemaDetail\'].toggleDDLEdit()">' + (this._DDLEditMode ? '&#10003; Done' : '&#9998; Edit') + '</button>';
566
+ tmpHtml += '</div>';
567
+
568
+ if (this._DDLEditMode)
569
+ {
570
+ // Detect which tracking columns are already present
571
+ let tmpHasAuditing = /&CreateDate/i.test(tmpDDL) || /&UpdateDate/i.test(tmpDDL);
572
+ let tmpHasSoftDeletes = /\^Deleted/i.test(tmpDDL) || /&DeleteDate/i.test(tmpDDL);
573
+
574
+ tmpHtml += '<div style="display:flex; gap:0.5em; margin-bottom:0.5em; flex-wrap:wrap;">';
575
+ if (tmpHasAuditing)
576
+ {
577
+ tmpHtml += '<button class="facto-btn facto-btn-secondary facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].removeAuditingColumns()" title="Remove CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser">&#10005; Remove Auditing</button>';
578
+ }
579
+ else
580
+ {
581
+ tmpHtml += '<button class="facto-btn facto-btn-secondary facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].addAuditingColumns()" title="Add CreateDate, CreatingIDUser, UpdateDate, UpdatingIDUser">&#43; Add Auditing</button>';
582
+ }
583
+ if (tmpHasSoftDeletes)
584
+ {
585
+ tmpHtml += '<button class="facto-btn facto-btn-secondary facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].removeSoftDeleteColumns()" title="Remove Deleted, DeleteDate, DeletingIDUser">&#10005; Remove Soft Deletes</button>';
586
+ }
587
+ else
588
+ {
589
+ tmpHtml += '<button class="facto-btn facto-btn-secondary facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].addSoftDeleteColumns()" title="Add Deleted, DeleteDate, DeletingIDUser">&#43; Add Soft Deletes</button>';
590
+ }
591
+ tmpHtml += '</div>';
592
+
593
+ tmpHtml += '<textarea id="Facto-SchemaDetail-DDLInput">' + (tmpDDL || '') + '</textarea>';
594
+ tmpHtml += '<div class="facto-schema-edit-actions">';
595
+ tmpHtml += '<button class="facto-btn facto-btn-primary" onclick="pict.views[\'Facto-Full-SchemaDetail\'].saveDDL()">Save &amp; Version</button>';
596
+ tmpHtml += '<button class="facto-btn facto-btn-secondary" onclick="pict.views[\'Facto-Full-SchemaDetail\'].compileDDL()">Compile Preview</button>';
597
+ tmpHtml += '<input type="text" id="Facto-SchemaDetail-ChangeDesc" placeholder="Change description (optional)" style="flex:1; margin-bottom:0;">';
598
+ tmpHtml += '</div>';
599
+ tmpHtml += '<div id="Facto-SchemaDetail-CompilePreview" style="margin-top:0.75em;"></div>';
600
+ }
601
+ else
602
+ {
603
+ if (tmpDDL)
604
+ {
605
+ tmpHtml += '<div class="facto-schema-ddl-wrap">' + tmpDDL.replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</div>';
606
+ }
607
+ else
608
+ {
609
+ tmpHtml += '<div class="facto-schema-ddl-wrap facto-schema-ddl-empty">No schema definition yet. Click Edit to add a MicroDDL definition.</div>';
610
+ }
611
+ }
612
+
613
+ tmpHtml += '</div>';
614
+ tmpEl.innerHTML = tmpHtml;
615
+ }
616
+
617
+ toggleDDLEdit()
618
+ {
619
+ this._DDLEditMode = !this._DDLEditMode;
620
+ if (this._SchemaData)
621
+ {
622
+ this._renderDDLSection(this._SchemaData);
623
+ }
624
+ }
625
+
626
+ saveDDL()
627
+ {
628
+ let tmpDDLInput = document.getElementById('Facto-SchemaDetail-DDLInput');
629
+ let tmpChangeDesc = (document.getElementById('Facto-SchemaDetail-ChangeDesc') || {}).value || '';
630
+ if (!tmpDDLInput) return;
631
+
632
+ let tmpDDL = tmpDDLInput.value;
633
+ let tmpProvider = this.pict.providers.Facto;
634
+
635
+ tmpProvider.saveSchema(this._CurrentIDSchema,
636
+ {
637
+ SchemaDefinition: tmpDDL,
638
+ ChangeDescription: tmpChangeDesc
639
+ }).then(
640
+ (pResponse) =>
641
+ {
642
+ if (pResponse && pResponse.Error)
643
+ {
644
+ this.pict.providers.FactoUI.showToast('Error: ' + pResponse.Error, 'error');
645
+ return;
646
+ }
647
+
648
+ this.pict.providers.FactoUI.showToast('Schema saved (v' + (pResponse.Version || '?') + ')', 'ok');
649
+ this._DDLEditMode = false;
650
+
651
+ // Reload the full detail
652
+ this._fetchAndDisplaySchema();
653
+ });
654
+ }
655
+
656
+ compileDDL()
657
+ {
658
+ let tmpDDLInput = document.getElementById('Facto-SchemaDetail-DDLInput');
659
+ let tmpPreview = document.getElementById('Facto-SchemaDetail-CompilePreview');
660
+ if (!tmpDDLInput || !tmpPreview) return;
661
+
662
+ let tmpDDL = tmpDDLInput.value;
663
+ if (!tmpDDL)
664
+ {
665
+ tmpPreview.innerHTML = '<div class="facto-status facto-status-warn">Enter a MicroDDL definition first.</div>';
666
+ return;
667
+ }
668
+
669
+ this.pict.providers.Facto.compileSchemaDefinition(this._CurrentIDSchema, tmpDDL).then(
670
+ (pResponse) =>
671
+ {
672
+ if (pResponse && pResponse.Error)
673
+ {
674
+ tmpPreview.innerHTML = '<div class="facto-status facto-status-error">Compile error: ' + pResponse.Error + '</div>';
675
+ return;
676
+ }
677
+
678
+ tmpPreview.innerHTML = '<div class="facto-schema-ddl-wrap" style="max-height:200px;">' + JSON.stringify(pResponse, null, 2).replace(/</g, '&lt;').replace(/>/g, '&gt;') + '</div>';
679
+ });
680
+ }
681
+
682
+ // ------------------------------------------------------------------
683
+ // Add/Remove Tracking Columns
684
+ // ------------------------------------------------------------------
685
+
686
+ _getAuditingColumns()
687
+ {
688
+ return ['&CreateDate', '#CreatingIDUser', '&UpdateDate', '#UpdatingIDUser'];
689
+ }
690
+
691
+ _getSoftDeleteColumns()
692
+ {
693
+ return ['^Deleted', '&DeleteDate', '#DeletingIDUser'];
694
+ }
695
+
696
+ _getDDLLines()
697
+ {
698
+ let tmpInput = document.getElementById('Facto-SchemaDetail-DDLInput');
699
+ if (!tmpInput) return [];
700
+ return tmpInput.value.split('\n');
701
+ }
702
+
703
+ _setDDLLines(pLines)
704
+ {
705
+ let tmpInput = document.getElementById('Facto-SchemaDetail-DDLInput');
706
+ if (!tmpInput) return;
707
+ tmpInput.value = pLines.join('\n');
708
+ // Re-render the DDL section to update button states
709
+ if (this._SchemaData)
710
+ {
711
+ this._SchemaData.SchemaDefinition = tmpInput.value;
712
+ this._renderDDLSection(this._SchemaData);
713
+ }
714
+ }
715
+
716
+ _columnExistsInDDL(pLines, pColumnName)
717
+ {
718
+ // Check if a column name (without prefix symbol) exists in any line
719
+ let tmpLower = pColumnName.toLowerCase();
720
+ for (let i = 0; i < pLines.length; i++)
721
+ {
722
+ let tmpLine = pLines[i].trim();
723
+ if (tmpLine.length < 2) continue;
724
+ // Extract column name: first char is the symbol, rest is the name (possibly with size)
725
+ let tmpName = tmpLine.substring(1).split(' ')[0].trim();
726
+ if (tmpName.toLowerCase() === tmpLower)
727
+ {
728
+ return true;
729
+ }
730
+ }
731
+ return false;
732
+ }
733
+
734
+ addAuditingColumns()
735
+ {
736
+ let tmpLines = this._getDDLLines();
737
+ let tmpColumns = this._getAuditingColumns();
738
+
739
+ for (let i = 0; i < tmpColumns.length; i++)
740
+ {
741
+ let tmpColName = tmpColumns[i].substring(1);
742
+ if (!this._columnExistsInDDL(tmpLines, tmpColName))
743
+ {
744
+ tmpLines.push(tmpColumns[i]);
745
+ }
746
+ }
747
+
748
+ this._setDDLLines(tmpLines);
749
+ }
750
+
751
+ removeAuditingColumns()
752
+ {
753
+ let tmpLines = this._getDDLLines();
754
+ let tmpColumnNames = this._getAuditingColumns().map(function(c) { return c.substring(1).toLowerCase(); });
755
+
756
+ let tmpFiltered = tmpLines.filter(
757
+ function(pLine)
758
+ {
759
+ let tmpTrimmed = pLine.trim();
760
+ if (tmpTrimmed.length < 2) return true;
761
+ let tmpName = tmpTrimmed.substring(1).split(' ')[0].trim().toLowerCase();
762
+ return tmpColumnNames.indexOf(tmpName) < 0;
763
+ });
764
+
765
+ this._setDDLLines(tmpFiltered);
766
+ }
767
+
768
+ addSoftDeleteColumns()
769
+ {
770
+ let tmpLines = this._getDDLLines();
771
+ let tmpColumns = this._getSoftDeleteColumns();
772
+
773
+ for (let i = 0; i < tmpColumns.length; i++)
774
+ {
775
+ let tmpColName = tmpColumns[i].substring(1);
776
+ if (!this._columnExistsInDDL(tmpLines, tmpColName))
777
+ {
778
+ tmpLines.push(tmpColumns[i]);
779
+ }
780
+ }
781
+
782
+ this._setDDLLines(tmpLines);
783
+ }
784
+
785
+ removeSoftDeleteColumns()
786
+ {
787
+ let tmpLines = this._getDDLLines();
788
+ let tmpColumnNames = this._getSoftDeleteColumns().map(function(c) { return c.substring(1).toLowerCase(); });
789
+
790
+ let tmpFiltered = tmpLines.filter(
791
+ function(pLine)
792
+ {
793
+ let tmpTrimmed = pLine.trim();
794
+ if (tmpTrimmed.length < 2) return true;
795
+ let tmpName = tmpTrimmed.substring(1).split(' ')[0].trim().toLowerCase();
796
+ return tmpColumnNames.indexOf(tmpName) < 0;
797
+ });
798
+
799
+ this._setDDLLines(tmpFiltered);
800
+ }
801
+
802
+ // ------------------------------------------------------------------
803
+ // Analyze Records
804
+ // ------------------------------------------------------------------
805
+
806
+ _populateAnalyzeDropdowns()
807
+ {
808
+ let tmpProvider = this.pict.providers.Facto;
809
+
810
+ // Load datasets and sources if not already loaded
811
+ let tmpDatasetsReady = (this.pict.AppData.Facto.Datasets && this.pict.AppData.Facto.Datasets.length > 0);
812
+ let tmpSourcesReady = (this.pict.AppData.Facto.Sources && this.pict.AppData.Facto.Sources.length > 0);
813
+
814
+ let tmpPromises = [];
815
+ if (!tmpDatasetsReady) tmpPromises.push(tmpProvider.loadDatasets());
816
+ if (!tmpSourcesReady) tmpPromises.push(tmpProvider.loadSources());
817
+
818
+ if (tmpPromises.length > 0)
819
+ {
820
+ Promise.all(tmpPromises).then(() => { this._fillAnalyzeSelects(); });
821
+ }
822
+ else
823
+ {
824
+ this._fillAnalyzeSelects();
825
+ }
826
+ }
827
+
828
+ _fillAnalyzeSelects()
829
+ {
830
+ let tmpDatasetSelect = document.getElementById('Facto-SchemaDetail-AnalyzeDataset');
831
+ let tmpSourceSelect = document.getElementById('Facto-SchemaDetail-AnalyzeSource');
832
+
833
+ if (tmpDatasetSelect)
834
+ {
835
+ let tmpDatasets = this.pict.AppData.Facto.Datasets || [];
836
+ for (let i = 0; i < tmpDatasets.length; i++)
837
+ {
838
+ let tmpOpt = document.createElement('option');
839
+ tmpOpt.value = tmpDatasets[i].IDDataset;
840
+ tmpOpt.textContent = tmpDatasets[i].Name + ' (' + (tmpDatasets[i].Type || '') + ')';
841
+ tmpDatasetSelect.appendChild(tmpOpt);
842
+ }
843
+ }
844
+
845
+ if (tmpSourceSelect)
846
+ {
847
+ let tmpSources = this.pict.AppData.Facto.Sources || [];
848
+ for (let i = 0; i < tmpSources.length; i++)
849
+ {
850
+ let tmpOpt = document.createElement('option');
851
+ tmpOpt.value = tmpSources[i].IDSource;
852
+ tmpOpt.textContent = tmpSources[i].Name;
853
+ tmpSourceSelect.appendChild(tmpOpt);
854
+ }
855
+ }
856
+ }
857
+
858
+ analyzeRecords()
859
+ {
860
+ let tmpDatasetVal = (document.getElementById('Facto-SchemaDetail-AnalyzeDataset') || {}).value || '';
861
+ let tmpSourceVal = (document.getElementById('Facto-SchemaDetail-AnalyzeSource') || {}).value || '';
862
+ let tmpSampleSize = parseInt((document.getElementById('Facto-SchemaDetail-AnalyzeSampleSize') || {}).value, 10) || 50;
863
+
864
+ let tmpIDDataset = parseInt(tmpDatasetVal, 10) || 0;
865
+ let tmpIDSource = parseInt(tmpSourceVal, 10) || 0;
866
+
867
+ if (!tmpIDDataset && !tmpIDSource)
868
+ {
869
+ this.pict.providers.FactoUI.showToast('Select a dataset or source to analyze', 'error');
870
+ return;
871
+ }
872
+
873
+ let tmpStatusEl = document.getElementById('Facto-SchemaDetail-AnalyzeStatus');
874
+ let tmpResultsEl = document.getElementById('Facto-SchemaDetail-AnalyzeResults');
875
+ if (tmpStatusEl)
876
+ {
877
+ tmpStatusEl.style.display = 'block';
878
+ tmpStatusEl.className = 'facto-status facto-status-info';
879
+ tmpStatusEl.textContent = 'Analyzing records...';
880
+ }
881
+ if (tmpResultsEl) tmpResultsEl.innerHTML = '';
882
+
883
+ this.pict.providers.Facto.analyzeRecords(tmpIDDataset, tmpIDSource, tmpSampleSize).then(
884
+ (pResponse) =>
885
+ {
886
+ if (tmpStatusEl) tmpStatusEl.style.display = 'none';
887
+
888
+ if (pResponse && pResponse.Error)
889
+ {
890
+ if (tmpStatusEl)
891
+ {
892
+ tmpStatusEl.className = 'facto-status facto-status-error';
893
+ tmpStatusEl.textContent = 'Error: ' + pResponse.Error;
894
+ tmpStatusEl.style.display = 'block';
895
+ }
896
+ return;
897
+ }
898
+
899
+ this._AnalyzedFields = pResponse.Fields || [];
900
+ this._AnalyzedRecordCount = pResponse.RecordsAnalyzed || 0;
901
+ this._renderAnalyzeResults();
902
+ });
903
+ }
904
+
905
+ _renderAnalyzeResults()
906
+ {
907
+ let tmpResultsEl = document.getElementById('Facto-SchemaDetail-AnalyzeResults');
908
+ if (!tmpResultsEl) return;
909
+
910
+ let tmpFields = this._AnalyzedFields || [];
911
+ if (tmpFields.length === 0)
912
+ {
913
+ tmpResultsEl.innerHTML = '<div class="facto-empty">No fields discovered in the sampled records.</div>';
914
+ return;
915
+ }
916
+
917
+ let tmpTypeOptions = ['String', 'Number', 'Integer', 'Float', 'Boolean', 'DateTime', 'Array', 'Object'];
918
+ let tmpTotalRecords = this._AnalyzedRecordCount || 1;
919
+
920
+ let tmpHtml = '<div style="font-size:0.85em; color:var(--facto-text-secondary); margin-bottom:0.5em;">Discovered <strong>' + tmpFields.length + '</strong> fields across <strong>' + tmpTotalRecords + '</strong> records</div>';
921
+ tmpHtml += '<table class="facto-schema-fields-table">';
922
+ tmpHtml += '<thead><tr>';
923
+ tmpHtml += '<th style="width:30px;"><input type="checkbox" id="Facto-SchemaDetail-AnalyzeSelectAll" checked onchange="pict.views[\'Facto-Full-SchemaDetail\'].toggleAllAnalyzedFields(this.checked)"></th>';
924
+ tmpHtml += '<th>Address</th><th>Hash</th><th>Name</th><th>DataType</th><th>Freq</th><th>Sample</th>';
925
+ tmpHtml += '</tr></thead><tbody>';
926
+
927
+ for (let i = 0; i < tmpFields.length; i++)
928
+ {
929
+ let tmpField = tmpFields[i];
930
+ let tmpChecked = tmpField.InSchema ? ' checked' : '';
931
+ let tmpSample = (tmpField.SampleValues && tmpField.SampleValues.length > 0) ? String(tmpField.SampleValues[0]) : '';
932
+ if (tmpSample.length > 60) tmpSample = tmpSample.substring(0, 57) + '\u2026';
933
+
934
+ tmpHtml += '<tr>';
935
+ tmpHtml += '<td><input type="checkbox" class="facto-analyze-field-check" data-idx="' + i + '"' + tmpChecked + '></td>';
936
+ tmpHtml += '<td class="facto-field-addr">' + tmpField.Address + '</td>';
937
+ tmpHtml += '<td><input type="text" class="facto-analyze-field-hash" data-idx="' + i + '" value="' + (tmpField.Hash || '').replace(/"/g, '&quot;') + '"></td>';
938
+ tmpHtml += '<td><input type="text" class="facto-analyze-field-name" data-idx="' + i + '" value="' + (tmpField.Name || '').replace(/"/g, '&quot;') + '"></td>';
939
+ tmpHtml += '<td><select class="facto-analyze-field-type" data-idx="' + i + '">';
940
+ for (let j = 0; j < tmpTypeOptions.length; j++)
941
+ {
942
+ let tmpSelected = (tmpTypeOptions[j] === tmpField.DataType) ? ' selected' : '';
943
+ tmpHtml += '<option value="' + tmpTypeOptions[j] + '"' + tmpSelected + '>' + tmpTypeOptions[j] + '</option>';
944
+ }
945
+ tmpHtml += '</select></td>';
946
+ tmpHtml += '<td class="facto-field-freq">' + tmpField.Frequency + '/' + tmpTotalRecords + '</td>';
947
+ tmpHtml += '<td class="facto-field-sample" title="' + tmpSample.replace(/"/g, '&quot;') + '">' + tmpSample.replace(/</g, '&lt;') + '</td>';
948
+ tmpHtml += '</tr>';
949
+ }
950
+
951
+ tmpHtml += '</tbody></table>';
952
+ tmpHtml += '<div class="facto-schema-analyze-actions">';
953
+ tmpHtml += '<button class="facto-btn facto-btn-success" onclick="pict.views[\'Facto-Full-SchemaDetail\'].applyAnalyzedSchema()">Apply to Schema</button>';
954
+ tmpHtml += '<button class="facto-btn facto-btn-secondary" onclick="document.getElementById(\'Facto-SchemaDetail-AnalyzeResults\').innerHTML=\'\'">Clear</button>';
955
+ tmpHtml += '</div>';
956
+
957
+ tmpResultsEl.innerHTML = tmpHtml;
958
+ }
959
+
960
+ toggleAllAnalyzedFields(pChecked)
961
+ {
962
+ let tmpCheckboxes = document.querySelectorAll('.facto-analyze-field-check');
963
+ for (let i = 0; i < tmpCheckboxes.length; i++)
964
+ {
965
+ tmpCheckboxes[i].checked = pChecked;
966
+ }
967
+ }
968
+
969
+ applyAnalyzedSchema()
970
+ {
971
+ let tmpFields = this._AnalyzedFields || [];
972
+ if (tmpFields.length === 0) return;
973
+
974
+ // Read edited values from DOM
975
+ let tmpSelectedDescriptors = [];
976
+ let tmpDDLLines = [];
977
+
978
+ for (let i = 0; i < tmpFields.length; i++)
979
+ {
980
+ let tmpCheck = document.querySelector('.facto-analyze-field-check[data-idx="' + i + '"]');
981
+ if (!tmpCheck || !tmpCheck.checked) continue;
982
+
983
+ let tmpHash = (document.querySelector('.facto-analyze-field-hash[data-idx="' + i + '"]') || {}).value || tmpFields[i].Hash;
984
+ let tmpName = (document.querySelector('.facto-analyze-field-name[data-idx="' + i + '"]') || {}).value || tmpFields[i].Name;
985
+ let tmpType = (document.querySelector('.facto-analyze-field-type[data-idx="' + i + '"]') || {}).value || tmpFields[i].DataType;
986
+
987
+ tmpSelectedDescriptors.push(
988
+ {
989
+ Address: tmpFields[i].Address,
990
+ Hash: tmpHash,
991
+ Name: tmpName,
992
+ DataType: tmpType,
993
+ Default: tmpFields[i].SampleValues && tmpFields[i].SampleValues.length > 0 ? tmpFields[i].SampleValues[0] : ''
994
+ });
995
+
996
+ // Generate MicroDDL line
997
+ let tmpDDLCol = this._typeToMicroDDL(tmpType, tmpHash);
998
+ if (tmpDDLCol) tmpDDLLines.push(tmpDDLCol);
999
+ }
1000
+
1001
+ if (tmpSelectedDescriptors.length === 0)
1002
+ {
1003
+ this.pict.providers.FactoUI.showToast('No fields selected', 'error');
1004
+ return;
1005
+ }
1006
+
1007
+ // Build the schema name from the current schema
1008
+ let tmpTableName = (this._SchemaData && this._SchemaData.Name) ? this._SchemaData.Name.replace(/[^a-zA-Z0-9]/g, '') : 'GeneratedSchema';
1009
+ let tmpDDL = '!' + tmpTableName + '\n@ID' + tmpTableName + '\n' + tmpDDLLines.join('\n');
1010
+ let tmpManyfestJSON = JSON.stringify(tmpSelectedDescriptors, null, 2);
1011
+
1012
+ // Save to the schema
1013
+ this.pict.providers.Facto.saveSchema(this._CurrentIDSchema,
1014
+ {
1015
+ SchemaDefinition: tmpDDL,
1016
+ ManyfestDefinition: tmpManyfestJSON,
1017
+ ChangeDescription: 'Generated from record analysis (' + this._AnalyzedRecordCount + ' records)'
1018
+ }).then(
1019
+ (pResponse) =>
1020
+ {
1021
+ if (pResponse && pResponse.Error)
1022
+ {
1023
+ this.pict.providers.FactoUI.showToast('Error: ' + pResponse.Error, 'error');
1024
+ return;
1025
+ }
1026
+ this.pict.providers.FactoUI.showToast('Schema applied (v' + (pResponse.Version || '?') + ')', 'ok');
1027
+ this._DDLEditMode = false;
1028
+ this._fetchAndDisplaySchema();
1029
+ });
1030
+ }
1031
+
1032
+ _typeToMicroDDL(pType, pName)
1033
+ {
1034
+ switch (pType)
1035
+ {
1036
+ case 'String': return '$' + pName + ' 200';
1037
+ case 'Number': return '#' + pName;
1038
+ case 'Integer': return '#' + pName;
1039
+ case 'Float': return '.' + pName + ' 10,2';
1040
+ case 'Boolean': return '^' + pName;
1041
+ case 'DateTime': return '&' + pName;
1042
+ case 'Array': return '*' + pName;
1043
+ case 'Object': return '*' + pName;
1044
+ default: return '$' + pName + ' 200';
1045
+ }
1046
+ }
1047
+
1048
+ // ------------------------------------------------------------------
1049
+ // Linked Datasets
1050
+ // ------------------------------------------------------------------
1051
+
1052
+ _renderLinkedDatasets()
1053
+ {
1054
+ let tmpEl = document.getElementById('Facto-SchemaDetail-LinkedDatasets');
1055
+ if (!tmpEl) return;
1056
+
1057
+ let tmpHtml = '<h2>Linked Datasets</h2>';
1058
+
1059
+ if (this._LinkedDatasets && this._LinkedDatasets.length > 0)
1060
+ {
1061
+ tmpHtml += '<table><thead><tr><th>ID</th><th>Name</th><th>Type</th><th>Actions</th></tr></thead><tbody>';
1062
+ for (let i = 0; i < this._LinkedDatasets.length; i++)
1063
+ {
1064
+ let tmpDS = this._LinkedDatasets[i];
1065
+ tmpHtml += '<tr>';
1066
+ tmpHtml += '<td>' + (tmpDS.IDDataset || '') + '</td>';
1067
+ tmpHtml += '<td>' + (tmpDS.Name || '') + '</td>';
1068
+ tmpHtml += '<td><span class="facto-badge facto-badge-primary">' + (tmpDS.Type || '') + '</span></td>';
1069
+ tmpHtml += '<td>';
1070
+ tmpHtml += '<button class="facto-btn facto-btn-secondary facto-btn-small" onclick="pict.PictApplication.navigateTo(\'/Projection/' + tmpDS.IDDataset + '\')">View</button> ';
1071
+ tmpHtml += '<button class="facto-btn facto-btn-danger facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].unlinkDataset(' + tmpDS.IDDataset + ')">Unlink</button>';
1072
+ tmpHtml += '</td>';
1073
+ tmpHtml += '</tr>';
1074
+ }
1075
+ tmpHtml += '</tbody></table>';
1076
+ }
1077
+ else
1078
+ {
1079
+ tmpHtml += '<div class="facto-empty">No datasets linked to this schema yet.</div>';
1080
+ }
1081
+
1082
+ // Link a dataset control
1083
+ tmpHtml += '<div class="facto-link-dataset-row">';
1084
+ tmpHtml += '<select id="Facto-SchemaDetail-LinkDatasetSelect"><option value="">Select a dataset to link...</option></select>';
1085
+ tmpHtml += '<button class="facto-btn facto-btn-success facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].linkDataset()">Link Dataset</button>';
1086
+ tmpHtml += '</div>';
1087
+
1088
+ tmpEl.innerHTML = tmpHtml;
1089
+
1090
+ // Populate the select with available datasets
1091
+ this._populateDatasetSelect();
1092
+ }
1093
+
1094
+ _populateDatasetSelect()
1095
+ {
1096
+ let tmpSelect = document.getElementById('Facto-SchemaDetail-LinkDatasetSelect');
1097
+ if (!tmpSelect) return;
1098
+
1099
+ let tmpDatasets = this.pict.AppData.Facto.Datasets || [];
1100
+ let tmpLinkedIDs = {};
1101
+ if (this._LinkedDatasets)
1102
+ {
1103
+ for (let i = 0; i < this._LinkedDatasets.length; i++)
1104
+ {
1105
+ tmpLinkedIDs[this._LinkedDatasets[i].IDDataset] = true;
1106
+ }
1107
+ }
1108
+
1109
+ for (let i = 0; i < tmpDatasets.length; i++)
1110
+ {
1111
+ if (!tmpLinkedIDs[tmpDatasets[i].IDDataset])
1112
+ {
1113
+ let tmpOpt = document.createElement('option');
1114
+ tmpOpt.value = tmpDatasets[i].IDDataset;
1115
+ tmpOpt.textContent = tmpDatasets[i].Name + ' (' + (tmpDatasets[i].Type || '') + ')';
1116
+ tmpSelect.appendChild(tmpOpt);
1117
+ }
1118
+ }
1119
+ }
1120
+
1121
+ linkDataset()
1122
+ {
1123
+ let tmpSelect = document.getElementById('Facto-SchemaDetail-LinkDatasetSelect');
1124
+ if (!tmpSelect || !tmpSelect.value) return;
1125
+
1126
+ let tmpIDDataset = parseInt(tmpSelect.value, 10);
1127
+ this.pict.providers.Facto.linkSchemaToDataset(this._CurrentIDSchema, tmpIDDataset).then(
1128
+ (pResponse) =>
1129
+ {
1130
+ if (pResponse && pResponse.Error)
1131
+ {
1132
+ this.pict.providers.FactoUI.showToast('Error: ' + pResponse.Error, 'error');
1133
+ return;
1134
+ }
1135
+ this.pict.providers.FactoUI.showToast('Dataset linked', 'ok');
1136
+ this._fetchAndDisplaySchema();
1137
+ });
1138
+ }
1139
+
1140
+ unlinkDataset(pIDDataset)
1141
+ {
1142
+ if (!confirm('Unlink this dataset from the schema?')) return;
1143
+ this.pict.providers.Facto.unlinkSchemaFromDataset(this._CurrentIDSchema, pIDDataset).then(
1144
+ (pResponse) =>
1145
+ {
1146
+ if (pResponse && pResponse.Error)
1147
+ {
1148
+ this.pict.providers.FactoUI.showToast('Error: ' + pResponse.Error, 'error');
1149
+ return;
1150
+ }
1151
+ this.pict.providers.FactoUI.showToast('Dataset unlinked', 'ok');
1152
+ this._fetchAndDisplaySchema();
1153
+ });
1154
+ }
1155
+
1156
+ // ------------------------------------------------------------------
1157
+ // Version History
1158
+ // ------------------------------------------------------------------
1159
+
1160
+ _renderVersionHistory()
1161
+ {
1162
+ let tmpEl = document.getElementById('Facto-SchemaDetail-VersionHistory');
1163
+ if (!tmpEl) return;
1164
+
1165
+ let tmpHtml = '<h2>Version History</h2>';
1166
+
1167
+ if (this._Versions && this._Versions.length > 0)
1168
+ {
1169
+ tmpHtml += '<table><thead><tr><th>Version</th><th>Hash</th><th>Change Description</th><th>Date</th></tr></thead><tbody>';
1170
+ for (let i = 0; i < this._Versions.length; i++)
1171
+ {
1172
+ let tmpVer = this._Versions[i];
1173
+ let tmpHash = tmpVer.SchemaHash || '';
1174
+ if (tmpHash.length > 12) tmpHash = tmpHash.substring(0, 12) + '\u2026';
1175
+ let tmpDate = tmpVer.CreateDate || '';
1176
+ if (tmpDate && tmpDate.length > 19) tmpDate = tmpDate.substring(0, 19);
1177
+ tmpHtml += '<tr>';
1178
+ tmpHtml += '<td><strong>v' + (tmpVer.Version || 0) + '</strong></td>';
1179
+ tmpHtml += '<td><code style="font-size:0.8em;">' + tmpHash + '</code></td>';
1180
+ tmpHtml += '<td>' + (tmpVer.ChangeDescription || '\u2014') + '</td>';
1181
+ tmpHtml += '<td>' + tmpDate + '</td>';
1182
+ tmpHtml += '</tr>';
1183
+ }
1184
+ tmpHtml += '</tbody></table>';
1185
+ }
1186
+ else
1187
+ {
1188
+ tmpHtml += '<div class="facto-empty">No versions yet. Save a schema definition to create the first version.</div>';
1189
+ }
1190
+
1191
+ tmpEl.innerHTML = tmpHtml;
1192
+ }
1193
+
1194
+ // ------------------------------------------------------------------
1195
+ // Documentation
1196
+ // ------------------------------------------------------------------
1197
+
1198
+ _renderDocList()
1199
+ {
1200
+ let tmpEl = document.getElementById('Facto-SchemaDetail-DocListWrap');
1201
+ if (!tmpEl) return;
1202
+
1203
+ let tmpHtml = '<div class="facto-doc-list">';
1204
+
1205
+ // New Document button
1206
+ tmpHtml += '<div class="facto-doc-new-input" id="Facto-SchemaDetail-NewDocWrap">';
1207
+ tmpHtml += '<input type="text" id="Facto-SchemaDetail-NewDocName" placeholder="Document name...">';
1208
+ tmpHtml += '<button class="facto-btn facto-btn-success facto-btn-small" onclick="pict.views[\'Facto-Full-SchemaDetail\'].createDocument()">New Document</button>';
1209
+ tmpHtml += '</div>';
1210
+
1211
+ tmpHtml += '</div>';
1212
+
1213
+ if (this._Documentation && this._Documentation.length > 0)
1214
+ {
1215
+ tmpHtml += '<div class="facto-doc-list">';
1216
+ for (let i = 0; i < this._Documentation.length; i++)
1217
+ {
1218
+ let tmpDoc = this._Documentation[i];
1219
+ let tmpActiveClass = (this._CurrentIDDoc && parseInt(this._CurrentIDDoc, 10) === tmpDoc.IDSchemaDocumentation) ? ' active' : '';
1220
+ tmpHtml += '<div class="facto-doc-item' + tmpActiveClass + '" onclick="pict.views[\'Facto-Full-SchemaDetail\'].selectDocument(' + tmpDoc.IDSchemaDocumentation + ')">';
1221
+ tmpHtml += (tmpDoc.Name || 'Untitled');
1222
+ tmpHtml += '</div>';
1223
+ }
1224
+ tmpHtml += '</div>';
1225
+ }
1226
+
1227
+ tmpEl.innerHTML = tmpHtml;
1228
+ }
1229
+
1230
+ selectDocument(pIDDoc)
1231
+ {
1232
+ let tmpProvider = this.pict.providers.Facto;
1233
+ this._CurrentIDDoc = pIDDoc;
1234
+
1235
+ if (window.history && window.history.replaceState)
1236
+ {
1237
+ window.history.replaceState(null, '', '#/Schema/' + this._CurrentIDSchema + '/Doc/' + pIDDoc);
1238
+ }
1239
+
1240
+ this._renderDocList();
1241
+
1242
+ tmpProvider.loadSchemaDocument(this._CurrentIDSchema, pIDDoc).then(
1243
+ (pResponse) =>
1244
+ {
1245
+ if (pResponse && pResponse.Error)
1246
+ {
1247
+ this.pict.log.error('Error loading document: ' + pResponse.Error);
1248
+ return;
1249
+ }
1250
+
1251
+ let tmpDoc = pResponse.Documentation;
1252
+ this._CurrentDocName = tmpDoc.Name || 'Untitled';
1253
+ this._CurrentDocContent = tmpDoc.Content || '';
1254
+
1255
+ this._showDocument();
1256
+ });
1257
+ }
1258
+
1259
+ _showDocument()
1260
+ {
1261
+ let tmpContentWrap = document.getElementById('Facto-SchemaDetail-ContentWrap');
1262
+ let tmpEditorWrap = document.getElementById('Facto-SchemaDetail-EditorWrap');
1263
+
1264
+ if (this._EditMode)
1265
+ {
1266
+ if (tmpContentWrap) tmpContentWrap.style.display = 'none';
1267
+ if (tmpEditorWrap) tmpEditorWrap.style.display = 'block';
1268
+
1269
+ let tmpEditorView = this.pict.views['Facto-Full-SchemaDocEditor'];
1270
+ if (tmpEditorView)
1271
+ {
1272
+ tmpEditorView.openEditor(this._CurrentIDSchema, this._CurrentIDDoc, this._CurrentDocName, this._CurrentDocContent);
1273
+ }
1274
+ }
1275
+ else
1276
+ {
1277
+ if (tmpEditorWrap) tmpEditorWrap.style.display = 'none';
1278
+ if (tmpContentWrap) tmpContentWrap.style.display = 'block';
1279
+
1280
+ this._renderReadOnlyContent();
1281
+ }
1282
+ }
1283
+
1284
+ _renderReadOnlyContent()
1285
+ {
1286
+ let tmpDisplayEl = document.getElementById('Facto-SchemaDetail-ContentDisplay');
1287
+ if (!tmpDisplayEl) return;
1288
+
1289
+ if (!this._CurrentDocContent)
1290
+ {
1291
+ tmpDisplayEl.innerHTML = '<p style="color:var(--facto-text-tertiary);">Empty document.</p>';
1292
+ return;
1293
+ }
1294
+
1295
+ let tmpHTML = this.pict.providers.PictContent.parseMarkdown(this._CurrentDocContent);
1296
+ tmpDisplayEl.innerHTML = tmpHTML;
1297
+ }
1298
+
1299
+ toggleEditMode()
1300
+ {
1301
+ let tmpToggleBtn = document.getElementById('Facto-SchemaDetail-EditToggle');
1302
+
1303
+ if (this._EditMode)
1304
+ {
1305
+ let tmpEditorView = this.pict.views['Facto-Full-SchemaDocEditor'];
1306
+ if (tmpEditorView)
1307
+ {
1308
+ let tmpResult = tmpEditorView.closeEditor();
1309
+ this._CurrentDocContent = tmpResult.Content;
1310
+ this._CurrentDocName = tmpResult.Name;
1311
+ }
1312
+
1313
+ this._EditMode = false;
1314
+ if (tmpToggleBtn)
1315
+ {
1316
+ tmpToggleBtn.innerHTML = '&#9998; Edit';
1317
+ tmpToggleBtn.classList.remove('active');
1318
+ }
1319
+ }
1320
+ else
1321
+ {
1322
+ this._EditMode = true;
1323
+ if (tmpToggleBtn)
1324
+ {
1325
+ tmpToggleBtn.innerHTML = '&#10003; Done';
1326
+ tmpToggleBtn.classList.add('active');
1327
+ }
1328
+ }
1329
+
1330
+ if (this._CurrentIDDoc)
1331
+ {
1332
+ this._showDocument();
1333
+ }
1334
+ }
1335
+
1336
+ createDocument()
1337
+ {
1338
+ let tmpNameInput = document.getElementById('Facto-SchemaDetail-NewDocName');
1339
+ let tmpName = tmpNameInput ? tmpNameInput.value.trim() : '';
1340
+ if (!tmpName)
1341
+ {
1342
+ let tmpUntitledCount = 0;
1343
+ if (this._Documentation)
1344
+ {
1345
+ for (let i = 0; i < this._Documentation.length; i++)
1346
+ {
1347
+ let tmpDocName = this._Documentation[i].Name || '';
1348
+ if (tmpDocName === 'Untitled' || tmpDocName.match(/^Untitled \d+$/))
1349
+ {
1350
+ tmpUntitledCount++;
1351
+ }
1352
+ }
1353
+ }
1354
+ tmpName = 'Untitled ' + (tmpUntitledCount + 1);
1355
+ }
1356
+
1357
+ let tmpProvider = this.pict.providers.Facto;
1358
+ tmpProvider.createSchemaDocument(this._CurrentIDSchema,
1359
+ {
1360
+ Name: tmpName,
1361
+ DocumentType: 'markdown',
1362
+ Content: '# ' + tmpName + '\n\n'
1363
+ }).then(
1364
+ (pResponse) =>
1365
+ {
1366
+ if (pResponse && pResponse.Success && pResponse.Documentation)
1367
+ {
1368
+ if (tmpNameInput) tmpNameInput.value = '';
1369
+
1370
+ let tmpNewID = pResponse.Documentation.IDSchemaDocumentation;
1371
+ return tmpProvider.loadSchemaDocumentation(this._CurrentIDSchema).then(
1372
+ (pDocsResponse) =>
1373
+ {
1374
+ this._Documentation = (pDocsResponse && pDocsResponse.Documentation) ? pDocsResponse.Documentation : [];
1375
+ this._renderDocList();
1376
+ this.selectDocument(tmpNewID);
1377
+ });
1378
+ }
1379
+ });
1380
+ }
1381
+
1382
+ onDocumentNameChanged(pIDDoc, pNewName)
1383
+ {
1384
+ for (let i = 0; i < this._Documentation.length; i++)
1385
+ {
1386
+ if (this._Documentation[i].IDSchemaDocumentation === parseInt(pIDDoc, 10))
1387
+ {
1388
+ this._Documentation[i].Name = pNewName;
1389
+ break;
1390
+ }
1391
+ }
1392
+ this._CurrentDocName = pNewName;
1393
+ this._renderDocList();
1394
+ }
1395
+
1396
+ goBack()
1397
+ {
1398
+ this.pict.PictApplication.navigateTo('/SchemaResearch');
1399
+ }
1400
+ }
1401
+
1402
+ module.exports = FactoFullSchemaDetailView;
1403
+
1404
+ module.exports.default_configuration = _ViewConfiguration;