diff --git a/.gitignore b/.gitignore index 82cbb8c..863d3a7 100644 --- a/.gitignore +++ b/.gitignore @@ -129,3 +129,6 @@ out .pnp.* *~ + +# Vim +*.swp diff --git a/sdk-demo-application/backend/client_data.js b/sdk-demo-application/backend/client_data.js new file mode 100644 index 0000000..4218d13 --- /dev/null +++ b/sdk-demo-application/backend/client_data.js @@ -0,0 +1,41 @@ +const { v4: uuidv4 } = require('uuid') + +const lastModified = Date.now() + +module.exports = [ + { + id: uuidv4(), + "firstName": "John", + "lastName": "Doe", + "phoneNumber": 1234567890, + lastModified + }, + { + id: uuidv4(), + "firstName": "Alice", + "lastName": "Smith", + "phoneNumber": 9876543210, + lastModified + }, + { + id: uuidv4(), + "firstName": "Robert", + "lastName": "Brown", + "phoneNumber": 5551234567, + lastModified + }, + { + id: uuidv4(), + "firstName": "Emily", + "lastName": "Johnson", + "phoneNumber": 4449876543, + lastModified + }, + { + id: uuidv4(), + "firstName": "Michael", + "lastName": "Williams", + "phoneNumber": 3332221111, + lastModified + } +] diff --git a/sdk-demo-application/backend/curl/list.sh b/sdk-demo-application/backend/curl/list.sh new file mode 100644 index 0000000..e99dfb0 --- /dev/null +++ b/sdk-demo-application/backend/curl/list.sh @@ -0,0 +1 @@ +curl -v "http://127.0.0.1:8000/api/TrelloSDK/board/list?idMember=me" | json diff --git a/sdk-demo-application/backend/package-lock.json b/sdk-demo-application/backend/package-lock.json new file mode 100644 index 0000000..99124cd --- /dev/null +++ b/sdk-demo-application/backend/package-lock.json @@ -0,0 +1,721 @@ +{ + "name": "backend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "backend", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "express": "^4.21.1", + "uuid": "^11.0.2" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.10", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.0.2.tgz", + "integrity": "sha512-14FfcOJmqdjbBPdDjFQyk/SdT4NySW4eM0zcG+HqbHP5jzuH56xO3J1DGhgs/cEMCfwYi3HQI1gnTO62iaG+tQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + } + } +} diff --git a/sdk-demo-application/backend/package.json b/sdk-demo-application/backend/package.json new file mode 100644 index 0000000..e90736e --- /dev/null +++ b/sdk-demo-application/backend/package.json @@ -0,0 +1,16 @@ +{ + "name": "backend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "export DEBUG=express:* && node server.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "express": "^4.21.1", + "uuid": "^11.0.2" + } +} diff --git a/sdk-demo-application/backend/phone_data.js b/sdk-demo-application/backend/phone_data.js new file mode 100644 index 0000000..18f5aa3 --- /dev/null +++ b/sdk-demo-application/backend/phone_data.js @@ -0,0 +1,106 @@ +const { v4: uuidv4 } = require('uuid') + +const lastModified = Date.now() + +module.exports = [ + { + id: uuidv4(), + "firstName": "John", + "lastName": "Doe", + "phoneNumber": 1234567890, + "address": "123 Elm Street", + "city": "Springfield", + "country": "USA", + lastModified + }, + { + id: uuidv4(), + "firstName": "Alice", + "lastName": "Smith", + "phoneNumber": 9876543210, + "address": "456 Oak Avenue", + "city": "Metropolis", + "country": "Canada", + lastModified + }, + { + id: uuidv4(), + "firstName": "Robert", + "lastName": "Brown", + "phoneNumber": 5551234567, + "address": "789 Pine Road", + "city": "Gotham", + "country": "USA", + lastModified + }, + { + id: uuidv4(), + "firstName": "Emily", + "lastName": "Johnson", + "phoneNumber": 4449876543, + "address": "101 Maple Lane", + "city": "Star City", + "country": "Canada", + lastModified + }, + { + id: uuidv4(), + "firstName": "Michael", + "lastName": "Williams", + "phoneNumber": 3332221111, + "address": "202 Birch Blvd", + "city": "Central City", + "country": "USA", + lastModified + }, + { + id: uuidv4(), + "firstName": "Sophia", + "lastName": "Taylor", + "phoneNumber": 8887776666, + "address": "303 Cedar Drive", + "city": "Smallville", + "country": "UK", + lastModified + }, + { + id: uuidv4(), + "firstName": "David", + "lastName": "Anderson", + "phoneNumber": 2223334444, + "address": "404 Redwood Court", + "city": "Hill Valley", + "country": "Australia", + lastModified + }, + { + id: uuidv4(), + "firstName": "Linda", + "lastName": "Martinez", + "phoneNumber": 7778889999, + "address": "505 Spruce Street", + "city": "Metropolis", + "country": "Brazil", + lastModified + }, + { + id: uuidv4(), + "firstName": "James", + "lastName": "Wilson", + "phoneNumber": 6665554444, + "address": "606 Willow Avenue", + "city": "Rivertown", + "country": "USA", + lastModified + }, + { + id: uuidv4(), + "firstName": "Olivia", + "lastName": "Moore", + "phoneNumber": 1112223333, + "address": "707 Aspen Trail", + "city": "Hawkins", + "country": "Ireland", + lastModified + } +] diff --git a/sdk-demo-application/backend/sdk.json b/sdk-demo-application/backend/sdk.json new file mode 100644 index 0000000..0576417 --- /dev/null +++ b/sdk-demo-application/backend/sdk.json @@ -0,0 +1,1919 @@ +{ + "name": "trello", + "main": { + "sdk": { + "build": { + "js": { + "title": "JavaScript", + "module": { + "name": "$ModuleName" + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "name": "js" + }, + "rb": { + "title": "Ruby", + "module": { + "name": "$ModuleName" + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "name": "rb" + }, + "py": { + "title": "Python", + "extension": "py", + "module": { + "name": "$ModuleName" + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "name": "py" + }, + "php": { + "title": "PHP", + "module": { + "name": "$ModuleName" + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "name": "php" + }, + "go": { + "title": "Go", + "module": { + "name": "$ModuleName" + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "name": "go" + } + }, + "test": { + "quick": { + "entity": { + "name": "foo" + } + } + }, + "entity": { + "board": { + "op": { + "create": { + "path": "/boards", + "method": "post", + "param": {}, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "create", + "Name": "Create", + "NAME": "CREATE" + }, + "load": { + "path": "/boards/{idBoard}", + "method": "get", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "actions": { + "required": false, + "name": "actions", + "Name": "Actions", + "NAME": "ACTIONS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_entities": { + "required": false, + "name": "actions_entities", + "Name": "Actions_entities", + "NAME": "ACTIONS_ENTITIES", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_display": { + "required": false, + "name": "actions_display", + "Name": "Actions_display", + "NAME": "ACTIONS_DISPLAY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_format": { + "required": false, + "name": "actions_format", + "Name": "Actions_format", + "NAME": "ACTIONS_FORMAT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_since": { + "required": false, + "name": "actions_since", + "Name": "Actions_since", + "NAME": "ACTIONS_SINCE", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_limit": { + "required": false, + "name": "actions_limit", + "Name": "Actions_limit", + "NAME": "ACTIONS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_fields": { + "required": false, + "name": "action_fields", + "Name": "Action_fields", + "NAME": "ACTION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_member": { + "required": false, + "name": "action_member", + "Name": "Action_member", + "NAME": "ACTION_MEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_member_fields": { + "required": false, + "name": "action_member_fields", + "Name": "Action_member_fields", + "NAME": "ACTION_MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_memberCreator": { + "required": false, + "name": "action_membercreator", + "Name": "Action_memberCreator", + "NAME": "ACTION_MEMBERCREATOR", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_memberCreator_fields": { + "required": false, + "name": "action_membercreator_fields", + "Name": "Action_memberCreator_fields", + "NAME": "ACTION_MEMBERCREATOR_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_attachments": { + "required": false, + "name": "card_attachments", + "Name": "Card_attachments", + "NAME": "CARD_ATTACHMENTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_attachment_fields": { + "required": false, + "name": "card_attachment_fields", + "Name": "Card_attachment_fields", + "NAME": "CARD_ATTACHMENT_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_checklists": { + "required": false, + "name": "card_checklists", + "Name": "Card_checklists", + "NAME": "CARD_CHECKLISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_stickers": { + "required": false, + "name": "card_stickers", + "Name": "Card_stickers", + "NAME": "CARD_STICKERS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "boardStars": { + "required": false, + "name": "boardstars", + "Name": "BoardStars", + "NAME": "BOARDSTARS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "labels": { + "required": false, + "name": "labels", + "Name": "Labels", + "NAME": "LABELS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "label_fields": { + "required": false, + "name": "label_fields", + "Name": "Label_fields", + "NAME": "LABEL_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "labels_limit": { + "required": false, + "name": "labels_limit", + "Name": "Labels_limit", + "NAME": "LABELS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "lists": { + "required": false, + "name": "lists", + "Name": "Lists", + "NAME": "LISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "list_fields": { + "required": false, + "name": "list_fields", + "Name": "List_fields", + "NAME": "LIST_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships": { + "required": false, + "name": "memberships", + "Name": "Memberships", + "NAME": "MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships_member": { + "required": false, + "name": "memberships_member", + "Name": "Memberships_member", + "NAME": "MEMBERSHIPS_MEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships_member_fields": { + "required": false, + "name": "memberships_member_fields", + "Name": "Memberships_member_fields", + "NAME": "MEMBERSHIPS_MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "members": { + "required": false, + "name": "members", + "Name": "Members", + "NAME": "MEMBERS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "member_fields": { + "required": false, + "name": "member_fields", + "Name": "Member_fields", + "NAME": "MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "membersInvited": { + "required": false, + "name": "membersinvited", + "Name": "MembersInvited", + "NAME": "MEMBERSINVITED", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "membersInvited_fields": { + "required": false, + "name": "membersinvited_fields", + "Name": "MembersInvited_fields", + "NAME": "MEMBERSINVITED_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "checklists": { + "required": false, + "name": "checklists", + "Name": "Checklists", + "NAME": "CHECKLISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "checklist_fields": { + "required": false, + "name": "checklist_fields", + "Name": "Checklist_fields", + "NAME": "CHECKLIST_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization": { + "required": false, + "name": "organization", + "Name": "Organization", + "NAME": "ORGANIZATION", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_fields": { + "required": false, + "name": "organization_fields", + "Name": "Organization_fields", + "NAME": "ORGANIZATION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_memberships": { + "required": false, + "name": "organization_memberships", + "Name": "Organization_memberships", + "NAME": "ORGANIZATION_MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "myPrefs": { + "required": false, + "name": "myprefs", + "Name": "MyPrefs", + "NAME": "MYPREFS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "load", + "Name": "Load", + "NAME": "LOAD" + }, + "save": { + "path": "/boards/{idBoard}", + "method": "put", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "save", + "Name": "Save", + "NAME": "SAVE" + }, + "remove": { + "path": "/boards/{idBoard}", + "method": "delete", + "param": {}, + "query": {}, + "name": "remove", + "Name": "Remove", + "NAME": "REMOVE" + }, + "list": { + "path": "/members/{idMember}/boards", + "method": "get", + "param": { + "idMember": { + "required": true, + "name": "idmember", + "Name": "IdMember", + "NAME": "IDMEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "filter": { + "required": false, + "name": "filter", + "Name": "Filter", + "NAME": "FILTER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions": { + "required": false, + "name": "actions", + "Name": "Actions", + "NAME": "ACTIONS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_entities": { + "required": false, + "name": "actions_entities", + "Name": "Actions_entities", + "NAME": "ACTIONS_ENTITIES", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_limit": { + "required": false, + "name": "actions_limit", + "Name": "Actions_limit", + "NAME": "ACTIONS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_format": { + "required": false, + "name": "actions_format", + "Name": "Actions_format", + "NAME": "ACTIONS_FORMAT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_since": { + "required": false, + "name": "actions_since", + "Name": "Actions_since", + "NAME": "ACTIONS_SINCE", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_fields": { + "required": false, + "name": "action_fields", + "Name": "Action_fields", + "NAME": "ACTION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships": { + "required": false, + "name": "memberships", + "Name": "Memberships", + "NAME": "MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization": { + "required": false, + "name": "organization", + "Name": "Organization", + "NAME": "ORGANIZATION", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_fields": { + "required": false, + "name": "organization_fields", + "Name": "Organization_fields", + "NAME": "ORGANIZATION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "lists": { + "required": false, + "name": "lists", + "Name": "Lists", + "NAME": "LISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "list", + "Name": "List", + "NAME": "LIST" + } + }, + "field": {}, + "cmd": {}, + "name": "board", + "Name": "Board", + "NAME": "BOARD", + "publish": true + }, + "list": { + "op": { + "create": { + "path": "/lists", + "method": "post", + "param": {}, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "create", + "Name": "Create", + "NAME": "CREATE" + }, + "load": { + "path": "/lists/{idList}", + "method": "get", + "param": { + "idList": { + "required": true, + "name": "idlist", + "Name": "IdList", + "NAME": "IDLIST", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "board": { + "required": false, + "name": "board", + "Name": "Board", + "NAME": "BOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "board_fields": { + "required": false, + "name": "board_fields", + "Name": "Board_fields", + "NAME": "BOARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "load", + "Name": "Load", + "NAME": "LOAD" + }, + "save": { + "path": "/lists/{idList}", + "method": "put", + "param": { + "idList": { + "required": true, + "name": "idlist", + "Name": "IdList", + "NAME": "IDLIST", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "save", + "Name": "Save", + "NAME": "SAVE" + }, + "list": { + "path": "/boards/{idBoard}/lists", + "method": "get", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "filter": { + "required": false, + "name": "filter", + "Name": "Filter", + "NAME": "FILTER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "list", + "Name": "List", + "NAME": "LIST" + } + }, + "field": {}, + "cmd": {}, + "name": "list", + "Name": "List", + "NAME": "LIST", + "publish": true + } + }, + "option": { + "endpoint": { + "kind": "String", + "short": "Trello API URL", + "name": "endpoint", + "publish": true + }, + "apikey": { + "kind": "String", + "short": "Trello API Key", + "name": "apikey", + "publish": true + }, + "fetch": { + "kind": "Any", + "publish": false, + "name": "fetch" + } + }, + "feature": {} + }, + "api": { + "entity": { + "board": { + "op": { + "create": { + "path": "/boards", + "method": "post", + "param": {}, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "create", + "Name": "Create", + "NAME": "CREATE" + }, + "load": { + "path": "/boards/{idBoard}", + "method": "get", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "actions": { + "required": false, + "name": "actions", + "Name": "Actions", + "NAME": "ACTIONS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_entities": { + "required": false, + "name": "actions_entities", + "Name": "Actions_entities", + "NAME": "ACTIONS_ENTITIES", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_display": { + "required": false, + "name": "actions_display", + "Name": "Actions_display", + "NAME": "ACTIONS_DISPLAY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_format": { + "required": false, + "name": "actions_format", + "Name": "Actions_format", + "NAME": "ACTIONS_FORMAT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_since": { + "required": false, + "name": "actions_since", + "Name": "Actions_since", + "NAME": "ACTIONS_SINCE", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_limit": { + "required": false, + "name": "actions_limit", + "Name": "Actions_limit", + "NAME": "ACTIONS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_fields": { + "required": false, + "name": "action_fields", + "Name": "Action_fields", + "NAME": "ACTION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_member": { + "required": false, + "name": "action_member", + "Name": "Action_member", + "NAME": "ACTION_MEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_member_fields": { + "required": false, + "name": "action_member_fields", + "Name": "Action_member_fields", + "NAME": "ACTION_MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_memberCreator": { + "required": false, + "name": "action_membercreator", + "Name": "Action_memberCreator", + "NAME": "ACTION_MEMBERCREATOR", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_memberCreator_fields": { + "required": false, + "name": "action_membercreator_fields", + "Name": "Action_memberCreator_fields", + "NAME": "ACTION_MEMBERCREATOR_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_attachments": { + "required": false, + "name": "card_attachments", + "Name": "Card_attachments", + "NAME": "CARD_ATTACHMENTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_attachment_fields": { + "required": false, + "name": "card_attachment_fields", + "Name": "Card_attachment_fields", + "NAME": "CARD_ATTACHMENT_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_checklists": { + "required": false, + "name": "card_checklists", + "Name": "Card_checklists", + "NAME": "CARD_CHECKLISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_stickers": { + "required": false, + "name": "card_stickers", + "Name": "Card_stickers", + "NAME": "CARD_STICKERS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "boardStars": { + "required": false, + "name": "boardstars", + "Name": "BoardStars", + "NAME": "BOARDSTARS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "labels": { + "required": false, + "name": "labels", + "Name": "Labels", + "NAME": "LABELS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "label_fields": { + "required": false, + "name": "label_fields", + "Name": "Label_fields", + "NAME": "LABEL_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "labels_limit": { + "required": false, + "name": "labels_limit", + "Name": "Labels_limit", + "NAME": "LABELS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "lists": { + "required": false, + "name": "lists", + "Name": "Lists", + "NAME": "LISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "list_fields": { + "required": false, + "name": "list_fields", + "Name": "List_fields", + "NAME": "LIST_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships": { + "required": false, + "name": "memberships", + "Name": "Memberships", + "NAME": "MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships_member": { + "required": false, + "name": "memberships_member", + "Name": "Memberships_member", + "NAME": "MEMBERSHIPS_MEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships_member_fields": { + "required": false, + "name": "memberships_member_fields", + "Name": "Memberships_member_fields", + "NAME": "MEMBERSHIPS_MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "members": { + "required": false, + "name": "members", + "Name": "Members", + "NAME": "MEMBERS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "member_fields": { + "required": false, + "name": "member_fields", + "Name": "Member_fields", + "NAME": "MEMBER_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "membersInvited": { + "required": false, + "name": "membersinvited", + "Name": "MembersInvited", + "NAME": "MEMBERSINVITED", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "membersInvited_fields": { + "required": false, + "name": "membersinvited_fields", + "Name": "MembersInvited_fields", + "NAME": "MEMBERSINVITED_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "checklists": { + "required": false, + "name": "checklists", + "Name": "Checklists", + "NAME": "CHECKLISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "checklist_fields": { + "required": false, + "name": "checklist_fields", + "Name": "Checklist_fields", + "NAME": "CHECKLIST_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization": { + "required": false, + "name": "organization", + "Name": "Organization", + "NAME": "ORGANIZATION", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_fields": { + "required": false, + "name": "organization_fields", + "Name": "Organization_fields", + "NAME": "ORGANIZATION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_memberships": { + "required": false, + "name": "organization_memberships", + "Name": "Organization_memberships", + "NAME": "ORGANIZATION_MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "myPrefs": { + "required": false, + "name": "myprefs", + "Name": "MyPrefs", + "NAME": "MYPREFS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "load", + "Name": "Load", + "NAME": "LOAD" + }, + "save": { + "path": "/boards/{idBoard}", + "method": "put", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "save", + "Name": "Save", + "NAME": "SAVE" + }, + "remove": { + "path": "/boards/{idBoard}", + "method": "delete", + "param": {}, + "query": {}, + "name": "remove", + "Name": "Remove", + "NAME": "REMOVE" + }, + "list": { + "path": "/members/{idMember}/boards", + "method": "get", + "param": { + "idMember": { + "required": true, + "name": "idmember", + "Name": "IdMember", + "NAME": "IDMEMBER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "filter": { + "required": false, + "name": "filter", + "Name": "Filter", + "NAME": "FILTER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions": { + "required": false, + "name": "actions", + "Name": "Actions", + "NAME": "ACTIONS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_entities": { + "required": false, + "name": "actions_entities", + "Name": "Actions_entities", + "NAME": "ACTIONS_ENTITIES", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_limit": { + "required": false, + "name": "actions_limit", + "Name": "Actions_limit", + "NAME": "ACTIONS_LIMIT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_format": { + "required": false, + "name": "actions_format", + "Name": "Actions_format", + "NAME": "ACTIONS_FORMAT", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "actions_since": { + "required": false, + "name": "actions_since", + "Name": "Actions_since", + "NAME": "ACTIONS_SINCE", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "action_fields": { + "required": false, + "name": "action_fields", + "Name": "Action_fields", + "NAME": "ACTION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "memberships": { + "required": false, + "name": "memberships", + "Name": "Memberships", + "NAME": "MEMBERSHIPS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization": { + "required": false, + "name": "organization", + "Name": "Organization", + "NAME": "ORGANIZATION", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "organization_fields": { + "required": false, + "name": "organization_fields", + "Name": "Organization_fields", + "NAME": "ORGANIZATION_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "lists": { + "required": false, + "name": "lists", + "Name": "Lists", + "NAME": "LISTS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "list", + "Name": "List", + "NAME": "LIST" + } + }, + "field": {}, + "cmd": {}, + "name": "board", + "Name": "Board", + "NAME": "BOARD" + }, + "list": { + "op": { + "create": { + "path": "/lists", + "method": "post", + "param": {}, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "create", + "Name": "Create", + "NAME": "CREATE" + }, + "load": { + "path": "/lists/{idList}", + "method": "get", + "param": { + "idList": { + "required": true, + "name": "idlist", + "Name": "IdList", + "NAME": "IDLIST", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "board": { + "required": false, + "name": "board", + "Name": "Board", + "NAME": "BOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "board_fields": { + "required": false, + "name": "board_fields", + "Name": "Board_fields", + "NAME": "BOARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "load", + "Name": "Load", + "NAME": "LOAD" + }, + "save": { + "path": "/lists/{idList}", + "method": "put", + "param": { + "idList": { + "required": true, + "name": "idlist", + "Name": "IdList", + "NAME": "IDLIST", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "body": { + "required": true, + "name": "body", + "Name": "Body", + "NAME": "BODY", + "type": "object", + "Type": "Object", + "TYPE": "OBJECT" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "save", + "Name": "Save", + "NAME": "SAVE" + }, + "list": { + "path": "/boards/{idBoard}/lists", + "method": "get", + "param": { + "idBoard": { + "required": true, + "name": "idboard", + "Name": "IdBoard", + "NAME": "IDBOARD", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "query": { + "cards": { + "required": false, + "name": "cards", + "Name": "Cards", + "NAME": "CARDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "card_fields": { + "required": false, + "name": "card_fields", + "Name": "Card_fields", + "NAME": "CARD_FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "filter": { + "required": false, + "name": "filter", + "Name": "Filter", + "NAME": "FILTER", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "fields": { + "required": false, + "name": "fields", + "Name": "Fields", + "NAME": "FIELDS", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "key": { + "required": true, + "name": "key", + "Name": "Key", + "NAME": "KEY", + "type": "string", + "Type": "String", + "TYPE": "STRING" + }, + "token": { + "required": true, + "name": "token", + "Name": "Token", + "NAME": "TOKEN", + "type": "string", + "Type": "String", + "TYPE": "STRING" + } + }, + "name": "list", + "Name": "List", + "NAME": "LIST" + } + }, + "field": {}, + "cmd": {}, + "name": "list", + "Name": "List", + "NAME": "LIST" + } + }, + "name": "trello", + "Name": "Trello", + "NAME": "TRELLO" + }, + "def": { + "desc": "This document describes the REST API of Trello as published by Trello.com.\n - Official Documentation\n - The HTML pages that were scraped in order to generate this specification." + } + } +} \ No newline at end of file diff --git a/sdk-demo-application/backend/server.js b/sdk-demo-application/backend/server.js new file mode 100644 index 0000000..fb26811 --- /dev/null +++ b/sdk-demo-application/backend/server.js @@ -0,0 +1,179 @@ + +const express = require('express') + +const sdk_model = require('./sdk.json') + +const { TrelloSDK } = require('trello-sdk') + +console.log(TrelloSDK) + + +const app = express() + +const port = 8000 + +app.use(express.json()) + +const SDK_NAME = "TrelloSDK" + +// TODO: transform from the model +const entities = { + 'board': { + 'load': {}, + 'list': { + query: { + idMember: String + } + }, + 'create': {}, + 'save': {}, + 'remove': {} + }, + 'list': { + 'load': {}, + 'list': { + query: { + idBoard: String + } + }, + 'create': {}, + 'save': {}, + // 'remove': {} + } +} + +function cap(s) { + return s[0].toUpperCase() + s.slice(1) +} + +const client = TrelloSDK.make({ + endpoint: process.env.TRELLO_ENDPOINT, + apikey: process.env.TRELLO_APIKEY, + token: process.env.TRELLO_TOKEN, +}) + +for(const entity_name in entities) { + const entity = entities[entity_name] + for(const op in entity) { + const settings = entity[op] + + if(op == 'list') { + app.get(`/api/${SDK_NAME}/${entity_name}/${op}`, async (req, res) => { + // console.log('cap: ', client[cap(entity_name)]()[op] ) + for(let q in settings.query) { + if(!req.query[q]) { + res.status(400) + return res.send(JSON.stringify(q + ': REQUIRED')) + } + } + try { + let list = await client[cap(entity_name)]().list(req.query) + res.status(200) + return res.send(JSON.stringify(list.map(item => item.data))) + } catch(err) { + res.status(400) + res.send(JSON.stringify("error occured")) + } + + }) + } + + if(op == 'load') { + app.get(`/api/${SDK_NAME}/${entity_name}/${op}/:uid`, async (req, res) => { + const id = req.params.uid + console.log('cap: ', client[cap(entity_name)]()[op] ) + for(let q in settings.query) { + if(!req.query[q]) { + res.status(400) + return res.send(JSON.stringify(q + ': REQUIRED')) + } + } + + try { + let item = await client[cap(entity_name)]().load({ id, }) + console.log('load item: ', item) + res.status(200) + return res.send(JSON.stringify(item.data ? item.data : item)) + } catch(err) { + res.status(400) + res.send(JSON.stringify("error occured")) + } + }) + + } + + } +} + + + +/* + +// "/api/${SDK_NAME}/${entity}/${op_name}" + +let phone_list_data = require('./phone_data.js') +const client_list_data = require('./client_data.js') +let entity = Object.keys(entities)[0] + +app.get(`/api/${SDK_NAME}/${entity}/list`, async (req, res) => { + res.status(200) + res.send(JSON.stringify(phone_list_data)) +}) + +app.get(`/api/${SDK_NAME}/${entity}/load/:uid`, async (req, res) => { + const id = req.params.uid + const res_body = phone_list_data.find(phone_item => phone_item.id == id) + + res.status(200) + res.send(JSON.stringify(res_body)) +}) + +app.put(`/api/${SDK_NAME}/${entity}/save/:uid`, async (req, res) => { + const id = req.params.uid + + const res_body = phone_list_data.find(phone_item => phone_item.id == id) + + + console.log('PUT: req.body: ', req.body) + + // DO modify/save + + res.status(200); + res.send(JSON.stringify(res_body)) +}) + +app.post(`/api/${SDK_NAME}/${entity}/create`, async (req, res) => { + // DO create + res.status(200); + res.send(JSON.stringify(req.body)) +}) + +app.delete(`/api/${SDK_NAME}/${entity}/remove/:uid`, async (req, res) => { + const id = req.params.uid + phone_list_data = phone_list_data.filter(phone_item => phone_item.id != id) + + res.status(200) + res.send(JSON.stringify('null')) +}) + +entity = Object.keys(entities)[1] +app.get(`/api/${SDK_NAME}/${entity}/list`, async (req, res) => { + res.status(200); + res.send(JSON.stringify(client_list_data)) +}) +app.get(`/api/${SDK_NAME}/${entity}/load/:uid`, async (req, res) => { + const id = req.params.uid + const res_body = client_list_data.find(client_item => client_item.id == id) + + res.status(200); + res.send(JSON.stringify(res_body)) +}) + +*/ + + +app.listen(port, () => { + console.log(`Sample Backend App listening on port 127.0.0.1:${port}`) +}) + + diff --git a/sdk-demo-application/frontend/css/styles.css b/sdk-demo-application/frontend/css/styles.css new file mode 100644 index 0000000..05c8ede --- /dev/null +++ b/sdk-demo-application/frontend/css/styles.css @@ -0,0 +1,310 @@ +/* + * TODO: Inject SDK Client style + */ + +body { + display: grid; + /* + height: 100%; + width: 100%; + */ +} + +*::-webkit-scrollbar { + width: 5px; +} + +*::-webkit-scrollbar-track { + background-color: #888; + border-radius: 4px; +} + +*::-webkit-scrollbar-thumb { + background-color: #444; + border-radius: 4px; + transition: background-color 0.3s; +} + +*::-webkit-scrollbar-thumb:hover { + background-color: #6c7ae0; +} + +.container { + display: flex; + /* + display: grid; + grid-template-columns: 1fr 1fr 1fr; + */ + height: 85vh; + /* height: 100%; */ + /* overflow: hidden; */ +} + +.split { + flex: inherit; + display: flex; + /* justify-content: space-around; */ + /* align-items: center; */ + /* justify-content: center; */ + padding: 1em; + position: relative; +} + +.centered { + text-align: center; +} + +#basicLedTable { + width: 100%; + border-collapse: collapse; + /* margin: 20px; */ + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); +} + +.tableheader, .tablecolumn { + padding: 12px; + border: 1px solid #ddd; + text-align: center; +} + +th { + background-color: #6c7ae0; + color: white; +} + +tr:nth-child(even) { + background-color: #f9f9f9; +} + +tr:hover { + background-color: #f1f1f1; +} + +table { + /* table-layout: fixed; */ + width: 100%; + border:1px solid; + margin-top:20px; + border-collapse: collapse; +} +td { + min-width: 250px; + border:1px solid; +} + +.edit-btn, .save-btn { + cursor: pointer; + padding: 5px 10px; + color: #6c7ae0; + border: 1px solid #6c7ae0; + background-color: white; + border-radius: 3px; + transition: background-color 0.2s; +} + +.edit-btn:hover, .save-btn:hover { + background-color: #6c7ae0; + color: white; +} + +.terminal { + position: absolute; /* never use this with "display: grid" */ + width: 90%; + /* height: 20vh; */ + + margin: 0.5em; + padding: 0.5em; + + max-width: 90%; + max-height: 70%; + background-color: #1e1e1e; + resize: both; + /* color: #00ff00; */ + font-family: "Courier New", Courier, monospace; + font-size: 14px; + border-radius: 5px; + box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2); + /* white-space: pre-wrap; */ + overflow: auto; +} + +.tab-header { + display: flex; + align-items: center; + background-color: #333; + color: white; + padding: 10px 20px; + border-radius: 8px 8px 0 0; + box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); + /*width: 100%;*/ + /*max-width: 150vh; */ +} + +.tab-header img { + height: 8vh; + width: 8vh; + margin-right: 15px; +} + +.tab-header h1 { + font-size: 18px; + margin-right: auto; + color: #fff; +} + +.tab-nav { + display: flex; + gap: 15px; +} + +.tab-nav a { + color: #ddd; + text-decoration: none; + font-size: 16px; + padding: 8px 12px; + border-radius: 4px; + transition: background-color 0.3s, color 0.3s; +} + +.tab-nav a:hover { + background-color: #555; + color: #fff; +} + +.tab-nav a.active { + background-color: #6c7ae0; + color: white; + font-weight: bold; +} + + +#formEditor { + background-color: #ffffff; + padding: 25px 20px; + width: 100%; + /* max-width: 500px; */ + border-radius: 10px; +} + +/* +.form-grid { +display: grid; +grid-template-columns: repeat(3, 1fr); +gap: 1em; +} + */ + + +.form-group label { + font-weight: bold; + color: #555; + display: block; + margin-bottom: 5px; +} + +.form-group input { + width: 100%; + padding: 10px; + font-size: 16px; + color: #333; + border: 1px solid #ddd; + border-radius: 5px; + transition: border-color 0.3s ease; +} + +.form-group input:focus, +.form-group select:focus, +.form-group textarea:focus { + border-color: #6c7ae0; + outline: none; +} + +.form-group button { + width: 100%; + padding: 12px; + font-size: 18px; + font-weight: bold; + color: #fff; + background-color: #6c7ae0; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +.form-group button:hover { + background-color: #5a6dd4; +} + +.sidenav { + /* height: 100vh; */ + width: 0; + background-color: #2b2f3a; + color: #fff; + overflow: auto; + transition: width 0.5s; + box-shadow: 2px 0 5px rgba(0, 0, 0, 0.2); +} + +.sidenav-header { + padding: 20px 30px; + font-size: 1.5rem; + background-color: #1f232b; + border-bottom: 1px solid #444; + display: flex; + align-items: center; + justify-content: space-between; +} + +.sidenav-header h2 { + margin: 0; + font-weight: normal; +} + +.closebtn { + font-size: 24px; + color: #bbb; + cursor: pointer; + transition: color 0.3s; +} + +.closebtn:hover { + color: #fff; +} + +.sidenav a { + padding: 15px 30px; + font-size: 1rem; + color: #bbb; + text-decoration: none; + display: flex; + align-items: center; + transition: background-color 0.3s, color 0.3s; +} + +.sidenav a:focus { + background-color:red; +} + +.sidenav a:hover { + background-color: #444; + color: #fff; +} + +.openbtn { + border-radius: 0.5em; + font-size: 18px; + cursor: pointer; + padding: 10px 15px; + color: #2b2f3a; + background-color: #ccc; + border: none; + top: 20px; + left: 20px; + transition: color 0.3s, background-color 0.3s; +} + +.openbtn:hover { + background-color: #e1e1e6; + color: #2b2f3a; +} diff --git a/sdk-demo-application/frontend/index.html b/sdk-demo-application/frontend/index.html new file mode 100644 index 0000000..b253b15 --- /dev/null +++ b/sdk-demo-application/frontend/index.html @@ -0,0 +1,48 @@ + + + + + + + + +
+ Logo + +
+
+ +
+
+
+

