]> git.proxmox.com Git - pve-docs.git/blob - api-viewer/PVEAPI.js
dd36fff5792a1f44bb9cbda663c8b9b6e5d14037
[pve-docs.git] / api-viewer / PVEAPI.js
1 // avoid errors when running without development tools
2 if (!Ext.isDefined(Ext.global.console)) {
3 var console = {
4 dir: function() {},
5 log: function() {}
6 };
7 }
8
9 Ext.onReady(function() {
10
11 Ext.define('pve-param-schema', {
12 extend: 'Ext.data.Model',
13 fields: [
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
25 var store = Ext.create('Ext.data.TreeStore', {
26 model: Ext.define('pve-api-doc', {
27 extend: 'Ext.data.Model',
28 fields: [
29 'path', 'info', 'text',
30 ]
31 }),
32 proxy: {
33 type: 'memory',
34 data: pveapi
35 },
36 sorters: [{
37 property: 'leaf',
38 direction: 'ASC'
39 }, {
40 property: 'text',
41 direction: 'ASC'
42 }]
43 });
44
45 var render_description = function(value, metaData, record) {
46 var pdef = record.data;
47
48 value = pdef.verbose_description || value;
49
50 // TODO: try to render asciidoc correctly
51
52 metaData.style = 'white-space:pre-wrap;'
53
54 return Ext.htmlEncode(value);
55 };
56
57 var render_type = function(value, metaData, record) {
58 var pdef = record.data;
59
60 return pdef['enum'] ? 'enum' : (pdef.type || 'string');
61 };
62
63 var render_format = function(value, metaData, record) {
64 var pdef = record.data;
65
66 metaData.style = 'white-space:normal;'
67
68 if (pdef.typetext)
69 return Ext.htmlEncode(pdef.typetext);
70
71 if (pdef['enum'])
72 return pdef['enum'].join(' | ');
73
74 if (pdef.format)
75 return pdef.format;
76
77 if (pdef.pattern)
78 return Ext.htmlEncode(pdef.pattern);
79
80 return '';
81 };
82
83 var render_docu = function(data) {
84 var md = data.info;
85
86 // console.dir(data);
87
88 var items = [];
89
90 var clicmdhash = {
91 GET: 'get',
92 POST: 'create',
93 PUT: 'set',
94 DELETE: 'delete'
95 };
96
97 Ext.Array.each(['GET', 'POST', 'PUT', 'DELETE'], function(method) {
98 var info = md[method];
99 if (info) {
100
101 var usage = "";
102
103 usage += "<table><tr><td>HTTP:&nbsp;&nbsp;&nbsp;</td><td>" + method + " /api2/json" + data.path + "</td></tr><tr><td>&nbsp</td></tr>";
104 usage += "<tr><td>CLI:</td><td>pvesh " + clicmdhash[method] + " " + data.path + "</td></tr></table>";
105
106 var sections = [
107 {
108 title: 'Description',
109 html: Ext.htmlEncode(info.description),
110 bodyPadding: 10
111 },
112 {
113 title: 'Usage',
114 html: usage,
115 bodyPadding: 10
116 }
117 ];
118
119 if (info.parameters && info.parameters.properties) {
120
121 var pstore = Ext.create('Ext.data.Store', {
122 model: 'pve-param-schema',
123 proxy: {
124 type: 'memory'
125 },
126 groupField: 'optional',
127 sorters: [
128 {
129 property: 'name',
130 direction: 'ASC'
131 }
132 ]
133 });
134
135 Ext.Object.each(info.parameters.properties, function(name, pdef) {
136 pdef.name = name;
137 pstore.add(pdef);
138 });
139
140 pstore.sort();
141
142 var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
143 enableGroupingMenu: false,
144 groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Required</tpl>'
145 });
146
147 sections.push({
148 xtype: 'gridpanel',
149 title: 'Parameters',
150 features: [groupingFeature],
151 store: pstore,
152 viewConfig: {
153 trackOver: false,
154 stripeRows: true
155 },
156 columns: [
157 {
158 header: 'Name',
159 dataIndex: 'name',
160 flex: 1
161 },
162 {
163 header: 'Type',
164 dataIndex: 'type',
165 renderer: render_type,
166 flex: 1
167 },
168 {
169 header: 'Default',
170 dataIndex: 'default',
171 flex: 1
172 },
173 {
174 header: 'Format',
175 dataIndex: 'type',
176 renderer: render_format,
177 flex: 2
178 },
179 {
180 header: 'Description',
181 dataIndex: 'description',
182 renderer: render_description,
183 flex: 6
184 }
185 ]
186 });
187
188 }
189
190 if (info.returns) {
191
192 var retinf = info.returns;
193 var rtype = retinf.type;
194 if (!rtype && retinf.items)
195 rtype = 'array';
196 if (!rtype)
197 rtype = 'object';
198
199 var rpstore = Ext.create('Ext.data.Store', {
200 model: 'pve-param-schema',
201 proxy: {
202 type: 'memory'
203 },
204 groupField: 'optional',
205 sorters: [
206 {
207 property: 'name',
208 direction: 'ASC'
209 }
210 ]
211 });
212
213 var properties;
214 if (rtype === 'array' && retinf.items.properties) {
215 properties = retinf.items.properties;
216 }
217
218 if (rtype === 'object' && retinf.properties) {
219 properties = retinf.properties;
220 }
221
222 Ext.Object.each(properties, function(name, pdef) {
223 pdef.name = name;
224 rpstore.add(pdef);
225 });
226
227 rpstore.sort();
228
229 var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{
230 enableGroupingMenu: false,
231 groupHeaderTpl: '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Obligatory</tpl>'
232 });
233 var returnhtml;
234 if (retinf.items) {
235 returnhtml = '<pre>items: ' + Ext.htmlEncode(JSON.stringify(retinf.items, null, 4)) + '</pre>';
236 }
237
238 if (retinf.properties) {
239 returnhtml = returnhtml || '';
240 returnhtml += '<pre>properties:' + Ext.htmlEncode(JSON.stringify(retinf.properties, null, 4)) + '</pre>';
241 }
242
243 var rawSection = Ext.create('Ext.panel.Panel', {
244 bodyPadding: '0px 10px 10px 10px',
245 html: returnhtml,
246 hidden: true
247 });
248
249 sections.push({
250 xtype: 'gridpanel',
251 title: 'Returns: ' + rtype,
252 features: [groupingFeature],
253 store: rpstore,
254 viewConfig: {
255 trackOver: false,
256 stripeRows: true
257 },
258 columns: [
259 {
260 header: 'Name',
261 dataIndex: 'name',
262 flex: 1
263 },
264 {
265 header: 'Type',
266 dataIndex: 'type',
267 renderer: render_type,
268 flex: 1
269 },
270 {
271 header: 'Default',
272 dataIndex: 'default',
273 flex: 1
274 },
275 {
276 header: 'Format',
277 dataIndex: 'type',
278 renderer: render_format,
279 flex: 2
280 },
281 {
282 header: 'Description',
283 dataIndex: 'description',
284 renderer: render_description,
285 flex: 6
286 }
287 ],
288 bbar: [
289 {
290 xtype: 'button',
291 text: 'Show RAW',
292 handler: function(btn) {
293 rawSection.setVisible(!rawSection.isVisible());
294 btn.setText(rawSection.isVisible() ? 'Hide RAW' : 'Show RAW');
295 }}
296 ]
297 });
298
299 sections.push(rawSection);
300
301
302 }
303
304 var permhtml = '';
305 if (!info.permissions) {
306 permhtml = "Root only.";
307 } else {
308 if (info.permissions.description) {
309 permhtml += "<div style='white-space:pre-wrap;padding-bottom:10px;'>" +
310 Ext.htmlEncode(info.permissions.description) + "</div>";
311 }
312
313 if (info.permissions.user) {
314 if (!info.permissions.description) {
315 if (info.permissions.user === 'world') {
316 permhtml += "Accessible without any authentication.";
317 } else if (info.permissions.user === 'all') {
318 permhtml += "Accessible by all authenticated users.";
319 } else {
320 permhtml += 'Onyl accessible by user "' +
321 info.permissions.user + '"';
322 }
323 }
324 } else if (info.permissions.check) {
325 permhtml += "<pre>Check: " +
326 Ext.htmlEncode(Ext.JSON.encode(info.permissions.check)) + "</pre>";
327 } else {
328 permhtml += "Unknown systax!";
329 }
330 }
331
332 sections.push({
333 title: 'Required permissions',
334 bodyPadding: 10,
335 html: permhtml
336 });
337
338
339 items.push({
340 title: method,
341 autoScroll: true,
342 defaults: {
343 border: false
344 },
345 items: sections
346 });
347 }
348 });
349
350 var ct = Ext.getCmp('docview');
351 ct.setTitle("Path: " + data.path);
352 ct.removeAll(true);
353 ct.add(items);
354 ct.setActiveTab(0);
355 };
356
357 var tree = Ext.create('Ext.tree.Panel', {
358 title: 'Resource Tree',
359 store: store,
360 width: 200,
361 region: 'west',
362 split: true,
363 margins: '5 0 5 5',
364 rootVisible: false,
365 listeners: {
366 selectionchange: function(v, selections) {
367 if (!selections[0])
368 return;
369 var rec = selections[0];
370 render_docu(rec.data);
371 location.hash = '#' + rec.data.path;
372 }
373 }
374 });
375
376 Ext.create('Ext.container.Viewport', {
377 layout: 'border',
378 renderTo: Ext.getBody(),
379 items: [
380 tree,
381 {
382 xtype: 'tabpanel',
383 title: 'Documentation',
384 id: 'docview',
385 region: 'center',
386 margins: '5 5 5 0',
387 layout: 'fit',
388 items: []
389 }
390 ]
391 });
392
393 var deepLink = function() {
394 var path = window.location.hash.substring(1);
395 var endpoint = store.findNode('path', path);
396
397 if (endpoint) {
398 tree.getSelectionModel().select(endpoint);
399 tree.expandPath(endpoint.getPath());
400 render_docu(endpoint.data);
401 }
402 }
403 window.onhashchange = deepLink;
404
405 deepLink();
406
407 });