]>
Commit | Line | Data |
---|---|---|
61568a65 | 1 | // avoid errors when running without development tools |
87ec83f4 TM |
2 | if (!Ext.isDefined(Ext.global.console)) { |
3 | var console = { | |
4 | dir: function() {}, | |
5 | log: function() {} | |
61568a65 DM |
6 | }; |
7 | } | |
8 | ||
9 | Ext.onReady(function() { | |
10 | ||
11 | Ext.define('pve-param-schema', { | |
12 | extend: 'Ext.data.Model', | |
87ec83f4 | 13 | fields: [ |
61e5a832 DM |
14 | 'name', 'type', 'typetext', 'description', 'verbose_description', |
15 | 'enum', 'minimum', 'maximum', 'minLength', 'maxLength', | |
61568a65 DM |
16 | 'pattern', 'title', 'requires', 'format', 'default', |
17 | 'disallow', 'extends', 'links', | |
18 | { | |
19 | name: 'optional', | |
20 | type: 'boolean' | |
21 | } | |
22 | ] | |
23 | }); | |
24 | ||
ab918a4f TM |
25 | var store = Ext.define('pve-updated-treestore', { |
26 | extend: 'Ext.data.TreeStore', | |
61568a65 DM |
27 | model: Ext.define('pve-api-doc', { |
28 | extend: 'Ext.data.Model', | |
87ec83f4 | 29 | fields: [ |
61568a65 DM |
30 | 'path', 'info', 'text', |
31 | ] | |
32 | }), | |
33 | proxy: { | |
34 | type: 'memory', | |
35 | data: pveapi | |
36 | }, | |
37 | sorters: [{ | |
38 | property: 'leaf', | |
39 | direction: 'ASC' | |
40 | }, { | |
41 | property: 'text', | |
42 | direction: 'ASC' | |
ab918a4f TM |
43 | }], |
44 | filterer: 'bottomup', | |
45 | doFilter: function(node) { | |
46 | this.filterNodes(node, this.getFilters().getFilterFn(), true); | |
47 | }, | |
48 | ||
49 | filterNodes: function(node, filterFn, parentVisible) { | |
50 | var me = this, | |
51 | bottomUpFiltering = me.filterer === 'bottomup', | |
52 | match = filterFn(node) && parentVisible || (node.isRoot() && !me.getRootVisible()), | |
53 | childNodes = node.childNodes, | |
54 | len = childNodes && childNodes.length, i, matchingChildren; | |
55 | ||
56 | if (len) { | |
57 | for (i = 0; i < len; ++i) { | |
58 | matchingChildren = me.filterNodes(childNodes[i], filterFn, match || bottomUpFiltering) || matchingChildren; | |
59 | } | |
60 | if (bottomUpFiltering) { | |
61 | match = matchingChildren || match; | |
62 | } | |
63 | } | |
64 | ||
65 | node.set("visible", match, me._silentOptions); | |
66 | return match; | |
67 | }, | |
68 | ||
69 | }).create(); | |
87ec83f4 | 70 | |
61e5a832 | 71 | var render_description = function(value, metaData, record) { |
61568a65 DM |
72 | var pdef = record.data; |
73 | ||
61e5a832 DM |
74 | value = pdef.verbose_description || value; |
75 | ||
6068d8ce | 76 | // TODO: try to render asciidoc correctly |
61e5a832 | 77 | |
61568a65 DM |
78 | metaData.style = 'white-space:pre-wrap;' |
79 | ||
80 | return Ext.htmlEncode(value); | |
81 | }; | |
82 | ||
83 | var render_type = function(value, metaData, record) { | |
84 | var pdef = record.data; | |
85 | ||
86 | return pdef['enum'] ? 'enum' : (pdef.type || 'string'); | |
87 | }; | |
88 | ||
89 | var render_format = function(value, metaData, record) { | |
90 | var pdef = record.data; | |
91 | ||
92 | metaData.style = 'white-space:normal;' | |
93 | ||
94 | if (pdef.typetext) | |
7f5866a3 | 95 | return Ext.htmlEncode(pdef.typetext); |
61568a65 DM |
96 | |
97 | if (pdef['enum']) | |
98 | return pdef['enum'].join(' | '); | |
99 | ||
87ec83f4 | 100 | if (pdef.format) |
61568a65 DM |
101 | return pdef.format; |
102 | ||
87ec83f4 | 103 | if (pdef.pattern) |
7f5866a3 | 104 | return Ext.htmlEncode(pdef.pattern); |
61568a65 DM |
105 | |
106 | return ''; | |
107 | }; | |
108 | ||
109 | var render_docu = function(data) { | |
110 | var md = data.info; | |
111 | ||
112 | // console.dir(data); | |
113 | ||
114 | var items = []; | |
115 | ||
116 | var clicmdhash = { | |
117 | GET: 'get', | |
118 | POST: 'create', | |
119 | PUT: 'set', | |
120 | DELETE: 'delete' | |
121 | }; | |
122 | ||
123 | Ext.Array.each(['GET', 'POST', 'PUT', 'DELETE'], function(method) { | |
124 | var info = md[method]; | |
125 | if (info) { | |
126 | ||
127 | var usage = ""; | |
128 | ||
129 | usage += "<table><tr><td>HTTP: </td><td>" + method + " /api2/json" + data.path + "</td></tr><tr><td> </td></tr>"; | |
130 | usage += "<tr><td>CLI:</td><td>pvesh " + clicmdhash[method] + " " + data.path + "</td></tr></table>"; | |
131 | ||
132 | var sections = [ | |
133 | { | |
134 | title: 'Description', | |
135 | html: Ext.htmlEncode(info.description), | |
136 | bodyPadding: 10 | |
137 | }, | |
138 | { | |
139 | title: 'Usage', | |
140 | html: usage, | |
141 | bodyPadding: 10 | |
142 | } | |
143 | ]; | |
144 | ||
145 | if (info.parameters && info.parameters.properties) { | |
146 | ||
147 | var pstore = Ext.create('Ext.data.Store', { | |
148 | model: 'pve-param-schema', | |
149 | proxy: { | |
150 | type: 'memory' | |
151 | }, | |
152 | groupField: 'optional', | |
153 | sorters: [ | |
154 | { | |
155 | property: 'name', | |
156 | direction: 'ASC' | |
157 | } | |
158 | ] | |
159 | }); | |
160 | ||
161 | Ext.Object.each(info.parameters.properties, function(name, pdef) { | |
162 | pdef.name = name; | |
163 | pstore.add(pdef); | |
164 | }); | |
165 | ||
166 | pstore.sort(); | |
167 | ||
168 | var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ | |
169 | enableGroupingMenu: false, | |
b2ff6d63 | 170 | groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Required</tpl>' |
61568a65 DM |
171 | }); |
172 | ||
173 | sections.push({ | |
174 | xtype: 'gridpanel', | |
175 | title: 'Parameters', | |
176 | features: [groupingFeature], | |
177 | store: pstore, | |
178 | viewConfig: { | |
179 | trackOver: false, | |
180 | stripeRows: true | |
181 | }, | |
182 | columns: [ | |
cd115543 | 183 | { |
61568a65 | 184 | header: 'Name', |
cd115543 TL |
185 | dataIndex: 'name', |
186 | flex: 1 | |
61568a65 | 187 | }, |
cd115543 | 188 | { |
61568a65 DM |
189 | header: 'Type', |
190 | dataIndex: 'type', | |
191 | renderer: render_type, | |
cd115543 | 192 | flex: 1 |
61568a65 | 193 | }, |
bc6d4d50 TL |
194 | { |
195 | header: 'Default', | |
196 | dataIndex: 'default', | |
cd115543 | 197 | flex: 1 |
bc6d4d50 TL |
198 | }, |
199 | { | |
61568a65 DM |
200 | header: 'Format', |
201 | dataIndex: 'type', | |
202 | renderer: render_format, | |
cd115543 | 203 | flex: 2 |
61568a65 | 204 | }, |
cd115543 | 205 | { |
61568a65 DM |
206 | header: 'Description', |
207 | dataIndex: 'description', | |
61e5a832 | 208 | renderer: render_description, |
cd115543 | 209 | flex: 6 |
61568a65 DM |
210 | } |
211 | ] | |
212 | }); | |
213 | ||
214 | } | |
215 | ||
216 | if (info.returns) { | |
217 | ||
69c4b956 TL |
218 | var retinf = info.returns; |
219 | var rtype = retinf.type; | |
220 | if (!rtype && retinf.items) | |
61568a65 DM |
221 | rtype = 'array'; |
222 | if (!rtype) | |
223 | rtype = 'object'; | |
224 | ||
8753d260 TM |
225 | var rpstore = Ext.create('Ext.data.Store', { |
226 | model: 'pve-param-schema', | |
227 | proxy: { | |
228 | type: 'memory' | |
229 | }, | |
230 | groupField: 'optional', | |
231 | sorters: [ | |
232 | { | |
233 | property: 'name', | |
234 | direction: 'ASC' | |
235 | } | |
236 | ] | |
237 | }); | |
69c4b956 | 238 | |
8753d260 TM |
239 | var properties; |
240 | if (rtype === 'array' && retinf.items.properties) { | |
241 | properties = retinf.items.properties; | |
242 | } | |
69c4b956 | 243 | |
8753d260 TM |
244 | if (rtype === 'object' && retinf.properties) { |
245 | properties = retinf.properties; | |
246 | } | |
247 | ||
248 | Ext.Object.each(properties, function(name, pdef) { | |
249 | pdef.name = name; | |
250 | rpstore.add(pdef); | |
251 | }); | |
252 | ||
253 | rpstore.sort(); | |
254 | ||
255 | var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ | |
256 | enableGroupingMenu: false, | |
257 | groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Obligatory</tpl>' | |
258 | }); | |
259 | var returnhtml; | |
260 | if (retinf.items) { | |
261 | returnhtml = '<pre>items: ' + Ext.htmlEncode(JSON.stringify(retinf.items, null, 4)) + '</pre>'; | |
262 | } | |
263 | ||
264 | if (retinf.properties) { | |
265 | returnhtml = returnhtml || ''; | |
266 | returnhtml += '<pre>properties:' + Ext.htmlEncode(JSON.stringify(retinf.properties, null, 4)) + '</pre>'; | |
267 | } | |
268 | ||
269 | var rawSection = Ext.create('Ext.panel.Panel', { | |
b77cddaa | 270 | bodyPadding: '0px 10px 10px 10px', |
8753d260 TM |
271 | html: returnhtml, |
272 | hidden: true | |
273 | }); | |
274 | ||
275 | sections.push({ | |
276 | xtype: 'gridpanel', | |
277 | title: 'Returns: ' + rtype, | |
278 | features: [groupingFeature], | |
279 | store: rpstore, | |
280 | viewConfig: { | |
281 | trackOver: false, | |
282 | stripeRows: true | |
283 | }, | |
284 | columns: [ | |
285 | { | |
286 | header: 'Name', | |
287 | dataIndex: 'name', | |
288 | flex: 1 | |
289 | }, | |
290 | { | |
291 | header: 'Type', | |
292 | dataIndex: 'type', | |
293 | renderer: render_type, | |
294 | flex: 1 | |
295 | }, | |
296 | { | |
297 | header: 'Default', | |
298 | dataIndex: 'default', | |
299 | flex: 1 | |
300 | }, | |
301 | { | |
302 | header: 'Format', | |
303 | dataIndex: 'type', | |
304 | renderer: render_format, | |
305 | flex: 2 | |
306 | }, | |
307 | { | |
308 | header: 'Description', | |
309 | dataIndex: 'description', | |
310 | renderer: render_description, | |
311 | flex: 6 | |
312 | } | |
313 | ], | |
b77cddaa | 314 | bbar: [ |
8753d260 TM |
315 | { |
316 | xtype: 'button', | |
b77cddaa TL |
317 | text: 'Show RAW', |
318 | handler: function(btn) { | |
8753d260 | 319 | rawSection.setVisible(!rawSection.isVisible()); |
b77cddaa | 320 | btn.setText(rawSection.isVisible() ? 'Hide RAW' : 'Show RAW'); |
8753d260 TM |
321 | }} |
322 | ] | |
323 | }); | |
324 | ||
325 | sections.push(rawSection); | |
326 | ||
327 | ||
61568a65 DM |
328 | } |
329 | ||
330 | var permhtml = ''; | |
331 | if (!info.permissions) { | |
332 | permhtml = "Root only."; | |
333 | } else { | |
334 | if (info.permissions.description) { | |
335 | permhtml += "<div style='white-space:pre-wrap;padding-bottom:10px;'>" + | |
336 | Ext.htmlEncode(info.permissions.description) + "</div>"; | |
337 | } | |
338 | ||
339 | if (info.permissions.user) { | |
340 | if (!info.permissions.description) { | |
341 | if (info.permissions.user === 'world') { | |
4a0cf6f8 | 342 | permhtml += "Accessible without any authentication."; |
61568a65 | 343 | } else if (info.permissions.user === 'all') { |
4a0cf6f8 | 344 | permhtml += "Accessible by all authenticated users."; |
61568a65 | 345 | } else { |
87ec83f4 | 346 | permhtml += 'Onyl accessible by user "' + |
61568a65 DM |
347 | info.permissions.user + '"'; |
348 | } | |
349 | } | |
350 | } else if (info.permissions.check) { | |
87ec83f4 | 351 | permhtml += "<pre>Check: " + |
61568a65 DM |
352 | Ext.htmlEncode(Ext.JSON.encode(info.permissions.check)) + "</pre>"; |
353 | } else { | |
354 | permhtml += "Unknown systax!"; | |
355 | } | |
356 | } | |
78f5fcdc FG |
357 | if (!info.allowtoken) { |
358 | permhtml += "<br />This API endpoint is not available for API tokens." | |
359 | } | |
61568a65 DM |
360 | |
361 | sections.push({ | |
362 | title: 'Required permissions', | |
363 | bodyPadding: 10, | |
364 | html: permhtml | |
365 | }); | |
87ec83f4 TM |
366 | |
367 | ||
61568a65 DM |
368 | items.push({ |
369 | title: method, | |
370 | autoScroll: true, | |
371 | defaults: { | |
372 | border: false | |
373 | }, | |
374 | items: sections | |
375 | }); | |
376 | } | |
377 | }); | |
378 | ||
379 | var ct = Ext.getCmp('docview'); | |
380 | ct.setTitle("Path: " + data.path); | |
381 | ct.removeAll(true); | |
382 | ct.add(items); | |
b4742419 | 383 | ct.setActiveTab(0); |
61568a65 DM |
384 | }; |
385 | ||
ab918a4f TM |
386 | Ext.define('Ext.form.SearchField', { |
387 | extend: 'Ext.form.field.Text', | |
388 | alias: 'widget.searchfield', | |
f081718e TL |
389 | |
390 | emptyText: 'Search...', | |
391 | ||
392 | flex: 1, | |
393 | ||
ab918a4f TM |
394 | inputType: 'search', |
395 | listeners: { | |
396 | 'change': function(){ | |
397 | ||
398 | var value = this.getValue(); | |
399 | if (!Ext.isEmpty(value)) { | |
400 | store.filter({ | |
401 | property: 'path', | |
402 | value: value, | |
403 | anyMatch: true | |
404 | }); | |
405 | } else { | |
406 | store.clearFilter(); | |
407 | } | |
408 | } | |
409 | } | |
410 | }); | |
411 | ||
61568a65 | 412 | var tree = Ext.create('Ext.tree.Panel', { |
ab918a4f TM |
413 | title: 'Resource Tree', |
414 | tbar: [ | |
415 | { | |
416 | xtype: 'searchfield', | |
417 | } | |
418 | ], | |
419 | tools: [ | |
420 | { | |
421 | type: 'expand', | |
afbe0fcc TL |
422 | tooltip: 'Expand all', |
423 | tooltipType: 'title', | |
424 | callback: (tree) => tree.expandAll(), | |
ab918a4f TM |
425 | }, |
426 | { | |
427 | type: 'collapse', | |
afbe0fcc TL |
428 | tooltip: 'Collapse all', |
429 | tooltipType: 'title', | |
430 | callback: (tree) => tree.collapseAll(), | |
ab918a4f TM |
431 | }, |
432 | ], | |
61568a65 DM |
433 | store: store, |
434 | width: 200, | |
435 | region: 'west', | |
436 | split: true, | |
437 | margins: '5 0 5 5', | |
438 | rootVisible: false, | |
439 | listeners: { | |
440 | selectionchange: function(v, selections) { | |
441 | if (!selections[0]) | |
442 | return; | |
443 | var rec = selections[0]; | |
444 | render_docu(rec.data); | |
16e6779d | 445 | location.hash = '#' + rec.data.path; |
61568a65 DM |
446 | } |
447 | } | |
448 | }); | |
449 | ||
450 | Ext.create('Ext.container.Viewport', { | |
451 | layout: 'border', | |
452 | renderTo: Ext.getBody(), | |
453 | items: [ | |
454 | tree, | |
455 | { | |
456 | xtype: 'tabpanel', | |
457 | title: 'Documentation', | |
458 | id: 'docview', | |
459 | region: 'center', | |
460 | margins: '5 5 5 0', | |
461 | layout: 'fit', | |
462 | items: [] | |
463 | } | |
464 | ] | |
465 | }); | |
466 | ||
16e6779d | 467 | var deepLink = function() { |
78bcda1d | 468 | var path = window.location.hash.substring(1).replace(/\/\s*$/, '') |
16e6779d TM |
469 | var endpoint = store.findNode('path', path); |
470 | ||
471 | if (endpoint) { | |
472 | tree.getSelectionModel().select(endpoint); | |
473 | tree.expandPath(endpoint.getPath()); | |
474 | render_docu(endpoint.data); | |
475 | } | |
476 | } | |
477 | window.onhashchange = deepLink; | |
478 | ||
479 | deepLink(); | |
480 | ||
61568a65 | 481 | }); |