From: Thomas Lamprecht Date: Wed, 2 Jun 2021 12:43:13 +0000 (+0200) Subject: don't shout: s/APIVIEWER/APIViewer/ X-Git-Url: https://git.proxmox.com/?p=proxmox-widget-toolkit.git;a=commitdiff_plain;h=2f8050530632fa4032582bcaaabc1d89ab945f13 don't shout: s/APIVIEWER/APIViewer/ Signed-off-by: Thomas Lamprecht --- diff --git a/debian/proxmox-widget-toolkit-dev.install b/debian/proxmox-widget-toolkit-dev.install index 514d1d0..620d69f 100644 --- a/debian/proxmox-widget-toolkit-dev.install +++ b/debian/proxmox-widget-toolkit-dev.install @@ -1,2 +1,2 @@ Toolkit.js /usr/share/javascript/proxmox-widget-toolkit-dev/ -api-viewer/APIVIEWER.js /usr/share/javascript/proxmox-widget-toolkit-dev/ +api-viewer/APIViewer.js /usr/share/javascript/proxmox-widget-toolkit-dev/ diff --git a/src/api-viewer/APIVIEWER.js b/src/api-viewer/APIVIEWER.js deleted file mode 100644 index c2864ed..0000000 --- a/src/api-viewer/APIVIEWER.js +++ /dev/null @@ -1,529 +0,0 @@ -// avoid errors when running without development tools -if (!Ext.isDefined(Ext.global.console)) { - var console = { - dir: function() {}, - log: function() {} - }; -} - -Ext.onReady(function() { - - Ext.define('pmx-param-schema', { - extend: 'Ext.data.Model', - fields: [ - 'name', 'type', 'typetext', 'description', 'verbose_description', - 'enum', 'minimum', 'maximum', 'minLength', 'maxLength', - 'pattern', 'title', 'requires', 'format', 'default', - 'disallow', 'extends', 'links', - { - name: 'optional', - type: 'boolean' - } - ] - }); - - var store = Ext.define('pmx-updated-treestore', { - extend: 'Ext.data.TreeStore', - model: Ext.define('pmx-api-doc', { - extend: 'Ext.data.Model', - fields: [ - 'path', 'info', 'text', - ] - }), - proxy: { - type: 'memory', - data: pmxapi - }, - sorters: [{ - property: 'leaf', - direction: 'ASC' - }, { - property: 'text', - direction: 'ASC' - }], - filterer: 'bottomup', - doFilter: function(node) { - this.filterNodes(node, this.getFilters().getFilterFn(), true); - }, - - filterNodes: function(node, filterFn, parentVisible) { - var me = this, - bottomUpFiltering = me.filterer === 'bottomup', - match = filterFn(node) && parentVisible || (node.isRoot() && !me.getRootVisible()), - childNodes = node.childNodes, - len = childNodes && childNodes.length, i, matchingChildren; - - if (len) { - for (i = 0; i < len; ++i) { - matchingChildren = me.filterNodes(childNodes[i], filterFn, match || bottomUpFiltering) || matchingChildren; - } - if (bottomUpFiltering) { - match = matchingChildren || match; - } - } - - node.set("visible", match, me._silentOptions); - return match; - }, - - }).create(); - - var render_description = function(value, metaData, record) { - var pdef = record.data; - - value = pdef.verbose_description || value; - - // TODO: try to render asciidoc correctly - - metaData.style = 'white-space:pre-wrap;' - - return Ext.htmlEncode(value); - }; - - var render_type = function(value, metaData, record) { - var pdef = record.data; - - return pdef['enum'] ? 'enum' : (pdef.type || 'string'); - }; - - let render_simple_format = function(pdef, type_fallback) { - if (pdef.typetext) - return pdef.typetext; - - if (pdef['enum']) - return pdef['enum'].join(' | '); - - if (pdef.format) - return pdef.format; - - if (pdef.pattern) - return pdef.pattern; - - if (pdef.type === 'boolean') - return ``; - - if (type_fallback && pdef.type) - return `<${pdef.type}>`; - - return; - }; - - let render_format = function(value, metaData, record) { - let pdef = record.data; - - metaData.style = 'white-space:normal;' - - if (pdef.type === 'array' && pdef.items) { - let format = render_simple_format(pdef.items, true); - return `[${Ext.htmlEncode(format)}, ...]`; - } - - return Ext.htmlEncode(render_simple_format(pdef) || ''); - }; - - var real_path = function(path) { - return path.replace(/^.*\/_upgrade_(\/)?/, "/"); - }; - - var permission_text = function(permission) { - let permhtml = ""; - - if (permission.user) { - if (!permission.description) { - if (permission.user === 'world') { - permhtml += "Accessible without any authentication."; - } else if (permission.user === 'all') { - permhtml += "Accessible by all authenticated users."; - } else { - permhtml += 'Onyl accessible by user "' + - permission.user + '"'; - } - } - } else if (permission.check) { - permhtml += "
Check: " +
-		Ext.htmlEncode(Ext.JSON.encode(permission.check))  + "
"; - } else if (permission.userParam) { - permhtml += `
Check if user matches parameter '${permission.userParam}'`; - } else if (permission.or) { - permhtml += "
Or
"; - Ext.Array.each(permission.or, function(sub_permission) { - permhtml += permission_text(sub_permission); - }) - permhtml += "
"; - } else if (permission.and) { - permhtml += "
And
"; - Ext.Array.each(permission.and, function(sub_permission) { - permhtml += permission_text(sub_permission); - }) - permhtml += "
"; - } else { - //console.log(permission); - permhtml += "Unknown syntax!"; - } - - return permhtml; - }; - - var render_docu = function(data) { - var md = data.info; - - // console.dir(data); - - var items = []; - - var clicmdhash = { - GET: 'get', - POST: 'create', - PUT: 'set', - DELETE: 'delete' - }; - - Ext.Array.each(['GET', 'POST', 'PUT', 'DELETE'], function(method) { - var info = md[method]; - if (info) { - - var usage = ""; - - usage += ""; - - if (typeof cliusage === 'function') { - usage += cliusage(method, real_path(data.path)); - } - - var sections = [ - { - title: 'Description', - html: Ext.htmlEncode(info.description), - bodyPadding: 10 - }, - { - title: 'Usage', - html: usage, - bodyPadding: 10 - } - ]; - - if (info.parameters && info.parameters.properties) { - - var pstore = Ext.create('Ext.data.Store', { - model: 'pmx-param-schema', - proxy: { - type: 'memory' - }, - groupField: 'optional', - sorters: [ - { - property: 'name', - direction: 'ASC' - } - ] - }); - - Ext.Object.each(info.parameters.properties, function(name, pdef) { - pdef.name = name; - pstore.add(pdef); - }); - - pstore.sort(); - - var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ - enableGroupingMenu: false, - groupHeaderTpl: 'OptionalRequired' - }); - - sections.push({ - xtype: 'gridpanel', - title: 'Parameters', - features: [groupingFeature], - store: pstore, - viewConfig: { - trackOver: false, - stripeRows: true - }, - columns: [ - { - header: 'Name', - dataIndex: 'name', - flex: 1 - }, - { - header: 'Type', - dataIndex: 'type', - renderer: render_type, - flex: 1 - }, - { - header: 'Default', - dataIndex: 'default', - flex: 1 - }, - { - header: 'Format', - dataIndex: 'type', - renderer: render_format, - flex: 2 - }, - { - header: 'Description', - dataIndex: 'description', - renderer: render_description, - flex: 6 - } - ] - }); - - } - - if (info.returns) { - - var retinf = info.returns; - var rtype = retinf.type; - if (!rtype && retinf.items) - rtype = 'array'; - if (!rtype) - rtype = 'object'; - - var rpstore = Ext.create('Ext.data.Store', { - model: 'pmx-param-schema', - proxy: { - type: 'memory' - }, - groupField: 'optional', - sorters: [ - { - property: 'name', - direction: 'ASC' - } - ] - }); - - var properties; - if (rtype === 'array' && retinf.items.properties) { - properties = retinf.items.properties; - } - - if (rtype === 'object' && retinf.properties) { - properties = retinf.properties; - } - - Ext.Object.each(properties, function(name, pdef) { - pdef.name = name; - rpstore.add(pdef); - }); - - rpstore.sort(); - - var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ - enableGroupingMenu: false, - groupHeaderTpl: 'OptionalObligatory' - }); - var returnhtml; - if (retinf.items) { - returnhtml = '
items: ' + Ext.htmlEncode(JSON.stringify(retinf.items, null, 4)) + '
'; - } - - if (retinf.properties) { - returnhtml = returnhtml || ''; - returnhtml += '
properties:' + Ext.htmlEncode(JSON.stringify(retinf.properties, null, 4)) + '
'; - } - - var rawSection = Ext.create('Ext.panel.Panel', { - bodyPadding: '0px 10px 10px 10px', - html: returnhtml, - hidden: true - }); - - sections.push({ - xtype: 'gridpanel', - title: 'Returns: ' + rtype, - features: [groupingFeature], - store: rpstore, - viewConfig: { - trackOver: false, - stripeRows: true - }, - columns: [ - { - header: 'Name', - dataIndex: 'name', - flex: 1 - }, - { - header: 'Type', - dataIndex: 'type', - renderer: render_type, - flex: 1 - }, - { - header: 'Default', - dataIndex: 'default', - flex: 1 - }, - { - header: 'Format', - dataIndex: 'type', - renderer: render_format, - flex: 2 - }, - { - header: 'Description', - dataIndex: 'description', - renderer: render_description, - flex: 6 - } - ], - bbar: [ - { - xtype: 'button', - text: 'Show RAW', - handler: function(btn) { - rawSection.setVisible(!rawSection.isVisible()); - btn.setText(rawSection.isVisible() ? 'Hide RAW' : 'Show RAW'); - }} - ] - }); - - sections.push(rawSection); - - - } - - if (!data.path.match(/\/_upgrade_/)) { - var permhtml = ''; - - if (!info.permissions) { - permhtml = "Root only."; - } else { - if (info.permissions.description) { - permhtml += "
" + - Ext.htmlEncode(info.permissions.description) + "
"; - } - permhtml += permission_text(info.permissions); - } - - if (info.allowtoken !== undefined && !info.allowtoken) { - permhtml += "
This API endpoint is not available for API tokens." - } - - sections.push({ - title: 'Required permissions', - bodyPadding: 10, - html: permhtml - }); - } - - items.push({ - title: method, - autoScroll: true, - defaults: { - border: false - }, - items: sections - }); - } - }); - - var ct = Ext.getCmp('docview'); - ct.setTitle("Path: " + real_path(data.path)); - ct.removeAll(true); - ct.add(items); - ct.setActiveTab(0); - }; - - Ext.define('Ext.form.SearchField', { - extend: 'Ext.form.field.Text', - alias: 'widget.searchfield', - - emptyText: 'Search...', - - flex: 1, - - inputType: 'search', - listeners: { - 'change': function(){ - - var value = this.getValue(); - if (!Ext.isEmpty(value)) { - store.filter({ - property: 'path', - value: value, - anyMatch: true - }); - } else { - store.clearFilter(); - } - } - } - }); - - var tree = Ext.create('Ext.tree.Panel', { - title: 'Resource Tree', - tbar: [ - { - xtype: 'searchfield', - } - ], - tools: [ - { - type: 'expand', - tooltip: 'Expand all', - tooltipType: 'title', - callback: (tree) => tree.expandAll(), - }, - { - type: 'collapse', - tooltip: 'Collapse all', - tooltipType: 'title', - callback: (tree) => tree.collapseAll(), - }, - ], - store: store, - width: 200, - region: 'west', - split: true, - margins: '5 0 5 5', - rootVisible: false, - listeners: { - selectionchange: function(v, selections) { - if (!selections[0]) - return; - var rec = selections[0]; - render_docu(rec.data); - location.hash = '#' + rec.data.path; - } - } - }); - - Ext.create('Ext.container.Viewport', { - layout: 'border', - renderTo: Ext.getBody(), - items: [ - tree, - { - xtype: 'tabpanel', - title: 'Documentation', - id: 'docview', - region: 'center', - margins: '5 5 5 0', - layout: 'fit', - items: [] - } - ] - }); - - var deepLink = function() { - var path = window.location.hash.substring(1).replace(/\/\s*$/, '') - var endpoint = store.findNode('path', path); - - if (endpoint) { - tree.getSelectionModel().select(endpoint); - tree.expandPath(endpoint.getPath()); - render_docu(endpoint.data); - } - } - window.onhashchange = deepLink; - - deepLink(); - -}); diff --git a/src/api-viewer/APIViewer.js b/src/api-viewer/APIViewer.js new file mode 100644 index 0000000..c2864ed --- /dev/null +++ b/src/api-viewer/APIViewer.js @@ -0,0 +1,529 @@ +// avoid errors when running without development tools +if (!Ext.isDefined(Ext.global.console)) { + var console = { + dir: function() {}, + log: function() {} + }; +} + +Ext.onReady(function() { + + Ext.define('pmx-param-schema', { + extend: 'Ext.data.Model', + fields: [ + 'name', 'type', 'typetext', 'description', 'verbose_description', + 'enum', 'minimum', 'maximum', 'minLength', 'maxLength', + 'pattern', 'title', 'requires', 'format', 'default', + 'disallow', 'extends', 'links', + { + name: 'optional', + type: 'boolean' + } + ] + }); + + var store = Ext.define('pmx-updated-treestore', { + extend: 'Ext.data.TreeStore', + model: Ext.define('pmx-api-doc', { + extend: 'Ext.data.Model', + fields: [ + 'path', 'info', 'text', + ] + }), + proxy: { + type: 'memory', + data: pmxapi + }, + sorters: [{ + property: 'leaf', + direction: 'ASC' + }, { + property: 'text', + direction: 'ASC' + }], + filterer: 'bottomup', + doFilter: function(node) { + this.filterNodes(node, this.getFilters().getFilterFn(), true); + }, + + filterNodes: function(node, filterFn, parentVisible) { + var me = this, + bottomUpFiltering = me.filterer === 'bottomup', + match = filterFn(node) && parentVisible || (node.isRoot() && !me.getRootVisible()), + childNodes = node.childNodes, + len = childNodes && childNodes.length, i, matchingChildren; + + if (len) { + for (i = 0; i < len; ++i) { + matchingChildren = me.filterNodes(childNodes[i], filterFn, match || bottomUpFiltering) || matchingChildren; + } + if (bottomUpFiltering) { + match = matchingChildren || match; + } + } + + node.set("visible", match, me._silentOptions); + return match; + }, + + }).create(); + + var render_description = function(value, metaData, record) { + var pdef = record.data; + + value = pdef.verbose_description || value; + + // TODO: try to render asciidoc correctly + + metaData.style = 'white-space:pre-wrap;' + + return Ext.htmlEncode(value); + }; + + var render_type = function(value, metaData, record) { + var pdef = record.data; + + return pdef['enum'] ? 'enum' : (pdef.type || 'string'); + }; + + let render_simple_format = function(pdef, type_fallback) { + if (pdef.typetext) + return pdef.typetext; + + if (pdef['enum']) + return pdef['enum'].join(' | '); + + if (pdef.format) + return pdef.format; + + if (pdef.pattern) + return pdef.pattern; + + if (pdef.type === 'boolean') + return ``; + + if (type_fallback && pdef.type) + return `<${pdef.type}>`; + + return; + }; + + let render_format = function(value, metaData, record) { + let pdef = record.data; + + metaData.style = 'white-space:normal;' + + if (pdef.type === 'array' && pdef.items) { + let format = render_simple_format(pdef.items, true); + return `[${Ext.htmlEncode(format)}, ...]`; + } + + return Ext.htmlEncode(render_simple_format(pdef) || ''); + }; + + var real_path = function(path) { + return path.replace(/^.*\/_upgrade_(\/)?/, "/"); + }; + + var permission_text = function(permission) { + let permhtml = ""; + + if (permission.user) { + if (!permission.description) { + if (permission.user === 'world') { + permhtml += "Accessible without any authentication."; + } else if (permission.user === 'all') { + permhtml += "Accessible by all authenticated users."; + } else { + permhtml += 'Onyl accessible by user "' + + permission.user + '"'; + } + } + } else if (permission.check) { + permhtml += "
Check: " +
+		Ext.htmlEncode(Ext.JSON.encode(permission.check))  + "
"; + } else if (permission.userParam) { + permhtml += `
Check if user matches parameter '${permission.userParam}'`; + } else if (permission.or) { + permhtml += "
Or
"; + Ext.Array.each(permission.or, function(sub_permission) { + permhtml += permission_text(sub_permission); + }) + permhtml += "
"; + } else if (permission.and) { + permhtml += "
And
"; + Ext.Array.each(permission.and, function(sub_permission) { + permhtml += permission_text(sub_permission); + }) + permhtml += "
"; + } else { + //console.log(permission); + permhtml += "Unknown syntax!"; + } + + return permhtml; + }; + + var render_docu = function(data) { + var md = data.info; + + // console.dir(data); + + var items = []; + + var clicmdhash = { + GET: 'get', + POST: 'create', + PUT: 'set', + DELETE: 'delete' + }; + + Ext.Array.each(['GET', 'POST', 'PUT', 'DELETE'], function(method) { + var info = md[method]; + if (info) { + + var usage = ""; + + usage += "
HTTP:   " - + method + " " + real_path("/api2/json" + data.path) + "
"; + + if (typeof cliusage === 'function') { + usage += cliusage(method, real_path(data.path)); + } + + var sections = [ + { + title: 'Description', + html: Ext.htmlEncode(info.description), + bodyPadding: 10 + }, + { + title: 'Usage', + html: usage, + bodyPadding: 10 + } + ]; + + if (info.parameters && info.parameters.properties) { + + var pstore = Ext.create('Ext.data.Store', { + model: 'pmx-param-schema', + proxy: { + type: 'memory' + }, + groupField: 'optional', + sorters: [ + { + property: 'name', + direction: 'ASC' + } + ] + }); + + Ext.Object.each(info.parameters.properties, function(name, pdef) { + pdef.name = name; + pstore.add(pdef); + }); + + pstore.sort(); + + var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ + enableGroupingMenu: false, + groupHeaderTpl: 'OptionalRequired' + }); + + sections.push({ + xtype: 'gridpanel', + title: 'Parameters', + features: [groupingFeature], + store: pstore, + viewConfig: { + trackOver: false, + stripeRows: true + }, + columns: [ + { + header: 'Name', + dataIndex: 'name', + flex: 1 + }, + { + header: 'Type', + dataIndex: 'type', + renderer: render_type, + flex: 1 + }, + { + header: 'Default', + dataIndex: 'default', + flex: 1 + }, + { + header: 'Format', + dataIndex: 'type', + renderer: render_format, + flex: 2 + }, + { + header: 'Description', + dataIndex: 'description', + renderer: render_description, + flex: 6 + } + ] + }); + + } + + if (info.returns) { + + var retinf = info.returns; + var rtype = retinf.type; + if (!rtype && retinf.items) + rtype = 'array'; + if (!rtype) + rtype = 'object'; + + var rpstore = Ext.create('Ext.data.Store', { + model: 'pmx-param-schema', + proxy: { + type: 'memory' + }, + groupField: 'optional', + sorters: [ + { + property: 'name', + direction: 'ASC' + } + ] + }); + + var properties; + if (rtype === 'array' && retinf.items.properties) { + properties = retinf.items.properties; + } + + if (rtype === 'object' && retinf.properties) { + properties = retinf.properties; + } + + Ext.Object.each(properties, function(name, pdef) { + pdef.name = name; + rpstore.add(pdef); + }); + + rpstore.sort(); + + var groupingFeature = Ext.create('Ext.grid.feature.Grouping',{ + enableGroupingMenu: false, + groupHeaderTpl: 'OptionalObligatory' + }); + var returnhtml; + if (retinf.items) { + returnhtml = '
items: ' + Ext.htmlEncode(JSON.stringify(retinf.items, null, 4)) + '
'; + } + + if (retinf.properties) { + returnhtml = returnhtml || ''; + returnhtml += '
properties:' + Ext.htmlEncode(JSON.stringify(retinf.properties, null, 4)) + '
'; + } + + var rawSection = Ext.create('Ext.panel.Panel', { + bodyPadding: '0px 10px 10px 10px', + html: returnhtml, + hidden: true + }); + + sections.push({ + xtype: 'gridpanel', + title: 'Returns: ' + rtype, + features: [groupingFeature], + store: rpstore, + viewConfig: { + trackOver: false, + stripeRows: true + }, + columns: [ + { + header: 'Name', + dataIndex: 'name', + flex: 1 + }, + { + header: 'Type', + dataIndex: 'type', + renderer: render_type, + flex: 1 + }, + { + header: 'Default', + dataIndex: 'default', + flex: 1 + }, + { + header: 'Format', + dataIndex: 'type', + renderer: render_format, + flex: 2 + }, + { + header: 'Description', + dataIndex: 'description', + renderer: render_description, + flex: 6 + } + ], + bbar: [ + { + xtype: 'button', + text: 'Show RAW', + handler: function(btn) { + rawSection.setVisible(!rawSection.isVisible()); + btn.setText(rawSection.isVisible() ? 'Hide RAW' : 'Show RAW'); + }} + ] + }); + + sections.push(rawSection); + + + } + + if (!data.path.match(/\/_upgrade_/)) { + var permhtml = ''; + + if (!info.permissions) { + permhtml = "Root only."; + } else { + if (info.permissions.description) { + permhtml += "
" + + Ext.htmlEncode(info.permissions.description) + "
"; + } + permhtml += permission_text(info.permissions); + } + + if (info.allowtoken !== undefined && !info.allowtoken) { + permhtml += "
This API endpoint is not available for API tokens." + } + + sections.push({ + title: 'Required permissions', + bodyPadding: 10, + html: permhtml + }); + } + + items.push({ + title: method, + autoScroll: true, + defaults: { + border: false + }, + items: sections + }); + } + }); + + var ct = Ext.getCmp('docview'); + ct.setTitle("Path: " + real_path(data.path)); + ct.removeAll(true); + ct.add(items); + ct.setActiveTab(0); + }; + + Ext.define('Ext.form.SearchField', { + extend: 'Ext.form.field.Text', + alias: 'widget.searchfield', + + emptyText: 'Search...', + + flex: 1, + + inputType: 'search', + listeners: { + 'change': function(){ + + var value = this.getValue(); + if (!Ext.isEmpty(value)) { + store.filter({ + property: 'path', + value: value, + anyMatch: true + }); + } else { + store.clearFilter(); + } + } + } + }); + + var tree = Ext.create('Ext.tree.Panel', { + title: 'Resource Tree', + tbar: [ + { + xtype: 'searchfield', + } + ], + tools: [ + { + type: 'expand', + tooltip: 'Expand all', + tooltipType: 'title', + callback: (tree) => tree.expandAll(), + }, + { + type: 'collapse', + tooltip: 'Collapse all', + tooltipType: 'title', + callback: (tree) => tree.collapseAll(), + }, + ], + store: store, + width: 200, + region: 'west', + split: true, + margins: '5 0 5 5', + rootVisible: false, + listeners: { + selectionchange: function(v, selections) { + if (!selections[0]) + return; + var rec = selections[0]; + render_docu(rec.data); + location.hash = '#' + rec.data.path; + } + } + }); + + Ext.create('Ext.container.Viewport', { + layout: 'border', + renderTo: Ext.getBody(), + items: [ + tree, + { + xtype: 'tabpanel', + title: 'Documentation', + id: 'docview', + region: 'center', + margins: '5 5 5 0', + layout: 'fit', + items: [] + } + ] + }); + + var deepLink = function() { + var path = window.location.hash.substring(1).replace(/\/\s*$/, '') + var endpoint = store.findNode('path', path); + + if (endpoint) { + tree.getSelectionModel().select(endpoint); + tree.expandPath(endpoint.getPath()); + render_docu(endpoint.data); + } + } + window.onhashchange = deepLink; + + deepLink(); + +});
HTTP:   " + + method + " " + real_path("/api2/json" + data.path) + "