2016-04-29 12:22:23 +02:00
// avoid errors when running without development tools
2019-12-10 14:04:27 +01:00
if ( ! Ext . isDefined ( Ext . global . console ) ) {
var console = {
dir : function ( ) { } ,
log : function ( ) { }
2016-04-29 12:22:23 +02:00
} ;
}
Ext . onReady ( function ( ) {
Ext . define ( 'pve-param-schema' , {
extend : 'Ext.data.Model' ,
2019-12-10 14:04:27 +01:00
fields : [
2016-09-05 09:42:35 +02:00
'name' , 'type' , 'typetext' , 'description' , 'verbose_description' ,
'enum' , 'minimum' , 'maximum' , 'minLength' , 'maxLength' ,
2016-04-29 12:22:23 +02:00
'pattern' , 'title' , 'requires' , 'format' , 'default' ,
'disallow' , 'extends' , 'links' ,
{
name : 'optional' ,
type : 'boolean'
}
]
} ) ;
2019-12-11 12:58:23 +01:00
var store = Ext . define ( 'pve-updated-treestore' , {
extend : 'Ext.data.TreeStore' ,
2016-04-29 12:22:23 +02:00
model : Ext . define ( 'pve-api-doc' , {
extend : 'Ext.data.Model' ,
2019-12-10 14:04:27 +01:00
fields : [
2016-04-29 12:22:23 +02:00
'path' , 'info' , 'text' ,
]
} ) ,
proxy : {
type : 'memory' ,
data : pveapi
} ,
sorters : [ {
property : 'leaf' ,
direction : 'ASC'
} , {
property : 'text' ,
direction : 'ASC'
2019-12-11 12:58:23 +01:00
} ] ,
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 ( ) ;
2019-12-10 14:04:27 +01:00
2016-09-05 09:42:35 +02:00
var render _description = function ( value , metaData , record ) {
2016-04-29 12:22:23 +02:00
var pdef = record . data ;
2016-09-05 09:42:35 +02:00
value = pdef . verbose _description || value ;
2016-09-05 10:07:41 +02:00
// TODO: try to render asciidoc correctly
2016-09-05 09:42:35 +02:00
2016-04-29 12:22:23 +02:00
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' ) ;
} ;
var render _format = function ( value , metaData , record ) {
var pdef = record . data ;
metaData . style = 'white-space:normal;'
if ( pdef . typetext )
2016-09-05 09:03:35 +02:00
return Ext . htmlEncode ( pdef . typetext ) ;
2016-04-29 12:22:23 +02:00
if ( pdef [ 'enum' ] )
return pdef [ 'enum' ] . join ( ' | ' ) ;
2019-12-10 14:04:27 +01:00
if ( pdef . format )
2016-04-29 12:22:23 +02:00
return pdef . format ;
2019-12-10 14:04:27 +01:00
if ( pdef . pattern )
2016-09-05 09:03:35 +02:00
return Ext . htmlEncode ( pdef . pattern ) ;
2016-04-29 12:22:23 +02:00
return '' ;
} ;
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 += "<table><tr><td>HTTP: </td><td>" + method + " /api2/json" + data . path + "</td></tr><tr><td> </td></tr>" ;
usage += "<tr><td>CLI:</td><td>pvesh " + clicmdhash [ method ] + " " + data . path + "</td></tr></table>" ;
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 : 'pve-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 ,
2016-04-30 15:02:17 +02:00
groupHeaderTpl : '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Required</tpl>'
2016-04-29 12:22:23 +02:00
} ) ;
sections . push ( {
xtype : 'gridpanel' ,
title : 'Parameters' ,
features : [ groupingFeature ] ,
store : pstore ,
viewConfig : {
trackOver : false ,
stripeRows : true
} ,
columns : [
2017-12-21 11:36:37 +01:00
{
2016-04-29 12:22:23 +02:00
header : 'Name' ,
2017-12-21 11:36:37 +01:00
dataIndex : 'name' ,
flex : 1
2016-04-29 12:22:23 +02:00
} ,
2017-12-21 11:36:37 +01:00
{
2016-04-29 12:22:23 +02:00
header : 'Type' ,
dataIndex : 'type' ,
renderer : render _type ,
2017-12-21 11:36:37 +01:00
flex : 1
2016-04-29 12:22:23 +02:00
} ,
2017-12-21 11:36:36 +01:00
{
header : 'Default' ,
dataIndex : 'default' ,
2017-12-21 11:36:37 +01:00
flex : 1
2017-12-21 11:36:36 +01:00
} ,
{
2016-04-29 12:22:23 +02:00
header : 'Format' ,
dataIndex : 'type' ,
renderer : render _format ,
2017-12-21 11:36:37 +01:00
flex : 2
2016-04-29 12:22:23 +02:00
} ,
2017-12-21 11:36:37 +01:00
{
2016-04-29 12:22:23 +02:00
header : 'Description' ,
dataIndex : 'description' ,
2016-09-05 09:42:35 +02:00
renderer : render _description ,
2017-12-21 11:36:37 +01:00
flex : 6
2016-04-29 12:22:23 +02:00
}
]
} ) ;
}
if ( info . returns ) {
2018-03-21 15:53:38 +01:00
var retinf = info . returns ;
var rtype = retinf . type ;
if ( ! rtype && retinf . items )
2016-04-29 12:22:23 +02:00
rtype = 'array' ;
if ( ! rtype )
rtype = 'object' ;
2019-12-10 14:04:28 +01:00
var rpstore = Ext . create ( 'Ext.data.Store' , {
model : 'pve-param-schema' ,
proxy : {
type : 'memory'
} ,
groupField : 'optional' ,
sorters : [
{
property : 'name' ,
direction : 'ASC'
}
]
} ) ;
2018-03-21 15:53:38 +01:00
2019-12-10 14:04:28 +01:00
var properties ;
if ( rtype === 'array' && retinf . items . properties ) {
properties = retinf . items . properties ;
}
2018-03-21 15:53:38 +01:00
2019-12-10 14:04:28 +01:00
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 : '<tpl if="groupValue">Optional</tpl><tpl if="!groupValue">Obligatory</tpl>'
} ) ;
var returnhtml ;
if ( retinf . items ) {
returnhtml = '<pre>items: ' + Ext . htmlEncode ( JSON . stringify ( retinf . items , null , 4 ) ) + '</pre>' ;
}
if ( retinf . properties ) {
returnhtml = returnhtml || '' ;
returnhtml += '<pre>properties:' + Ext . htmlEncode ( JSON . stringify ( retinf . properties , null , 4 ) ) + '</pre>' ;
}
var rawSection = Ext . create ( 'Ext.panel.Panel' , {
2019-12-10 14:51:53 +01:00
bodyPadding : '0px 10px 10px 10px' ,
2019-12-10 14:04:28 +01:00
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
}
] ,
2019-12-10 14:51:53 +01:00
bbar : [
2019-12-10 14:04:28 +01:00
{
xtype : 'button' ,
2019-12-10 14:51:53 +01:00
text : 'Show RAW' ,
handler : function ( btn ) {
2019-12-10 14:04:28 +01:00
rawSection . setVisible ( ! rawSection . isVisible ( ) ) ;
2019-12-10 14:51:53 +01:00
btn . setText ( rawSection . isVisible ( ) ? 'Hide RAW' : 'Show RAW' ) ;
2019-12-10 14:04:28 +01:00
} }
]
} ) ;
sections . push ( rawSection ) ;
2016-04-29 12:22:23 +02:00
}
var permhtml = '' ;
if ( ! info . permissions ) {
permhtml = "Root only." ;
} else {
if ( info . permissions . description ) {
permhtml += "<div style='white-space:pre-wrap;padding-bottom:10px;'>" +
Ext . htmlEncode ( info . permissions . description ) + "</div>" ;
}
if ( info . permissions . user ) {
if ( ! info . permissions . description ) {
if ( info . permissions . user === 'world' ) {
2018-02-13 11:54:11 +01:00
permhtml += "Accessible without any authentication." ;
2016-04-29 12:22:23 +02:00
} else if ( info . permissions . user === 'all' ) {
2018-02-13 11:54:11 +01:00
permhtml += "Accessible by all authenticated users." ;
2016-04-29 12:22:23 +02:00
} else {
2019-12-10 14:04:27 +01:00
permhtml += 'Onyl accessible by user "' +
2016-04-29 12:22:23 +02:00
info . permissions . user + '"' ;
}
}
} else if ( info . permissions . check ) {
2019-12-10 14:04:27 +01:00
permhtml += "<pre>Check: " +
2016-04-29 12:22:23 +02:00
Ext . htmlEncode ( Ext . JSON . encode ( info . permissions . check ) ) + "</pre>" ;
} else {
permhtml += "Unknown systax!" ;
}
}
sections . push ( {
title : 'Required permissions' ,
bodyPadding : 10 ,
html : permhtml
} ) ;
2019-12-10 14:04:27 +01:00
2016-04-29 12:22:23 +02:00
items . push ( {
title : method ,
autoScroll : true ,
defaults : {
border : false
} ,
items : sections
} ) ;
}
} ) ;
var ct = Ext . getCmp ( 'docview' ) ;
ct . setTitle ( "Path: " + data . path ) ;
ct . removeAll ( true ) ;
ct . add ( items ) ;
2016-09-02 12:50:38 +02:00
ct . setActiveTab ( 0 ) ;
2016-04-29 12:22:23 +02:00
} ;
2019-12-11 12:58:23 +01:00
Ext . define ( 'Ext.form.SearchField' , {
extend : 'Ext.form.field.Text' ,
alias : 'widget.searchfield' ,
2019-12-11 15:45:22 +01:00
emptyText : 'Search...' ,
flex : 1 ,
2019-12-11 12:58:23 +01:00
inputType : 'search' ,
listeners : {
'change' : function ( ) {
var value = this . getValue ( ) ;
if ( ! Ext . isEmpty ( value ) ) {
store . filter ( {
property : 'path' ,
value : value ,
anyMatch : true
} ) ;
} else {
store . clearFilter ( ) ;
}
}
}
} ) ;
2016-04-29 12:22:23 +02:00
var tree = Ext . create ( 'Ext.tree.Panel' , {
2019-12-11 12:58:23 +01:00
title : 'Resource Tree' ,
tbar : [
{
xtype : 'searchfield' ,
}
] ,
tools : [
{
type : 'expand' ,
2019-12-11 15:45:51 +01:00
tooltip : 'Expand all' ,
tooltipType : 'title' ,
callback : ( tree ) => tree . expandAll ( ) ,
2019-12-11 12:58:23 +01:00
} ,
{
type : 'collapse' ,
2019-12-11 15:45:51 +01:00
tooltip : 'Collapse all' ,
tooltipType : 'title' ,
callback : ( tree ) => tree . collapseAll ( ) ,
2019-12-11 12:58:23 +01:00
} ,
] ,
2016-04-29 12:22:23 +02:00
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 ) ;
2019-12-11 12:58:22 +01:00
location . hash = '#' + rec . data . path ;
2016-04-29 12:22:23 +02:00
}
}
} ) ;
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 : [ ]
}
]
} ) ;
2019-12-11 12:58:22 +01:00
var deepLink = function ( ) {
2019-12-11 14:38:58 +01:00
var path = window . location . hash . substring ( 1 ) . replace ( /\/\s*$/ , '' )
2019-12-11 12:58:22 +01:00
var endpoint = store . findNode ( 'path' , path ) ;
if ( endpoint ) {
tree . getSelectionModel ( ) . select ( endpoint ) ;
tree . expandPath ( endpoint . getPath ( ) ) ;
render _docu ( endpoint . data ) ;
}
}
window . onhashchange = deepLink ;
deepLink ( ) ;
2016-04-29 12:22:23 +02:00
} ) ;