]>
Commit | Line | Data |
---|---|---|
410dc2c9 | 1 | // avoid errors when running without development tools |
ab3ca263 TL |
2 | if (!Ext.isDefined(Ext.global.console)) { |
3 | var console = { | |
4 | dir: function() {}, | |
5 | log: function() {} | |
410dc2c9 DM |
6 | }; |
7 | } | |
8 | ||
9 | Ext.onReady(function() { | |
10 | ||
11 | Ext.define('pmg-param-schema', { | |
12 | extend: 'Ext.data.Model', | |
ab3ca263 | 13 | fields: [ |
410dc2c9 DM |
14 | 'name', 'type', 'typetext', 'description', 'verbose_description', |
15 | 'enum', 'minimum', 'maximum', 'minLength', 'maxLength', | |
16 | 'pattern', 'title', 'requires', 'format', 'default', | |
17 | 'disallow', 'extends', 'links', | |
18 | { | |
19 | name: 'optional', | |
20 | type: 'boolean' | |
21 | } | |
22 | ] | |
23 | }); | |
24 | ||
622d092d TL |
25 | var store = Ext.define('pmg-updated-treestore', { |
26 | extend: 'Ext.data.TreeStore', | |
410dc2c9 | 27 | model: Ext.define('pmg-api-doc', { |
622d092d TL |
28 | extend: 'Ext.data.Model', |
29 | fields: [ | |
410dc2c9 DM |
30 | 'path', 'info', 'text', |
31 | ] | |
32 | }), | |
622d092d TL |
33 | proxy: { |
34 | type: 'memory', | |
35 | data: pmgapi | |
36 | }, | |
37 | sorters: [{ | |
38 | property: 'leaf', | |
39 | direction: 'ASC' | |
40 | }, { | |
41 | property: 'text', | |
42 | direction: 'ASC' | |
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(); | |
70 | ||
410dc2c9 DM |
71 | var render_description = function(value, metaData, record) { |
72 | var pdef = record.data; | |
73 | ||
74 | value = pdef.verbose_description || value; | |
75 | ||
76 | // TODO: try to render asciidoc correctly | |
77 | ||
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) | |
95 | return Ext.htmlEncode(pdef.typetext); | |
96 | ||
97 | if (pdef['enum']) | |
98 | return pdef['enum'].join(' | '); | |
99 | ||
ab3ca263 | 100 | if (pdef.format) |
410dc2c9 DM |
101 | return pdef.format; |
102 | ||
ab3ca263 | 103 | if (pdef.pattern) |
410dc2c9 DM |
104 | return Ext.htmlEncode(pdef.pattern); |
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>pmgsh " + 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: 'pmg-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, | |
170 | groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Required</tpl>' | |
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: [ | |
1a268897 | 183 | { |
410dc2c9 | 184 | header: 'Name', |
1a268897 TL |
185 | dataIndex: 'name', |
186 | flex: 1 | |
410dc2c9 | 187 | }, |
1a268897 | 188 | { |
410dc2c9 DM |
189 | header: 'Type', |
190 | dataIndex: 'type', | |
191 | renderer: render_type, | |
1a268897 | 192 | flex: 1 |
410dc2c9 | 193 | }, |
92a42334 TL |
194 | { |
195 | header: 'Default', | |
196 | dataIndex: 'default', | |
1a268897 | 197 | flex: 1 |
92a42334 TL |
198 | }, |
199 | { | |
410dc2c9 DM |
200 | header: 'Format', |
201 | dataIndex: 'type', | |
202 | renderer: render_format, | |
1a268897 | 203 | flex: 2 |
410dc2c9 | 204 | }, |
1a268897 | 205 | { |
410dc2c9 DM |
206 | header: 'Description', |
207 | dataIndex: 'description', | |
208 | renderer: render_description, | |
1a268897 | 209 | flex: 6 |
410dc2c9 DM |
210 | } |
211 | ] | |
212 | }); | |
213 | ||
214 | } | |
215 | ||
216 | if (info.returns) { | |
217 | ||
ab3ca263 TL |
218 | var retinf = info.returns; |
219 | var rtype = retinf.type; | |
220 | if (!rtype && retinf.items) | |
410dc2c9 DM |
221 | rtype = 'array'; |
222 | if (!rtype) | |
223 | rtype = 'object'; | |
224 | ||
622d092d TL |
225 | var rpstore = Ext.create('Ext.data.Store', { |
226 | model: 'pmg-param-schema', | |
227 | proxy: { | |
228 | type: 'memory' | |
229 | }, | |
230 | groupField: 'optional', | |
231 | sorters: [ | |
232 | { | |
233 | property: 'name', | |
234 | direction: 'ASC' | |
235 | } | |
236 | ] | |
237 | }); | |
238 | ||
239 | var properties; | |
240 | if (rtype === 'array' && retinf.items.properties) { | |
241 | properties = retinf.items.properties; | |
242 | } | |
243 | ||
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', { | |
270 | bodyPadding: '0px 10px 10px 10px', | |
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 | ], | |
314 | bbar: [ | |
315 | { | |
316 | xtype: 'button', | |
317 | text: 'Show RAW', | |
318 | handler: function(btn) { | |
319 | rawSection.setVisible(!rawSection.isVisible()); | |
320 | btn.setText(rawSection.isVisible() ? 'Hide RAW' : 'Show RAW'); | |
321 | }} | |
322 | ] | |
323 | }); | |
324 | ||
325 | sections.push(rawSection); | |
326 | ||
327 | ||
410dc2c9 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') { | |
ab3ca263 | 342 | permhtml += "Accessible without any authentication."; |
410dc2c9 | 343 | } else if (info.permissions.user === 'all') { |
ab3ca263 | 344 | permhtml += "Accessible by all authenticated users."; |
410dc2c9 | 345 | } else { |
ab3ca263 | 346 | permhtml += 'Onyl accessible by user "' + |
410dc2c9 DM |
347 | info.permissions.user + '"'; |
348 | } | |
349 | } | |
350 | } else if (info.permissions.check) { | |
ab3ca263 | 351 | permhtml += "<pre>Check: " + |
410dc2c9 DM |
352 | Ext.htmlEncode(Ext.JSON.encode(info.permissions.check)) + "</pre>"; |
353 | } else { | |
354 | permhtml += "Unknown systax!"; | |
355 | } | |
356 | } | |
622d092d TL |
357 | if (!info.allowtoken) { |
358 | // PMG doesn't fully supports API token, and probably won't ever!? | |
6bd70b95 | 359 | permhtml += "<br />This API endpoint is not available for API tokens." |
622d092d | 360 | } |
410dc2c9 DM |
361 | |
362 | sections.push({ | |
363 | title: 'Required permissions', | |
364 | bodyPadding: 10, | |
365 | html: permhtml | |
366 | }); | |
ab3ca263 TL |
367 | |
368 | ||
410dc2c9 DM |
369 | items.push({ |
370 | title: method, | |
371 | autoScroll: true, | |
372 | defaults: { | |
373 | border: false | |
374 | }, | |
375 | items: sections | |
376 | }); | |
377 | } | |
378 | }); | |
379 | ||
380 | var ct = Ext.getCmp('docview'); | |
381 | ct.setTitle("Path: " + data.path); | |
382 | ct.removeAll(true); | |
383 | ct.add(items); | |
384 | ct.setActiveTab(0); | |
385 | }; | |
386 | ||
622d092d TL |
387 | Ext.define('Ext.form.SearchField', { |
388 | extend: 'Ext.form.field.Text', | |
389 | alias: 'widget.searchfield', | |
390 | ||
391 | emptyText: 'Search...', | |
392 | ||
393 | flex: 1, | |
394 | ||
395 | inputType: 'search', | |
396 | listeners: { | |
397 | 'change': function(){ | |
398 | ||
399 | var value = this.getValue(); | |
400 | if (!Ext.isEmpty(value)) { | |
401 | store.filter({ | |
402 | property: 'path', | |
403 | value: value, | |
404 | anyMatch: true | |
405 | }); | |
406 | } else { | |
407 | store.clearFilter(); | |
408 | } | |
409 | } | |
410 | } | |
411 | }); | |
412 | ||
410dc2c9 | 413 | var tree = Ext.create('Ext.tree.Panel', { |
622d092d TL |
414 | title: 'Resource Tree', |
415 | tbar: [ | |
416 | { | |
417 | xtype: 'searchfield', | |
418 | } | |
419 | ], | |
420 | tools: [ | |
421 | { | |
422 | type: 'expand', | |
423 | tooltip: 'Expand all', | |
424 | tooltipType: 'title', | |
425 | callback: (tree) => tree.expandAll(), | |
426 | }, | |
427 | { | |
428 | type: 'collapse', | |
429 | tooltip: 'Collapse all', | |
430 | tooltipType: 'title', | |
431 | callback: (tree) => tree.collapseAll(), | |
432 | }, | |
433 | ], | |
410dc2c9 DM |
434 | store: store, |
435 | width: 200, | |
436 | region: 'west', | |
437 | split: true, | |
438 | margins: '5 0 5 5', | |
439 | rootVisible: false, | |
440 | listeners: { | |
441 | selectionchange: function(v, selections) { | |
442 | if (!selections[0]) | |
443 | return; | |
444 | var rec = selections[0]; | |
445 | render_docu(rec.data); | |
622d092d | 446 | location.hash = '#' + rec.data.path; |
410dc2c9 DM |
447 | } |
448 | } | |
449 | }); | |
450 | ||
451 | Ext.create('Ext.container.Viewport', { | |
452 | layout: 'border', | |
453 | renderTo: Ext.getBody(), | |
454 | items: [ | |
455 | tree, | |
456 | { | |
457 | xtype: 'tabpanel', | |
458 | title: 'Documentation', | |
459 | id: 'docview', | |
460 | region: 'center', | |
461 | margins: '5 5 5 0', | |
462 | layout: 'fit', | |
463 | items: [] | |
464 | } | |
465 | ] | |
466 | }); | |
467 | ||
622d092d TL |
468 | var deepLink = function() { |
469 | var path = window.location.hash.substring(1).replace(/\/\s*$/, '') | |
470 | var endpoint = store.findNode('path', path); | |
471 | ||
472 | if (endpoint) { | |
473 | tree.getSelectionModel().select(endpoint); | |
474 | tree.expandPath(endpoint.getPath()); | |
475 | render_docu(endpoint.data); | |
476 | } | |
477 | } | |
478 | window.onhashchange = deepLink; | |
479 | ||
480 | deepLink(); | |
481 | ||
410dc2c9 | 482 | }); |