Editor

+
+
+
+
+ + + diff --git a/sdk-demo-application/frontend/js/DataTable.js b/sdk-demo-application/frontend/js/DataTable.js new file mode 100644 index 0000000..28aaa0d --- /dev/null +++ b/sdk-demo-application/frontend/js/DataTable.js @@ -0,0 +1,112 @@ + +function createTable(header, data, rowClick = function() {}) { + let div = document.createElement('div') + let table = document.createElement('table') + + table.id = "basicLedTable" + + + let thead = document.createElement('thead') + let tbody = document.createElement('tbody') + + let thr = document.createElement('tr') + + + for(const column of header) { + /* + if(column.title == 'id') { + continue + } + */ + + const th = document.createElement('th') + th.classList.add('tableheader') + th.textContent = column.title || 'Blank' + + thr.appendChild(th) + + } + thead.appendChild(thr) + + let selected_rows = { + prev: null + } + + data.forEach(entry => { + let tbr = document.createElement('tr') + let i = 0 // TODO: Refactor once we define the interface for header + + if(entry.id != null) { + tbr.dataset.id = entry.id + } + + for(let column of header) { + /* + if(column.key == 'id') { + continue + } + */ + let key = column.key + const td = document.createElement('td') + td.classList.add('tablecolumn') + + // tbr.id = entry.id || i++; + + // TODO: Try to come up with a more efficient way since entry[key] is basically stored in the td.textContent + // See: https://developer.mozilla.org/en-US/docs/Web/API/DOMStringMap + + if(typeof entry[key] == 'object' && entry[key] != null) { + // key + '_json' + tbr.dataset[key] = JSON.stringify(entry[key]) + } else { + tbr.dataset[key] = entry[key] + } + + td.textContent = entry[key] + + tbr.appendChild(td) + } + + tbr.addEventListener('click', async function (event) { + // Even use the Lexical Environment(tbr) or event.target.parentNode + // console.log(this.dataset) + if(selected_rows.prev) { + selected_rows.prev.style.border = '0' + selected_rows.prev.style.backgroundColor = '' + } + + selected_rows.prev = this // HTMLElement + + this.style.border = '3px solid #9abde1' + this.style.backgroundColor = '#9abde1' + + await rowClick.bind(this)(event, this.dataset) + }) + tbody.appendChild(tbr) + }) + + table.appendChild(thead) + table.appendChild(tbody) + + // Removed when div: style: { display: 'grid' } + div.style.maxHeight = '60%' + div.style.maxWidth = '100%' + div.style.overflow = 'auto' + + /* + background: #fff; + border-radius: 5px; + */ + + // See: https://medium.com/evodeck/responsive-data-tables-with-css-grid-3c58ecf04723 + div.style.display = 'grid'; + div.style.gridTemplateColumns = 'repeat(auto-fit, 20em)' + div.style.overflowX = 'scroll' + + div.appendChild(table) + + return div + +} + +export default createTable; diff --git a/sdk-demo-application/frontend/js/Editor.js b/sdk-demo-application/frontend/js/Editor.js new file mode 100644 index 0000000..d285971 --- /dev/null +++ b/sdk-demo-application/frontend/js/Editor.js @@ -0,0 +1,185 @@ +import { $create } from './Utils.js' + +function capitalize(s) { + return s[0].toUpperCase() + s.slice(1) +} + +function createForm(config, data_item) { + let form = document.createElement('form') + + let { + fields = {}, + op = 'create', + del_enabled, + save_enabled, + } = config + + const handler = config.handler || (() => {}) + + const { editables = {} } = fields + + + op = op.toLowerCase() + + + if(data_item.id != null) { + form.dataset.id = data_item.id + } + // form.classList.add('ford-grid') + + form.style.display = 'grid' + // TODO: Should come from config + form.style.gridTemplateColumns = '1fr '.repeat(2).trim() + form.style.gap = '1em' + + // visiable fields are a combination of data_item and editables in order to determine what field is viewable(disabled) and what editable - all in line with the swagger. + // See: `if((key in data_item) && !(key in editables)) {` below + let visible_fields = new Set([ + ...Object.keys(data_item), + ...Object.keys(editables)]) + + for(let key of visible_fields) { + /* + if(key == 'id') { + continue + } + */ + + let div = document.createElement('div') + let value = data_item[key] + + // TODO: Dynamically build the style + div.classList.add('form-group') + + let label = document.createElement('label') + let input = document.createElement('input') + + // TODO: password, email, tel, etc. + input.type = 'text' + + // NOTE: NEEDED for FormData + input.name = key + input.id = key + + let field_options = fields[key] + if(field_options) { + if(field_options.disabled) { + input.disabled = true + input.style.backgroundColor = '#ccc' + } + } + + if(!(key in editables)) { + input.disabled = true + input.style.backgroundColor = '#ccc' + } + + label.textContent = key + input.defaultValue = value != null && value || '' + + // TODO: refine to be editable but this is disabled for now + if(typeof value == 'object' && value != null) { + input.disabled = true + input.defaultValue = JSON.stringify(value) + input.style.backgroundColor = '#ccc' + } else if(value == null) { + input.disabled = true + input.defaultValue = 'null' + input.style.backgroundColor = '#ccc' + } + + div.appendChild(label) + div.appendChild(input) + + form.appendChild(div) + + } + + let div_button = $create({ + elem: 'div', + classes: [ 'form-group' ], + style: { + display: 'grid', + gridColumn: '1 / -1', + gap: '1em', + // TODO: Depending on the number of operations - usually save and delete + gridTemplateColumns: op == 'create' ? '1fr' : '1fr 1fr' + }, + children: [ + $create({ + elem: 'button', + textContent: capitalize(op), + style: op != 'create' ? { + filter: save_enabled ? 'none': 'brightness(1.5)', + pointerEvents: save_enabled ? 'all' : 'none' + } : {}, + props: { + type: 'submit', + dataset: { + 'op': op + } + } + }), + (op != 'create' ? $create({ + elem: 'button', + textContent: 'Delete', + // NOTE: ONLY For DELETE + style: { + backgroundColor: '#dd1010', + filter: del_enabled ? 'none': 'brightness(1.5)', + pointerEvents: del_enabled ? 'all' : 'none' + }, + props: { + type: 'submit', + dataset: { + 'op': 'delete' + } + } + }) : null ) + ] + }) + + form.appendChild(div_button) + + attachSubmitHandler(form, handler) + + return form +} + +function attachSubmitHandler(form, userHandler) { + + const formToJSON = (form) => { + const data = new FormData(form) + // console.log(form, data) + let result = {} + let data_keys = data.keys() + for(let key of data_keys) { + result[key] = data.get(key) + } + return result + } + + const handler = async (event) => { + event.preventDefault() + const result = formToJSON(event.target) + + result.id = form.dataset.id != null ? form.dataset.id : '' + + // TODO: NOTE THIS MAY BE SWAGGER/CASE SPECIFIC + for(let key in result) { + if(result[key] == '' || result[key] == null) { + delete result[key] + } + } + + await userHandler(event.submitter.dataset.op || '', result) + } + + form.addEventListener('submit', handler) +} + + + +export { + createForm +} diff --git a/sdk-demo-application/frontend/js/Utils.js b/sdk-demo-application/frontend/js/Utils.js new file mode 100644 index 0000000..6495333 --- /dev/null +++ b/sdk-demo-application/frontend/js/Utils.js @@ -0,0 +1,77 @@ +function $create(config) { + const { + classes = [], + style = {}, + children = [], + props = {} + } = config + + let elem = document.createElement(config.elem || 'div') + + config.id != null && (elem.id = config.id) + config.textContent != null + && (elem.textContent = config.textContent) + + Object.assign(elem.style, style) + + for(let prop in props) { + if(prop == 'dataset') { + let dataset = props[prop] + for(let set_key in dataset) { + elem.dataset[set_key] = dataset[set_key] + } + } else { + elem[prop] = props[prop] + } + } + + for(let i = 0; i < classes.length; i++) { + let cssClass = config.classes[i] + elem.classList.add(cssClass) + } + + if(typeof config.onclick == 'function') { + elem.addEventListener('click', config.onclick) + } + + // NOTE: innerHTML take priority over children + // TODO: Unless it is actually a String ( &233; ) + if(config.innerHTML != null) { + elem.innerHTML = config.innerHTML + return elem + } + + + + if(typeof children == 'function') { + elem.appendChild(children()) + return elem + } + + for(let i = 0; i < children.length; i++) { + let child = children[i] + if(typeof child == 'function') { + let node = child() + // if node is "iterateable" + if(node[Symbol.iterator] != null) { + for(let item of node) { + elem.appendChild(item) + } + } else { + elem.appendChild(node) + } + } else if(child == null) { + continue + } else { + elem.appendChild(child) + } + } + + return elem + +} + + +export { + $create +} diff --git a/sdk-demo-application/frontend/js/component.js b/sdk-demo-application/frontend/js/component.js new file mode 100644 index 0000000..721c40d --- /dev/null +++ b/sdk-demo-application/frontend/js/component.js @@ -0,0 +1,851 @@ +import { $create } from "./Utils.js" + +import JSONDOMViewer from "./json-dom-viewer.js" +import createTable from "./DataTable.js" + +import { createForm } from './Editor.js' + +const SDK_NAME = 'TrelloSDK' + +// TODO: Figure the best way to export this globally +window.createForm = createForm + +window[SDK_NAME].fields = {} + +// TODO: Separate editables for both create and save but usually the fields added in POST are the same for PUT for most Swaggers. +window[SDK_NAME].fields.editables = { + 'board': { + "post": { + "closed": { // required but NOT indicated by the SWAGGER + "type": "string", + "values": ["true", "false"] + }, + "desc": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "idBoardSource": { + "type": "string", + "description": "The id of the board to copy into the new board" + }, + "idOrganization": { + "type": "string", + "description": "The id or name of the organization to add the board to" + }, + "keepFromSource": { + "type": "string", + "description": "Components of the source board to copy" + }, + "labelNames": { + "blue": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "green": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "orange": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "purple": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "red": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "yellow": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + } + }, + "name": { + "type": "string", + "length": { + "min": 1, + "max": 16384 + } + }, + "powerUps": { + "type": "string", + "values": ["all", "calendar", "cardAging", "recap", "voting"] + }, + "prefs": { + "background": { + "type": "string", + "description": "A standard background name, or the id of a custom background" + }, + "calendarFeedEnabled": { + "type": "string", + "values": ["true", "false"] + }, + "cardAging": { + "type": "string", + "values": ["pirate", "regular"] + }, + "cardCovers": { + "type": "string", + "values": ["true", "false"] + }, + "comments": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "invitations": { + "type": "string", + "values": ["admins", "members"] + }, + "permissionLevel": { + "type": "string", + "values": ["org", "private", "public"] + }, + "selfJoin": { + "type": "string", + "values": ["true", "false"] + }, + "voting": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + } + }, + "prefs_background": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "prefs_cardAging": { + "type": "string", + "values": ["pirate", "regular"] + }, + "prefs_cardCovers": { + "type": "string", + "values": ["true", "false"] + }, + "prefs_comments": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "prefs_invitations": { + "type": "string", + "values": ["admins", "members"] + }, + "prefs_permissionLevel": { + "type": "string", + "values": ["org", "private", "public"] + }, + "prefs_selfJoin": { + "type": "string", + "values": ["true", "false"] + }, + "prefs_voting": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "subscribed": { + "type": "string", + "values": ["true", "false"] + } + }, + "put": { + "closed": { // required but NOT indicated by the SWAGGER + "type": "string", + "values": ["true", "false"] + }, + "desc": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "idBoardSource": { + "type": "string", + "description": "The id of the board to copy into the new board" + }, + "idOrganization": { + "type": "string", + "description": "The id or name of the organization to add the board to" + }, + "keepFromSource": { + "type": "string", + "description": "Components of the source board to copy" + }, + "labelNames": { + "blue": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "green": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "orange": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "purple": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "red": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "yellow": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + } + }, + "name": { + "type": "string", + "length": { + "min": 1, + "max": 16384 + } + }, + "powerUps": { + "type": "string", + "values": ["all", "calendar", "cardAging", "recap", "voting"] + }, + "prefs": { + "background": { + "type": "string", + "description": "A standard background name, or the id of a custom background" + }, + "calendarFeedEnabled": { + "type": "string", + "values": ["true", "false"] + }, + "cardAging": { + "type": "string", + "values": ["pirate", "regular"] + }, + "cardCovers": { + "type": "string", + "values": ["true", "false"] + }, + "comments": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "invitations": { + "type": "string", + "values": ["admins", "members"] + }, + "permissionLevel": { + "type": "string", + "values": ["org", "private", "public"] + }, + "selfJoin": { + "type": "string", + "values": ["true", "false"] + }, + "voting": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + } + }, + "prefs_background": { + "type": "string", + "length": { + "min": 0, + "max": 16384 + } + }, + "prefs_cardAging": { + "type": "string", + "values": ["pirate", "regular"] + }, + "prefs_cardCovers": { + "type": "string", + "values": ["true", "false"] + }, + "prefs_comments": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "prefs_invitations": { + "type": "string", + "values": ["admins", "members"] + }, + "prefs_permissionLevel": { + "type": "string", + "values": ["org", "private", "public"] + }, + "prefs_selfJoin": { + "type": "string", + "values": ["true", "false"] + }, + "prefs_voting": { + "type": "string", + "values": ["disabled", "members", "observers", "org", "public"] + }, + "subscribed": { + "type": "string", + "values": ["true", "false"] + } + }, + }, + + "list": { + "post": { + "closed": { + "type": "string", + "values": ["true", "false"] + }, + "idBoard": { + "type": "string", + "description": "id of the board that the list should be added to" + }, + "idListSource": { + "type": "string", + "description": "The id of the list to copy into a new list" + }, + "name": { + "type": "string", + "length": { + "min": 1, + "max": 16384 + } + }, + "pos": { + "type": "string", + "values": ["top", "bottom"], + "description": "A position. 'top', 'bottom', or a positive number" + }, + "subscribed": { + "type": "string", + "values": ["true", "false"] + } + }, + "put": { + "closed": { + "type": "string", + "values": ["true", "false"] + }, + "idBoard": { + "type": "string", + "description": "id of the board that the list should be added to" + }, + "idListSource": { + "type": "string", + "description": "The id of the list to copy into a new list" + }, + "name": { + "type": "string", + "length": { + "min": 1, + "max": 16384 + } + }, + "pos": { + "type": "string", + "values": ["top", "bottom"], + "description": "A position. 'top', 'bottom', or a positive number" + }, + "subscribed": { + "type": "string", + "values": ["true", "false"] + } + } + } + +} + +let entities = [ + { + name: 'board', + title: 'Board', // just capitalized + + // TODO: Transform from model + op: { + save: {}, + create: {}, + list: { + query: { + idMember: { + type: String, + // HARDCODED - make a query button/form + default: 'me' + } + } + }, + remove: {} + }, + + // TODO: Transform from model + formFields: Object.keys(window[SDK_NAME].fields.editables['board'].post) + }, + { + name: 'list', + title: 'List', + + // TODO: Transform from model + op: { + save: {}, + create: {}, + list: { + query: { + idBoard: { + type: String, + // HARDCODED - make a query button/form + default: '6735f4225f8fbbd10bba2da0' + } + } + }, + // If not found here, it is considered "UNSUPPORTED" + // remove: {} + }, + + formFields: Object.keys(window[SDK_NAME].fields.editables['list'].post) + } +] + +console.log(SDK_NAME, window[SDK_NAME]) +window[SDK_NAME].ui.current_entity = entities[0] // DEFAULT + + + +function injectDataEditor(data, op, handler) { + let dataEditorDivContainer = document.querySelector('#dataEditor') + let formContainer; + + op = op[0].toUpperCase() + op.slice(1) + + // console.log('data: ', data) + + dataEditorDivContainer.innerHTML = '' + + let form = createForm({ + fields: { + 'id': { disabled: true }, + 'lastModified': { disabled: true }, + editables: window[SDK_NAME].fields.editables[ + window[SDK_NAME].ui.current_entity.name].put + }, + op, // TODO: ops: ['Save', 'Delete'] + handler: handler || ((op, json_data) => console.log('result: ', op, json_data)), + del_enabled: !!window[SDK_NAME].ui.current_entity.op.remove, + save_enabled: !!window[SDK_NAME].ui.current_entity.op.save + }, data) + + + let div = $create({ + elem: 'div', + children: [ + $create({ + elem: 'h1', + textContent: 'Editor' + }), + $create({ + elem: 'div', + id: 'formEditor', + children: () => form + }), + $create({ + elem: 'h3', + textContent: 'Json Viewer' + }), + $create({ + elem: 'div', + classes: ['terminal'], + children: () => JSONDOMViewer(data) + }) + ] + }) + dataEditorDivContainer.appendChild(div) + +} + +function injectForm(form) { + let formContainer = document.querySelector('#formEditor') + + // See https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML + formContainer.innerHTML = '' + + formContainer.appendChild(form) +} + + +async function loadComponents(current_entity) { + + let entityTableContainer = document.querySelector('#entityTable') + let dataEditor = document.querySelector('#dataEditor') + + entityTableContainer.innerHTML = '' + dataEditor.innerHTML = '' + + // Default DataEditor Container for now + dataEditor.appendChild($create({ + elem: 'div', + children: [ + $create({ + elem: 'h1', + textContent: 'Editor' + }) + ] + })) + + + /* + +
+

Entity Table

+ +
+ */ + let entityTable = $create({ + elem: 'div', + children: [ + $create({ + elem: 'h1', + textContent: 'Entity Table' + }), + $create({ + elem: 'div', + style: { + display: 'grid', + gridTemplateColumns: '1fr 1fr', + gap: '40em' + }, + children: [ + $create({ + elem: 'button', + id: 'openSidebarEntities', + classes: ['openbtn'], + innerHTML: window[SDK_NAME].ui.navtab.opened + ? "« Hide Entities" : "» Show Entities", + onclick: function() { + let navopened = window[SDK_NAME].ui.navtab.opened + if(!navopened) { + SideNav.style.width = "25vh" + this.innerHTML = "« Hide Entities" + window[SDK_NAME].ui.navtab.opened = true + } else { + SideNav.style.width = '0' + this.innerHTML = "» Show Entities" + window[SDK_NAME].ui.navtab.opened = false + } + } + }), + $create({ + elem: 'button', + classes: ['openbtn'], + textContent: 'Add Entity', + onclick: function() { + let new_entity = window[SDK_NAME].ui.current_entity.formFields.reduce((acc, item) => { + acc[item] = '' + return acc + }, {}) + + console.log('new entity: ', new_entity) + + // TODO: Exclude delete button/op, Only create button + injectDataEditor(new_entity, 'create', async (op, item) => { + + if(op == 'create') { + let post_item = await fetch(`/api/${SDK_NAME}/${window[SDK_NAME].ui.current_entity.name}/create`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + ...item + }) + }) + let json_out = await post_item.json() + console.log('post: ', json_out) + + // TODO: more efficient solution // add to a table + await loadComponents(window[SDK_NAME].ui.current_entity) + + } + + }) + + } + }) + ] + }) + ] + + }) + + entityTableContainer.appendChild(entityTable) + + const query_entries = Object.entries(current_entity.op.list.query || {}) + let query = query_entries.reduce((acc, entry, i) => { + acc += entry[0] + '=' + entry[1].default + if(i < query_entries.length-1) acc += '&' + + return acc + }, '') + + query = query == '' ? '' : '?' + query + + let out = await fetch(`/api/${SDK_NAME}/${current_entity.name}/list${query}`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json' + } + }) + + let json_out = await out.json() + + // TODO: Explicit transformed header from the model + let header = json_out[0] != null && Object.keys(json_out[0]).map(key=>({title: key, key})) + + // [ { title: ..., key: ..., }, ... ] + + console.log(header) + + // See if we need to do this + // loadForm(json_out[0] || {}) + + let table = createTable(header, + json_out, // .map(item => item.data), // backend or frontend processing? + async function (event, item) { + + + // console.log('selected row: ', this) + + + console.log('item.id: ', item.id) + + let load_entity + + if(window[SDK_NAME].ui.datatable.load == 'data') { + // TODO: Fix Object Object bug as now the item nested objects are strings from the data-set so the content aren't lost. Should we JSON.stringify in both cases: stringify everything and pass it around, in other words? + let entity = { ...item } + + // TODO: Refactor possibly. For now, using this UGLY work-around + for(let key in entity) { + if(entity[key][0] == '{' || entity[key][0] == '[') { + try { + entity[key] = JSON.parse(entity[key]) + } catch(err) { + // ignore + } + } + } + + load_entity = entity + } else if(window[SDK_NAME].ui.datatable.load == 'network') { + let out = await fetch(`/api/${SDK_NAME}/${window[SDK_NAME].ui.current_entity.name}/load/${item.id}`, { + headers: { + 'Content-Type': 'application/json' + }, + method: 'GET', + }) + load_entity = await out.json() + + } + + + + console.log('load_entity: ', load_entity) + + injectDataEditor(load_entity, 'save', async (op, item) => { + console.log('ddd: ', op, item) // { ...item } + + if(op == 'save') { + let put_item = await fetch(`/api/${SDK_NAME}/${window[SDK_NAME].ui.current_entity.name}/save/${item.id}`, { + method: 'PUT', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + ...item + }) + }) + let json_out = await put_item.json() + console.log('put: ', json_out) + + + } else if(op == 'delete') { + let remove_item = await fetch(`/api/${SDK_NAME}/${window[SDK_NAME].ui.current_entity.name}/remove/${item.id}`, { + method: 'DELETE', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + ...item + }) + }) + let json_out = await remove_item.json() + console.log('remove: ', json_out) + } + + // TODO: more efficient solution // add to a table + await loadComponents(window[SDK_NAME].ui.current_entity) + + }) + + + // console.log('item::::', item) + + } + ) + + entityTable.appendChild(table) + + let terminal = $create({ + elem: 'div', + classes: ['terminal'], + children: [ + JSONDOMViewer(json_out) + ] + }) + + entityTable.appendChild( + $create({ + elem: 'h3', + textContent: 'Json Viewer' + }) + ) + entityTable.appendChild(terminal) + +} + +/* +function loadForm(data_item) { + + */ + +/* + let data_item = { + "firstName": "John", + "lastName": "Doe", + "phoneNumber": 1234567890, + "address": "123 Elm Street", + "city": "Springfield", + "country": "USA", + lastModified: Date.now() + } + */ + +/* + let config = { + fields: { + 'lastModified': { disabled: true } + }, + op: 'Save', // TODO: ops: ['Save', 'Delete'] + handler: (op, data) => console.log('data: ', op, data), + } + + let form = createForm(config, data_item) + + injectForm(form) +} + */ + +;(async function load_root() { + + await loadComponents(window[SDK_NAME].ui.current_entity) + + let sideNav = $create({ + elem: 'div', + id: 'SideNav', + classes: ['sidenav'], + children: [ + $create({ + elem: 'div', + classes: ['sidenav-header'], + children: [ + $create({ + elem: 'h2', + textContent: 'Entities' + }), + // TODO: access parent by "this.prior" feature + /* + $create({ + elem: 'span', + innerHTML: '«', + classes: ['closebtn'], + onclick: function(event) { + let SideNav = event.target.parentNode.parentNode + SideNav.style.width = '0' + document.querySelector('#openSidebarEntities').style.display = "block" + } + + }) + */ + ] + + }), + function* () { + for(let entity of entities) { + let switch_entity = $create({ + elem: 'a', + textContent: entity.title + }) + + switch_entity.addEventListener('click', async function () { + console.log('entity: ', entity) + + window[SDK_NAME].ui.current_entity = entity + + console.log(window[SDK_NAME]) + + await loadComponents(window[SDK_NAME].ui.current_entity) + }) + + yield switch_entity + } + } + + ] + + }) + + let split_side_bar = document.querySelector('#sidebar.split') + + console.log(sideNav, split_side_bar) + + split_side_bar.appendChild(sideNav) + +})(); diff --git a/sdk-demo-application/frontend/js/json-dom-viewer.js b/sdk-demo-application/frontend/js/json-dom-viewer.js new file mode 100644 index 0000000..e31e792 --- /dev/null +++ b/sdk-demo-application/frontend/js/json-dom-viewer.js @@ -0,0 +1,284 @@ +/* + * (c) 2022-2023 Aleksandar Milenkovic + * MIT License +*/ + +const SPACE = ' ', + DOWN_TRIANGLE = '▼', + RIGHT_TRIANGLE = '▶' + +function applyStyle(elem, style) { + Object.assign(elem.style, style) +} + +function type(obj) { + if(!obj) { // JSON null + return false + } + return obj.constructor +} + +function newType(constructor){ + let style = {'number': {color: '#746eed'}, + 'string': {color: '#2fd0b0'}, + 'boolean': {color: '#746eed'}, + } + return style[constructor] +} + +function simpleDiv(content = '', style, typing){ + let el, html + el = document.createElement('div') + applyStyle(el, {display: 'inline',}) + if(typeof content == 'string' && typing) { + el.innerHTML += '"' + } + + // value content + if(content === null) { // null - special case + el.innerHTML = 'null' + }else { + el.innerHTML += content.toString() + } + + if(typeof content == 'string' && typing) { + el.innerHTML += '"' + } + if(style) { + applyStyle(el, style) + } + + if(content === null) { // null - special case + applyStyle(el, {color: 'gray',}) + } + /* + return Object.create({ $el: el, addTo(elem){ + elem.appendChild(this.$el) + }, + }) + */ + return el +} + +function valueDiv(value, typing) { + let style = newType(typeof value) + return simpleDiv(value, style, typing) +} + +function create(obj, dotted = false, spacing = 0, path, cache){ + let el, html, tab, opening, closing + let b + el = document.createElement('div') + el.id = 'dict' + applyStyle(el, {color: 'white',}) + applyStyle(el, {display: 'inline',}) + // el.innerHTML = `${JSON.stringify(obj)}` + tab = SPACE.repeat(spacing) + + el.appendChild(opening = simpleDiv('{')) + + opening.addEventListener('mouseover', (event) => { // highligher + applyStyle(opening, {color: 'red'}) + applyStyle(closing, {color: 'red'}) + }) + opening.addEventListener('mouseleave', (event) => { + applyStyle(opening, {color: 'white'}) + applyStyle(closing, {color: 'white'}) + }) + + let keys = Object.keys(obj), key + for(let i in keys) { + let keyDom, valueDom + + b = true + key = keys[i] + // console.log([key, obj[key]]) + el.appendChild(document.createElement('br')) + el.appendChild(simpleDiv(tab)) + el.appendChild(keyDom = simpleDiv(key.toString(), {color: '#5db0d7',})) + el.appendChild(simpleDiv(':')) + el.appendChild(simpleDiv(SPACE)) + // el.appendChild(simpleDiv(key.toString() + ': ')) + + // console.log(keyDom.style) + // console.log(keyDom) + + + // :hover keyDom + keyDom.addEventListener('mouseover', (event) => { + event.stopPropagation() + applyStyle(keyDom, {opacity: 0.5, 'background-color': 'white', + padding: '1px', border: '1px solid white', 'border-radius': '6px',}) + }) + keyDom.addEventListener('mouseleave', (event) => { + event.stopPropagation() + applyStyle(keyDom, {opacity: '', 'background-color': '', + padding: '', border: '', 'border-radius': '',}) // reset style + }) + + keyDom.addEventListener('click', event=>{ + if(!keyDom.enabled) { + applyStyle(valueDom, {'background-color': '#29323d', + padding: '0px', border: '1px inset #5db0d7', 'border-radius': '6px',}) + /* + let _popup = document.createElement('div') + _popup.textContent = path + _popup.id = 'popup' + applyStyle(_popup, {'position': 'absolute', + 'top': '200px', + 'right': '200px', + }) + keyDom.appendChild(_popup) + */ + keyDom.enabled = true + }else { + applyStyle(valueDom, {'background-color': '', + padding: '', border: '', 'border-radius': '',}) + keyDom.enabled = false + /* + for(let child of keyDom.children) { + if(child.id == 'popup'){ + child.remove() + } + } + */ + } + }) + + if(type(obj[key]) === Object || type(obj[key]) == Array) { + if(Object.keys(obj[key]).length != 0) { + el.appendChild(valueDom = viewJSON(obj[key], spacing+2, path+'.'+key, cache)) + } + else { // empty Object => {} + el.appendChild(valueDom = simpleDiv("{}")) + } + }else if(obj[key] === null) { + el.appendChild(valueDom = valueDiv(null, true)) + }else { + el.appendChild(valueDom = valueDiv(obj[key], true)) + } + + if(keys.length - i - 1) { + el.appendChild(simpleDiv(',')) + } + + /* + // :hover valueDom - TBD + valueDom.addEventListener('mouseover', (event) => { + applyStyle(valueDom, {'background-color': '#29323d', + padding: '0px', border: '1px inset #5db0d7', 'border-radius': '6px',}) + }) + valueDom.addEventListener('mouseleave', (event) => { + applyStyle(valueDom, {'background-color': '', + padding: '', border: '', 'border-radius': '',}) + }) + */ + } + + if(dotted) { + el.appendChild(simpleDiv('...')) + } + if(keys.length != 0) { + el.appendChild(document.createElement('br')) // '\n' + tab = SPACE.repeat(spacing-2) + // ( spacing - indent ) => correct indent + // console.log('tab: ', {tab, path, spacing} ) + el.appendChild(closing = simpleDiv(tab + '}')) + }else { + el.appendChild(closing = simpleDiv('}')) + } + + closing.addEventListener('mouseover', (event) => { + applyStyle(opening, {color: 'red'}) + applyStyle(closing, {color: 'red'}) + }) + closing.addEventListener('mouseleave', (event) => { + applyStyle(opening, {color: 'white'}) + applyStyle(closing, {color: 'white'}) + }) + + return el +} + +function icon(obj, dict, spacing, path, cache){ + let el; + let rendered; + el = document.createElement('div'); + el.innerHTML = RIGHT_TRIANGLE; + applyStyle(el, {color: 'gray', 'font-size': '12px'}); // default style + (function _open(){ + let found_path = cache[path] + if(found_path) { + obj[0].remove() + if(!obj[0].enabled) { + el.innerHTML = DOWN_TRIANGLE + applyStyle(el, {color: 'gray'}) // update style + obj[0] = create(dict, false, spacing, path, cache) + applyStyle(obj[0], {display: "inline"}) + obj[0].enabled = true + } else { + applyStyle(el, {color: 'gray'}) // update style + el.innerHTML = RIGHT_TRIANGLE + obj[0] = create({}, true, 0, path, cache) + obj[0].enabled = false + } + // console.log(obj[0]) + } + + })() + el.addEventListener('click', e=>{ + // console.log('e: ', e) + // console.log('path: ', path) + e.stopPropagation() + obj[0].remove() + if(!obj[0].enabled) { + el.innerHTML = DOWN_TRIANGLE + applyStyle(el, {color: 'gray'}) // update style + obj[0] = create(dict, false, spacing, path, cache) + applyStyle(obj[0], {display: "inline"}) + obj[0].enabled = true + + cache[path] = true + + + } else { + applyStyle(el, {color: 'gray'}) // update style + el.innerHTML = RIGHT_TRIANGLE + obj[0] = create({}, true, 0, path, cache) + obj[0].enabled = false + + // delete all the paths starting with that path - this will help close child objects once a main parent object closes + for(let _path in cache) { + if(_path.startsWith(path + '.') || _path === path) { // '.b1' startsWith '.b' bug + delete cache[_path] + } + } + // delete cache[path] + + } + + // console.log('cache: ', cache) + // console.log('retrievedObject: ', JSON.parse(retrievedObject)); + + // console.log('obj: ', obj[0]) // for debugging + el.parentNode.appendChild(obj[0]) // similar to linked list - prev, next + }) + applyStyle(el, {display: 'inline',}) + return el +} + +function viewJSON(dict, spacing = 2, path = '', cache = {}) { + let obj = [create({}, true, 0)] // default + let div = document.createElement('div') + applyStyle(div, {display: 'inline',}) + div.appendChild(icon(obj, dict, spacing, path, cache)) + div.appendChild(obj[0]) + return div +} + +function viewJSONAsString(json_string) { // obsolete + return viewJSON(JSON.parse(json_string)) +} + + +export default viewJSON; diff --git a/sdk-demo-application/frontend/js/main.js b/sdk-demo-application/frontend/js/main.js new file mode 100644 index 0000000..edc754b --- /dev/null +++ b/sdk-demo-application/frontend/js/main.js @@ -0,0 +1 @@ +import "./component.js" diff --git a/sdk-demo-application/frontend/package-lock.json b/sdk-demo-application/frontend/package-lock.json new file mode 100644 index 0000000..fe4a13e --- /dev/null +++ b/sdk-demo-application/frontend/package-lock.json @@ -0,0 +1,508 @@ +{ + "name": "frontend", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "frontend", + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "http-server": "^14.1.1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-14.1.1.tgz", + "integrity": "sha512-+cbxadF40UXd9T01zUHgA+rlo2Bg1Srer4+B4NwIHdaGxAGGv59nYRnGGDJ9LBk7alpS0US+J+bLLdQOOkJq4A==", + "dependencies": { + "basic-auth": "^2.0.1", + "chalk": "^4.1.2", + "corser": "^2.0.1", + "he": "^1.2.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy": "^1.18.1", + "mime": "^1.6.0", + "minimist": "^1.2.6", + "opener": "^1.5.1", + "portfinder": "^1.0.28", + "secure-compare": "3.0.1", + "union": "~0.5.0", + "url-join": "^4.0.1" + }, + "bin": { + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/object-inspect": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", + "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/portfinder": { + "version": "1.0.32", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.32.tgz", + "integrity": "sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==", + "dependencies": { + "async": "^2.6.4", + "debug": "^3.2.7", + "mkdirp": "^0.5.6" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha512-AckIIV90rPDcBcglUwXPF3kg0P0qmPsPXAj6BBEENQE1p5yA1xfmDJzfi1Tappj37Pv2mVbKpL3Z1T+Nn7k1Qw==" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==" + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + } + } +} diff --git a/sdk-demo-application/frontend/package.json b/sdk-demo-application/frontend/package.json new file mode 100644 index 0000000..7174559 --- /dev/null +++ b/sdk-demo-application/frontend/package.json @@ -0,0 +1,15 @@ +{ + "name": "frontend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "serve": "http-server -p 8080 -c-1 --proxy http://127.0.0.1:8000", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "http-server": "^14.1.1" + } +} diff --git a/sdk-demo-application/package-lock.json b/sdk-demo-application/package-lock.json new file mode 100644 index 0000000..410032a --- /dev/null +++ b/sdk-demo-application/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "sdk-demo-application", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "sdk-demo-application", + "version": "1.0.0", + "license": "MIT" + } + } +} diff --git a/sdk-demo-application/package.json b/sdk-demo-application/package.json new file mode 100644 index 0000000..b1d2894 --- /dev/null +++ b/sdk-demo-application/package.json @@ -0,0 +1,11 @@ +{ + "name": "sdk-demo-application", + "version": "1.0.0", + "description": "", + "main": "", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT" +} diff --git a/src/docgen.ts b/src/docgen.ts index c9959ad..ac8ea38 100644 --- a/src/docgen.ts +++ b/src/docgen.ts @@ -10,8 +10,13 @@ import { prettyPino, Pino } from '@voxgig/util' import { Index } from './static/Index' import { Main } from './static/Main' +// Sample App +import { SampleApp } from './sample_app/SampleApp' + import { PrepareOpenAPI } from './prepare-openapi' +import { ApiDef } from '@voxgig/apidef' + type DocGenOptions = { folder: string @@ -78,9 +83,10 @@ function DocGen(opts: DocGenOptions) { DocGen.makeBuild = async function(opts: DocGenOptions) { + let docgen: any = undefined - const config = { + const config: any = { root: opts.root, def: opts.def || 'no-def', kind: 'openapi-3', @@ -89,6 +95,7 @@ DocGen.makeBuild = async function(opts: DocGenOptions) { entity: opts.model ? opts.model.entity : undefined, } + return async function build(model: any, build: any) { if (null == docgen) { @@ -98,6 +105,13 @@ DocGen.makeBuild = async function(opts: DocGenOptions) { }) } + // TEMPORARY FIX: TODO: apidef should be it's own action, same as sdkgen and docgen + const apidef = ApiDef({ + pino: build.log, + }) + + await apidef.generate(config) + await docgen.generate({ model, build, config }) } } @@ -169,6 +183,7 @@ export const Inject: Component = JostracaModule.Inject export { Index, Main, + SampleApp, Jostraca, DocGen, diff --git a/src/sample_app/SampleApp.ts b/src/sample_app/SampleApp.ts new file mode 100644 index 0000000..b170ed3 --- /dev/null +++ b/src/sample_app/SampleApp.ts @@ -0,0 +1,22 @@ + +import { cmp, each, File, Folder, Content, Fragment, Copy } from 'jostraca' + + +import { Server } from './Server' + + + +const SampleApp = cmp(function SampleApp(props: any) { + const { ctx$ } = props + const { model } = ctx$ + + Folder({ name: 'sampleapp' }, () => { + Server(props) + }) + +}) + + +export { + SampleApp +} diff --git a/src/sample_app/Server.ts b/src/sample_app/Server.ts new file mode 100644 index 0000000..eaa0a8f --- /dev/null +++ b/src/sample_app/Server.ts @@ -0,0 +1,233 @@ + +import { cmp, each, File, Folder, Content, Fragment, Copy, camelify } from 'jostraca' + +// import { resolvePath } from '../utility' + + + +const Server = cmp(function Server(props: any) { + const { ctx$ } = props + const { model } = ctx$ + + const { entity } = model.main.sdk + + // console.log('Index', model.test) + + console.log('Server: guide:', ctx$.meta.spec.config.guideModel.guide.manual) + + // TODO: Will have to look for alternative solutions as this is developer-defined. + const { entities } = ctx$.meta.spec.config.guideModel.guide.manual.sampleapp.backend + + // TODO: selected features should be active by default! + + const featureOptions = each(model.main.sdk.feature) + .filter((f: any) => f.active) + .reduce((a: any, f: any) => a + `\n ${f.name}: { active: true },`, '') + + + console.log('entities: ', entities, model.Name, model.name) + + // console.log('Server entity op: ', entity.board.op) + + const SDK_NAME = model.Name + 'SDK' + + + Folder({ name: 'backend' }, () => { + + Copy({ from: `${__dirname}/../../src/sample_app/backend/package.json`, exclude: true }) + + File({ name: 'server.js' }, () => { + Content(` +const express = require('express') + +const { TrelloSDK } = require('trello-sdk') + + +const app = express() + +const port = 8000 + +app.use(express.json()) + + +const client = ${model.Name}SDK.make({ + endpoint: process.env.${model.NAME}_ENDPOINT, + apikey: process.env.${model.NAME}_APIKEY, + token: process.env.${model.NAME}_TOKEN, // NOTE: Hardcoded only for Trello + ${featureOptions} +}) +`) + + for(let entity_name in entities) { + let entity = entities[entity_name] + + for(let op_key in entity.op) { + let op = entity.op[op_key] + console.log('op: ', entity_name, op_key, op) + + if(op_key == 'list') { + Content(` +app.get('/api/${SDK_NAME}/${entity_name.toLowerCase()}/${op_key}', async (req, res) => { +`) + + if(op.query) { + for(let query_key in op.query) { + Content(` + if(!req.query['${query_key}']) { + res.status(400) + return res.send(JSON.stringify('${query_key + ': Required'}')) + } + + `) + } + + } + Content(` + try { + let list = await client.${camelify(entity_name)}().list(req.query) + list = list.map(item => item.data) + res.status(200) + return res.send(JSON.stringify(list)) + } catch(err) { + console.log(err) + res.status(400) + res.send(JSON.stringify("error occured")) + } + +}) +`) + + + } else if(op_key == 'load') { + Content(` +app.get('/api/${SDK_NAME}/${entity_name.toLowerCase()}/${op_key}/:uid', async (req, res) => { +`) + if(op.query) { + for(let query_key in op.query) { + Content(` + if(!req.query['${query_key}']) { + res.status(400) + return res.send(JSON.stringify('${query_key + ': Required'}')) + } + + `) + } + + } + + + Content(` + try { + const id = req.params.uid + let item = await client.${camelify(entity_name)}().load({ id, }) + // console.log('load item: ', item) + res.status(200) + return res.send(JSON.stringify(item.data ? item.data : item)) + } catch(err) { + console.log(err) + res.status(400) + res.send(JSON.stringify("error occured")) + } +})`) + + } else if(op_key == 'save') { + Content(` +app.put('/api/${SDK_NAME}/${entity_name.toLowerCase()}/${op_key}/:uid', async (req, res) => { + try { + const id = req.params.uid + const body = req.body + + + + // delete body.prefs + // delete body.labelNames + + console.log('SAVE', id, body) + + let item = await client.${camelify(entity_name)}().save({ id, ...body }) + + + res.status(200) + return res.send(JSON.stringify(item.data ? item.data : item)) + } catch(err) { + console.log(err) + res.status(400) + res.send(JSON.stringify("error occured")) + } + + +}) +`) + + } else if(op_key == 'create') { + Content(` +app.post('/api/${SDK_NAME}/${entity_name.toLowerCase()}/${op_key}', async (req, res) => { + try { + const body = req.body + + + + // delete body.prefs + // delete body.labelNames + + console.log('CREATE', body) + + let item = await client.${camelify(entity_name)}().create({ ...body }) + + + res.status(200) + return res.send(JSON.stringify(item.data ? item.data : item)) + } catch(err) { + console.log(err) + res.status(400) + res.send(JSON.stringify("error occured")) + } + + +}) +`) + + } else if(op_key == 'remove') { + Content(` +app.delete('/api/${SDK_NAME}/${entity_name.toLowerCase()}/${op_key}/:uid', async (req, res) => { + try { + const id = req.params.uid + + console.log('REMOVE', id) + + let item = await client.${camelify(entity_name)}().remove({ id }) + + + res.status(200) + return res.send(JSON.stringify(item)) + } catch(err) { + console.log(err) + res.status(400) + res.send(JSON.stringify("error occured")) + } + + +}) +`) + } + + + } + + } + + Content(` +app.listen(port, () => { + console.log('Sample Backend App listening on port 127.0.0.1:' + port) +})`) + + }) + + }) + +}) + + +export { + Server +} diff --git a/src/sample_app/backend/package.json b/src/sample_app/backend/package.json new file mode 100644 index 0000000..e90736e --- /dev/null +++ b/src/sample_app/backend/package.json @@ -0,0 +1,16 @@ +{ + "name": "backend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "export DEBUG=express:* && node server.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "express": "^4.21.1", + "uuid": "^11.0.2" + } +}