From 9a09a8c9b320fdbd22d2ba0d74492dfe6e004598 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Oct 2021 15:33:24 +0000 Subject: [PATCH 001/148] Bump vm2 from 3.9.3 to 3.9.4 in /packages/server Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.3 to 3.9.4. - [Release notes](https://github.com/patriksimek/vm2/releases) - [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md) - [Commits](https://github.com/patriksimek/vm2/compare/3.9.3...3.9.4) --- updated-dependencies: - dependency-name: vm2 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- packages/server/yarn.lock | 808 +++++++++++++++++++++++++++++++++++++- 1 file changed, 789 insertions(+), 19 deletions(-) diff --git a/packages/server/yarn.lock b/packages/server/yarn.lock index bcca0c0ad..db4824e8e 100644 --- a/packages/server/yarn.lock +++ b/packages/server/yarn.lock @@ -943,6 +943,29 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@budibase/auth@^0.9.169-alpha.1": + version "0.9.169" + resolved "https://registry.yarnpkg.com/@budibase/auth/-/auth-0.9.169.tgz#fd2a8fc271782ba857259ace15118a4d53b3d161" + integrity sha512-Q087k/54Nzx6Oeg5uL7YD/9BB+qkBWIv7h4ct+cNQJFNK/aKKN8JLQft+z3mBN5omHTkdJYFmbgXWFxtX+rR3Q== + dependencies: + "@techpass/passport-openidconnect" "^0.3.0" + aws-sdk "^2.901.0" + bcryptjs "^2.4.3" + cls-hooked "^4.2.2" + ioredis "^4.27.1" + jsonwebtoken "^8.5.1" + koa-passport "^4.1.4" + lodash "^4.17.21" + node-fetch "^2.6.1" + passport-google-auth "^1.0.2" + passport-google-oauth "^2.0.0" + passport-jwt "^4.0.0" + passport-local "^1.0.0" + sanitize-s3-objectkey "^0.0.1" + tar-fs "^2.1.1" + uuid "^8.3.2" + zlib "^1.0.5" + "@budibase/bbui@^0.9.139": version "0.9.139" resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.139.tgz#e6cfc90e8f6c2aa3526fc6a7bef251bccdaf51bb" @@ -992,6 +1015,94 @@ svelte-flatpickr "^3.1.0" svelte-portal "^1.0.0" +"@budibase/bbui@^0.9.169": + version "0.9.169" + resolved "https://registry.yarnpkg.com/@budibase/bbui/-/bbui-0.9.169.tgz#e8dac59b9792a7edf03c4301a9069760e2ebd2f4" + integrity sha512-2hks6GEjcXbDUzC37WgJvgloiqTP5ZS7IuRjlHU9kStDr6dAnXuy8pO6JNJmKrTXt+rgtwhHHrVWzzcmNLIYxA== + dependencies: + "@adobe/spectrum-css-workflow-icons" "^1.2.1" + "@spectrum-css/actionbutton" "^1.0.1" + "@spectrum-css/actiongroup" "^1.0.1" + "@spectrum-css/avatar" "^3.0.2" + "@spectrum-css/button" "^3.0.1" + "@spectrum-css/buttongroup" "^3.0.2" + "@spectrum-css/checkbox" "^3.0.2" + "@spectrum-css/dialog" "^3.0.1" + "@spectrum-css/divider" "^1.0.3" + "@spectrum-css/dropzone" "^3.0.2" + "@spectrum-css/fieldgroup" "^3.0.2" + "@spectrum-css/fieldlabel" "^3.0.1" + "@spectrum-css/icon" "^3.0.1" + "@spectrum-css/illustratedmessage" "^3.0.2" + "@spectrum-css/inputgroup" "^3.0.2" + "@spectrum-css/label" "^2.0.10" + "@spectrum-css/link" "^3.1.1" + "@spectrum-css/menu" "^3.0.1" + "@spectrum-css/modal" "^3.0.1" + "@spectrum-css/pagination" "^3.0.3" + "@spectrum-css/picker" "^1.0.1" + "@spectrum-css/popover" "^3.0.1" + "@spectrum-css/progressbar" "^1.0.2" + "@spectrum-css/progresscircle" "^1.0.2" + "@spectrum-css/radio" "^3.0.2" + "@spectrum-css/search" "^3.0.2" + "@spectrum-css/sidenav" "^3.0.2" + "@spectrum-css/statuslight" "^3.0.2" + "@spectrum-css/stepper" "^3.0.3" + "@spectrum-css/switch" "^1.0.2" + "@spectrum-css/table" "^3.0.1" + "@spectrum-css/tabs" "^3.0.1" + "@spectrum-css/tags" "^3.0.2" + "@spectrum-css/textfield" "^3.0.1" + "@spectrum-css/toast" "^3.0.1" + "@spectrum-css/tooltip" "^3.0.3" + "@spectrum-css/treeview" "^3.0.2" + "@spectrum-css/typography" "^3.0.1" + "@spectrum-css/underlay" "^2.0.9" + "@spectrum-css/vars" "^3.0.1" + dayjs "^1.10.4" + svelte-flatpickr "^3.2.3" + svelte-portal "^1.0.0" + +"@budibase/client@^0.9.169-alpha.1": + version "0.9.169" + resolved "https://registry.yarnpkg.com/@budibase/client/-/client-0.9.169.tgz#bec370b8f069b42f62483b281d6b9e2c7c8625f3" + integrity sha512-/bDnwv2iRysZrcrBQJEKzuxdwkwoJ2FalmQFhsfj+V/MWBN/wpQSDbJZQwf/YcI5bQk8f7xIn95O+DMH/m5izg== + dependencies: + "@budibase/bbui" "^0.9.169" + "@budibase/standard-components" "^0.9.139" + "@budibase/string-templates" "^0.9.169" + regexparam "^1.3.0" + shortid "^2.2.15" + svelte-spa-router "^3.0.5" + +"@budibase/handlebars-helpers@^0.11.7": + version "0.11.7" + resolved "https://registry.yarnpkg.com/@budibase/handlebars-helpers/-/handlebars-helpers-0.11.7.tgz#8e5f9843d7dd10503e9f608555a96ccf4d836c46" + integrity sha512-PvGHAv22cWSFExs1kc0WglwsmCEUEOqWvSp6JCFZwtc3qAAr5yMfLK8WGVQ63ALvyzWZiyxF+yrlzeeaohCMJw== + dependencies: + array-sort "^1.0.0" + define-property "^2.0.2" + extend-shallow "^3.0.2" + for-in "^1.0.2" + get-object "^0.2.0" + get-value "^3.0.1" + handlebars "^4.7.7" + handlebars-utils "^1.0.6" + has-value "^2.0.2" + helper-date "^1.0.1" + helper-markdown "^1.0.0" + helper-md "^0.2.2" + html-tag "^2.0.0" + is-even "^1.0.0" + is-glob "^4.0.1" + kind-of "^6.0.3" + micromatch "^3.1.5" + relative "^3.0.2" + striptags "^3.1.1" + to-gfm-code-block "^0.1.1" + year "^0.2.1" + "@budibase/standard-components@^0.9.139": version "0.9.139" resolved "https://registry.yarnpkg.com/@budibase/standard-components/-/standard-components-0.9.139.tgz#cf8e2b759ae863e469e50272b3ca87f2827e66e3" @@ -1010,6 +1121,17 @@ svelte-apexcharts "^1.0.2" svelte-flatpickr "^3.1.0" +"@budibase/string-templates@^0.9.169", "@budibase/string-templates@^0.9.169-alpha.1": + version "0.9.169" + resolved "https://registry.yarnpkg.com/@budibase/string-templates/-/string-templates-0.9.169.tgz#3c0be97718f39a92ff6b2dbb8b470aaa7851005e" + integrity sha512-JUyg6XuUgFqnfdDSCAplo4cTtrqdSZ9NPrU3iGudZEQjO/Wk5sezWPznl3Yw/kFHKmPLjFHIveEa2+lODEAxIA== + dependencies: + "@budibase/handlebars-helpers" "^0.11.7" + dayjs "^1.10.4" + handlebars "^4.7.6" + handlebars-utils "^1.0.6" + lodash "^4.17.20" + "@cnakazawa/watch@^1.0.3": version "1.0.4" resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" @@ -2012,6 +2134,17 @@ dependencies: defer-to-connect "^1.0.1" +"@techpass/passport-openidconnect@^0.3.0": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz#f8fd5d97256286665dbf26dac92431f977ab1e63" + integrity sha512-fnCtEiexXSHA029B//hJcCJlLJrT3lhpNCyA0rnz58Qttz0BLGCVv6yMT8HmOnGThH6vcDOVwdgKM3kbCQtEhw== + dependencies: + base64url "^3.0.1" + oauth "^0.9.15" + passport-strategy "^1.0.0" + request "^2.88.0" + webfinger "^0.4.2" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -2658,7 +2791,7 @@ arg@^4.1.0: resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: +argparse@^1.0.10, argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== @@ -2705,6 +2838,15 @@ array-flatten@1.1.1: resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= +array-sort@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-sort/-/array-sort-1.0.0.tgz#e4c05356453f56f53512a7d1d6123f2c54c0a88a" + integrity sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg== + dependencies: + default-compare "^1.0.0" + get-value "^2.0.6" + kind-of "^5.0.2" + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -2747,6 +2889,13 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async-hook-jl@^1.7.6: + version "1.7.6" + resolved "https://registry.yarnpkg.com/async-hook-jl/-/async-hook-jl-1.7.6.tgz#4fd25c2f864dbaf279c610d73bf97b1b28595e68" + integrity sha512-gFaHkFfSxTjvoxDMYqDuGHlcRyUuamF8s+ZTtJdDzqjws4mCt7v0vuV79/E2Wr2/riMQgtG4/yUtXWs1gZ7JMg== + dependencies: + stack-chain "^1.3.7" + async-limiter@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" @@ -2764,6 +2913,13 @@ async@^2.6.3: dependencies: lodash "^4.17.14" +async@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/async/-/async-2.1.5.tgz#e587c68580994ac67fc56ff86d3ac56bdbe810bc" + integrity sha1-5YfGhYCZSsZ/xW/4bTrFa9voELw= + dependencies: + lodash "^4.14.0" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -2779,6 +2935,13 @@ atomic-sleep@^1.0.0: resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== +autolinker@~0.28.0: + version "0.28.1" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.28.1.tgz#0652b491881879f0775dace0cdca3233942a4e47" + integrity sha1-BlK0kYgYefB3XazgzcoyM5QqTkc= + dependencies: + gulp-header "^1.7.1" + aws-sdk@^2.767.0: version "2.981.0" resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.981.0.tgz#b2e6205db23d755e1c8fcbd0618e8309e69d3767" @@ -2794,6 +2957,21 @@ aws-sdk@^2.767.0: uuid "3.3.2" xml2js "0.4.19" +aws-sdk@^2.901.0: + version "2.1010.0" + resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1010.0.tgz#a0ff308149e2e358522b991f3b21d2f06c856f0c" + integrity sha512-ZiFMY0wJfgBSybAPKl4hEYi4zjs6c6A+kPmifF36C1bFja83Q4iNRUr2P13R41wJn/fdxMyWDgmx6r/5NNLUqg== + dependencies: + buffer "4.9.2" + events "1.1.1" + ieee754 "1.1.13" + jmespath "0.15.0" + querystring "0.2.0" + sax "1.2.1" + url "0.10.3" + uuid "3.3.2" + xml2js "0.4.19" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -2968,6 +3146,11 @@ base64-js@^1.0.2, base64-js@^1.3.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +base64url@3.x.x, base64url@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d" + integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -2988,7 +3171,7 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -bcryptjs@2.4.3: +bcryptjs@2.4.3, bcryptjs@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= @@ -3033,6 +3216,15 @@ bl@^3.0.0: dependencies: readable-stream "^3.0.1" +bl@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + bluebird@^3.5.1: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" @@ -3402,6 +3594,11 @@ chokidar@^3.2.2: optionalDependencies: fsevents "~2.3.2" +chownr@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + ci-info@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" @@ -3474,6 +3671,15 @@ clone-response@1.0.2, clone-response@^1.0.2: dependencies: mimic-response "^1.0.0" +cls-hooked@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/cls-hooked/-/cls-hooked-4.2.2.tgz#ad2e9a4092680cdaffeb2d3551da0e225eae1908" + integrity sha512-J4Xj5f5wq/4jAvcdgoGsL3G103BtWpZrMo8NEinRltN+xpTZdI+M38pyQqhuFU/P792xkMFvnKSf+Lm81U1bxw== + dependencies: + async-hook-jl "^1.7.6" + emitter-listener "^1.0.1" + semver "^5.4.1" + cluster-key-slot@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" @@ -3595,6 +3801,13 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +concat-with-sourcemaps@*: + version "1.1.0" + resolved "https://registry.yarnpkg.com/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz#d4ea93f05ae25790951b99e7b3b09e3908a4082e" + integrity sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg== + dependencies: + source-map "^0.6.1" + configstore@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" @@ -3811,6 +4024,13 @@ date-utils@*: resolved "https://registry.yarnpkg.com/date-utils/-/date-utils-1.2.21.tgz#61fb16cdc1274b3c9acaaffe9fc69df8720a2b64" integrity sha1-YfsWzcEnSzyayq/+n8ad+HIKK2Q= +date.js@^0.3.1: + version "0.3.3" + resolved "https://registry.yarnpkg.com/date.js/-/date.js-0.3.3.tgz#ef1e92332f507a638795dbb985e951882e50bbda" + integrity sha512-HgigOS3h3k6HnW011nAb43c5xx5rBXk8P2v/WIT9Zv4koIaVXiH2BURguI78VVp+5Qc076T7OR378JViCnZtBw== + dependencies: + debug "~3.1.0" + dateformat@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" @@ -3954,6 +4174,13 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== +default-compare@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-compare/-/default-compare-1.0.0.tgz#cb61131844ad84d84788fb68fd01681ca7781a2f" + integrity sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ== + dependencies: + kind-of "^5.0.2" + default-shell@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/default-shell/-/default-shell-1.0.1.tgz#752304bddc6174f49eb29cb988feea0b8813c8bc" @@ -4193,6 +4420,13 @@ electron-to-chromium@^1.3.811: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.827.tgz#c725e8db8c5be18b472a919e5f57904512df0fc1" integrity sha512-ye+4uQOY/jbjRutMcE/EmOcNwUeo1qo9aKL2tPyb09cU3lmxNeyDF4RWiemmkknW+p29h7dyDqy02higTxc9/A== +emitter-listener@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/emitter-listener/-/emitter-listener-1.1.2.tgz#56b140e8f6992375b3d7cb2cab1cc7432d9632e8" + integrity sha512-Bt1sBAGFHY9DKY+4/2cV6izcKJUf5T7/gkdmkxzX/qv9CcGH8xSwVRW5mtX03SWJtRTWSOpzCuWN9rBFYZepZQ== + dependencies: + shimmer "^1.2.0" + emittery@^0.8.1: version "0.8.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" @@ -4223,7 +4457,7 @@ encoding-down@^6.3.0: level-codec "^9.0.0" level-errors "^2.0.0" -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -4237,6 +4471,11 @@ end-stream@~0.1.0: dependencies: write-stream "~0.4.3" +ent@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" + integrity sha1-6WQhkyWiHQX0RGai9obtbOX13R0= + errno@~0.1.1: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" @@ -5057,6 +5296,11 @@ fs-constants@^1.0.0: resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + integrity sha1-mC1ok6+RjnLQjeyehnP/K1qNat0= + fs-extra@8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -5113,6 +5357,14 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-object@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/get-object/-/get-object-0.2.0.tgz#d92ff7d5190c64530cda0543dac63a3d47fe8c0c" + integrity sha1-2S/31RkMZFMM2gVD2sY6PUf+jAw= + dependencies: + is-number "^2.0.2" + isobject "^0.2.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -5160,6 +5412,13 @@ get-value@^2.0.3, get-value@^2.0.6: resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= +get-value@^3.0.0, get-value@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-3.0.1.tgz#5efd2a157f1d6a516d7524e124ac52d0a39ef5a8" + integrity sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA== + dependencies: + isobject "^3.0.1" + getopts@2.2.5: version "2.2.5" resolved "https://registry.yarnpkg.com/getopts/-/getopts-2.2.5.tgz#67a0fe471cacb9c687d817cab6450b96dde8313b" @@ -5249,6 +5508,32 @@ globby@^11.0.3: merge2 "^1.3.0" slash "^3.0.0" +google-auth-library@~0.10.0: + version "0.10.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-0.10.0.tgz#6e15babee85fd1dd14d8d128a295b6838d52136e" + integrity sha1-bhW6vuhf0d0U2NEoopW2g41SE24= + dependencies: + gtoken "^1.2.1" + jws "^3.1.4" + lodash.noop "^3.0.1" + request "^2.74.0" + +google-p12-pem@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-0.1.2.tgz#33c46ab021aa734fa0332b3960a9a3ffcb2f3177" + integrity sha1-M8RqsCGqc0+gMys5YKmj/8svMXc= + dependencies: + node-forge "^0.7.1" + +googleapis@^16.0.0: + version "16.1.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-16.1.0.tgz#0f19f2d70572d918881a0f626e3b1a2fa8629576" + integrity sha1-Dxny1wVy2RiIGg9ibjsaL6hilXY= + dependencies: + async "~2.1.4" + google-auth-library "~0.10.0" + string-template "~1.0.0" + got@^8.3.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" @@ -5294,6 +5579,45 @@ graceful-fs@^4.1.10, graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1. resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== +gtoken@^1.2.1: + version "1.2.3" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-1.2.3.tgz#5509571b8afd4322e124cf66cf68115284c476d8" + integrity sha512-wQAJflfoqSgMWrSBk9Fg86q+sd6s7y6uJhIvvIPz++RElGlMtEqsdAR2oWwZ/WTEtp7P9xFbJRrT976oRgzJ/w== + dependencies: + google-p12-pem "^0.1.0" + jws "^3.0.0" + mime "^1.4.1" + request "^2.72.0" + +gulp-header@^1.7.1: + version "1.8.12" + resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.12.tgz#ad306be0066599127281c4f8786660e705080a84" + integrity sha512-lh9HLdb53sC7XIZOYzTXM4lFuXElv3EVkSDhsd7DoJBj7hm+Ni7D3qYbb+Rr8DuM8nRanBvkVO9d7askreXGnQ== + dependencies: + concat-with-sourcemaps "*" + lodash.template "^4.4.0" + through2 "^2.0.0" + +handlebars-utils@^1.0.2, handlebars-utils@^1.0.4, handlebars-utils@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/handlebars-utils/-/handlebars-utils-1.0.6.tgz#cb9db43362479054782d86ffe10f47abc76357f9" + integrity sha512-d5mmoQXdeEqSKMtQQZ9WkiUcO1E3tPbWxluCK9hVgIDPzQa9WsKo3Lbe/sGflTe7TomHEeZaOgwIkyIr1kfzkw== + dependencies: + kind-of "^6.0.0" + typeof-article "^0.1.1" + +handlebars@^4.7.6, handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + har-schema@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" @@ -5364,6 +5688,14 @@ has-value@^1.0.0: has-values "^1.0.0" isobject "^3.0.0" +has-value@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-2.0.2.tgz#d0f12e8780ba8e90e66ad1a21c707fdb67c25658" + integrity sha512-ybKOlcRsK2MqrM3Hmz/lQxXHZ6ejzSPzpNabKB45jb5qDgJvKPa3SdapTsTLwEb9WltgWpOmNax7i+DzNOk4TA== + dependencies: + get-value "^3.0.0" + has-values "^2.0.1" + has-values@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" @@ -5377,6 +5709,13 @@ has-values@^1.0.0: is-number "^3.0.0" kind-of "^4.0.0" +has-values@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-2.0.1.tgz#3876200ff86d8a8546a9264a952c17d5fc17579d" + integrity sha512-+QdH3jOmq9P8GfdjFg0eJudqx1FqU62NQJ4P16rOEHeRdl7ckgwn6uqQjzYE0ZoHVV/e5E2esuJ5Gl5+HUW19w== + dependencies: + kind-of "^6.0.2" + has-yarn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" @@ -5389,6 +5728,39 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +helper-date@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/helper-date/-/helper-date-1.0.1.tgz#12fedea3ad8e44a7ca4c4efb0ff4104a5120cffb" + integrity sha512-wU3VOwwTJvGr/w5rZr3cprPHO+hIhlblTJHD6aFBrKLuNbf4lAmkawd2iK3c6NbJEvY7HAmDpqjOFSI5/+Ey2w== + dependencies: + date.js "^0.3.1" + handlebars-utils "^1.0.4" + moment "^2.18.1" + +helper-markdown@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/helper-markdown/-/helper-markdown-1.0.0.tgz#ee7e9fc554675007d37eb90f7853b13ce74f3e10" + integrity sha512-AnDqMS4ejkQK0MXze7pA9TM3pu01ZY+XXsES6gEE0RmCGk5/NIfvTn0NmItfyDOjRAzyo9z6X7YHbHX4PzIvOA== + dependencies: + handlebars-utils "^1.0.2" + highlight.js "^9.12.0" + remarkable "^1.7.1" + +helper-md@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/helper-md/-/helper-md-0.2.2.tgz#c1f59d7e55bbae23362fd8a0e971607aec69d41f" + integrity sha1-wfWdflW7riM2L9ig6XFgeuxp1B8= + dependencies: + ent "^2.2.0" + extend-shallow "^2.0.1" + fs-exists-sync "^0.1.0" + remarkable "^1.6.2" + +highlight.js@^9.12.0: + version "9.18.5" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825" + integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA== + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -5418,6 +5790,14 @@ html-escaper@^2.0.0: resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== +html-tag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/html-tag/-/html-tag-2.0.0.tgz#36c3bc8d816fd30b570d5764a497a641640c2fed" + integrity sha512-XxzooSo6oBoxBEUazgjdXj7VwTn/iSTSZzTYKzYY6I916tkaYzypHxy+pbVU1h+0UQ9JlVf5XkNQyxOAiiQO1g== + dependencies: + is-self-closing "^1.0.1" + kind-of "^6.0.0" + http-assert@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.5.0.tgz#c389ccd87ac16ed2dfa6246fd73b926aa00e6b8f" @@ -5701,6 +6081,23 @@ ioredis@^4.27.0: redis-parser "^3.0.0" standard-as-callback "^2.1.0" +ioredis@^4.27.1: + version "4.28.0" + resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-4.28.0.tgz#5a2be3f37ff2075e2332f280eaeb02ab4d9ff0d3" + integrity sha512-I+zkeeWp3XFgPT2CtJKxvaF5FjGBGt4yGYljRjQecdQKteThuAsKqffeF1lgHVlYnuNeozRbPOCDNZ7tDWPeig== + dependencies: + cluster-key-slot "^1.1.0" + debug "^4.3.1" + denque "^1.1.0" + lodash.defaults "^4.2.0" + lodash.flatten "^4.4.0" + lodash.isarguments "^3.1.0" + p-map "^2.1.0" + redis-commands "1.7.0" + redis-errors "^1.2.0" + redis-parser "^3.0.0" + standard-as-callback "^2.1.0" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -5832,6 +6229,13 @@ is-docker@^2.0.0: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-even@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-even/-/is-even-1.0.0.tgz#76b5055fbad8d294a86b6a949015e1c97b717c06" + integrity sha1-drUFX7rY0pSoa2qUkBXhyXtxfAY= + dependencies: + is-odd "^0.1.2" + is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" @@ -5921,6 +6325,13 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" +is-number@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + integrity sha1-Afy7s5NGOlSPL0ZszhbezknbkI8= + dependencies: + kind-of "^3.0.2" + is-number@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" @@ -5943,6 +6354,13 @@ is-object@^1.0.1: resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== +is-odd@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-odd/-/is-odd-0.1.2.tgz#bc573b5ce371ef2aad6e6f49799b72bef13978a7" + integrity sha1-vFc7XONx7yqtbm9JeZtyvvE5eKc= + dependencies: + is-number "^3.0.0" + is-path-inside@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -5978,6 +6396,13 @@ is-retry-allowed@^1.1.0: resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== +is-self-closing@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-self-closing/-/is-self-closing-1.0.1.tgz#5f406b527c7b12610176320338af0fa3896416e4" + integrity sha512-E+60FomW7Blv5GXTlYee2KDrnG6srxF7Xt1SjrhWUGUEsTFIqY/nq2y3DaftCsgUMdh89V07IVfhY9KIJhLezg== + dependencies: + self-closing-tags "^1.0.1" + is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" @@ -6053,6 +6478,11 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +isobject@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-0.2.0.tgz#a3432192f39b910b5f02cc989487836ec70aa85e" + integrity sha1-o0MhkvObkQtfAsyYlIeDbscKqF4= + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -7053,6 +7483,22 @@ jsonschema@1.4.0: resolved "https://registry.yarnpkg.com/jsonschema/-/jsonschema-1.4.0.tgz#1afa34c4bc22190d8e42271ec17ac8b3404f87b2" integrity sha512-/YgW6pRMr6M7C+4o8kS+B/2myEpHCrxO4PEWnqJNBFMjn7EWXqlQ4tGwL6xTHeRplwuZmcAncdvfOad1nT2yMw== +jsonwebtoken@^8.2.0, jsonwebtoken@^8.5.1: + version "8.5.1" + resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" + integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== + dependencies: + jws "^3.2.2" + lodash.includes "^4.3.0" + lodash.isboolean "^3.0.3" + lodash.isinteger "^4.0.4" + lodash.isnumber "^3.0.3" + lodash.isplainobject "^4.0.6" + lodash.isstring "^4.0.1" + lodash.once "^4.0.0" + ms "^2.1.1" + semver "^5.6.0" + jsprim@^1.2.2: version "1.4.1" resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" @@ -7092,7 +7538,7 @@ jwa@^1.4.1: ecdsa-sig-formatter "1.0.11" safe-buffer "^5.0.1" -jws@3.x.x: +jws@3.x.x, jws@^3.0.0, jws@^3.1.4, jws@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== @@ -7119,7 +7565,7 @@ keyv@^3.0.0: dependencies: json-buffer "3.0.0" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: +kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.1.0, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= @@ -7133,12 +7579,12 @@ kind-of@^4.0.0: dependencies: is-buffer "^1.1.5" -kind-of@^5.0.0: +kind-of@^5.0.0, kind-of@^5.0.2: version "5.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2: +kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== @@ -7217,6 +7663,13 @@ koa-is-json@^1.0.0: resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" integrity sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ= +koa-passport@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/koa-passport/-/koa-passport-4.1.4.tgz#5f1665c1c2a37ace79af9f970b770885ca30ccfa" + integrity sha512-dJBCkl4X+zdYxbI2V2OtoGy0PUenpvp2ZLLWObc8UJhsId0iQpTFT8RVcuA0709AL2txGwRHnSPoT1bYNGa6Kg== + dependencies: + passport "^0.4.0" + koa-pino-logger@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/koa-pino-logger/-/koa-pino-logger-3.0.0.tgz#27600b4f3639e8767dfc6b66493109c5457f53ba" @@ -7498,6 +7951,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash._reinterpolate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" + integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -7513,16 +7971,46 @@ lodash.flatten@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= +lodash.includes@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" + integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= + lodash.isarguments@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" integrity sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= +lodash.isboolean@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" + integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= + lodash.isequal@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= +lodash.isinteger@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" + integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= + +lodash.isnumber@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" + integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + +lodash.isstring@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" + integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= + lodash.keys@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-4.2.0.tgz#a08602ac12e4fb83f91fc1fb7a360a4d9ba35205" @@ -7533,11 +8021,21 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lodash.noop@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/lodash.noop/-/lodash.noop-3.0.1.tgz#38188f4d650a3a474258439b96ec45b32617133c" + integrity sha1-OBiPTWUKOkdCWEObluxFsyYXEzw= + lodash.omit@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.omit/-/lodash.omit-4.5.0.tgz#6eb19ae5a1ee1dd9df0b969e66ce0b7fa30b5e60" integrity sha1-brGa5aHuHdnfC5aeZs4Lf6MLXmA= +lodash.once@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + lodash.pick@^4.0.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -7548,6 +8046,21 @@ lodash.sortby@^4.7.0: resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= +lodash.template@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" + integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.templatesettings "^4.0.0" + +lodash.templatesettings@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" + integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== + dependencies: + lodash._reinterpolate "^3.0.0" + lodash.without@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.without/-/lodash.without-4.4.0.tgz#3cd4574a00b67bae373a94b748772640507b7aac" @@ -7558,7 +8071,7 @@ lodash.xor@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.xor/-/lodash.xor-4.5.0.tgz#4d48ed7e98095b0632582ba714d3ff8ae8fb1db6" integrity sha1-TUjtfpgJWwYyWCunFNP/iuj7HbY= -lodash@4.17.21, lodash@4.x, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0: +lodash@4.17.21, lodash@4.x, lodash@^4.14.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -7728,7 +8241,7 @@ methods@^1.0.1, methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= -micromatch@^3.1.10, micromatch@^3.1.4: +micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.5: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -7817,6 +8330,11 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mkdirp-classic@^0.5.2: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -7836,7 +8354,7 @@ moment-timezone@^0.5.31: dependencies: moment ">= 2.9.0" -"moment@>= 2.9.0": +"moment@>= 2.9.0", moment@^2.18.1: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== @@ -7930,6 +8448,11 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== +nanoid@^2.1.0: + version "2.1.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" + integrity sha512-s/snB+WGm6uwi0WjsZdaVcuf3KJXlfGl2LcxgwkEwJF0D/BWzVWAZW/XY4bFaiR7s0Jk3FPvlnepg1H1b1UwlA== + nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -7977,6 +8500,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -7997,6 +8525,11 @@ node-fetch@^2.6.0, node-fetch@^2.6.1: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-forge@^0.7.1: + version "0.7.6" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" + integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== + node-gyp-build@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" @@ -8108,6 +8641,11 @@ oauth-sign@~0.9.0: resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== +oauth@0.9.x, oauth@^0.9.15: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= + object-assign@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" @@ -8405,6 +8943,84 @@ pascalcase@^0.1.1: resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= +passport-google-auth@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/passport-google-auth/-/passport-google-auth-1.0.2.tgz#8b300b5aa442ef433de1d832ed3112877d0b2938" + integrity sha1-izALWqRC70M94dgy7TESh30LKTg= + dependencies: + googleapis "^16.0.0" + passport-strategy "1.x" + +passport-google-oauth1@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth1/-/passport-google-oauth1-1.0.0.tgz#af74a803df51ec646f66a44d82282be6f108e0cc" + integrity sha1-r3SoA99R7GRvZqRNgigr5vEI4Mw= + dependencies: + passport-oauth1 "1.x.x" + +passport-google-oauth20@2.x.x: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz#0d241b2d21ebd3dc7f2b60669ec4d587e3a674ef" + integrity sha512-KSk6IJ15RoxuGq7D1UKK/8qKhNfzbLeLrG3gkLZ7p4A6DBCcv7xpyQwuXtWdpyR0+E0mwkpjY1VfPOhxQrKzdQ== + dependencies: + passport-oauth2 "1.x.x" + +passport-google-oauth@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/passport-google-oauth/-/passport-google-oauth-2.0.0.tgz#f6eb4bc96dd6c16ec0ecfdf4e05ec48ca54d4dae" + integrity sha512-JKxZpBx6wBQXX1/a1s7VmdBgwOugohH+IxCy84aPTZNq/iIPX6u7Mqov1zY7MKRz3niFPol0KJz8zPLBoHKtYA== + dependencies: + passport-google-oauth1 "1.x.x" + passport-google-oauth20 "2.x.x" + +passport-jwt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/passport-jwt/-/passport-jwt-4.0.0.tgz#7f0be7ba942e28b9f5d22c2ebbb8ce96ef7cf065" + integrity sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg== + dependencies: + jsonwebtoken "^8.2.0" + passport-strategy "^1.0.0" + +passport-local@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee" + integrity sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4= + dependencies: + passport-strategy "1.x.x" + +passport-oauth1@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/passport-oauth1/-/passport-oauth1-1.2.0.tgz#5229d431781bf5b265bec86ce9a9cce58a756cf9" + integrity sha512-Sv2YWodC6jN12M/OXwmR4BIXeeIHjjbwYTQw4kS6tHK4zYzSEpxBgSJJnknBjICA5cj0ju3FSnG1XmHgIhYnLg== + dependencies: + oauth "0.9.x" + passport-strategy "1.x.x" + utils-merge "1.x.x" + +passport-oauth2@1.x.x: + version "1.6.1" + resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.1.tgz#c5aee8f849ce8bd436c7f81d904a3cd1666f181b" + integrity sha512-ZbV43Hq9d/SBSYQ22GOiglFsjsD1YY/qdiptA+8ej+9C1dL1TVB+mBE5kDH/D4AJo50+2i8f4bx0vg4/yDDZCQ== + dependencies: + base64url "3.x.x" + oauth "0.9.x" + passport-strategy "1.x.x" + uid2 "0.0.x" + utils-merge "1.x.x" + +passport-strategy@1.x, passport-strategy@1.x.x, passport-strategy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4" + integrity sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ= + +passport@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.1.tgz#941446a21cb92fc688d97a0861c38ce9f738f270" + integrity sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg== + dependencies: + passport-strategy "1.x.x" + pause "0.0.1" + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -8459,6 +9075,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pause@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" + integrity sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10= + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -9171,7 +9792,7 @@ readable-stream@1.1.14, readable-stream@^1.0.27-1: isarray "0.0.1" string_decoder "~0.10.x" -"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.4.0, readable-stream@^3.6.0: +"readable-stream@2 || 3", readable-stream@^3.0.0, readable-stream@^3.0.1, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== @@ -9305,6 +9926,16 @@ regex-not@^1.0.0, regex-not@^1.0.2: extend-shallow "^3.0.2" safe-regex "^1.1.0" +regexparam@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-2.0.0.tgz#059476767d5f5f87f735fc7922d133fd1a118c8c" + integrity sha512-gJKwd2MVPWHAIFLsaYDZfyKzHNS4o7E/v8YmNf44vmeV2e4YfVoDToTOKTvE7ab68cRJ++kLuEXJBaEeJVt5ow== + +regexparam@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/regexparam/-/regexparam-1.3.0.tgz#2fe42c93e32a40eff6235d635e0ffa344b92965f" + integrity sha512-6IQpFBv6e5vz1QAqI+V4k8P2e/3gRrqfCJ9FI+O1FLQTO+Uz6RXZEZOPmTJ6hlGj7gkERzY5BRCv09whKP96/g== + regexpp@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" @@ -9348,6 +9979,21 @@ regjsparser@^0.6.4: dependencies: jsesc "~0.5.0" +relative@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/relative/-/relative-3.0.2.tgz#0dcd8ec54a5d35a3c15e104503d65375b5a5367f" + integrity sha1-Dc2OxUpdNaPBXhBFA9ZTdbWlNn8= + dependencies: + isobject "^2.0.0" + +remarkable@^1.6.2, remarkable@^1.7.1: + version "1.7.4" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.4.tgz#19073cb960398c87a7d6546eaa5e50d2022fcd00" + integrity sha512-e6NKUXgX95whv7IgddywbeN/ItCkWbISmc2DiqHJb0wTrqZIexqdco5b8Z3XZoo/48IdNVKM9ZCvTPJ4F5uvhg== + dependencies: + argparse "^1.0.10" + autolinker "~0.28.0" + remove-trailing-separator@^1.0.1: version "1.1.0" resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" @@ -9384,7 +10030,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0: +request@^2.72.0, request@^2.74.0, request@^2.87.0, request@^2.88.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -9576,6 +10222,11 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" +sanitize-s3-objectkey@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/sanitize-s3-objectkey/-/sanitize-s3-objectkey-0.0.1.tgz#efa9887cd45275b40234fb4bb12fc5754fe64e7e" + integrity sha512-ZTk7aqLxy4sD40GWcYWoLfbe05XLmkKvh6vGKe13ADlei24xlezcvjgKy1qRArlaIbIMYaqK7PCalvZtulZlaQ== + saslprep@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" @@ -9588,7 +10239,7 @@ sax@1.2.1: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a" integrity sha1-e45lYZCyKOgaZq6nSEgNgozS03o= -sax@>=0.6.0, sax@^1.2.4: +sax@>=0.1.1, sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -9612,6 +10263,11 @@ seek-bzip@^1.0.5: dependencies: commander "^2.8.1" +self-closing-tags@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/self-closing-tags/-/self-closing-tags-1.0.1.tgz#6c5fa497994bb826b484216916371accee490a5d" + integrity sha512-7t6hNbYMxM+VHXTgJmxwgZgLGktuXtVVD5AivWzNTdJBM4DBjnDKDzkf2SrNjihaArpeJYNjxkELBu1evI4lQA== + semver-diff@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" @@ -9619,7 +10275,7 @@ semver-diff@^3.1.1: dependencies: semver "^6.3.0" -"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.1: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -9745,6 +10401,18 @@ shell-path@^2.1.0: dependencies: shell-env "^0.3.0" +shimmer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/shimmer/-/shimmer-1.2.1.tgz#610859f7de327b587efebf501fb43117f9aff337" + integrity sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw== + +shortid@^2.2.15: + version "2.2.16" + resolved "https://registry.yarnpkg.com/shortid/-/shortid-2.2.16.tgz#b742b8f0cb96406fd391c76bfc18a67a57fe5608" + integrity sha512-Ugt+GIZqvGXCIItnsL+lvFJOiN7RYqlGy7QE41O3YC1xbNSeDGIRO7xg2JJXIAj1cAGnOeC1r7/T9pgrtQbv4g== + dependencies: + nanoid "^2.1.0" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -9989,6 +10657,11 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" +stack-chain@^1.3.7: + version "1.3.7" + resolved "https://registry.yarnpkg.com/stack-chain/-/stack-chain-1.3.7.tgz#d192c9ff4ea6a22c94c4dd459171e3f00cea1285" + integrity sha1-0ZLJ/06moiyUxN1FkXHj8AzqEoU= + stack-utils@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" @@ -10031,6 +10704,11 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= +step@0.0.x: + version "0.0.6" + resolved "https://registry.yarnpkg.com/step/-/step-0.0.6.tgz#143e7849a5d7d3f4a088fe29af94915216eeede2" + integrity sha1-FD54SaXX0/SgiP4pr5SRUhbu7eI= + strict-uri-encode@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" @@ -10044,6 +10722,11 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +string-template@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string-template/-/string-template-1.0.0.tgz#9e9f2233dc00f218718ec379a28a5673ecca8b96" + integrity sha1-np8iM9wA8hhxjsN5oopWc+zKi5Y= + string-width@^3.0.0, string-width@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" @@ -10169,6 +10852,11 @@ strip-outer@^1.0.0: dependencies: escape-string-regexp "^1.0.2" +striptags@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/striptags/-/striptags-3.2.0.tgz#cc74a137db2de8b0b9a370006334161f7dd67052" + integrity sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw== + sublevel-pouchdb@7.2.2: version "7.2.2" resolved "https://registry.yarnpkg.com/sublevel-pouchdb/-/sublevel-pouchdb-7.2.2.tgz#49e46cd37883bf7ff5006d7c5b9bcc7bcc1f422f" @@ -10253,11 +10941,25 @@ svelte-flatpickr@^3.1.0: dependencies: flatpickr "^4.5.2" +svelte-flatpickr@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/svelte-flatpickr/-/svelte-flatpickr-3.2.3.tgz#db5dd7ad832ef83262b45e09737955ad3d591fc8" + integrity sha512-PNkqK4Napx8nTvCwkaUXdnKo8dISThaxEOK+szTUXcY6H0dQM0TSyuoMaVWY2yX7pM+PN5cpCQCcVe8YvTRFSw== + dependencies: + flatpickr "^4.5.2" + svelte-portal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svelte-portal/-/svelte-portal-1.0.0.tgz#36a47c5578b1a4d9b4dc60fa32a904640ec4cdd3" integrity sha512-nHf+DS/jZ6jjnZSleBMSaZua9JlG5rZv9lOGKgJuaZStfevtjIlUJrkLc3vbV8QdBvPPVmvcjTlazAzfKu0v3Q== +svelte-spa-router@^3.0.5: + version "3.2.0" + resolved "https://registry.yarnpkg.com/svelte-spa-router/-/svelte-spa-router-3.2.0.tgz#fae3311d292451236cb57131262406cf312b15ee" + integrity sha512-igemo5Vs82TGBBw+DjWt6qKameXYzNs6aDXcTxou5XbEvOjiRcAM6MLkdVRCatn6u8r42dE99bt/br7T4qe/AQ== + dependencies: + regexparam "2.0.0" + svelte@^3.38.2: version "3.42.4" resolved "https://registry.yarnpkg.com/svelte/-/svelte-3.42.4.tgz#838ed98fa7b26fc5fffe4df0d7ba345f1c54cf4f" @@ -10333,6 +11035,16 @@ table@^5.2.3: slice-ansi "^2.1.0" string-width "^3.0.0" +tar-fs@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + tar-stream@^1.5.2: version "1.6.2" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" @@ -10346,6 +11058,17 @@ tar-stream@^1.5.2: to-buffer "^1.1.1" xtend "^4.0.0" +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tarn@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/tarn/-/tarn-1.1.5.tgz#7be88622e951738b9fa3fb77477309242cdddc2d" @@ -10517,6 +11240,11 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= +to-gfm-code-block@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/to-gfm-code-block/-/to-gfm-code-block-0.1.1.tgz#25d045a5fae553189e9637b590900da732d8aa82" + integrity sha1-JdBFpfrlUxielje1kJANpzLYqoI= + to-json-schema@0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/to-json-schema/-/to-json-schema-0.2.5.tgz#ef3c3f11ad64460dcfbdbafd0fd525d69d62a98f" @@ -10728,11 +11456,28 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" +typeof-article@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/typeof-article/-/typeof-article-0.1.1.tgz#9f07e733c3fbb646ffa9e61c08debacd460e06af" + integrity sha1-nwfnM8P7tkb/qeYcCN66zUYOBq8= + dependencies: + kind-of "^3.1.0" + typescript@^4.3.5: version "4.3.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" integrity sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA== +uglify-js@^3.1.4: + version "3.14.2" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.14.2.tgz#d7dd6a46ca57214f54a2d0a43cad0f35db82ac99" + integrity sha512-rtPMlmcO4agTUfz10CbgJ1k6UAoXM2gWb3GoMPPZB/+/Ackf8lNWk11K4rYi2D0apgoFRLtQOZhb+/iGNJq26A== + +uid2@0.0.x: + version "0.0.4" + resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.4.tgz#033f3b1d5d32505f5ce5f888b9f3b667123c0a44" + integrity sha512-IevTus0SbGwQzYh3+fRsAMTVVPOoIVufzacXcHPmdlle1jUpq7BRL+mw3dgeLanvGZdwwbWhRV6XrcFNdBmjWA== + unbox-primitive@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" @@ -10924,7 +11669,7 @@ util.promisify@^1.0.0, util.promisify@^1.0.1: has-symbols "^1.0.1" object.getownpropertydescriptors "^2.1.1" -utils-merge@1.0.1: +utils-merge@1.0.1, utils-merge@1.x.x: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= @@ -10996,9 +11741,9 @@ verror@1.10.0: extsprintf "^1.2.0" vm2@^3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.3.tgz#29917f6cc081cc43a3f580c26c5b553fd3c91f40" - integrity sha512-smLS+18RjXYMl9joyJxMNI9l4w7biW8ilSDaVRvFBDwOH8P0BK1ognFQTpg0wyQ6wIKLTblHJvROW692L/E53Q== + version "3.9.4" + resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.4.tgz#2e118290fefe7bd8ea09ebe2f5faf53730dbddaa" + integrity sha512-sOdharrJ7KEePIpHekiWaY1DwgueuiBeX/ZBJUPgETsVlJsXuEx0K0/naATq2haFvJrvZnRiORQRubR0b7Ye6g== vuvuzela@1.0.3: version "1.0.3" @@ -11026,6 +11771,14 @@ walker@^1.0.7, walker@~1.0.5: dependencies: makeerror "1.0.x" +webfinger@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/webfinger/-/webfinger-0.4.2.tgz#3477a6d97799461896039fcffc650b73468ee76d" + integrity sha1-NHem2XeZRhiWA5/P/GULc0aO520= + dependencies: + step "0.0.x" + xml2js "0.1.x" + webidl-conversions@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" @@ -11122,6 +11875,11 @@ word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -11220,6 +11978,13 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= +xml2js@0.1.x: + version "0.1.14" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.1.14.tgz#5274e67f5a64c5f92974cd85139e0332adc6b90c" + integrity sha1-UnTmf1pkxfkpdM2FE54DMq3GuQw= + dependencies: + sax ">=0.1.1" + xml2js@0.4.19: version "0.4.19" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" @@ -11358,6 +12123,11 @@ yauzl@^2.4.2: buffer-crc32 "~0.2.3" fd-slicer "~1.1.0" +year@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/year/-/year-0.2.1.tgz#4083ae520a318b23ec86037f3000cb892bdf9bb0" + integrity sha1-QIOuUgoxiyPshgN/MADLiSvfm7A= + ylru@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/ylru/-/ylru-1.2.1.tgz#f576b63341547989c1de7ba288760923b27fe84f" @@ -11368,7 +12138,7 @@ yn@3.1.1: resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -zlib@1.0.5: +zlib@1.0.5, zlib@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/zlib/-/zlib-1.0.5.tgz#6e7c972fc371c645a6afb03ab14769def114fcc0" integrity sha1-bnyXL8NxxkWmr7A6sUdp3vEU/MA= From a23e1a87e11294e371685b2eedb1ec93aa314427 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Tue, 26 Oct 2021 15:11:14 +0200 Subject: [PATCH 002/148] allow opening a template directly from a URL --- .../pages/builder/portal/apps/index.svelte | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index a0b75a3a2..8a3b6c41b 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -18,7 +18,7 @@ import { onMount } from "svelte" import { apps, auth, admin } from "stores/portal" import download from "downloadjs" - import { goto } from "@roxi/routify" + import { goto, params } from "@roxi/routify" import ConfirmDialog from "components/common/ConfirmDialog.svelte" import AppCard from "components/start/AppCard.svelte" import AppRow from "components/start/AppRow.svelte" @@ -184,9 +184,27 @@ } } + function createAppFromTemplateUrl(templateKey) { + // validate the template key just to make sure + const templateParts = templateKey.split("/") + if (templateParts.length === 2 && templateParts[0] === "app") { + template = { + key: templateKey, + } + initiateAppCreation() + } else { + notifications.error("Your Template URL is invalid. Please try another.") + } + } + onMount(async () => { await apps.load() loaded = true + + // if the portal is loaded from an external URL + const templateKey = $params["?template"] + if (!templateKey) return + createAppFromTemplateUrl(templateKey) }) From 484a38c9f5c71e168007981eed288d2162c89afb Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Wed, 27 Oct 2021 15:13:34 +0000 Subject: [PATCH 003/148] v0.9.173 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index aebd39aca..d879d3c65 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.173-alpha.3", + "version": "0.9.173", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 5f6866e9e..cecb16d00 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 80bacada0..8cd9b1452 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index d262839f1..1b337e2ba 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.173-alpha.3", - "@budibase/client": "^0.9.173-alpha.3", + "@budibase/bbui": "^0.9.173", + "@budibase/client": "^0.9.173", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.173-alpha.3", + "@budibase/string-templates": "^0.9.173", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index bdf01c50b..0ed0c9826 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 7cca15572..9edca0f2a 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.173-alpha.3", + "@budibase/bbui": "^0.9.173", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.173-alpha.3", + "@budibase/string-templates": "^0.9.173", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 2945578e7..a1271be56 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.173-alpha.3", - "@budibase/client": "^0.9.173-alpha.3", - "@budibase/string-templates": "^0.9.173-alpha.3", + "@budibase/auth": "^0.9.173", + "@budibase/client": "^0.9.173", + "@budibase/string-templates": "^0.9.173", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index a3b90b595..1906bfde0 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index cf489d2d9..05a322c82 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.173-alpha.3", + "version": "0.9.173", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.173-alpha.3", - "@budibase/string-templates": "^0.9.173-alpha.3", + "@budibase/auth": "^0.9.173", + "@budibase/string-templates": "^0.9.173", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 0ddd689b893ff05010ff2c4920fe035e4502fb79 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 27 Oct 2021 16:21:19 +0100 Subject: [PATCH 004/148] Postgres: Use another schema other than 'public' --- packages/server/src/integrations/postgres.ts | 21 ++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index abd1fa928..3cf1bdb3e 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -27,6 +27,7 @@ module PostgresModule { database: string user: string password: string + schema: string ssl?: boolean ca?: string rejectUnauthorized?: boolean @@ -64,6 +65,11 @@ module PostgresModule { default: "root", required: true, }, + schema: { + type: DatasourceFieldTypes.STRING, + default: "public", + required: true, + }, ssl: { type: DatasourceFieldTypes.BOOLEAN, default: false, @@ -137,8 +143,7 @@ module PostgresModule { private readonly client: any private readonly config: PostgresConfig - COLUMNS_SQL = - "select * from information_schema.columns where not table_schema = 'information_schema' and not table_schema = 'pg_catalog'" + COLUMNS_SQL!: string PRIMARY_KEYS_SQL = ` select tc.table_schema, tc.table_name, kc.column_name as primary_key @@ -168,6 +173,18 @@ module PostgresModule { } this.client = this.pool + this.setSchema() + + } + + setSchema() { + if (!this.config.schema) { + this.config.schema = 'public' + } + this.client.on('connect', (client: any) => { + client.query(`SET search_path TO ${this.config.schema}`); + }); + this.COLUMNS_SQL = `select * from information_schema.columns where table_schema = '${this.config.schema}'` } /** From 8b8c923541b48157f7f65ff2d7a14fdc6f9e5051 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 27 Oct 2021 17:21:29 +0100 Subject: [PATCH 005/148] Update tests --- packages/server/__mocks__/pg.ts | 3 +++ packages/server/src/integrations/tests/postgres.spec.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/packages/server/__mocks__/pg.ts b/packages/server/__mocks__/pg.ts index 0ec823ea3..ba7803f9a 100644 --- a/packages/server/__mocks__/pg.ts +++ b/packages/server/__mocks__/pg.ts @@ -21,15 +21,18 @@ module PgMock { function Pool() { } + const on = jest.fn() Pool.prototype.query = query Pool.prototype.connect = jest.fn(() => { // @ts-ignore return new Client() }) + Pool.prototype.on = on pg.Client = Client pg.Pool = Pool pg.queryMock = query + pg.on = on module.exports = pg } diff --git a/packages/server/src/integrations/tests/postgres.spec.js b/packages/server/src/integrations/tests/postgres.spec.js index 4ce5f12e9..5c0d086ce 100644 --- a/packages/server/src/integrations/tests/postgres.spec.js +++ b/packages/server/src/integrations/tests/postgres.spec.js @@ -15,6 +15,10 @@ describe("Postgres Integration", () => { config = new TestConfiguration() }) + it("calls the connection callback", async () => { + expect(pg.on).toHaveBeenCalledWith('connect', expect.anything()) + }) + it("calls the create method with the correct params", async () => { const sql = "insert into users (name, age) values ('Joe', 123);" await config.integration.create({ From c210802b4ce0154f98859bcaca42d0b38f67d658 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 27 Oct 2021 17:23:52 +0100 Subject: [PATCH 006/148] Remove whitespace --- packages/server/src/integrations/postgres.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index 3cf1bdb3e..237ffc4c6 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -174,7 +174,6 @@ module PostgresModule { this.client = this.pool this.setSchema() - } setSchema() { From 09d83dea399cfea2d44c92f8989d6a2c84f63e6b Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 27 Oct 2021 17:32:02 +0100 Subject: [PATCH 007/148] Adding docker compose for ms-sql with products, tasks table setup. --- .../integrations/mssql/data/Dockerfile | 9 +++++ .../integrations/mssql/data/entrypoint.sh | 24 +++++++++++++ .../scripts/integrations/mssql/data/setup.sql | 34 +++++++++++++++++++ .../integrations/mssql/docker-compose.yaml | 12 +++++++ .../scripts/integrations/mssql/reset.sh | 3 ++ 5 files changed, 82 insertions(+) create mode 100644 packages/server/scripts/integrations/mssql/data/Dockerfile create mode 100644 packages/server/scripts/integrations/mssql/data/entrypoint.sh create mode 100644 packages/server/scripts/integrations/mssql/data/setup.sql create mode 100644 packages/server/scripts/integrations/mssql/docker-compose.yaml create mode 100755 packages/server/scripts/integrations/mssql/reset.sh diff --git a/packages/server/scripts/integrations/mssql/data/Dockerfile b/packages/server/scripts/integrations/mssql/data/Dockerfile new file mode 100644 index 000000000..8ac56409a --- /dev/null +++ b/packages/server/scripts/integrations/mssql/data/Dockerfile @@ -0,0 +1,9 @@ +FROM mcr.microsoft.com/mssql/server + +ENV ACCEPT_EULA=Y +ENV SA_PASSWORD=Passw0rd + +COPY ./data / + +ENTRYPOINT [ "/bin/bash", "entrypoint.sh" ] +CMD [ "/opt/mssql/bin/sqlservr" ] diff --git a/packages/server/scripts/integrations/mssql/data/entrypoint.sh b/packages/server/scripts/integrations/mssql/data/entrypoint.sh new file mode 100644 index 000000000..04780d085 --- /dev/null +++ b/packages/server/scripts/integrations/mssql/data/entrypoint.sh @@ -0,0 +1,24 @@ +#!/bin/bash +set -e + +if [ "$1" = '/opt/mssql/bin/sqlservr' ]; then + # If this is the container's first run, initialize the application database + if [ ! -f /tmp/app-initialized ]; then + # Initialize the application database asynchronously in a background process. This allows a) the SQL Server process to be the main process in the container, which allows graceful shutdown and other goodies, and b) us to only start the SQL Server process once, as opposed to starting, stopping, then starting it again. + function initialize_app_database() { + # Wait a bit for SQL Server to start. SQL Server's process doesn't provide a clever way to check if it's up or not, and it needs to be up before we can import the application database + sleep 30s + + echo "RUNNING BUDIBASE SETUP" + + #run the setup script to create the DB and the schema in the DB + /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P Passw0rd -i setup.sql + + # Note that the container has been initialized so future starts won't wipe changes to the data + touch /tmp/app-initialized + } + initialize_app_database & + fi +fi + +exec "$@" diff --git a/packages/server/scripts/integrations/mssql/data/setup.sql b/packages/server/scripts/integrations/mssql/data/setup.sql new file mode 100644 index 000000000..f6c94ee2c --- /dev/null +++ b/packages/server/scripts/integrations/mssql/data/setup.sql @@ -0,0 +1,34 @@ +USE master; + +IF OBJECT_ID ('dbo.products', 'U') IS NOT NULL + DROP TABLE products; +GO +CREATE TABLE products +( + id int IDENTITY(1,1), + name varchar (20), + description varchar(30) +); +IF OBJECT_ID ('dbo.tasks', 'U') IS NOT NULL + DROP TABLE tasks; +GO +CREATE TABLE tasks +( + taskid int IDENTITY(1,1), + taskname varchar (20) +); + +INSERT products + (name, description) +VALUES + ('Bananas', 'Fruit thing'); + +INSERT products + (name, description) +VALUES + ('Meat', 'Animal thing'); + +INSERT tasks + (taskname) +VALUES + ('Processing'); diff --git a/packages/server/scripts/integrations/mssql/docker-compose.yaml b/packages/server/scripts/integrations/mssql/docker-compose.yaml new file mode 100644 index 000000000..89222edda --- /dev/null +++ b/packages/server/scripts/integrations/mssql/docker-compose.yaml @@ -0,0 +1,12 @@ +version: "3.8" +services: + # password: Passw0rd + # user: sa + # database: master + mssql: + image: bb/mssql + build: + context: . + dockerfile: data/Dockerfile + ports: + - "1433:1433" diff --git a/packages/server/scripts/integrations/mssql/reset.sh b/packages/server/scripts/integrations/mssql/reset.sh new file mode 100755 index 000000000..32778bd11 --- /dev/null +++ b/packages/server/scripts/integrations/mssql/reset.sh @@ -0,0 +1,3 @@ +#!/bin/bash +docker-compose down +docker volume prune -f From 5e846ac64d644bcba0dc6a1a48610cce7105a909 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 27 Oct 2021 18:36:27 +0100 Subject: [PATCH 008/148] First version of schema generation for ms-sql, able to retrieve basic tables and rows. --- .../src/integrations/microsoftSqlServer.ts | 103 +++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 2c0108acf..d97c5f36b 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -6,10 +6,18 @@ import { SqlQuery, } from "../definitions/datasource" import { getSqlQuery } from "./utils" +import { DatasourcePlus } from "./base/datasourcePlus" +import { Table, TableSchema } from "../definitions/common"; module MSSQLModule { const sqlServer = require("mssql") const Sql = require("./base/sql") + const { FieldTypes } = require("../constants") + const { + buildExternalTableId, + convertType, + finaliseExternalTables, + } = require("./utils") interface MSSQLConfig { user: string @@ -22,6 +30,7 @@ module MSSQLModule { const SCHEMA: Integration = { docs: "https://github.com/tediousjs/node-mssql", + plus: true, description: "Microsoft SQL Server is a relational database management system developed by Microsoft. ", friendlyName: "MS SQL Server", @@ -69,18 +78,66 @@ module MSSQLModule { }, } + // TODO: need to update this + const TYPE_MAP = { + text: FieldTypes.LONGFORM, + blob: FieldTypes.LONGFORM, + enum: FieldTypes.STRING, + varchar: FieldTypes.STRING, + float: FieldTypes.NUMBER, + int: FieldTypes.NUMBER, + numeric: FieldTypes.NUMBER, + bigint: FieldTypes.NUMBER, + mediumint: FieldTypes.NUMBER, + decimal: FieldTypes.NUMBER, + dec: FieldTypes.NUMBER, + double: FieldTypes.NUMBER, + real: FieldTypes.NUMBER, + fixed: FieldTypes.NUMBER, + smallint: FieldTypes.NUMBER, + timestamp: FieldTypes.DATETIME, + date: FieldTypes.DATETIME, + datetime: FieldTypes.DATETIME, + time: FieldTypes.DATETIME, + tinyint: FieldTypes.BOOLEAN, + json: DatasourceFieldTypes.JSON, + } + async function internalQuery(client: any, query: SqlQuery) { try { - return await client.query(query.sql, query.bindings || {}) + if (Array.isArray(query.bindings)) { + let count = 0 + for (let binding of query.bindings) { + client.input(`p${count++}`, binding) + } + } + return await client.query(query.sql) } catch (err) { // @ts-ignore throw new Error(err) } } - class SqlServerIntegration extends Sql { + class SqlServerIntegration extends Sql implements DatasourcePlus { private readonly config: MSSQLConfig static pool: any + public tables: Record = {} + public schemaErrors: Record = {} + + MASTER_TABLES = [ + "spt_fallback_db", + "spt_fallback_dev", + "spt_fallback_usg", + "spt_monitor", + "MSreplication_options" + ] + TABLES_SQL = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" + + getDefinitionSQL(tableName: string) { + return `select * + from INFORMATION_SCHEMA.COLUMNS + where TABLE_NAME='${tableName}'` + } constructor(config: MSSQLConfig) { super("mssql") @@ -89,6 +146,7 @@ module MSSQLModule { ...this.config, options: { encrypt: this.config.encrypt, + enableArithAbort: true, }, } delete clientCfg.encrypt @@ -107,6 +165,46 @@ module MSSQLModule { } } + /** + * Fetches the tables from the sql server database and assigns them to the datasource. + * @param {*} datasourceId - datasourceId to fetch + * @param entities - the tables that are to be built + */ + async buildSchema(datasourceId: string, entities: Record) { + + await this.connect() + let tableNames = await internalQuery(this.client, getSqlQuery(this.TABLES_SQL)) + if (tableNames == null || !Array.isArray(tableNames.recordset)) { + throw "Unable to get list of tables in database" + } + tableNames = tableNames.recordset.map((record: any) => record.TABLE_NAME).filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1) + const tables: Record = {} + for (let tableName of tableNames) { + const definition = await internalQuery(this.client, getSqlQuery(this.getDefinitionSQL(tableName))) + let schema: TableSchema = {} + for (let def of definition.recordset) { + const name = def.COLUMN_NAME + if (typeof name !== "string") { + continue + } + const type: string = convertType(def.DATA_TYPE, TYPE_MAP) + const identity = false + schema[name] = { + autocolumn: identity, + name: name, + type, + } + } + tables[tableName] = { + _id: buildExternalTableId(datasourceId, tableName), + primary: ["id"], + name: tableName, + schema, + } + } + this.tables = tables + } + async read(query: SqlQuery | string) { await this.connect() const response = await internalQuery(this.client, getSqlQuery(query)) @@ -132,6 +230,7 @@ module MSSQLModule { } async query(json: QueryJson) { + await this.connect() const operation = this._operation(json).toLowerCase() const input = this._query(json) const response = await internalQuery(this.client, input) From 329156d6cc9c7b1a729f30391ad2ee518f31b462 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 28 Oct 2021 19:39:42 +0100 Subject: [PATCH 009/148] SQL table building. --- .../backend/DataTable/DataTable.svelte | 4 +- .../components/backend/DataTable/Table.svelte | 2 +- .../DataTable/modals/CreateEditColumn.svelte | 29 +++- .../popovers/EditTablePopover.svelte | 11 +- .../[selectedDatasource]/index.svelte | 21 +++ .../modals/CreateExternalTableModal.svelte | 44 +++++ packages/builder/src/stores/backend/tables.js | 3 + .../server/src/api/controllers/datasource.js | 4 +- .../api/controllers/row/ExternalRequest.ts | 22 +-- .../server/src/api/controllers/row/utils.js | 13 +- .../src/api/controllers/table/external.js | 116 +++++++++++++ .../server/src/api/controllers/table/index.js | 162 +++--------------- .../src/api/controllers/table/internal.js | 138 +++++++++++++++ packages/server/src/constants/index.js | 3 + packages/server/src/definitions/common.ts | 2 +- packages/server/src/definitions/datasource.ts | 5 + packages/server/src/integrations/base/sql.ts | 31 ++-- .../server/src/integrations/base/sqlTable.ts | 132 ++++++++++++++ .../server/src/integrations/base/utils.ts | 19 ++ packages/server/src/integrations/postgres.ts | 12 +- 20 files changed, 583 insertions(+), 190 deletions(-) create mode 100644 packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte create mode 100644 packages/server/src/api/controllers/table/external.js create mode 100644 packages/server/src/api/controllers/table/internal.js create mode 100644 packages/server/src/integrations/base/sqlTable.ts create mode 100644 packages/server/src/integrations/base/utils.ts diff --git a/packages/builder/src/components/backend/DataTable/DataTable.svelte b/packages/builder/src/components/backend/DataTable/DataTable.svelte index 336bb5167..1af703800 100644 --- a/packages/builder/src/components/backend/DataTable/DataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/DataTable.svelte @@ -98,9 +98,7 @@ on:updatecolumns={onUpdateColumns} on:updaterows={onUpdateRows} > - {#if isInternal} - - {/if} + {#if schema && Object.keys(schema).length > 0} {#if !isUsersTable} editColumn(e.detail)} on:editrow={e => editRow(e.detail)} diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index cd437bcad..221d391cb 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -56,7 +56,7 @@ let deletion $: tableOptions = $tables.list.filter( - table => table._id !== $tables.draft._id && table.type !== "external" + opt => opt._id !== $tables.draft._id && opt.type === table.type ) $: required = !!field?.constraints?.presence || primaryDisplay $: uneditable = @@ -83,6 +83,7 @@ $: canBeRequired = field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE $: relationshipOptions = getRelationshipOptions(field) + $: external = table.type === "external" async function saveColumn() { if (field.type === AUTO_TYPE) { @@ -193,6 +194,27 @@ }, ] } + + function getAllowedTypes() { + if (!external) { + return [ + ...Object.values(fieldDefinitions), + { name: "Auto Column", type: AUTO_TYPE }, + ] + } else { + return [ + FIELDS.STRING, + FIELDS.LONGFORM, + FIELDS.OPTIONS, + FIELDS.DATETIME, + FIELDS.NUMBER, + FIELDS.BOOLEAN, + FIELDS.ARRAY, + FIELDS.FORMULA, + FIELDS.LINK, + ] + } + } field.name} getOptionValue={field => field.type} /> diff --git a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte index 2513c6c7e..04094b881 100644 --- a/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte +++ b/packages/builder/src/components/backend/TableNavigator/popovers/EditTablePopover.svelte @@ -1,7 +1,7 @@ @@ -130,6 +137,10 @@ + + + + {#if datasource && integration}
@@ -189,6 +200,11 @@ /> {/if}
+
+ + New table + +
{#each plusTables as table}
onClickTable(table)}>

{table.name}

@@ -325,4 +341,9 @@ .table-buttons div { grid-column-end: -1; } + + .add-table { + margin-right: 0; + margin-left: auto; + } diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte new file mode 100644 index 000000000..c7a040d89 --- /dev/null +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte @@ -0,0 +1,44 @@ + + + + Provide a name for your new table; you can add columns once it is created. + + diff --git a/packages/builder/src/stores/backend/tables.js b/packages/builder/src/stores/backend/tables.js index 161877f66..7f90a04a0 100644 --- a/packages/builder/src/stores/backend/tables.js +++ b/packages/builder/src/stores/backend/tables.js @@ -62,6 +62,9 @@ export function createTablesStore() { const response = await api.post(`/api/tables`, updatedTable) const savedTable = await response.json() await fetch() + if (table.type === "external") { + await datasources.fetch() + } await select(savedTable) return savedTable } diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index d75a8f8ce..604fee004 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -9,7 +9,7 @@ const { } = require("../../db/utils") const { BuildSchemaErrors } = require("../../constants") const { integrations } = require("../../integrations") -const { makeExternalQuery } = require("./row/utils") +const { getDatasourceAndQuery } = require("./row/utils") exports.fetch = async function (ctx) { const database = new CouchDB(ctx.appId) @@ -138,7 +138,7 @@ exports.find = async function (ctx) { exports.query = async function (ctx) { const queryJson = ctx.request.body try { - ctx.body = await makeExternalQuery(ctx.appId, queryJson) + ctx.body = await getDatasourceAndQuery(ctx.appId, queryJson) } catch (err) { ctx.throw(400, err) } diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index c58364af0..f538e01f7 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -36,7 +36,7 @@ interface RunConfig { } module External { - const { makeExternalQuery } = require("./utils") + const { getDatasourceAndQuery } = require("./utils") const { DataSourceOperation, FieldTypes, @@ -46,6 +46,7 @@ module External { const { processObjectSync } = require("@budibase/string-templates") const { cloneDeep } = require("lodash/fp") const CouchDB = require("../../../db") + const { processFormulas } = require("../../../utilities/rowProcessor/utils") function buildFilters( id: string | undefined, @@ -225,7 +226,7 @@ module External { manyRelationships: ManyRelationship[] = [] for (let [key, field] of Object.entries(table.schema)) { // if set already, or not set just skip it - if ((!row[key] && row[key] !== "") || newRow[key] || field.autocolumn) { + if (row[key] == null || newRow[key] || field.autocolumn || field.type === FieldTypes.FORMULA) { continue } // if its an empty string then it means return the column to null (if possible) @@ -361,7 +362,7 @@ module External { relationships ) } - return Object.values(finalRows) + return processFormulas(table, Object.values(finalRows)) } /** @@ -428,7 +429,7 @@ module External { const tableId = isMany ? field.through : field.tableId const manyKey = field.throughFrom || primaryKey const fieldName = isMany ? manyKey : field.fieldName - const response = await makeExternalQuery(this.appId, { + const response = await getDatasourceAndQuery(this.appId, { endpoint: getEndpoint(tableId, DataSourceOperation.READ), filters: { equal: { @@ -479,7 +480,7 @@ module External { : DataSourceOperation.CREATE if (!found) { promises.push( - makeExternalQuery(appId, { + getDatasourceAndQuery(appId, { endpoint: getEndpoint(tableId, operation), // if we're doing many relationships then we're writing, only one response body, @@ -509,7 +510,7 @@ module External { : DataSourceOperation.UPDATE const body = isMany ? null : { [colName]: null } promises.push( - makeExternalQuery(this.appId, { + getDatasourceAndQuery(this.appId, { endpoint: getEndpoint(tableId, op), body, filters, @@ -532,16 +533,17 @@ module External { table: Table, includeRelations: IncludeRelationships = IncludeRelationships.INCLUDE ) { - function extractNonLinkFieldNames(table: Table, existing: string[] = []) { + function extractRealFields(table: Table, existing: string[] = []) { return Object.entries(table.schema) .filter( column => column[1].type !== FieldTypes.LINK && + column[1].type !== FieldTypes.FORMULA && !existing.find((field: string) => field === column[0]) ) .map(column => `${table.name}.${column[0]}`) } - let fields = extractNonLinkFieldNames(table) + let fields = extractRealFields(table) for (let field of Object.values(table.schema)) { if (field.type !== FieldTypes.LINK || !includeRelations) { continue @@ -549,7 +551,7 @@ module External { const { tableName: linkTableName } = breakExternalTableId(field.tableId) const linkTable = this.tables[linkTableName] if (linkTable) { - const linkedFields = extractNonLinkFieldNames(linkTable, fields) + const linkedFields = extractRealFields(linkTable, fields) fields = fields.concat(linkedFields) } } @@ -609,7 +611,7 @@ module External { }, } // can't really use response right now - const response = await makeExternalQuery(appId, json) + const response = await getDatasourceAndQuery(appId, json) // handle many to many relationships now if we know the ID (could be auto increment) if ( operation !== DataSourceOperation.READ && diff --git a/packages/server/src/api/controllers/row/utils.js b/packages/server/src/api/controllers/row/utils.js index ca6c78271..bd2df084a 100644 --- a/packages/server/src/api/controllers/row/utils.js +++ b/packages/server/src/api/controllers/row/utils.js @@ -4,8 +4,8 @@ const CouchDB = require("../../../db") const { InternalTables } = require("../../../db/utils") const userController = require("../user") const { FieldTypes } = require("../../../constants") -const { integrations } = require("../../../integrations") const { processStringSync } = require("@budibase/string-templates") +const { makeExternalQuery } = require("../../../integrations/base/utils") validateJs.extend(validateJs.validators.datetime, { parse: function (value) { @@ -17,18 +17,11 @@ validateJs.extend(validateJs.validators.datetime, { }, }) -exports.makeExternalQuery = async (appId, json) => { +exports.getDatasourceAndQuery = async (appId, json) => { const datasourceId = json.endpoint.datasourceId const db = new CouchDB(appId) const datasource = await db.get(datasourceId) - const Integration = integrations[datasource.source] - // query is the opinionated function - if (Integration.prototype.query) { - const integration = new Integration(datasource.config) - return integration.query(json) - } else { - throw "Datasource does not support query." - } + return makeExternalQuery(datasource, json) } exports.findRow = async (ctx, db, tableId, rowId) => { diff --git a/packages/server/src/api/controllers/table/external.js b/packages/server/src/api/controllers/table/external.js new file mode 100644 index 000000000..42454fd2e --- /dev/null +++ b/packages/server/src/api/controllers/table/external.js @@ -0,0 +1,116 @@ +const CouchDB = require("../../../db") +const { + buildExternalTableId, + breakExternalTableId, +} = require("../../../integrations/utils") +const { getTable } = require("./utils") +const { DataSourceOperation, FieldTypes } = require("../../../constants") +const { makeExternalQuery } = require("../../../integrations/base/utils") +const { cloneDeep } = require("lodash/fp") + +async function makeTableRequest( + datasource, + operation, + table, + tables, + oldTable = null +) { + const json = { + endpoint: { + datasourceId: datasource._id, + entityId: table._id, + operation, + }, + meta: { + tables, + }, + table, + } + if (oldTable) { + json.meta.table = oldTable + } + return makeExternalQuery(datasource, json) +} + +function getDatasourceId(table) { + if (!table) { + throw "No table supplied" + } + if (table.sourceId) { + return table.sourceId + } + return breakExternalTableId(table._id).datasourceId +} + +exports.save = async function (ctx) { + const appId = ctx.appId + const table = ctx.request.body + // can't do this + delete table.dataImport + const datasourceId = getDatasourceId(ctx.request.body) + let tableToSave = { + type: "table", + _id: buildExternalTableId(datasourceId, table.name), + ...table, + } + + let oldTable + if (ctx.request.body && ctx.request.body._id) { + oldTable = await getTable(appId, ctx.request.body._id) + } + + const db = new CouchDB(appId) + const datasource = await db.get(datasourceId) + const tables = datasource.entities + + // check if relations need setup + for (let [key, schema] of Object.entries(tableToSave.schema)) { + // TODO: this assumes all relationships are the same, need to handle cardinality and many to many + if (schema.type === FieldTypes.LINK) { + const relatedTable = Object.values(tables).find( + table => table._id === schema.tableId + ) + const relatedField = schema.fieldName + const foreignKey = `fk_${relatedTable.name}_${schema.fieldName}` + // create foreign key + tableToSave.schema[foreignKey] = { type: FieldTypes.NUMBER } + // setup the relation in other table and this one + schema.foreignKey = foreignKey + schema.fieldName = foreignKey + schema.main = true + const relatedSchema = cloneDeep(schema) + relatedSchema.fieldName = key + delete relatedSchema.main + relatedTable.schema[relatedField] = relatedSchema + } + } + + const operation = oldTable + ? DataSourceOperation.UPDATE_TABLE + : DataSourceOperation.CREATE_TABLE + await makeTableRequest(datasource, operation, tableToSave, tables, oldTable) + + // store it into couch now for budibase reference + datasource.entities[tableToSave.name] = tableToSave + await db.put(datasource) + + return tableToSave +} + +exports.destroy = async function (ctx) { + const appId = ctx.appId + const tableToDelete = await getTable(appId, ctx.params.tableId) + const datasourceId = getDatasourceId(tableToDelete) + + const db = new CouchDB(appId) + const datasource = await db.get(datasourceId) + const tables = datasource.entities + + const operation = DataSourceOperation.DELETE_TABLE + await makeTableRequest(datasource, operation, tableToDelete, tables) + + delete datasource.entities[tableToDelete.name] + await db.put(datasource) + + return tableToDelete +} diff --git a/packages/server/src/api/controllers/table/index.js b/packages/server/src/api/controllers/table/index.js index d4356c9c8..97b48943b 100644 --- a/packages/server/src/api/controllers/table/index.js +++ b/packages/server/src/api/controllers/table/index.js @@ -1,16 +1,28 @@ const CouchDB = require("../../../db") -const linkRows = require("../../../db/linkedRows") +const internal = require("./internal") +const external = require("./external") const csvParser = require("../../../utilities/csvParser") +const { isExternalTable } = require("../../../integrations/utils") const { - getRowParams, getTableParams, - generateTableID, getDatasourceParams, BudibaseInternalDB, } = require("../../../db/utils") -const { FieldTypes } = require("../../../constants") -const { TableSaveFunctions, getTable } = require("./utils") +const { getTable } = require("./utils") +function pickApi({ tableId, table }) { + if (table && !tableId) { + tableId = table._id + } + if (table && table.type === "external") { + return external + } else if (tableId && isExternalTable(tableId)) { + return external + } + return internal +} + +// covers both internal and external exports.fetch = async function (ctx) { const db = new CouchDB(ctx.appId) @@ -50,143 +62,23 @@ exports.find = async function (ctx) { exports.save = async function (ctx) { const appId = ctx.appId - const db = new CouchDB(appId) - const { dataImport, ...rest } = ctx.request.body - let tableToSave = { - type: "table", - _id: generateTableID(), - views: {}, - ...rest, - } - - // if the table obj had an _id then it will have been retrieved - let oldTable - if (ctx.request.body && ctx.request.body._id) { - oldTable = await db.get(ctx.request.body._id) - } - - // saving a table is a complex operation, involving many different steps, this - // has been broken out into a utility to make it more obvious/easier to manipulate - const tableSaveFunctions = new TableSaveFunctions({ - db, - ctx, - oldTable, - dataImport, - }) - tableToSave = await tableSaveFunctions.before(tableToSave) - - // make sure that types don't change of a column, have to remove - // the column if you want to change the type - if (oldTable && oldTable.schema) { - for (let propKey of Object.keys(tableToSave.schema)) { - let column = tableToSave.schema[propKey] - let oldColumn = oldTable.schema[propKey] - if (oldColumn && oldColumn.type === "internal") { - oldColumn.type = "auto" - } - if (oldColumn && oldColumn.type !== column.type) { - ctx.throw(400, "Cannot change the type of a column") - } - } - } - - // Don't rename if the name is the same - let { _rename } = tableToSave - /* istanbul ignore next */ - if (_rename && _rename.old === _rename.updated) { - _rename = null - delete tableToSave._rename - } - - // rename row fields when table column is renamed - /* istanbul ignore next */ - if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) { - ctx.throw(400, "Cannot rename a linked column.") - } - - tableToSave = await tableSaveFunctions.mid(tableToSave) - - // update schema of non-statistics views when new columns are added - for (let view in tableToSave.views) { - const tableView = tableToSave.views[view] - if (!tableView) continue - - if (tableView.schema.group || tableView.schema.field) continue - tableView.schema = tableToSave.schema - } - - // update linked rows - try { - const linkResp = await linkRows.updateLinks({ - appId, - eventType: oldTable - ? linkRows.EventType.TABLE_UPDATED - : linkRows.EventType.TABLE_SAVE, - table: tableToSave, - oldTable: oldTable, - }) - if (linkResp != null && linkResp._rev) { - tableToSave._rev = linkResp._rev - } - } catch (err) { - ctx.throw(400, err) - } - - // don't perform any updates until relationships have been - // checked by the updateLinks function - const updatedRows = tableSaveFunctions.getUpdatedRows() - if (updatedRows && updatedRows.length !== 0) { - await db.bulkDocs(updatedRows) - } - const result = await db.put(tableToSave) - tableToSave._rev = result.rev - - tableToSave = await tableSaveFunctions.after(tableToSave) - - ctx.eventEmitter && - ctx.eventEmitter.emitTable(`table:save`, appId, tableToSave) - + const table = ctx.request.body + const savedTable = await pickApi({ table }).save(ctx) ctx.status = 200 - ctx.message = `Table ${ctx.request.body.name} saved successfully.` - ctx.body = tableToSave + ctx.message = `Table ${table.name} saved successfully.` + ctx.eventEmitter && + ctx.eventEmitter.emitTable(`table:save`, appId, savedTable) + ctx.body = savedTable } exports.destroy = async function (ctx) { const appId = ctx.appId - const db = new CouchDB(appId) - const tableToDelete = await db.get(ctx.params.tableId) - - // Delete all rows for that table - const rows = await db.allDocs( - getRowParams(ctx.params.tableId, null, { - include_docs: true, - }) - ) - await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true }))) - - // update linked rows - await linkRows.updateLinks({ - appId, - eventType: linkRows.EventType.TABLE_DELETE, - table: tableToDelete, - }) - - // don't remove the table itself until very end - await db.remove(tableToDelete) - - // remove table search index - const currentIndexes = await db.getIndexes() - const existingIndex = currentIndexes.indexes.find( - existing => existing.name === `search:${ctx.params.tableId}` - ) - if (existingIndex) { - await db.deleteIndex(existingIndex) - } - + const tableId = ctx.params.tableId + const deletedTable = await pickApi({ tableId }).destroy(ctx) ctx.eventEmitter && - ctx.eventEmitter.emitTable(`table:delete`, appId, tableToDelete) + ctx.eventEmitter.emitTable(`table:delete`, appId, deletedTable) ctx.status = 200 - ctx.body = { message: `Table ${ctx.params.tableId} deleted.` } + ctx.body = { message: `Table ${tableId} deleted.` } } exports.validateCSVSchema = async function (ctx) { diff --git a/packages/server/src/api/controllers/table/internal.js b/packages/server/src/api/controllers/table/internal.js new file mode 100644 index 000000000..898cd0593 --- /dev/null +++ b/packages/server/src/api/controllers/table/internal.js @@ -0,0 +1,138 @@ +const CouchDB = require("../../../db") +const linkRows = require("../../../db/linkedRows") +const { getRowParams, generateTableID } = require("../../../db/utils") +const { FieldTypes } = require("../../../constants") +const { TableSaveFunctions } = require("./utils") + +exports.save = async function (ctx) { + const appId = ctx.appId + const db = new CouchDB(appId) + const { dataImport, ...rest } = ctx.request.body + let tableToSave = { + type: "table", + _id: generateTableID(), + views: {}, + ...rest, + } + + // if the table obj had an _id then it will have been retrieved + let oldTable + if (ctx.request.body && ctx.request.body._id) { + oldTable = await db.get(ctx.request.body._id) + } + + // saving a table is a complex operation, involving many different steps, this + // has been broken out into a utility to make it more obvious/easier to manipulate + const tableSaveFunctions = new TableSaveFunctions({ + db, + ctx, + oldTable, + dataImport, + }) + tableToSave = await tableSaveFunctions.before(tableToSave) + + // make sure that types don't change of a column, have to remove + // the column if you want to change the type + if (oldTable && oldTable.schema) { + for (let propKey of Object.keys(tableToSave.schema)) { + let column = tableToSave.schema[propKey] + let oldColumn = oldTable.schema[propKey] + if (oldColumn && oldColumn.type === "internal") { + oldColumn.type = "auto" + } + if (oldColumn && oldColumn.type !== column.type) { + ctx.throw(400, "Cannot change the type of a column") + } + } + } + + // Don't rename if the name is the same + let { _rename } = tableToSave + /* istanbul ignore next */ + if (_rename && _rename.old === _rename.updated) { + _rename = null + delete tableToSave._rename + } + + // rename row fields when table column is renamed + /* istanbul ignore next */ + if (_rename && tableToSave.schema[_rename.updated].type === FieldTypes.LINK) { + ctx.throw(400, "Cannot rename a linked column.") + } + + tableToSave = await tableSaveFunctions.mid(tableToSave) + + // update schema of non-statistics views when new columns are added + for (let view in tableToSave.views) { + const tableView = tableToSave.views[view] + if (!tableView) continue + + if (tableView.schema.group || tableView.schema.field) continue + tableView.schema = tableToSave.schema + } + + // update linked rows + try { + const linkResp = await linkRows.updateLinks({ + appId, + eventType: oldTable + ? linkRows.EventType.TABLE_UPDATED + : linkRows.EventType.TABLE_SAVE, + table: tableToSave, + oldTable: oldTable, + }) + if (linkResp != null && linkResp._rev) { + tableToSave._rev = linkResp._rev + } + } catch (err) { + ctx.throw(400, err) + } + + // don't perform any updates until relationships have been + // checked by the updateLinks function + const updatedRows = tableSaveFunctions.getUpdatedRows() + if (updatedRows && updatedRows.length !== 0) { + await db.bulkDocs(updatedRows) + } + const result = await db.put(tableToSave) + tableToSave._rev = result.rev + + tableToSave = await tableSaveFunctions.after(tableToSave) + + return tableToSave +} + +exports.destroy = async function (ctx) { + const appId = ctx.appId + const db = new CouchDB(appId) + const tableToDelete = await db.get(ctx.params.tableId) + + // Delete all rows for that table + const rows = await db.allDocs( + getRowParams(ctx.params.tableId, null, { + include_docs: true, + }) + ) + await db.bulkDocs(rows.rows.map(row => ({ ...row.doc, _deleted: true }))) + + // update linked rows + await linkRows.updateLinks({ + appId, + eventType: linkRows.EventType.TABLE_DELETE, + table: tableToDelete, + }) + + // don't remove the table itself until very end + await db.remove(tableToDelete) + + // remove table search index + const currentIndexes = await db.getIndexes() + const existingIndex = currentIndexes.indexes.find( + existing => existing.name === `search:${ctx.params.tableId}` + ) + if (existingIndex) { + await db.deleteIndex(existingIndex) + } + + return tableToDelete +} diff --git a/packages/server/src/constants/index.js b/packages/server/src/constants/index.js index 7a8958c36..80c62cd02 100644 --- a/packages/server/src/constants/index.js +++ b/packages/server/src/constants/index.js @@ -62,6 +62,9 @@ exports.DataSourceOperation = { READ: "READ", UPDATE: "UPDATE", DELETE: "DELETE", + CREATE_TABLE: "CREATE_TABLE", + UPDATE_TABLE: "UPDATE_TABLE", + DELETE_TABLE: "DELETE_TABLE", } exports.SortDirection = { diff --git a/packages/server/src/definitions/common.ts b/packages/server/src/definitions/common.ts index f439fc0d2..b2ab203be 100644 --- a/packages/server/src/definitions/common.ts +++ b/packages/server/src/definitions/common.ts @@ -36,7 +36,7 @@ export interface TableSchema { export interface Table extends Base { type?: string views?: {} - name?: string + name: string primary?: string[] schema: TableSchema primaryDisplay?: string diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts index c4b248fa1..a82e50b14 100644 --- a/packages/server/src/definitions/datasource.ts +++ b/packages/server/src/definitions/datasource.ts @@ -5,6 +5,9 @@ export enum Operation { READ = "READ", UPDATE = "UPDATE", DELETE = "DELETE", + CREATE_TABLE = "CREATE_TABLE", + UPDATE_TABLE = "UPDATE_TABLE", + DELETE_TABLE = "DELETE_TABLE", } export enum SortDirection { @@ -142,8 +145,10 @@ export interface QueryJson { sort?: SortJson paginate?: PaginationJson body?: object + table?: Table meta?: { table?: Table + tables?: Record } extra?: { idFilter?: SearchFilters diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 316e20e35..738b44afc 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -1,19 +1,24 @@ import { Knex, knex } from "knex" -const BASE_LIMIT = 5000 import { + Operation, QueryJson, - SearchFilters, QueryOptions, - SortDirection, - Operation, RelationshipsJson, + SearchFilters, + SortDirection, } from "../../definitions/datasource" import { isIsoDateString } from "../utils" +import SqlTableQueryBuilder from "./sqlTable" + +const BASE_LIMIT = 5000 type KnexQuery = Knex.QueryBuilder | Knex function parseBody(body: any) { for (let [key, value] of Object.entries(body)) { + if (Array.isArray(value)) { + body[key] = JSON.stringify(value) + } if (typeof value !== "string") { continue } @@ -243,23 +248,14 @@ function buildDelete( } } -class SqlQueryBuilder { - private readonly sqlClient: string +class SqlQueryBuilder extends SqlTableQueryBuilder { private readonly limit: number // pass through client to get flavour of SQL constructor(client: string, limit: number = BASE_LIMIT) { - this.sqlClient = client + super(client) this.limit = limit } - /** - * @param json the input JSON structure from which an SQL query will be built. - * @return {string} the operation that was found in the JSON. - */ - _operation(json: QueryJson): Operation { - return json.endpoint.operation - } - /** * @param json The JSON query DSL which is to be converted to SQL. * @param opts extra options which are to be passed into the query builder, e.g. disableReturning @@ -267,7 +263,8 @@ class SqlQueryBuilder { * @return {{ sql: string, bindings: object }} the query ready to be passed to the driver. */ _query(json: QueryJson, opts: QueryOptions = {}) { - const client = knex({ client: this.sqlClient }) + const sqlClient = this.getSqlClient() + const client = knex({ client: sqlClient }) let query switch (this._operation(json)) { case Operation.CREATE: @@ -282,6 +279,8 @@ class SqlQueryBuilder { case Operation.DELETE: query = buildDelete(client, json, opts) break + case Operation.CREATE_TABLE: case Operation.UPDATE_TABLE: case Operation.DELETE_TABLE: + return this._tableQuery(json) default: throw `Operation type is not supported by SQL query builder` } diff --git a/packages/server/src/integrations/base/sqlTable.ts b/packages/server/src/integrations/base/sqlTable.ts new file mode 100644 index 000000000..f2e727ce6 --- /dev/null +++ b/packages/server/src/integrations/base/sqlTable.ts @@ -0,0 +1,132 @@ +import { Knex, knex } from "knex" +import { Table } from "../../definitions/common" +import { Operation, QueryJson } from "../../definitions/datasource" +import { breakExternalTableId } from "../utils" +import SchemaBuilder = Knex.SchemaBuilder +import CreateTableBuilder = Knex.CreateTableBuilder +const { FieldTypes } = require("../../constants") + +function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record, oldTable: null | Table = null) { + let primaryKey = table && table.primary ? table.primary[0] : null + // can't change primary once its set for now + if (primaryKey && !oldTable) { + schema.increments(primaryKey).primary() + } + const foreignKeys = Object.values(table.schema).map(col => col.foreignKey) + for (let [key, column] of Object.entries(table.schema)) { + // skip things that are already correct + const oldColumn = oldTable ? oldTable.schema[key] : null + if ((oldColumn && oldColumn.type === column.type) || primaryKey === key) { + continue + } + switch (column.type) { + case FieldTypes.STRING: case FieldTypes.OPTIONS: case FieldTypes.LONGFORM: + schema.string(key) + break + case FieldTypes.NUMBER: + if (foreignKeys.indexOf(key) === -1) { + schema.float(key) + } + break + case FieldTypes.BOOLEAN: + schema.boolean(key) + break + case FieldTypes.DATETIME: + schema.datetime(key) + break + case FieldTypes.ARRAY: + schema.json(key) + break + case FieldTypes.LINK: + if (!column.foreignKey || !column.tableId) { + throw "Invalid relationship schema" + } + const { tableName } = breakExternalTableId(column.tableId) + // @ts-ignore + const relatedTable = tables[tableName] + if (!relatedTable) { + throw "Referenced table doesn't exist" + } + schema.integer(column.foreignKey).unsigned() + schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`) + } + } + return schema +} + +function buildCreateTable( + knex: Knex, + table: Table, + tables: Record, +): SchemaBuilder { + return knex.schema.createTable(table.name, schema => { + generateSchema(schema, table, tables) + }) +} + +function buildUpdateTable( + knex: Knex, + table: Table, + tables: Record, + oldTable: Table, +): SchemaBuilder { + return knex.schema.alterTable(table.name, schema => { + generateSchema(schema, table, tables, oldTable) + }) +} + +function buildDeleteTable( + knex: Knex, + table: Table, +): SchemaBuilder { + return knex.schema.dropTable(table.name) +} + +class SqlTableQueryBuilder { + private readonly sqlClient: string + + // pass through client to get flavour of SQL + constructor(client: string) { + this.sqlClient = client + } + + getSqlClient(): string { + return this.sqlClient + } + + /** + * @param json the input JSON structure from which an SQL query will be built. + * @return {string} the operation that was found in the JSON. + */ + _operation(json: QueryJson): Operation { + return json.endpoint.operation + } + + _tableQuery(json: QueryJson): any { + const client = knex({ client: this.sqlClient }) + let query + if (!json.table || !json.meta || !json.meta.tables) { + throw "Cannot execute without table being specified" + } + switch (this._operation(json)) { + case Operation.CREATE_TABLE: + query = buildCreateTable(client, json.table, json.meta.tables) + break + case Operation.UPDATE_TABLE: + if (!json.meta || !json.meta.table) { + throw "Must specify old table for update" + } + query = buildUpdateTable(client, json.table, json.meta.tables, json.meta.table) + break + case Operation.DELETE_TABLE: + query = buildDeleteTable(client, json.table) + break + default: + throw "Table operation is of unknown type" + } + return query.toSQL() + } +} + +export default SqlTableQueryBuilder +module.exports = SqlTableQueryBuilder \ No newline at end of file diff --git a/packages/server/src/integrations/base/utils.ts b/packages/server/src/integrations/base/utils.ts new file mode 100644 index 000000000..5757232bc --- /dev/null +++ b/packages/server/src/integrations/base/utils.ts @@ -0,0 +1,19 @@ +import { QueryJson } from "../../definitions/datasource" +import { Datasource } from "../../definitions/common" + +module DatasourceUtils { + const { integrations } = require("../index") + + export async function makeExternalQuery(datasource: Datasource, json: QueryJson) { + const Integration = integrations[datasource.source] + // query is the opinionated function + if (Integration.prototype.query) { + const integration = new Integration(datasource.config) + return integration.query(json) + } else { + throw "Datasource does not support query." + } + } + + module.exports.makeExternalQuery = makeExternalQuery +} diff --git a/packages/server/src/integrations/postgres.ts b/packages/server/src/integrations/postgres.ts index dd7ecd576..adae9b5fc 100644 --- a/packages/server/src/integrations/postgres.ts +++ b/packages/server/src/integrations/postgres.ts @@ -263,8 +263,16 @@ module PostgresModule { async query(json: QueryJson) { const operation = this._operation(json).toLowerCase() const input = this._query(json) - const response = await internalQuery(this.client, input) - return response.rows.length ? response.rows : [{ [operation]: true }] + if (Array.isArray(input)) { + const responses = [] + for (let query of input) { + responses.push(await internalQuery(this.client, query)) + } + return responses + } else { + const response = await internalQuery(this.client, input) + return response.rows.length ? response.rows : [{ [operation]: true }] + } } } From 949c6b8653b61a0a18038e39da61b8730597dccf Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 28 Oct 2021 22:44:31 +0100 Subject: [PATCH 010/148] Adding SQL relationship building. --- .../DataTable/modals/CreateEditColumn.svelte | 6 ++- .../src/api/controllers/table/external.js | 41 ++++++++++++++----- 2 files changed, 35 insertions(+), 12 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 221d391cb..54bbb7fad 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -89,6 +89,10 @@ if (field.type === AUTO_TYPE) { field = buildAutoColumn($tables.draft.name, field.name, field.subtype) } + // for now you can't create other options, just many to many for SQL + if (field.type === LINK_TYPE && external) { + field.relationshipType = RelationshipTypes.ONE_TO_MANY + } await tables.saveField({ originalName, field, @@ -324,7 +328,7 @@ getOptionLabel={table => table.name} getOptionValue={table => table._id} /> - {#if relationshipOptions && relationshipOptions.length > 0} + {#if relationshipOptions && relationshipOptions.length > 0 && !external} table._id === schema.tableId ) + // setup the schema in this table const relatedField = schema.fieldName + const relatedPrimary = relatedTable.primary[0] + // generate a foreign key const foreignKey = `fk_${relatedTable.name}_${schema.fieldName}` - // create foreign key - tableToSave.schema[foreignKey] = { type: FieldTypes.NUMBER } - // setup the relation in other table and this one + + schema.relationshipType = RelationshipTypes.ONE_TO_MANY schema.foreignKey = foreignKey - schema.fieldName = foreignKey + schema.fieldName = relatedPrimary schema.main = true - const relatedSchema = cloneDeep(schema) - relatedSchema.fieldName = key - delete relatedSchema.main - relatedTable.schema[relatedField] = relatedSchema + + relatedTable.schema[relatedField] = generateRelatedSchema(schema, table) + tableToSave.schema[foreignKey] = { + type: FieldTypes.NUMBER, + constraints: {}, + } } } From a94376ce430002c002686d5251e1898ed0681127 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Oct 2021 13:34:10 +0100 Subject: [PATCH 011/148] Fixing a lot of issues around dropping columns, updating columns, relationships and bi-directionality, display columns now default to something for SQL tables as well. --- .../backend/DataTable/RowFieldControl.svelte | 4 +- .../DataTable/modals/CreateEditColumn.svelte | 41 ++++++++++++++---- .../[selectedDatasource]/index.svelte | 12 ++---- .../server/src/api/controllers/datasource.js | 10 +++++ .../src/api/controllers/table/external.js | 43 ++++++++++++++++++- .../server/src/integrations/base/sqlTable.ts | 19 +++++++- 6 files changed, 109 insertions(+), 20 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte index e82c55679..25ad67b52 100644 --- a/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte +++ b/packages/builder/src/components/backend/DataTable/RowFieldControl.svelte @@ -16,8 +16,8 @@ export let value = defaultValue || (meta.type === "boolean" ? false : "") export let readonly - $: type = meta.type - $: label = capitalise(meta.name) + $: type = meta?.type + $: label = meta.name ? capitalise(meta.name) : "" {#if type === "options"} diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 54bbb7fad..9af07fe28 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -31,6 +31,9 @@ const AUTO_TYPE = "auto" const FORMULA_TYPE = FIELDS.FORMULA.type const LINK_TYPE = FIELDS.LINK.type + const STRING_TYPE = FIELDS.STRING.type + const NUMBER_TYPE = FIELDS.NUMBER.type + const dispatch = createEventDispatcher() const PROHIBITED_COLUMN_NAMES = ["type", "_id", "_rev", "tableId"] const { hide } = getContext(Context.Modal) @@ -55,6 +58,7 @@ let confirmDeleteDialog let deletion + $: checkConstraints(field) $: tableOptions = $tables.list.filter( opt => opt._id !== $tables.draft._id && opt.type === table.type ) @@ -180,23 +184,26 @@ } const thisName = truncate(table.name, { length: 14 }), linkName = truncate(linkTable.name, { length: 14 }) - return [ + const options = [ { name: `Many ${thisName} rows → many ${linkName} rows`, alt: `Many ${table.name} rows → many ${linkTable.name} rows`, value: RelationshipTypes.MANY_TO_MANY, }, - { - name: `One ${linkName} row → many ${thisName} rows`, - alt: `One ${linkTable.name} rows → many ${table.name} rows`, - value: RelationshipTypes.ONE_TO_MANY, - }, { name: `One ${thisName} row → many ${linkName} rows`, alt: `One ${table.name} rows → many ${linkTable.name} rows`, value: RelationshipTypes.MANY_TO_ONE, }, ] + if (!external) { + options.push({ + name: `One ${linkName} row → many ${thisName} rows`, + alt: `One ${linkTable.name} rows → many ${table.name} rows`, + value: RelationshipTypes.ONE_TO_MANY, + }) + } + return options } function getAllowedTypes() { @@ -219,6 +226,24 @@ ] } } + + function checkConstraints(fieldToCheck) { + // most types need this, just make sure its always present + if (fieldToCheck && !fieldToCheck.constraints) { + fieldToCheck.constraints = {} + } + // some string types may have been built by server, may not always have constraints + if (fieldToCheck.type === STRING_TYPE && !fieldToCheck.constraints.length) { + fieldToCheck.constraints.length = {} + } + // some number types made server-side will be missing constraints + if ( + fieldToCheck.type === NUMBER_TYPE && + !fieldToCheck.constraints.numericality + ) { + fieldToCheck.constraints.numericality = {} + } + } {/if} - {#if canBeSearched} + {#if canBeSearched && !external}
table.name} getOptionValue={table => table._id} /> - {#if relationshipOptions && relationshipOptions.length > 0 && !external} + {#if relationshipOptions && relationshipOptions.length > 0} {/if}
-
- - New table - -
{#each plusTables as table}
onClickTable(table)}>

{table.name}

@@ -212,6 +206,9 @@

→

{/each} +
+ +
{#if plusTables?.length !== 0} @@ -343,7 +340,6 @@ } .add-table { - margin-right: 0; - margin-left: auto; + margin-top: var(--spacing-m); } diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index 604fee004..6f33faf3d 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -152,6 +152,16 @@ const buildSchemaHelper = async datasource => { await connector.buildSchema(datasource._id, datasource.entities) datasource.entities = connector.tables + // make sure they all have a display name selected + for (let entity of Object.values(datasource.entities)) { + if (entity.primaryDisplay) { + continue + } + entity.primaryDisplay = Object.values(entity.schema).find( + schema => !schema.autocolumn + ).name + } + const errors = connector.schemaErrors let error = null if (errors && Object.keys(errors).length > 0) { diff --git a/packages/server/src/api/controllers/table/external.js b/packages/server/src/api/controllers/table/external.js index 5fe923cb9..d0ec01a1d 100644 --- a/packages/server/src/api/controllers/table/external.js +++ b/packages/server/src/api/controllers/table/external.js @@ -36,6 +36,35 @@ async function makeTableRequest( return makeExternalQuery(datasource, json) } +function cleanupRelationships(table, tables, oldTable = null) { + const tableToIterate = oldTable ? oldTable : table + // clean up relationships in couch table schemas + for (let [key, schema] of Object.entries(tableToIterate.schema)) { + if ( + schema.type === FieldTypes.LINK && + (!oldTable || table.schema[key] == null) + ) { + const relatedTable = Object.values(tables).find( + table => table._id === schema.tableId + ) + const foreignKey = schema.foreignKey + if (!relatedTable || !foreignKey) { + continue + } + for (let [relatedKey, relatedSchema] of Object.entries( + relatedTable.schema + )) { + if ( + relatedSchema.type === FieldTypes.LINK && + relatedSchema.fieldName === foreignKey + ) { + delete relatedSchema[relatedKey] + } + } + } + } +} + function getDatasourceId(table) { if (!table) { throw "No table supplied" @@ -57,6 +86,14 @@ function generateRelatedSchema(linkColumn, table) { return relatedSchema } +function oneToManyRelationshipNeedsSetup(column) { + return ( + column.type === FieldTypes.LINK && + column.relationshipType === RelationshipTypes.ONE_TO_MANY && + !column.foreignKey + ) +} + exports.save = async function (ctx) { const appId = ctx.appId const table = ctx.request.body @@ -81,7 +118,7 @@ exports.save = async function (ctx) { // check if relations need setup for (let schema of Object.values(tableToSave.schema)) { // TODO: many to many handling - if (schema.type === FieldTypes.LINK) { + if (oneToManyRelationshipNeedsSetup(schema)) { const relatedTable = Object.values(tables).find( table => table._id === schema.tableId ) @@ -104,6 +141,8 @@ exports.save = async function (ctx) { } } + cleanupRelationships(tableToSave, tables, oldTable) + const operation = oldTable ? DataSourceOperation.UPDATE_TABLE : DataSourceOperation.CREATE_TABLE @@ -128,6 +167,8 @@ exports.destroy = async function (ctx) { const operation = DataSourceOperation.DELETE_TABLE await makeTableRequest(datasource, operation, tableToDelete, tables) + cleanupRelationships(tableToDelete, tables) + delete datasource.entities[tableToDelete.name] await db.put(datasource) diff --git a/packages/server/src/integrations/base/sqlTable.ts b/packages/server/src/integrations/base/sqlTable.ts index f2e727ce6..87d0f1e3b 100644 --- a/packages/server/src/integrations/base/sqlTable.ts +++ b/packages/server/src/integrations/base/sqlTable.ts @@ -4,7 +4,7 @@ import { Operation, QueryJson } from "../../definitions/datasource" import { breakExternalTableId } from "../utils" import SchemaBuilder = Knex.SchemaBuilder import CreateTableBuilder = Knex.CreateTableBuilder -const { FieldTypes } = require("../../constants") +const { FieldTypes, RelationshipTypes } = require("../../constants") function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record, oldTable: null | Table = null) { let primaryKey = table && table.primary ? table.primary[0] : null @@ -12,6 +12,8 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record if (primaryKey && !oldTable) { schema.increments(primaryKey).primary() } + + // check if any columns need added const foreignKeys = Object.values(table.schema).map(col => col.foreignKey) for (let [key, column] of Object.entries(table.schema)) { // skip things that are already correct @@ -38,6 +40,10 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record schema.json(key) break case FieldTypes.LINK: + // this side of the relationship doesn't need any SQL work + if (column.relationshipType === RelationshipTypes.MANY_TO_ONE) { + break + } if (!column.foreignKey || !column.tableId) { throw "Invalid relationship schema" } @@ -51,6 +57,17 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`) } } + + // need to check if any columns have been deleted + if (oldTable) { + const deletedColumns = Object.entries(oldTable.schema) + .filter(([key, schema]) => schema.type !== FieldTypes.LINK && table.schema[key] == null) + .map(([key]) => key) + deletedColumns.forEach(key => { + schema.dropColumn(key) + }) + } + return schema } From f071cc5219d311a428638bb7bc5514c3c4f58019 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Oct 2021 18:37:29 +0100 Subject: [PATCH 012/148] Adding many to many support, generating junction table and setting up constraints. --- .../DataTable/modals/CreateEditColumn.svelte | 19 +-- .../server/src/api/controllers/datasource.js | 7 +- .../src/api/controllers/table/external.js | 154 ++++++++++++++---- .../server/src/api/controllers/table/utils.js | 20 +++ packages/server/src/definitions/common.ts | 5 + .../server/src/integrations/base/sqlTable.ts | 46 ++++-- 6 files changed, 186 insertions(+), 65 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index 9af07fe28..ebfea9cee 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -93,10 +93,6 @@ if (field.type === AUTO_TYPE) { field = buildAutoColumn($tables.draft.name, field.name, field.subtype) } - // for now you can't create other options, just many to many for SQL - if (field.type === LINK_TYPE && external) { - field.relationshipType = RelationshipTypes.ONE_TO_MANY - } await tables.saveField({ originalName, field, @@ -184,26 +180,23 @@ } const thisName = truncate(table.name, { length: 14 }), linkName = truncate(linkTable.name, { length: 14 }) - const options = [ + return [ { name: `Many ${thisName} rows → many ${linkName} rows`, alt: `Many ${table.name} rows → many ${linkTable.name} rows`, value: RelationshipTypes.MANY_TO_MANY, }, + { + name: `One ${linkName} row → many ${thisName} rows`, + alt: `One ${linkTable.name} rows → many ${table.name} rows`, + value: RelationshipTypes.ONE_TO_MANY, + }, { name: `One ${thisName} row → many ${linkName} rows`, alt: `One ${table.name} rows → many ${linkTable.name} rows`, value: RelationshipTypes.MANY_TO_ONE, }, ] - if (!external) { - options.push({ - name: `One ${linkName} row → many ${thisName} rows`, - alt: `One ${linkTable.name} rows → many ${table.name} rows`, - value: RelationshipTypes.ONE_TO_MANY, - }) - } - return options } function getAllowedTypes() { diff --git a/packages/server/src/api/controllers/datasource.js b/packages/server/src/api/controllers/datasource.js index 6f33faf3d..643e822a3 100644 --- a/packages/server/src/api/controllers/datasource.js +++ b/packages/server/src/api/controllers/datasource.js @@ -157,9 +157,12 @@ const buildSchemaHelper = async datasource => { if (entity.primaryDisplay) { continue } - entity.primaryDisplay = Object.values(entity.schema).find( + const notAutoColumn = Object.values(entity.schema).find( schema => !schema.autocolumn - ).name + ) + if (notAutoColumn) { + entity.primaryDisplay = notAutoColumn.name + } } const errors = connector.schemaErrors diff --git a/packages/server/src/api/controllers/table/external.js b/packages/server/src/api/controllers/table/external.js index d0ec01a1d..7d332519b 100644 --- a/packages/server/src/api/controllers/table/external.js +++ b/packages/server/src/api/controllers/table/external.js @@ -3,7 +3,12 @@ const { buildExternalTableId, breakExternalTableId, } = require("../../../integrations/utils") -const { getTable } = require("./utils") +const { + getTable, + generateForeignKey, + generateJunctionTableName, + foreignKeyStructure, +} = require("./utils") const { DataSourceOperation, FieldTypes, @@ -58,7 +63,7 @@ function cleanupRelationships(table, tables, oldTable = null) { relatedSchema.type === FieldTypes.LINK && relatedSchema.fieldName === foreignKey ) { - delete relatedSchema[relatedKey] + delete relatedTable.schema[relatedKey] } } } @@ -75,23 +80,78 @@ function getDatasourceId(table) { return breakExternalTableId(table._id).datasourceId } -function generateRelatedSchema(linkColumn, table) { +function otherRelationshipType(type) { + if (type === RelationshipTypes.MANY_TO_MANY) { + return RelationshipTypes.MANY_TO_MANY + } + return type === RelationshipTypes.ONE_TO_MANY + ? RelationshipTypes.MANY_TO_ONE + : RelationshipTypes.ONE_TO_MANY +} + +function generateManyLinkSchema(datasource, column, table, relatedTable) { + const primary = table.name + table.primary[0] + const relatedPrimary = relatedTable.name + relatedTable.primary[0] + const jcTblName = generateJunctionTableName(column, table, relatedTable) + // first create the new table + const junctionTable = { + _id: buildExternalTableId(datasource._id, jcTblName), + name: jcTblName, + primary: [primary, relatedPrimary], + schema: { + [primary]: foreignKeyStructure(primary, { + toTable: table.name, + toKey: table.primary[0], + }), + [relatedPrimary]: foreignKeyStructure(relatedPrimary, { + toTable: relatedTable.name, + toKey: relatedTable.primary[0], + }), + }, + } + column.through = junctionTable._id + column.throughFrom = primary + column.throughTo = relatedPrimary + column.fieldName = relatedPrimary + return junctionTable +} + +function generateLinkSchema(column, table, relatedTable, type) { + const isOneSide = type === RelationshipTypes.ONE_TO_MANY + const primary = isOneSide ? relatedTable.primary[0] : table.primary[0] + // generate a foreign key + const foreignKey = generateForeignKey(column, relatedTable) + column.relationshipType = type + column.foreignKey = isOneSide ? foreignKey : primary + column.fieldName = isOneSide ? primary : foreignKey + return foreignKey +} + +function generateRelatedSchema(linkColumn, table, relatedTable, columnName) { // generate column for other table const relatedSchema = cloneDeep(linkColumn) - relatedSchema.fieldName = linkColumn.foreignKey - relatedSchema.foreignKey = linkColumn.fieldName - relatedSchema.relationshipType = RelationshipTypes.MANY_TO_ONE - relatedSchema.tableId = table._id - delete relatedSchema.main - return relatedSchema + // swap them from the main link + if (linkColumn.foreignKey) { + relatedSchema.fieldName = linkColumn.foreignKey + relatedSchema.foreignKey = linkColumn.fieldName + } + // is many to many + else { + // don't need to copy through, already got it + relatedSchema.fieldName = linkColumn.throughFrom + relatedSchema.throughTo = linkColumn.throughFrom + relatedSchema.throughFrom = linkColumn.throughTo + } + relatedSchema.relationshipType = otherRelationshipType( + linkColumn.relationshipType + ) + relatedSchema.tableId = relatedTable._id + relatedSchema.name = columnName + table.schema[columnName] = relatedSchema } -function oneToManyRelationshipNeedsSetup(column) { - return ( - column.type === FieldTypes.LINK && - column.relationshipType === RelationshipTypes.ONE_TO_MANY && - !column.foreignKey - ) +function isRelationshipSetup(column) { + return column.foreignKey || column.through } exports.save = async function (ctx) { @@ -113,32 +173,50 @@ exports.save = async function (ctx) { const db = new CouchDB(appId) const datasource = await db.get(datasourceId) + const oldTables = cloneDeep(datasource.entities) const tables = datasource.entities + const extraTablesToUpdate = [] + // check if relations need setup for (let schema of Object.values(tableToSave.schema)) { - // TODO: many to many handling - if (oneToManyRelationshipNeedsSetup(schema)) { - const relatedTable = Object.values(tables).find( - table => table._id === schema.tableId + if (schema.type !== FieldTypes.LINK || isRelationshipSetup(schema)) { + continue + } + const relatedTable = Object.values(tables).find( + table => table._id === schema.tableId + ) + const relatedColumnName = schema.fieldName + const relationType = schema.relationshipType + if (relationType === RelationshipTypes.MANY_TO_MANY) { + const junctionTable = generateManyLinkSchema( + datasource, + schema, + table, + relatedTable ) - // setup the schema in this table - const relatedField = schema.fieldName - const relatedPrimary = relatedTable.primary[0] - // generate a foreign key - const foreignKey = `fk_${relatedTable.name}_${schema.fieldName}` - - schema.relationshipType = RelationshipTypes.ONE_TO_MANY - schema.foreignKey = foreignKey - schema.fieldName = relatedPrimary - schema.main = true - - relatedTable.schema[relatedField] = generateRelatedSchema(schema, table) - tableToSave.schema[foreignKey] = { - type: FieldTypes.NUMBER, - constraints: {}, + if (tables[junctionTable.name]) { + throw "Junction table already exists, cannot create another relationship." + } + tables[junctionTable.name] = junctionTable + extraTablesToUpdate.push(junctionTable) + } else { + const fkTable = + relationType === RelationshipTypes.ONE_TO_MANY ? table : relatedTable + const foreignKey = generateLinkSchema( + schema, + table, + relatedTable, + relationType + ) + fkTable.schema[foreignKey] = foreignKeyStructure(foreignKey) + // foreign key is in other table, need to save it to external + if (fkTable._id !== table._id) { + extraTablesToUpdate.push(fkTable) } } + generateRelatedSchema(schema, relatedTable, table, relatedColumnName) + schema.main = true } cleanupRelationships(tableToSave, tables, oldTable) @@ -147,6 +225,14 @@ exports.save = async function (ctx) { ? DataSourceOperation.UPDATE_TABLE : DataSourceOperation.CREATE_TABLE await makeTableRequest(datasource, operation, tableToSave, tables, oldTable) + // update any extra tables (like foreign keys in other tables) + for (let extraTable of extraTablesToUpdate) { + const oldExtraTable = oldTables[extraTable.name] + let op = oldExtraTable + ? DataSourceOperation.UPDATE_TABLE + : DataSourceOperation.CREATE_TABLE + await makeTableRequest(datasource, op, extraTable, tables, oldExtraTable) + } // store it into couch now for budibase reference datasource.entities[tableToSave.name] = tableToSave diff --git a/packages/server/src/api/controllers/table/utils.js b/packages/server/src/api/controllers/table/utils.js index 65c081f90..1cca4c41d 100644 --- a/packages/server/src/api/controllers/table/utils.js +++ b/packages/server/src/api/controllers/table/utils.js @@ -315,4 +315,24 @@ exports.checkForViewUpdates = async (db, table, rename, deletedColumns) => { } } +exports.generateForeignKey = (column, relatedTable) => { + return `fk_${relatedTable.name}_${column.fieldName}` +} + +exports.generateJunctionTableName = (column, table, relatedTable) => { + return `jt_${table.name}_${relatedTable.name}_${column.name}_${column.fieldName}` +} + +exports.foreignKeyStructure = (keyName, meta = null) => { + const structure = { + type: FieldTypes.NUMBER, + constraints: {}, + name: keyName, + } + if (meta) { + structure.meta = meta + } + return structure +} + exports.TableSaveFunctions = TableSaveFunctions diff --git a/packages/server/src/definitions/common.ts b/packages/server/src/definitions/common.ts index b2ab203be..4308aff0a 100644 --- a/packages/server/src/definitions/common.ts +++ b/packages/server/src/definitions/common.ts @@ -17,6 +17,11 @@ export interface FieldSchema { autocolumn?: boolean throughFrom?: string throughTo?: string + main?: boolean + meta?: { + toTable: string + toKey: string + } constraints?: { type?: string email?: boolean diff --git a/packages/server/src/integrations/base/sqlTable.ts b/packages/server/src/integrations/base/sqlTable.ts index 87d0f1e3b..6eb6d02c3 100644 --- a/packages/server/src/integrations/base/sqlTable.ts +++ b/packages/server/src/integrations/base/sqlTable.ts @@ -8,9 +8,15 @@ const { FieldTypes, RelationshipTypes } = require("../../constants") function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record, oldTable: null | Table = null) { let primaryKey = table && table.primary ? table.primary[0] : null + const columns = Object.values(table.schema) + // all columns in a junction table will be meta + let metaCols = columns.filter(col => col.meta) + let isJunction = metaCols.length === columns.length // can't change primary once its set for now - if (primaryKey && !oldTable) { + if (primaryKey && !oldTable && !isJunction) { schema.increments(primaryKey).primary() + } else if (!oldTable && isJunction) { + schema.primary(metaCols.map(col => col.name)) } // check if any columns need added @@ -18,7 +24,7 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record for (let [key, column] of Object.entries(table.schema)) { // skip things that are already correct const oldColumn = oldTable ? oldTable.schema[key] : null - if ((oldColumn && oldColumn.type === column.type) || primaryKey === key) { + if ((oldColumn && oldColumn.type === column.type) || (primaryKey === key && !isJunction)) { continue } switch (column.type) { @@ -26,7 +32,12 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record schema.string(key) break case FieldTypes.NUMBER: - if (foreignKeys.indexOf(key) === -1) { + // if meta is specified then this is a junction table entry + if (column.meta && column.meta.toKey && column.meta.toTable) { + const { toKey, toTable } = column.meta + schema.integer(key).unsigned() + schema.foreign(key).references(`${toTable}.${toKey}`) + } else if (foreignKeys.indexOf(key) === -1) { schema.float(key) } break @@ -41,20 +52,23 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record break case FieldTypes.LINK: // this side of the relationship doesn't need any SQL work - if (column.relationshipType === RelationshipTypes.MANY_TO_ONE) { - break + if ( + column.relationshipType !== RelationshipTypes.MANY_TO_ONE && + column.relationshipType !== RelationshipTypes.MANY_TO_MANY + ) { + if (!column.foreignKey || !column.tableId) { + throw "Invalid relationship schema" + } + const { tableName } = breakExternalTableId(column.tableId) + // @ts-ignore + const relatedTable = tables[tableName] + if (!relatedTable) { + throw "Referenced table doesn't exist" + } + schema.integer(column.foreignKey).unsigned() + schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`) } - if (!column.foreignKey || !column.tableId) { - throw "Invalid relationship schema" - } - const { tableName } = breakExternalTableId(column.tableId) - // @ts-ignore - const relatedTable = tables[tableName] - if (!relatedTable) { - throw "Referenced table doesn't exist" - } - schema.integer(column.foreignKey).unsigned() - schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`) + break } } From 835b0efe740e6b7172750cd53fac1d1a009986de Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 29 Oct 2021 18:43:50 +0100 Subject: [PATCH 013/148] Adding mysql support. --- packages/server/src/integrations/mysql.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index eba288da5..c6f271b6f 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -262,6 +262,13 @@ module MySQLModule { const operation = this._operation(json) this.client.connect() const input = this._query(json, { disableReturning: true }) + if (Array.isArray(input)) { + const responses = [] + for (let query of input) { + responses.push(await internalQuery(this.client, query)) + } + return responses + } let row // need to manage returning, a feature mySQL can't do if (operation === operation.DELETE) { From 7efa06901e220adb94204fddb2761f469344358f Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 1 Nov 2021 16:03:53 +0000 Subject: [PATCH 014/148] Adding error scenario for table name already in use. --- .../modals/CreateExternalTableModal.svelte | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte index c7a040d89..1d9e246d2 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/CreateExternalTableModal.svelte @@ -6,8 +6,9 @@ export let datasource let name = "" - - $: valid = name && name.length > 0 + $: valid = name && name.length > 0 && !datasource?.entities[name] + $: error = + name && datasource?.entities[name] ? "Table name already in use." : null function buildDefaultTable(tableName, datasourceId) { return { @@ -40,5 +41,5 @@ Provide a name for your new table; you can add columns once it is created. - + From e9dd47b562d1dc9775234655e4ebca714551d80c Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 1 Nov 2021 17:18:38 +0000 Subject: [PATCH 015/148] Add initial structure of table with search block --- .../design/AppPreview/componentStructure.json | 7 ++ packages/client/manifest.json | 83 ++++++++++++++++ .../app/blocks/TableWithSearch.svelte | 99 +++++++++++++++++++ .../components/app/blocks/block-builder.js | 14 +++ .../app/blocks/component-builder.js | 49 +++++++++ .../client/src/components/app/blocks/index.js | 1 + packages/client/src/components/app/index.js | 1 + 7 files changed, 254 insertions(+) create mode 100644 packages/client/src/components/app/blocks/TableWithSearch.svelte create mode 100644 packages/client/src/components/app/blocks/block-builder.js create mode 100644 packages/client/src/components/app/blocks/component-builder.js create mode 100644 packages/client/src/components/app/blocks/index.js diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index 3bc2554fd..b6675c248 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -1,4 +1,11 @@ [ + { + "name": "Blocks", + "icon": "Article", + "children": [ + "tablewithsearch" + ] + }, "section", "container", "dataprovider", diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 2adfd9662..9b0bf7605 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2574,5 +2574,88 @@ "label": "Horizontal" } ] + }, + "tablewithsearch": { + "block": true, + "name": "Table with search", + "icon": "Table", + "styles": ["size"], + "settings": [ + { + "type": "dataSource", + "label": "Data", + "key": "dataSource" + }, + { + "type": "multifield", + "label": "Search Columns", + "key": "searchColumns", + "dependsOn": "dataSource", + "placeholder": "All columns" + }, + { + "type": "filter", + "label": "Filtering", + "key": "filter" + }, + { + "type": "field", + "label": "Sort Column", + "key": "sortColumn" + }, + { + "type": "select", + "label": "Sort Order", + "key": "sortOrder", + "options": ["Ascending", "Descending"], + "defaultValue": "Descending" + }, + { + "type": "boolean", + "label": "Paginate", + "key": "paginate", + "defaultValue": true + }, + { + "type": "number", + "label": "Row Count", + "key": "rowCount", + "defaultValue": 8 + }, + { + "type": "multifield", + "label": "Table Columns", + "key": "tableColumns", + "dependsOn": "dataSource", + "placeholder": "All columns" + }, + { + "type": "select", + "label": "Size", + "key": "size", + "defaultValue": "spectrum--medium", + "options": [ + { + "label": "Medium", + "value": "spectrum--medium" + }, + { + "label": "Large", + "value": "spectrum--large" + } + ] + }, + { + "type": "boolean", + "label": "Quiet", + "key": "quiet" + }, + { + "type": "boolean", + "label": "Auto Columns", + "key": "showAutoColumns", + "defaultValue": false + } + ] } } diff --git a/packages/client/src/components/app/blocks/TableWithSearch.svelte b/packages/client/src/components/app/blocks/TableWithSearch.svelte new file mode 100644 index 000000000..dba50eb4b --- /dev/null +++ b/packages/client/src/components/app/blocks/TableWithSearch.svelte @@ -0,0 +1,99 @@ + + +
+ +
diff --git a/packages/client/src/components/app/blocks/block-builder.js b/packages/client/src/components/app/blocks/block-builder.js new file mode 100644 index 000000000..2d5609480 --- /dev/null +++ b/packages/client/src/components/app/blocks/block-builder.js @@ -0,0 +1,14 @@ +import { ComponentBuilder } from "./component-builder" + +export class BlockBuilder { + context + componentCount = 0 + + constructor(context) { + this.context = context + } + + createComponent(type, props) { + return new ComponentBuilder(this, type, props) + } +} diff --git a/packages/client/src/components/app/blocks/component-builder.js b/packages/client/src/components/app/blocks/component-builder.js new file mode 100644 index 000000000..90ce30c06 --- /dev/null +++ b/packages/client/src/components/app/blocks/component-builder.js @@ -0,0 +1,49 @@ +export class ComponentBuilder { + context + + constructor(blockBuilder, type, props) { + this.blockBuilder = blockBuilder + this.type = type + this.id = `${blockBuilder.context.id}-${blockBuilder.componentCount++}` + this.props = props + this.children = [] + this.styles = null + } + + setProp(key, value) { + this.props[key] = value + return this + } + + setProps(props) { + this.props = { + ...this.props, + ...props, + } + return this + } + + setStyles(styles) { + this.styles = styles + return this + } + + addChild(component) { + this.children.push(component) + return this + } + + build() { + return { + _component: `@budibase/standard-components/${this.type}`, + _id: this.id, + _children: this.children?.map(child => child.build()), + _styles: { + normal: { + ...this.styles, + }, + }, + ...this.props, + } + } +} diff --git a/packages/client/src/components/app/blocks/index.js b/packages/client/src/components/app/blocks/index.js new file mode 100644 index 000000000..16b123d17 --- /dev/null +++ b/packages/client/src/components/app/blocks/index.js @@ -0,0 +1 @@ +export { default as tablewithsearch } from "./TableWithSearch.svelte" diff --git a/packages/client/src/components/app/index.js b/packages/client/src/components/app/index.js index b01763e2f..92725f073 100644 --- a/packages/client/src/components/app/index.js +++ b/packages/client/src/components/app/index.js @@ -32,6 +32,7 @@ export { default as spectrumcard } from "./SpectrumCard.svelte" export * from "./charts" export * from "./forms" export * from "./table" +export * from "./blocks" // Deprecated component left for compatibility in old apps export { default as navigation } from "./deprecated/Navigation.svelte" From c82cf534d80e70e997595c81de234e7108d226bd Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 1 Nov 2021 21:15:46 +0000 Subject: [PATCH 016/148] Updating external table UI a bit, adding the concept of defining an existing relationship, updating the data sources UI to make it a bit less cluttered and make the creation of tables more obvious. --- .../backend/DataTable/DataTable.svelte | 7 +++ .../buttons/ExistingRelationshipButton.svelte | 54 +++++++++++++++++++ .../CreateEditRelationship.svelte | 30 ++++++++++- .../backend/Datasources}/TableSelect.svelte | 0 .../[selectedDatasource]/index.svelte | 32 ++++++++--- packages/builder/src/stores/backend/tables.js | 1 + 6 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 packages/builder/src/components/backend/DataTable/buttons/ExistingRelationshipButton.svelte rename packages/builder/src/{pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship => components/backend/Datasources}/CreateEditRelationship.svelte (92%) rename packages/builder/src/{pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship => components/backend/Datasources}/TableSelect.svelte (100%) diff --git a/packages/builder/src/components/backend/DataTable/DataTable.svelte b/packages/builder/src/components/backend/DataTable/DataTable.svelte index 1af703800..6bebf2ca0 100644 --- a/packages/builder/src/components/backend/DataTable/DataTable.svelte +++ b/packages/builder/src/components/backend/DataTable/DataTable.svelte @@ -4,6 +4,7 @@ import CreateRowButton from "./buttons/CreateRowButton.svelte" import CreateColumnButton from "./buttons/CreateColumnButton.svelte" import CreateViewButton from "./buttons/CreateViewButton.svelte" + import ExistingRelationshipButton from "./buttons/ExistingRelationshipButton.svelte" import ExportButton from "./buttons/ExportButton.svelte" import EditRolesButton from "./buttons/EditRolesButton.svelte" import ManageAccessButton from "./buttons/ManageAccessButton.svelte" @@ -114,6 +115,12 @@ {#if isUsersTable} {/if} + {#if !isInternal} + + {/if} diff --git a/packages/builder/src/components/backend/DataTable/buttons/ExistingRelationshipButton.svelte b/packages/builder/src/components/backend/DataTable/buttons/ExistingRelationshipButton.svelte new file mode 100644 index 000000000..4a7abf487 --- /dev/null +++ b/packages/builder/src/components/backend/DataTable/buttons/ExistingRelationshipButton.svelte @@ -0,0 +1,54 @@ + + +{#if table.sourceId} +
+ + Define existing relationship + +
+ + + +{/if} diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte b/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte similarity index 92% rename from packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte rename to packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte index 583ca5e88..81032da71 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/CreateEditRelationship.svelte +++ b/packages/builder/src/components/backend/Datasources/CreateEditRelationship.svelte @@ -18,10 +18,19 @@ export let fromRelationship = {} export let toRelationship = {} export let close + export let selectedFromTable let originalFromName = fromRelationship.name, originalToName = toRelationship.name + if (fromRelationship && !fromRelationship.relationshipType) { + fromRelationship.relationshipType = RelationshipTypes.MANY_TO_ONE + } + + if (toRelationship && selectedFromTable) { + toRelationship.tableId = selectedFromTable._id + } + function inSchema(table, prop, ogName) { if (!table || !prop || prop === ogName) { return false @@ -114,6 +123,7 @@ }, ] $: updateRelationshipType(fromRelationship?.relationshipType) + $: tableChanged(fromTable, toTable) function updateRelationshipType(fromType) { if (fromType === RelationshipTypes.MANY_TO_MANY) { @@ -205,7 +215,6 @@ originalToName = toRelationship.name originalFromName = fromRelationship.name await save() - await tables.fetch() } async function deleteRelationship() { @@ -215,10 +224,26 @@ await tables.fetch() close() } + + function tableChanged(fromTbl, toTbl) { + fromRelationship.name = toTbl?.name || "" + errors.fromCol = "" + toRelationship.name = fromTbl?.name || "" + errors.toCol = "" + if (toTbl || fromTbl) { + checkForErrors( + fromTable, + toTable, + through, + fromRelationship, + toRelationship + ) + } + } ($touched.from = true)} bind:error={errors.from} bind:value={toRelationship.tableId} diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/TableSelect.svelte b/packages/builder/src/components/backend/Datasources/TableSelect.svelte similarity index 100% rename from packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/CreateEditRelationship/TableSelect.svelte rename to packages/builder/src/components/backend/Datasources/TableSelect.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte index 7c56d502e..9bd2e10a0 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte @@ -8,11 +8,12 @@ Layout, Modal, InlineAlert, + ActionButton, } from "@budibase/bbui" import { datasources, integrations, queries, tables } from "stores/backend" import { notifications } from "@budibase/bbui" import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" - import CreateEditRelationship from "./CreateEditRelationship/CreateEditRelationship.svelte" + import CreateEditRelationship from "components/backend/Datasources/CreateEditRelationship.svelte" import CreateExternalTableModal from "./modals/CreateExternalTableModal.svelte" import DisplayColumnModal from "./modals/EditDisplayColumnsModal.svelte" import ICONS from "components/backend/DatasourceNavigator/icons" @@ -174,14 +175,24 @@ Tables
{#if plusTables && plusTables.length !== 0} - + {/if}
- +
@@ -214,9 +225,15 @@
Relationships - + Define existing relationship +
Tell budibase how your tables are related to get even more smart @@ -331,7 +348,6 @@ .table-buttons { display: grid; - grid-gap: var(--spacing-l); grid-template-columns: 1fr 1fr; } diff --git a/packages/builder/src/stores/backend/tables.js b/packages/builder/src/stores/backend/tables.js index 7f90a04a0..baa9e38ab 100644 --- a/packages/builder/src/stores/backend/tables.js +++ b/packages/builder/src/stores/backend/tables.js @@ -11,6 +11,7 @@ export function createTablesStore() { const tablesResponse = await api.get(`/api/tables`) const tables = await tablesResponse.json() update(state => ({ ...state, list: tables })) + return tables } async function select(table) { From 5d40882c665af02494fdf8224f29411811a377cc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Mon, 1 Nov 2021 21:17:51 +0000 Subject: [PATCH 017/148] Removing the edit display columns modal as it was very specific and a little confusing, these are defaulted now anyway like internal tables. --- .../[selectedDatasource]/index.svelte | 20 --------- .../modals/EditDisplayColumnsModal.svelte | 43 ------------------- 2 files changed, 63 deletions(-) delete mode 100644 packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/modals/EditDisplayColumnsModal.svelte diff --git a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte index 9bd2e10a0..b1867db24 100644 --- a/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte +++ b/packages/builder/src/pages/builder/app/[application]/data/datasource/[selectedDatasource]/index.svelte @@ -15,12 +15,10 @@ import IntegrationConfigForm from "components/backend/DatasourceNavigator/TableIntegrationMenu/IntegrationConfigForm.svelte" import CreateEditRelationship from "components/backend/Datasources/CreateEditRelationship.svelte" import CreateExternalTableModal from "./modals/CreateExternalTableModal.svelte" - import DisplayColumnModal from "./modals/EditDisplayColumnsModal.svelte" import ICONS from "components/backend/DatasourceNavigator/icons" import { capitalise } from "helpers" let relationshipModal - let displayColumnModal let createExternalTableModal let selectedFromRelationship, selectedToRelationship @@ -113,10 +111,6 @@ relationshipModal.show() } - function openDisplayColumnModal() { - displayColumnModal.show() - } - function createNewTable() { createExternalTableModal.show() } @@ -133,10 +127,6 @@ /> - - - - @@ -174,16 +164,6 @@
Tables
- {#if plusTables && plusTables.length !== 0} - - Update display columns - - {/if}
- import { ModalContent, Select, Body } from "@budibase/bbui" - import { tables } from "stores/backend" - - export let datasource - export let plusTables - export let save - - async function saveDisplayColumns() { - // be explicit about copying over - for (let table of plusTables) { - datasource.entities[table.name].primaryDisplay = table.primaryDisplay - } - save() - await tables.fetch() - } - - function getColumnOptions(table) { - if (!table || !table.schema) { - return [] - } - return Object.entries(table.schema) - .filter(field => field[1].type !== "link") - .map(([fieldName]) => fieldName) - } - - - - Select the columns that will be shown when displaying relationships. - {#each plusTables as table} - From f8b2429bd0179dd47162a25f95c44a92e70dd77e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 3 Nov 2021 13:12:20 +0000 Subject: [PATCH 035/148] Fixing REST PUT using POST as per #3227. --- packages/server/src/api/controllers/query.js | 3 --- packages/server/src/integrations/rest.ts | 14 ++++++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/server/src/api/controllers/query.js b/packages/server/src/api/controllers/query.js index 89bf1a8ab..a22cda4eb 100644 --- a/packages/server/src/api/controllers/query.js +++ b/packages/server/src/api/controllers/query.js @@ -23,9 +23,6 @@ function formatResponse(resp) { try { resp = JSON.parse(resp) } catch (err) { - console.error( - "Error parsing JSON response. Returning string in array instead." - ) resp = { response: resp } } } diff --git a/packages/server/src/integrations/rest.ts b/packages/server/src/integrations/rest.ts index 9c6ece52d..cf234518d 100644 --- a/packages/server/src/integrations/rest.ts +++ b/packages/server/src/integrations/rest.ts @@ -142,13 +142,11 @@ module RestModule { } async parseResponse(response: any) { - switch (this.headers.Accept) { - case "application/json": - return await response.json() - case "text/html": - return await response.text() - default: - return await response.json() + const contentType = response.headers.get("content-type") + if (contentType && contentType.indexOf("application/json") !== -1) { + return await response.json() + } else { + return await response.text() } } @@ -191,7 +189,7 @@ module RestModule { } const response = await fetch(this.getUrl(path, queryString), { - method: "POST", + method: "PUT", headers: this.headers, body: JSON.stringify(json), }) From ea6646f055cb9f2a9c3c6ea0750cf96c6a9df52d Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 3 Nov 2021 13:13:22 +0000 Subject: [PATCH 036/148] Fixing #3237 and #3235 - always apply headers on out going webhooks if they are specified and handle a range of response codes. --- .../src/automations/steps/outgoingWebhook.js | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/server/src/automations/steps/outgoingWebhook.js b/packages/server/src/automations/steps/outgoingWebhook.js index 34299d23b..f0637c335 100644 --- a/packages/server/src/automations/steps/outgoingWebhook.js +++ b/packages/server/src/automations/steps/outgoingWebhook.js @@ -85,6 +85,18 @@ exports.run = async function ({ inputs }) { const request = { method: requestMethod, } + if (headers) { + try { + const customHeaders = + typeof headers === "string" ? JSON.parse(headers) : headers + request.headers = { ...request.headers, ...customHeaders } + } catch (err) { + return { + success: false, + response: "Unable to process headers, must be a JSON object.", + } + } + } if ( requestBody && requestBody.length !== 0 && @@ -95,21 +107,9 @@ exports.run = async function ({ inputs }) { ? requestBody : JSON.stringify(requestBody) request.headers = { + ...request.headers, "Content-Type": "application/json", } - - if (headers) { - try { - const customHeaders = - typeof headers === "string" ? JSON.parse(headers) : headers - request.headers = { ...request.headers, ...customHeaders } - } catch (err) { - return { - success: false, - response: "Unable to process headers, must be a JSON object.", - } - } - } } try { @@ -122,7 +122,7 @@ exports.run = async function ({ inputs }) { return { httpStatus: status, response: message, - success: status === 200, + success: status >= 200 && status <= 206, } } catch (err) { /* istanbul ignore next */ From 88a729913cacdf91acdda3d22a8c5b763c5c2841 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 3 Nov 2021 14:08:47 +0000 Subject: [PATCH 037/148] Fixing an issue with webhooks, couldn't use them in development (like getting schema) and making sure trigger will always use production app #3143. --- .../server/src/api/controllers/webhook.js | 49 ++++++++++++------- packages/server/src/automations/utils.js | 7 ++- packages/server/src/middleware/authorized.js | 7 +-- packages/server/src/middleware/currentapp.js | 2 + packages/server/src/middleware/utils.js | 7 +++ 5 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 packages/server/src/middleware/utils.js diff --git a/packages/server/src/api/controllers/webhook.js b/packages/server/src/api/controllers/webhook.js index c810f8500..15ee748d8 100644 --- a/packages/server/src/api/controllers/webhook.js +++ b/packages/server/src/api/controllers/webhook.js @@ -3,6 +3,7 @@ const { generateWebhookID, getWebhookParams } = require("../../db/utils") const toJsonSchema = require("to-json-schema") const validate = require("jsonschema").validate const triggers = require("../../automations/triggers") +const { getDeployedAppID } = require("@budibase/auth/db") const AUTOMATION_DESCRIPTION = "Generated from Webhook Schema" @@ -76,24 +77,34 @@ exports.buildSchema = async ctx => { } exports.trigger = async ctx => { - const db = new CouchDB(ctx.params.instance) - const webhook = await db.get(ctx.params.id) - // validate against the schema - if (webhook.bodySchema) { - validate(ctx.request.body, webhook.bodySchema) - } - const target = await db.get(webhook.action.target) - if (webhook.action.type === exports.WebhookType.AUTOMATION) { - // trigger with both the pure request and then expand it - // incase the user has produced a schema to bind to - await triggers.externalTrigger(target, { - body: ctx.request.body, - ...ctx.request.body, - appId: ctx.params.instance, - }) - } - ctx.status = 200 - ctx.body = { - message: "Webhook trigger fired successfully", + const prodAppId = getDeployedAppID(ctx.params.instance) + try { + const db = new CouchDB(prodAppId) + const webhook = await db.get(ctx.params.id) + // validate against the schema + if (webhook.bodySchema) { + validate(ctx.request.body, webhook.bodySchema) + } + const target = await db.get(webhook.action.target) + if (webhook.action.type === exports.WebhookType.AUTOMATION) { + // trigger with both the pure request and then expand it + // incase the user has produced a schema to bind to + await triggers.externalTrigger(target, { + body: ctx.request.body, + ...ctx.request.body, + appId: prodAppId, + }) + } + ctx.status = 200 + ctx.body = { + message: "Webhook trigger fired successfully", + } + } catch (err) { + if (err.status === 404) { + ctx.status = 200 + ctx.body = { + message: "Application not deployed yet.", + } + } } } diff --git a/packages/server/src/automations/utils.js b/packages/server/src/automations/utils.js index 4bef91a15..f2d1bf569 100644 --- a/packages/server/src/automations/utils.js +++ b/packages/server/src/automations/utils.js @@ -6,6 +6,7 @@ const { queue } = require("./bullboard") const newid = require("../db/newid") const { updateEntityMetadata } = require("../utilities") const { MetadataTypes } = require("../constants") +const { getDeployedAppID } = require("@budibase/auth/db") const WH_STEP_ID = definitions.WEBHOOK.stepId const CRON_STEP_ID = definitions.CRON.stepId @@ -150,9 +151,13 @@ exports.checkForWebhooks = async ({ appId, oldAuto, newAuto }) => { await webhooks.save(ctx) const id = ctx.body.webhook._id newTrigger.webhookId = id + // the app ID has to be development for this endpoint + // it can only be used when building the app + // but the trigger endpoint will always be used in production + const prodAppId = getDeployedAppID(appId) newTrigger.inputs = { schemaUrl: `api/webhooks/schema/${appId}/${id}`, - triggerUrl: `api/webhooks/trigger/${appId}/${id}`, + triggerUrl: `api/webhooks/trigger/${prodAppId}/${id}`, } } return newAuto diff --git a/packages/server/src/middleware/authorized.js b/packages/server/src/middleware/authorized.js index bd064f7e6..d91311e16 100644 --- a/packages/server/src/middleware/authorized.js +++ b/packages/server/src/middleware/authorized.js @@ -5,20 +5,17 @@ const { doesHaveBasePermission, } = require("@budibase/auth/permissions") const builderMiddleware = require("./builder") +const { isWebhookEndpoint } = require("./utils") function hasResource(ctx) { return ctx.resourceId != null } -const WEBHOOK_ENDPOINTS = new RegExp( - ["webhooks/trigger", "webhooks/schema"].join("|") -) - module.exports = (permType, permLevel = null) => async (ctx, next) => { // webhooks don't need authentication, each webhook unique - if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) { + if (isWebhookEndpoint(ctx)) { return next() } diff --git a/packages/server/src/middleware/currentapp.js b/packages/server/src/middleware/currentapp.js index 01b9dcc24..5682a860b 100644 --- a/packages/server/src/middleware/currentapp.js +++ b/packages/server/src/middleware/currentapp.js @@ -9,6 +9,7 @@ const { isUserInAppTenant } = require("@budibase/auth/tenancy") const { getCachedSelf } = require("../utilities/global") const CouchDB = require("../db") const env = require("../environment") +const { isWebhookEndpoint } = require("./utils") module.exports = async (ctx, next) => { // try to get the appID from the request @@ -38,6 +39,7 @@ module.exports = async (ctx, next) => { // deny access to application preview if ( isDevAppID(requestAppId) && + !isWebhookEndpoint(ctx) && (!ctx.user || !ctx.user.builder || !ctx.user.builder.global) ) { clearCookie(ctx, Cookies.CurrentApp) diff --git a/packages/server/src/middleware/utils.js b/packages/server/src/middleware/utils.js new file mode 100644 index 000000000..b1eea8cd6 --- /dev/null +++ b/packages/server/src/middleware/utils.js @@ -0,0 +1,7 @@ +const WEBHOOK_ENDPOINTS = new RegExp( + ["webhooks/trigger", "webhooks/schema"].join("|") +) + +exports.isWebhookEndpoint = ctx => { + return WEBHOOK_ENDPOINTS.test(ctx.request.url) +} From fbaedd6a3472ab0396620ebdd5d0d0bfec344d3f Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 3 Nov 2021 15:04:05 +0000 Subject: [PATCH 038/148] Fix: Prevent user updates in multi tenant mode from deleting user password. Also forward the authentication error from the backend to the login page to warn when an sso user is trying to log in with a password when one is not present --- packages/auth/src/middleware/passport/local.js | 14 ++++++++++++++ packages/auth/src/utils.js | 4 ++-- .../builder/src/pages/builder/auth/login.svelte | 2 +- packages/builder/src/stores/portal/auth.js | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/packages/auth/src/middleware/passport/local.js b/packages/auth/src/middleware/passport/local.js index 0db40d64e..50c2b18d8 100644 --- a/packages/auth/src/middleware/passport/local.js +++ b/packages/auth/src/middleware/passport/local.js @@ -9,6 +9,7 @@ const { createASession } = require("../../security/sessions") const { getTenantId } = require("../../tenancy") const INVALID_ERR = "Invalid Credentials" +const SSO_NO_PASSWORD = "SSO user does not have a password set" exports.options = { passReqToCallback: true, @@ -36,6 +37,19 @@ exports.authenticate = async function (ctx, email, password, done) { return authError(done, INVALID_ERR) } + // check that the user has a stored password before proceeding + if (!dbUser.password) { + if ( + (dbUser.account && dbUser.account.authType === "sso") || // root account sso + dbUser.thirdPartyProfile // internal sso + ) { + return authError(done, SSO_NO_PASSWORD) + } + + console.error("User has no password", dbUser) + return authError(done, INVALID_ERR) + } + // authenticate if (await compare(password, dbUser.password)) { const sessionId = newid() diff --git a/packages/auth/src/utils.js b/packages/auth/src/utils.js index e1df289d6..f7ab5d699 100644 --- a/packages/auth/src/utils.js +++ b/packages/auth/src/utils.js @@ -181,8 +181,8 @@ exports.saveUser = async ( // check budibase users in other tenants if (env.MULTI_TENANCY) { - dbUser = await getTenantUser(email) - if (dbUser != null && dbUser.tenantId !== tenantId) { + const tenantUser = await getTenantUser(email) + if (tenantUser != null && tenantUser.tenantId !== tenantId) { throw `Email address ${email} already in use.` } } diff --git a/packages/builder/src/pages/builder/auth/login.svelte b/packages/builder/src/pages/builder/auth/login.svelte index 737467823..5a5a27eb6 100644 --- a/packages/builder/src/pages/builder/auth/login.svelte +++ b/packages/builder/src/pages/builder/auth/login.svelte @@ -44,7 +44,7 @@ } } catch (err) { console.error(err) - notifications.error("Invalid credentials") + notifications.error(err.message ? err.message : "Invalid Credentials") } } diff --git a/packages/builder/src/stores/portal/auth.js b/packages/builder/src/stores/portal/auth.js index 333226e3b..134232dd7 100644 --- a/packages/builder/src/stores/portal/auth.js +++ b/packages/builder/src/stores/portal/auth.js @@ -112,7 +112,7 @@ export function createAuthStore() { if (response.status === 200) { setUser(json.user) } else { - throw "Invalid credentials" + throw new Error(json.message ? json.message : "Invalid credentials") } return json }, From 58d7b13e9e7d8fb8d60fc4aeef348fd94e88bcea Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Wed, 3 Nov 2021 15:10:20 +0000 Subject: [PATCH 039/148] v0.9.174 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index d879d3c65..084882930 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.173", + "version": "0.9.174", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index cecb16d00..8d6ff8c6a 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.173", + "version": "0.9.174", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 8cd9b1452..78edb8122 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.173", + "version": "0.9.174", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 1b337e2ba..79b4f3b6d 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.173", + "version": "0.9.174", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.173", - "@budibase/client": "^0.9.173", + "@budibase/bbui": "^0.9.174", + "@budibase/client": "^0.9.174", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.173", + "@budibase/string-templates": "^0.9.174", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 0ed0c9826..1dac63f12 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.173", + "version": "0.9.174", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 9edca0f2a..b8cc017d6 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.173", + "version": "0.9.174", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.173", + "@budibase/bbui": "^0.9.174", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.173", + "@budibase/string-templates": "^0.9.174", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index a1271be56..c96e8e5ed 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.173", + "version": "0.9.174", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.173", - "@budibase/client": "^0.9.173", - "@budibase/string-templates": "^0.9.173", + "@budibase/auth": "^0.9.174", + "@budibase/client": "^0.9.174", + "@budibase/string-templates": "^0.9.174", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 1906bfde0..0b29019c4 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.173", + "version": "0.9.174", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 05a322c82..ba75b2e7d 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.173", + "version": "0.9.174", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.173", - "@budibase/string-templates": "^0.9.173", + "@budibase/auth": "^0.9.174", + "@budibase/string-templates": "^0.9.174", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 512ed5aa2a1357655b7fc6281a390a9682b7d518 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 3 Nov 2021 15:26:15 +0000 Subject: [PATCH 040/148] Add support for tables updating server-side sorting --- .../src/components/app/DataProvider.svelte | 68 +++++++++++++++---- .../src/components/app/table/Table.svelte | 15 +++- packages/client/src/constants.js | 1 + 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/client/src/components/app/DataProvider.svelte b/packages/client/src/components/app/DataProvider.svelte index 54e758ad3..a8e53f490 100644 --- a/packages/client/src/components/app/DataProvider.svelte +++ b/packages/client/src/components/app/DataProvider.svelte @@ -35,28 +35,36 @@ let pageNumber = 0 let query = null + // Sorting can be overridden at run time, so we can't use the prop directly + let currentSortColumn = sortColumn + let currentSortOrder = sortOrder + $: query = buildLuceneQuery(filter) $: internalTable = dataSource?.type === "table" $: nestedProvider = dataSource?.type === "provider" $: hasNextPage = bookmarks[pageNumber + 1] != null $: hasPrevPage = pageNumber > 0 $: getSchema(dataSource) - $: sortType = getSortType(schema, sortColumn) + $: sortType = getSortType(schema, currentSortColumn) + + // Wait until schema loads before loading data, so that we can determine + // the correct sort type first time $: { - // Wait until schema loads before loading data, so that we can determine - // the correct sort type first time if (schemaLoaded) { fetchData( dataSource, + schema, query, limit, - sortColumn, - sortOrder, + currentSortColumn, + currentSortOrder, sortType, paginate ) } } + + // Reactively filter and sort rows if required $: { if (internalTable) { // Internal tables are already processed server-side @@ -65,10 +73,17 @@ // For anything else we use client-side implementations to filter, sort // and limit const filtered = luceneQuery(allRows, query) - const sorted = luceneSort(filtered, sortColumn, sortOrder, sortType) + const sorted = luceneSort( + filtered, + currentSortColumn, + currentSortOrder, + sortType + ) rows = luceneLimit(sorted, limit) } } + + // Build our action context $: actions = [ { type: ActionTypes.RefreshDatasource, @@ -79,7 +94,20 @@ type: ActionTypes.SetDataProviderQuery, callback: newQuery => (query = newQuery), }, + { + type: ActionTypes.SetDataProviderSorting, + callback: ({ column, order }) => { + if (column) { + currentSortColumn = column + } + if (order) { + currentSortOrder = order + } + }, + }, ] + + // Build our data context $: dataContext = { rows, schema, @@ -88,7 +116,11 @@ // Undocumented properties. These aren't supposed to be used in builder // bindings, but are used internally by other components id: $component?.id, - state: { query }, + state: { + query, + sortColumn: currentSortColumn, + sortOrder: currentSortOrder, + }, loaded, } @@ -104,10 +136,11 @@ if (schemaLoaded && !nestedProvider) { fetchData( dataSource, + schema, query, limit, - sortColumn, - sortOrder, + currentSortColumn, + currentSortOrder, sortType, paginate ) @@ -116,6 +149,7 @@ const fetchData = async ( dataSource, + schema, query, limit, sortColumn, @@ -125,12 +159,16 @@ ) => { loading = true if (dataSource?.type === "table") { + // Sanity check sort column, as using a non-existant column will prevent + // results coming back at all + const sort = schema?.[sortColumn] ? sortColumn : undefined + // For internal tables we use server-side processing const res = await API.searchTable({ tableId: dataSource.tableId, query, limit, - sort: sortColumn, + sort, sortOrder: sortOrder?.toLowerCase() ?? "ascending", sortType, paginate, @@ -181,13 +219,14 @@ if (!hasNextPage || !internalTable) { return } + const sort = schema?.[currentSortColumn] ? currentSortColumn : undefined const res = await API.searchTable({ tableId: dataSource?.tableId, query, bookmark: bookmarks[pageNumber + 1], limit, - sort: sortColumn, - sortOrder: sortOrder?.toLowerCase() ?? "ascending", + sort, + sortOrder: currentSortOrder?.toLowerCase() ?? "ascending", sortType, paginate: true, }) @@ -202,13 +241,14 @@ if (!hasPrevPage || !internalTable) { return } + const sort = schema?.[currentSortColumn] ? currentSortColumn : undefined const res = await API.searchTable({ tableId: dataSource?.tableId, query, bookmark: bookmarks[pageNumber - 1], limit, - sort: sortColumn, - sortOrder: sortOrder?.toLowerCase() ?? "ascending", + sort, + sortOrder: currentSortOrder?.toLowerCase() ?? "ascending", sortType, paginate: true, }) diff --git a/packages/client/src/components/app/table/Table.svelte b/packages/client/src/components/app/table/Table.svelte index ba9f3aae9..a6508c576 100644 --- a/packages/client/src/components/app/table/Table.svelte +++ b/packages/client/src/components/app/table/Table.svelte @@ -11,7 +11,11 @@ export let size const component = getContext("component") - const { styleable } = getContext("sdk") + const { styleable, getAction, ActionTypes } = getContext("sdk") + const setSorting = getAction( + dataProvider?.id, + ActionTypes.SetDataProviderSorting + ) const customColumnKey = `custom-${Math.random()}` const customRenderers = [ { @@ -70,6 +74,13 @@ }) return newSchema } + + const onSort = e => { + setSorting({ + column: e.detail.column, + order: e.detail.order, + }) + }
@@ -84,6 +95,8 @@ allowEditRows={false} allowEditColumns={false} showAutoColumns={true} + disableSorting + on:sort={onSort} > diff --git a/packages/client/src/constants.js b/packages/client/src/constants.js index d2237ba3b..c660d8d86 100644 --- a/packages/client/src/constants.js +++ b/packages/client/src/constants.js @@ -6,6 +6,7 @@ export const ActionTypes = { ValidateForm: "ValidateForm", RefreshDatasource: "RefreshDatasource", SetDataProviderQuery: "SetDataProviderQuery", + SetDataProviderSorting: "SetDataProviderSorting", ClearForm: "ClearForm", ChangeFormStep: "ChangeFormStep", } From b2bf5056b54f6213ca2ac2dbe13bc7e840d4d1b1 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 3 Nov 2021 15:45:19 +0000 Subject: [PATCH 041/148] Fixing rest test mocking. --- packages/server/src/integrations/tests/rest.spec.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/server/src/integrations/tests/rest.spec.js b/packages/server/src/integrations/tests/rest.spec.js index cb69d3c38..7b128a6d1 100644 --- a/packages/server/src/integrations/tests/rest.spec.js +++ b/packages/server/src/integrations/tests/rest.spec.js @@ -1,5 +1,11 @@ jest.mock("node-fetch", () => - jest.fn(() => ({ json: jest.fn(), text: jest.fn() })) + jest.fn(() => ({ + headers: { + get: () => ["application/json"] + }, + json: jest.fn(), + text: jest.fn() + })) ) const fetch = require("node-fetch") const RestIntegration = require("../rest") From 044579b829d2f5ad2cfbe59abc18c0663da91965 Mon Sep 17 00:00:00 2001 From: Rory Powell Date: Wed, 3 Nov 2021 15:46:45 +0000 Subject: [PATCH 042/148] Add expired user notification --- packages/auth/src/middleware/passport/local.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/auth/src/middleware/passport/local.js b/packages/auth/src/middleware/passport/local.js index 50c2b18d8..f95c3a173 100644 --- a/packages/auth/src/middleware/passport/local.js +++ b/packages/auth/src/middleware/passport/local.js @@ -10,6 +10,7 @@ const { getTenantId } = require("../../tenancy") const INVALID_ERR = "Invalid Credentials" const SSO_NO_PASSWORD = "SSO user does not have a password set" +const EXPIRED = "This account has expired. Please reset your password" exports.options = { passReqToCallback: true, @@ -46,8 +47,8 @@ exports.authenticate = async function (ctx, email, password, done) { return authError(done, SSO_NO_PASSWORD) } - console.error("User has no password", dbUser) - return authError(done, INVALID_ERR) + console.error("Non SSO usser has no password set", dbUser) + return authError(done, EXPIRED) } // authenticate From 4019eeaa26e848a5c4b498c025680977fbfe8b93 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 3 Nov 2021 15:53:45 +0000 Subject: [PATCH 043/148] Fix picker width in table with search block and enable autosizing of other search components --- .../client/src/components/app/blocks/TableWithSearch.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/app/blocks/TableWithSearch.svelte b/packages/client/src/components/app/blocks/TableWithSearch.svelte index b3b6598ce..09fa43934 100644 --- a/packages/client/src/components/app/blocks/TableWithSearch.svelte +++ b/packages/client/src/components/app/blocks/TableWithSearch.svelte @@ -150,7 +150,7 @@ max-width: 100%; flex-wrap: wrap; } - .search :global(.component > *) { + .search:not(.mobile) :global(.spectrum-Form-itemField > .spectrum-Picker) { width: 200px; } .search :global(.spectrum-InputGroup .spectrum-InputGroup-input) { From 294dd232bc71276083714e333a96eef3cdf4eb8e Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 3 Nov 2021 16:17:45 +0000 Subject: [PATCH 044/148] Revert changes to medium sized checkbox --- packages/bbui/src/Form/Core/Checkbox.svelte | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/bbui/src/Form/Core/Checkbox.svelte b/packages/bbui/src/Form/Core/Checkbox.svelte index 429098433..a5b366c26 100644 --- a/packages/bbui/src/Form/Core/Checkbox.svelte +++ b/packages/bbui/src/Form/Core/Checkbox.svelte @@ -51,11 +51,6 @@ diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 11aa033c1..655f2f32e 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -161,9 +161,15 @@ const confirmTextMap = { */ export const enrichButtonActions = (actions, context) => { // Prevent button actions in the builder preview - if (get(builderStore).inBuilder) { + if (!actions || get(builderStore).inBuilder) { return () => {} } + + // If this is a function then it has already been enriched + if (typeof actions === "function") { + return actions + } + const handlers = actions.map(def => handlerMap[def["##eventHandlerType"]]) return async () => { for (let i = 0; i < handlers.length; i++) { diff --git a/packages/client/src/utils/componentProps.js b/packages/client/src/utils/componentProps.js index a181d1ea4..d600fdef0 100644 --- a/packages/client/src/utils/componentProps.js +++ b/packages/client/src/utils/componentProps.js @@ -36,17 +36,19 @@ export const enrichProps = (props, context) => { let enrichedProps = enrichDataBindings(props, totalContext) // Enrich click actions if they exist - if (enrichedProps.onClick) { - enrichedProps.onClick = enrichButtonActions( - enrichedProps.onClick, - totalContext - ) - } + Object.keys(enrichedProps).forEach(prop => { + if (prop?.toLowerCase().includes("onclick")) { + enrichedProps[prop] = enrichButtonActions( + enrichedProps[prop], + totalContext + ) + } + }) // Enrich any click actions in conditions if (enrichedProps._conditions) { enrichedProps._conditions.forEach(condition => { - if (condition.setting === "onClick") { + if (condition.setting?.toLowerCase().includes("onclick")) { condition.settingValue = enrichButtonActions( condition.settingValue, totalContext From d5983d56039686d478328e2b6f5b72baf0e5d334 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Thu, 4 Nov 2021 11:31:43 +0000 Subject: [PATCH 055/148] Lint --- packages/client/src/utils/styleable.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/src/utils/styleable.js b/packages/client/src/utils/styleable.js index f35e45d3f..c93742d56 100644 --- a/packages/client/src/utils/styleable.js +++ b/packages/client/src/utils/styleable.js @@ -1,4 +1,3 @@ -import { get } from "svelte/store" import { builderStore } from "stores" /** From b80a93d6d5eda97cc8ed38296b9e93a7da005db7 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 4 Nov 2021 14:03:18 +0100 Subject: [PATCH 056/148] cookie based approach --- packages/auth/src/constants.js | 1 + .../components/start/CreateAppModal.svelte | 2 +- .../builder/src/pages/builder/_layout.svelte | 7 ++++++- .../src/pages/builder/auth/_layout.svelte | 6 +----- .../pages/builder/portal/apps/index.svelte | 7 ++++--- packages/builder/src/stores/portal/auth.js | 21 +++++++------------ .../worker/src/api/controllers/global/auth.js | 11 ++++++++++ packages/worker/src/api/routes/global/auth.js | 2 ++ 8 files changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/auth/src/constants.js b/packages/auth/src/constants.js index 4b4aef5a4..9892275be 100644 --- a/packages/auth/src/constants.js +++ b/packages/auth/src/constants.js @@ -6,6 +6,7 @@ exports.UserStatus = { exports.Cookies = { CurrentApp: "budibase:currentapp", Auth: "budibase:auth", + Init: "budibase:init", OIDC_CONFIG: "budibase:oidc:config", } diff --git a/packages/builder/src/components/start/CreateAppModal.svelte b/packages/builder/src/components/start/CreateAppModal.svelte index d25acf249..1db5e4626 100644 --- a/packages/builder/src/components/start/CreateAppModal.svelte +++ b/packages/builder/src/components/start/CreateAppModal.svelte @@ -139,7 +139,7 @@ } const userResp = await api.post(`/api/users/metadata/self`, user) await userResp.json() - auth.resetInitTemplate() + await auth.setInitInfo({}) $goto(`/builder/app/${appJson.instance._id}`) } catch (error) { console.error(error) diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 39c93f0fb..9ef171d7c 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -1,5 +1,5 @@ diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index 94198caea..f9aac6e0c 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -201,9 +201,10 @@ await apps.load() loaded = true // if the portal is loaded from an external URL with a template param - const templateKey = $auth.initTemplate - if (templateKey) { - createAppFromTemplateUrl(templateKey) + const initInfo = await auth.getInitInfo() + console.log(initInfo) + if (initInfo.init_template) { + createAppFromTemplateUrl(initInfo.init_template) } }) diff --git a/packages/builder/src/stores/portal/auth.js b/packages/builder/src/stores/portal/auth.js index 9723b64ff..47ebbfe7e 100644 --- a/packages/builder/src/stores/portal/auth.js +++ b/packages/builder/src/stores/portal/auth.js @@ -33,7 +33,6 @@ export function createAuthStore() { user: $store.user, tenantId: $store.tenantId, tenantSet: $store.tenantSet, - initTemplate: $store.initTemplate, loaded: $store.loaded, initials, isAdmin, @@ -81,28 +80,22 @@ export function createAuthStore() { } } - function updateInitTemplate(template) { - auth.update(store => { - store.initTemplate = template - return store - }) - } - return { subscribe: store.subscribe, - resetInitTemplate: () => updateInitTemplate(null), setOrganisation: setOrganisation, + getInitInfo: async () => { + const response = await api.get(`/api/global/auth/init`) + return await response.json() + }, + setInitInfo: async info => { + await api.post(`/api/global/auth/init`, info) + }, checkQueryString: async () => { const urlParams = new URLSearchParams(window.location.search) if (urlParams.has("tenantId")) { const tenantId = urlParams.get("tenantId") await setOrganisation(tenantId) } - - // set the template to create an app from - if (urlParams.has("template")) { - updateInitTemplate(urlParams.get("template")) - } }, setOrg: async tenantId => { await setOrganisation(tenantId) diff --git a/packages/worker/src/api/controllers/global/auth.js b/packages/worker/src/api/controllers/global/auth.js index 50b4ec969..e11161904 100644 --- a/packages/worker/src/api/controllers/global/auth.js +++ b/packages/worker/src/api/controllers/global/auth.js @@ -77,6 +77,17 @@ exports.authenticate = async (ctx, next) => { })(ctx, next) } +exports.setInitInfo = ctx => { + const initInfo = ctx.request.body + setCookie(ctx, initInfo, Cookies.Init) + ctx.status = 200 +} + +exports.getInitInfo = ctx => { + const initInfo = getCookie(ctx, Cookies.Init) + ctx.body = initInfo +} + /** * Reset the user password, used as part of a forgotten password flow. */ diff --git a/packages/worker/src/api/routes/global/auth.js b/packages/worker/src/api/routes/global/auth.js index 9cd77ce15..7baad60ec 100644 --- a/packages/worker/src/api/routes/global/auth.js +++ b/packages/worker/src/api/routes/global/auth.js @@ -56,6 +56,8 @@ router authController.resetUpdate ) .post("/api/global/auth/logout", authController.logout) + .post("/api/global/auth/init", authController.setInitInfo) + .get("/api/global/auth/init", authController.getInitInfo) .get( "/api/global/auth/:tenantId/google", updateTenant, From e8889719365c4fd588cd662b7e8ec9eb700f4c83 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 4 Nov 2021 14:04:58 +0100 Subject: [PATCH 057/148] remove logs --- packages/builder/src/pages/builder/_layout.svelte | 1 - packages/builder/src/pages/builder/portal/apps/index.svelte | 1 - 2 files changed, 2 deletions(-) diff --git a/packages/builder/src/pages/builder/_layout.svelte b/packages/builder/src/pages/builder/_layout.svelte index 9ef171d7c..179131107 100644 --- a/packages/builder/src/pages/builder/_layout.svelte +++ b/packages/builder/src/pages/builder/_layout.svelte @@ -48,7 +48,6 @@ onMount(async () => { if ($params["?template"]) { - console.log("SETTING COOKIE", $params["?template"]) await auth.setInitInfo({ init_template: $params["?template"] }) } diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index f9aac6e0c..2c8cbb109 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -202,7 +202,6 @@ loaded = true // if the portal is loaded from an external URL with a template param const initInfo = await auth.getInitInfo() - console.log(initInfo) if (initInfo.init_template) { createAppFromTemplateUrl(initInfo.init_template) } From 8c4c0ae93ebc0dfc87edf09ffe4697ff5e883a2d Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Thu, 4 Nov 2021 13:56:13 +0000 Subject: [PATCH 058/148] v0.9.177 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index ec4dd2b52..217743355 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.176", + "version": "0.9.177", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 73215d66a..5a6692c2a 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.176", + "version": "0.9.177", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index dffea62d0..e4be1ddb3 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.176", + "version": "0.9.177", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 77951831b..c86268f2b 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.176", + "version": "0.9.177", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.176", - "@budibase/client": "^0.9.176", + "@budibase/bbui": "^0.9.177", + "@budibase/client": "^0.9.177", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.176", + "@budibase/string-templates": "^0.9.177", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 3d105de85..2b87fc014 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.176", + "version": "0.9.177", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 610cd87c0..21825fb7d 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.176", + "version": "0.9.177", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.176", + "@budibase/bbui": "^0.9.177", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.176", + "@budibase/string-templates": "^0.9.177", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index c2fbd8141..08c5f7103 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.176", + "version": "0.9.177", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.176", - "@budibase/client": "^0.9.176", - "@budibase/string-templates": "^0.9.176", + "@budibase/auth": "^0.9.177", + "@budibase/client": "^0.9.177", + "@budibase/string-templates": "^0.9.177", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 156e835dc..e0b7c5558 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.176", + "version": "0.9.177", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 5827027a9..6e8b25bea 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.176", + "version": "0.9.177", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.176", - "@budibase/string-templates": "^0.9.176", + "@budibase/auth": "^0.9.177", + "@budibase/string-templates": "^0.9.177", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 94ee13ffc4da6bffb7c919f9db23d50ffecb689a Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 4 Nov 2021 14:53:03 +0000 Subject: [PATCH 059/148] Adding the sync call from the worker for creation, updating and deletion of users. Making sure that production and development apps are always up to date with user metadata. --- hosting/docker-compose.yaml | 1 + .../templates/worker-service-deployment.yaml | 2 + packages/server/src/api/controllers/user.js | 64 ++++++++++++++++--- packages/server/src/middleware/authorized.js | 3 +- packages/server/src/utilities/global.js | 1 + packages/server/src/utilities/index.js | 10 ++- packages/worker/scripts/dev/manage.js | 1 + .../src/api/controllers/global/users.js | 8 ++- packages/worker/src/environment.js | 8 +++ packages/worker/src/utilities/appService.js | 23 +++++++ 10 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 packages/worker/src/utilities/appService.js diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index 66b24f4e4..c94d1520a 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -45,6 +45,7 @@ services: MINIO_ACCESS_KEY: ${MINIO_ACCESS_KEY} MINIO_SECRET_KEY: ${MINIO_SECRET_KEY} MINIO_URL: http://minio-service:9000 + APPS_URL: http://app-service:4002 COUCH_DB_USERNAME: ${COUCH_DB_USER} COUCH_DB_PASSWORD: ${COUCH_DB_PASSWORD} COUCH_DB_URL: http://${COUCH_DB_USER}:${COUCH_DB_PASSWORD}@couchdb-service:5984 diff --git a/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml index d7d870256..6cded8545 100644 --- a/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml +++ b/hosting/kubernetes/budibase/templates/worker-service-deployment.yaml @@ -113,6 +113,8 @@ spec: value: {{ .Values.globals.smtp.port | quote }} - name: SMTP_FROM_ADDRESS value: {{ .Values.globals.smtp.from | quote }} + - name: APPS_URL + value: http://app-service:{{ .Values.services.apps.port }} image: budibase/worker imagePullPolicy: Always name: bbworker diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index 0362d1298..5faf82134 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -8,8 +8,13 @@ const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global") const { getFullUser } = require("../../utilities/users") const { isEqual } = require("lodash") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") -const { getDevelopmentAppID } = require("@budibase/auth/db") +const { + getDevelopmentAppID, + getAllApps, + isDevAppID, +} = require("@budibase/auth/db") const { doesDatabaseExist } = require("../../utilities") +const { UserStatus } = require("@budibase/auth/constants") async function rawMetadata(db) { return ( @@ -21,7 +26,7 @@ async function rawMetadata(db) { ).rows.map(row => row.doc) } -async function combineMetadataAndUser(user, metadata) { +function combineMetadataAndUser(user, metadata) { // skip users with no access if (user.roleId === BUILTIN_ROLE_IDS.PUBLIC) { return null @@ -67,22 +72,61 @@ exports.syncGlobalUsers = async appId => { } exports.syncUser = async function (ctx) { - const user = await getRawGlobalUser(ctx.params.id) + let deleting = false, + user + const userId = ctx.params.id + try { + user = await getRawGlobalUser(userId) + } catch (err) { + user = {} + deleting = true + } const roles = user.roles + // remove props which aren't useful to metadata + delete user.password + delete user.forceResetPassword delete user.roles - for (let [prodAppId, roleId] of Object.entries(roles)) { - if (roleId === BUILTIN_ROLE_IDS.PUBLIC) { - continue - } + // run through all production appIDs in the users roles + let prodAppIds + // if they are a builder then get all production app IDs + if ((user.builder && user.builder.global) || deleting) { + prodAppIds = (await getAllApps(CouchDB, { idsOnly: true })).filter( + id => !isDevAppID(id) + ) + } else { + prodAppIds = Object.entries(roles) + .filter(entry => entry[1] !== BUILTIN_ROLE_IDS.PUBLIC) + .map(([appId]) => appId) + } + for (let prodAppId of prodAppIds) { const devAppId = getDevelopmentAppID(prodAppId) for (let appId of [prodAppId, devAppId]) { if (!(await doesDatabaseExist(appId))) { continue } const db = new CouchDB(appId) - const userId = generateUserMetadataID(user._id) - const metadata = await db.get(userId) - const combined = combineMetadataAndUser(user, metadata) + const metadataId = generateUserMetadataID(userId) + let metadata + try { + metadata = await db.get(metadataId) + } catch (err) { + if (deleting) { + continue + } + metadata = { + tableId: InternalTables.USER_METADATA, + } + } + let combined + if (deleting) { + combined = { + ...metadata, + status: UserStatus.INACTIVE, + metadata: BUILTIN_ROLE_IDS.PUBLIC, + } + } else { + combined = combineMetadataAndUser(user, metadata) + } await db.put(combined) } } diff --git a/packages/server/src/middleware/authorized.js b/packages/server/src/middleware/authorized.js index bd064f7e6..a30e034be 100644 --- a/packages/server/src/middleware/authorized.js +++ b/packages/server/src/middleware/authorized.js @@ -18,7 +18,8 @@ module.exports = (permType, permLevel = null) => async (ctx, next) => { // webhooks don't need authentication, each webhook unique - if (WEBHOOK_ENDPOINTS.test(ctx.request.url)) { + // also internal requests (between services) don't need authorized + if (WEBHOOK_ENDPOINTS.test(ctx.request.url) || ctx.internal) { return next() } diff --git a/packages/server/src/utilities/global.js b/packages/server/src/utilities/global.js index eb64aa7f7..6527aa060 100644 --- a/packages/server/src/utilities/global.js +++ b/packages/server/src/utilities/global.js @@ -77,6 +77,7 @@ exports.getGlobalUsers = async (appId = null, users = null) => { .filter(user => user != null) .map(user => { delete user.password + delete user.forceResetPassword return user }) if (!appId) { diff --git a/packages/server/src/utilities/index.js b/packages/server/src/utilities/index.js index d67c8f1da..266ee09f9 100644 --- a/packages/server/src/utilities/index.js +++ b/packages/server/src/utilities/index.js @@ -136,7 +136,11 @@ exports.stringToReadStream = string => { } exports.doesDatabaseExist = async dbName => { - const db = new CouchDB(dbName, { skip_setup: true }) - const info = await db.info() - return info && !info.error + try { + const db = new CouchDB(dbName, { skip_setup: true }) + const info = await db.info() + return info && !info.error + } catch (err) { + return false + } } diff --git a/packages/worker/scripts/dev/manage.js b/packages/worker/scripts/dev/manage.js index e0b8c3586..179167883 100644 --- a/packages/worker/scripts/dev/manage.js +++ b/packages/worker/scripts/dev/manage.js @@ -25,6 +25,7 @@ async function init() { ACCOUNT_PORTAL_URL: "http://localhost:10001", ACCOUNT_PORTAL_API_KEY: "budibase", PLATFORM_URL: "http://localhost:10000", + APPS_URL: "http://localhost:4001", } let envFile = "" Object.keys(envFileJson).forEach(key => { diff --git a/packages/worker/src/api/controllers/global/users.js b/packages/worker/src/api/controllers/global/users.js index ed70d6122..42166faad 100644 --- a/packages/worker/src/api/controllers/global/users.js +++ b/packages/worker/src/api/controllers/global/users.js @@ -19,6 +19,7 @@ const { } = require("@budibase/auth/tenancy") const { removeUserFromInfoDB } = require("@budibase/auth/deprovision") const env = require("../../../environment") +const { syncUserInApps } = require("../../../utilities/appService") async function allUsers() { const db = getGlobalDB() @@ -32,7 +33,10 @@ async function allUsers() { exports.save = async ctx => { try { - ctx.body = await saveUser(ctx.request.body, getTenantId()) + const user = await saveUser(ctx.request.body, getTenantId()) + // let server know to sync user + await syncUserInApps(user._id) + ctx.body = user } catch (err) { ctx.throw(err.status || 400, err) } @@ -129,6 +133,8 @@ exports.destroy = async ctx => { await db.remove(dbUser._id, dbUser._rev) await userCache.invalidateUser(dbUser._id) await invalidateSessions(dbUser._id) + // let server know to sync user + await syncUserInApps(dbUser._id) ctx.body = { message: `User ${ctx.params.id} deleted.`, } diff --git a/packages/worker/src/environment.js b/packages/worker/src/environment.js index a1fab8411..91f06ea46 100644 --- a/packages/worker/src/environment.js +++ b/packages/worker/src/environment.js @@ -42,6 +42,7 @@ module.exports = { SMTP_FROM_ADDRESS: process.env.SMTP_FROM_ADDRESS, PLATFORM_URL: process.env.PLATFORM_URL, COOKIE_DOMAIN: process.env.COOKIE_DOMAIN, + APPS_URL: process.env.APPS_URL, _set(key, value) { process.env[key] = value module.exports[key] = value @@ -53,6 +54,13 @@ module.exports = { }, } +// if some var haven't been set, define them +if (!module.exports.APPS_URL) { + module.exports.APPS_URL = isDev() + ? "http://localhost:4001" + : "http://app-service:4002" +} + // clean up any environment variable edge cases for (let [key, value] of Object.entries(module.exports)) { // handle the edge case of "0" to disable an environment variable diff --git a/packages/worker/src/utilities/appService.js b/packages/worker/src/utilities/appService.js new file mode 100644 index 000000000..a7be05b22 --- /dev/null +++ b/packages/worker/src/utilities/appService.js @@ -0,0 +1,23 @@ +const fetch = require("node-fetch") +const { Headers } = require("@budibase/auth/constants") +const { getTenantId, isTenantIdSet } = require("@budibase/auth/tenancy") +const { checkSlashesInUrl } = require("../utilities") +const env = require("../environment") + +exports.syncUserInApps = async userId => { + const request = { headers: {} } + request.headers[Headers.API_KEY] = env.INTERNAL_API_KEY + if (isTenantIdSet()) { + request.headers[Headers.TENANT_ID] = getTenantId() + } + request.headers["Content-Type"] = "application/json" + request.body = JSON.stringify({}) + request.method = "POST" + const response = await fetch( + checkSlashesInUrl(env.APPS_URL + `/api/users/sync/${userId}`), + request + ) + if (response.status !== 200) { + throw "Unable to sync user." + } +} From 193d40bbf3f1efb941359fcee801ac94c579297d Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 28 Oct 2021 19:40:46 +0200 Subject: [PATCH 060/148] refactor switch into a key value handler object tidy up - remove logs and comments update windowed modals to use postMessage --- .../AppPreview/CurrentItemPreview.svelte | 55 +++++++++++-------- .../design/AppPreview/iframeTemplate.js | 11 ++-- .../overlay/PeekScreenDisplay.svelte | 47 +++++++++------- packages/client/src/stores/builder.js | 6 +- packages/client/src/stores/notification.js | 18 ++++-- packages/server/src/integrations/utils.ts | 5 +- 6 files changed, 84 insertions(+), 58 deletions(-) diff --git a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte index d2d67bf99..99de9f794 100644 --- a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte @@ -32,6 +32,16 @@ .component("@budibase/standard-components/screenslot") .instanceName("Content Placeholder") .json() + + // Messages that can be sent from the iframe preview to the builder + // Budibase events are and initalisation events + const MessageTypes = { + IFRAME_LOADED: "iframe-loaded", + READY: "ready", + ERROR: "error", + BUDIBASE: "type", + KEYDOWN: "keydown" + } // Construct iframe template $: template = iframeTemplate.replace( @@ -80,46 +90,44 @@ // Refresh the preview when required $: refreshContent(strippedJson) - onMount(() => { - // Initialise the app when mounted - iframe.contentWindow.addEventListener( - "ready", - () => { + function receiveMessage(message) { + const handlers = { + [MessageTypes.READY]: () => { + // Initialise the app when mounted // Display preview immediately if the intelligent loading feature // is not supported + if (!loading) return + if (!$store.clientFeatures.intelligentLoading) { loading = false } refreshContent(strippedJson) }, - { once: true } - ) - - // Catch any app errors - iframe.contentWindow.addEventListener( - "error", - event => { + [MessageTypes.ERROR]: event => { + // Catch any app errors loading = false - error = event.detail || "An unknown error occurred" + error = event.error || "An unknown error occurred" }, - { once: true } - ) + [MessageTypes.KEYDOWN]: handleKeydownEvent + } + + const messageHandler = handlers[message.data.type] || handleBudibaseEvent + messageHandler(message) + } - // Add listener for events sent by client library in preview - iframe.contentWindow.addEventListener("bb-event", handleBudibaseEvent) - iframe.contentWindow.addEventListener("keydown", handleKeydownEvent) + onMount(() => { + window.addEventListener("message", receiveMessage) }) // Remove all iframe event listeners on component destroy onDestroy(() => { if (iframe.contentWindow) { - iframe.contentWindow.removeEventListener("bb-event", handleBudibaseEvent) - iframe.contentWindow.removeEventListener("keydown", handleKeydownEvent) + window.removeEventListener("message", receiveMessage) // } }) const handleBudibaseEvent = event => { - const { type, data } = event.detail + const { type, data } = event.data if (type === "select-component" && data.id) { store.actions.components.select({ _id: data.id }) } else if (type === "update-prop") { @@ -151,13 +159,14 @@ store.actions.components.paste(destination, data.mode) } } else { - console.warning(`Client sent unknown event type: ${type}`) + console.warn(`Client sent unknown event type: ${type}`) } } const handleKeydownEvent = event => { + const { key } = event.data if ( - (event.key === "Delete" || event.key === "Backspace") && + (key === "Delete" || key === "Backspace") && selectedComponentId && ["input", "textarea"].indexOf( iframe.contentWindow.document.activeElement?.tagName.toLowerCase() diff --git a/packages/builder/src/components/design/AppPreview/iframeTemplate.js b/packages/builder/src/components/design/AppPreview/iframeTemplate.js index 58557273f..89fa63012 100644 --- a/packages/builder/src/components/design/AppPreview/iframeTemplate.js +++ b/packages/builder/src/components/design/AppPreview/iframeTemplate.js @@ -54,7 +54,7 @@ export default ` if (!parsed) { return } - + // Extract data from message const { selectedComponentId, @@ -84,17 +84,20 @@ export default ` if (window.loadBudibase) { window.loadBudibase() document.documentElement.classList.add("loaded") - window.dispatchEvent(new Event("iframe-loaded")) + window.parent.postMessage({ type: "iframe-loaded" }) } else { throw "The client library couldn't be loaded" } } catch (error) { - window.dispatchEvent(new CustomEvent("error", { detail: error })) + window.parent.postMessage({ type: "error", error }) } } window.addEventListener("message", receiveMessage) - window.dispatchEvent(new Event("ready")) + window.addEventListener("keydown", evt => { + window.parent.postMessage({ type: "keydown", key: event.key }) + }) + window.parent.postMessage({ type: "ready" }) diff --git a/packages/client/src/components/overlay/PeekScreenDisplay.svelte b/packages/client/src/components/overlay/PeekScreenDisplay.svelte index 0af1ba499..51ff4412d 100644 --- a/packages/client/src/components/overlay/PeekScreenDisplay.svelte +++ b/packages/client/src/components/overlay/PeekScreenDisplay.svelte @@ -8,6 +8,12 @@ import { Modal, ModalContent, ActionButton } from "@budibase/bbui" import { onDestroy } from "svelte" + const MessageTypes = { + NOTIFICATION: "notification", + CLOSE_SCREEN_MODAL: "close-screen-modal", + INVALIDATE_DATASOURCE: "invalidate-datasource", + } + let iframe let listenersAttached = false @@ -21,32 +27,33 @@ notificationStore.actions.send(message, type, icon) } + function receiveMessage(message) { + const handlers = { + [MessageTypes.NOTIFICATION]: () => { + proxyNotification(message.data) + }, + [MessageTypes.CLOSE_SCREEN_MODAL]: peekStore.actions.hidePeek, + [MessageTypes.INVALIDATE_DATASOURCE]: () => { + invalidateDataSource(message.data) + }, + } + + const messageHandler = handlers[message.data.type] + if (messageHandler) { + messageHandler(message) + } else { + console.warning("Unknown event type", message?.data?.type) + } + } + const attachListeners = () => { // Mirror datasource invalidation to keep the parent window up to date - iframe.contentWindow.addEventListener( - "invalidate-datasource", - invalidateDataSource - ) - // Listen for a close event to close the screen peek - iframe.contentWindow.addEventListener( - "close-screen-modal", - peekStore.actions.hidePeek - ) - // Proxy notifications back to the parent window instead of iframe - iframe.contentWindow.addEventListener("notification", proxyNotification) + window.addEventListener("message", receiveMessage) } const handleCancel = () => { peekStore.actions.hidePeek() - iframe.contentWindow.removeEventListener( - "invalidate-datasource", - invalidateDataSource - ) - iframe.contentWindow.removeEventListener( - "close-screen-modal", - peekStore.actions.hidePeek - ) - iframe.contentWindow.removeEventListener("notification", proxyNotification) + window.removeEventListener("message", receiveMessage) } const handleFullscreen = () => { diff --git a/packages/client/src/stores/builder.js b/packages/client/src/stores/builder.js index 2740a4551..baea5cb83 100644 --- a/packages/client/src/stores/builder.js +++ b/packages/client/src/stores/builder.js @@ -4,11 +4,7 @@ import { findComponentById, findComponentPathById } from "../utils/components" import { pingEndUser } from "../api" const dispatchEvent = (type, data = {}) => { - window.dispatchEvent( - new CustomEvent("bb-event", { - detail: { type, data }, - }) - ) + window.parent.postMessage({ type, data }) } const createBuilderStore = () => { diff --git a/packages/client/src/stores/notification.js b/packages/client/src/stores/notification.js index e3af9aacd..97193b209 100644 --- a/packages/client/src/stores/notification.js +++ b/packages/client/src/stores/notification.js @@ -26,11 +26,19 @@ const createNotificationStore = () => { // If peeking, pass notifications back to parent window if (get(routeStore).queryParams?.peek) { - window.dispatchEvent( - new CustomEvent("notification", { - detail: { message, type, icon }, - }) - ) + window.parent.postMessage({ + type: "notification", + detail: { + message, + type, + icon, + }, + }) + // window.dispatchEvent( + // new CustomEvent("notification", { + // detail: { message, type, icon }, + // }) + // ) return } diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index 4d139fa28..f91d25423 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -124,7 +124,10 @@ function copyExistingPropsOver( return table } -export function finaliseExternalTables(tables: { [key: string]: any }, entities: { [key: string]: any }) { +export function finaliseExternalTables( + tables: { [key: string]: any }, + entities: { [key: string]: any } +) { const finalTables: { [key: string]: any } = {} const errors: { [key: string]: string } = {} for (let [name, table] of Object.entries(tables)) { From 1219c532509cce945b48682c6be54eea021a7d7e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 4 Nov 2021 17:22:02 +0100 Subject: [PATCH 061/148] fix safari --- .../AppPreview/CurrentItemPreview.svelte | 55 +++++++++++-------- .../design/AppPreview/iframeTemplate.js | 11 ++-- .../overlay/PeekScreenDisplay.svelte | 47 +++++++++------- packages/client/src/stores/builder.js | 6 +- packages/client/src/stores/notification.js | 18 ++++-- 5 files changed, 80 insertions(+), 57 deletions(-) diff --git a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte index d2d67bf99..99de9f794 100644 --- a/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte +++ b/packages/builder/src/components/design/AppPreview/CurrentItemPreview.svelte @@ -32,6 +32,16 @@ .component("@budibase/standard-components/screenslot") .instanceName("Content Placeholder") .json() + + // Messages that can be sent from the iframe preview to the builder + // Budibase events are and initalisation events + const MessageTypes = { + IFRAME_LOADED: "iframe-loaded", + READY: "ready", + ERROR: "error", + BUDIBASE: "type", + KEYDOWN: "keydown" + } // Construct iframe template $: template = iframeTemplate.replace( @@ -80,46 +90,44 @@ // Refresh the preview when required $: refreshContent(strippedJson) - onMount(() => { - // Initialise the app when mounted - iframe.contentWindow.addEventListener( - "ready", - () => { + function receiveMessage(message) { + const handlers = { + [MessageTypes.READY]: () => { + // Initialise the app when mounted // Display preview immediately if the intelligent loading feature // is not supported + if (!loading) return + if (!$store.clientFeatures.intelligentLoading) { loading = false } refreshContent(strippedJson) }, - { once: true } - ) - - // Catch any app errors - iframe.contentWindow.addEventListener( - "error", - event => { + [MessageTypes.ERROR]: event => { + // Catch any app errors loading = false - error = event.detail || "An unknown error occurred" + error = event.error || "An unknown error occurred" }, - { once: true } - ) + [MessageTypes.KEYDOWN]: handleKeydownEvent + } + + const messageHandler = handlers[message.data.type] || handleBudibaseEvent + messageHandler(message) + } - // Add listener for events sent by client library in preview - iframe.contentWindow.addEventListener("bb-event", handleBudibaseEvent) - iframe.contentWindow.addEventListener("keydown", handleKeydownEvent) + onMount(() => { + window.addEventListener("message", receiveMessage) }) // Remove all iframe event listeners on component destroy onDestroy(() => { if (iframe.contentWindow) { - iframe.contentWindow.removeEventListener("bb-event", handleBudibaseEvent) - iframe.contentWindow.removeEventListener("keydown", handleKeydownEvent) + window.removeEventListener("message", receiveMessage) // } }) const handleBudibaseEvent = event => { - const { type, data } = event.detail + const { type, data } = event.data if (type === "select-component" && data.id) { store.actions.components.select({ _id: data.id }) } else if (type === "update-prop") { @@ -151,13 +159,14 @@ store.actions.components.paste(destination, data.mode) } } else { - console.warning(`Client sent unknown event type: ${type}`) + console.warn(`Client sent unknown event type: ${type}`) } } const handleKeydownEvent = event => { + const { key } = event.data if ( - (event.key === "Delete" || event.key === "Backspace") && + (key === "Delete" || key === "Backspace") && selectedComponentId && ["input", "textarea"].indexOf( iframe.contentWindow.document.activeElement?.tagName.toLowerCase() diff --git a/packages/builder/src/components/design/AppPreview/iframeTemplate.js b/packages/builder/src/components/design/AppPreview/iframeTemplate.js index 58557273f..89fa63012 100644 --- a/packages/builder/src/components/design/AppPreview/iframeTemplate.js +++ b/packages/builder/src/components/design/AppPreview/iframeTemplate.js @@ -54,7 +54,7 @@ export default ` if (!parsed) { return } - + // Extract data from message const { selectedComponentId, @@ -84,17 +84,20 @@ export default ` if (window.loadBudibase) { window.loadBudibase() document.documentElement.classList.add("loaded") - window.dispatchEvent(new Event("iframe-loaded")) + window.parent.postMessage({ type: "iframe-loaded" }) } else { throw "The client library couldn't be loaded" } } catch (error) { - window.dispatchEvent(new CustomEvent("error", { detail: error })) + window.parent.postMessage({ type: "error", error }) } } window.addEventListener("message", receiveMessage) - window.dispatchEvent(new Event("ready")) + window.addEventListener("keydown", evt => { + window.parent.postMessage({ type: "keydown", key: event.key }) + }) + window.parent.postMessage({ type: "ready" }) diff --git a/packages/client/src/components/overlay/PeekScreenDisplay.svelte b/packages/client/src/components/overlay/PeekScreenDisplay.svelte index 0af1ba499..51ff4412d 100644 --- a/packages/client/src/components/overlay/PeekScreenDisplay.svelte +++ b/packages/client/src/components/overlay/PeekScreenDisplay.svelte @@ -8,6 +8,12 @@ import { Modal, ModalContent, ActionButton } from "@budibase/bbui" import { onDestroy } from "svelte" + const MessageTypes = { + NOTIFICATION: "notification", + CLOSE_SCREEN_MODAL: "close-screen-modal", + INVALIDATE_DATASOURCE: "invalidate-datasource", + } + let iframe let listenersAttached = false @@ -21,32 +27,33 @@ notificationStore.actions.send(message, type, icon) } + function receiveMessage(message) { + const handlers = { + [MessageTypes.NOTIFICATION]: () => { + proxyNotification(message.data) + }, + [MessageTypes.CLOSE_SCREEN_MODAL]: peekStore.actions.hidePeek, + [MessageTypes.INVALIDATE_DATASOURCE]: () => { + invalidateDataSource(message.data) + }, + } + + const messageHandler = handlers[message.data.type] + if (messageHandler) { + messageHandler(message) + } else { + console.warning("Unknown event type", message?.data?.type) + } + } + const attachListeners = () => { // Mirror datasource invalidation to keep the parent window up to date - iframe.contentWindow.addEventListener( - "invalidate-datasource", - invalidateDataSource - ) - // Listen for a close event to close the screen peek - iframe.contentWindow.addEventListener( - "close-screen-modal", - peekStore.actions.hidePeek - ) - // Proxy notifications back to the parent window instead of iframe - iframe.contentWindow.addEventListener("notification", proxyNotification) + window.addEventListener("message", receiveMessage) } const handleCancel = () => { peekStore.actions.hidePeek() - iframe.contentWindow.removeEventListener( - "invalidate-datasource", - invalidateDataSource - ) - iframe.contentWindow.removeEventListener( - "close-screen-modal", - peekStore.actions.hidePeek - ) - iframe.contentWindow.removeEventListener("notification", proxyNotification) + window.removeEventListener("message", receiveMessage) } const handleFullscreen = () => { diff --git a/packages/client/src/stores/builder.js b/packages/client/src/stores/builder.js index 2740a4551..baea5cb83 100644 --- a/packages/client/src/stores/builder.js +++ b/packages/client/src/stores/builder.js @@ -4,11 +4,7 @@ import { findComponentById, findComponentPathById } from "../utils/components" import { pingEndUser } from "../api" const dispatchEvent = (type, data = {}) => { - window.dispatchEvent( - new CustomEvent("bb-event", { - detail: { type, data }, - }) - ) + window.parent.postMessage({ type, data }) } const createBuilderStore = () => { diff --git a/packages/client/src/stores/notification.js b/packages/client/src/stores/notification.js index e3af9aacd..97193b209 100644 --- a/packages/client/src/stores/notification.js +++ b/packages/client/src/stores/notification.js @@ -26,11 +26,19 @@ const createNotificationStore = () => { // If peeking, pass notifications back to parent window if (get(routeStore).queryParams?.peek) { - window.dispatchEvent( - new CustomEvent("notification", { - detail: { message, type, icon }, - }) - ) + window.parent.postMessage({ + type: "notification", + detail: { + message, + type, + icon, + }, + }) + // window.dispatchEvent( + // new CustomEvent("notification", { + // detail: { message, type, icon }, + // }) + // ) return } From ff9130c49c3ae0433f1858986cc8b18577f67bfe Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Thu, 4 Nov 2021 17:28:07 +0100 Subject: [PATCH 062/148] tidy up --- packages/client/src/stores/dataSource.js | 9 ++++----- packages/client/src/stores/notification.js | 5 ----- packages/client/src/utils/buttonActions.js | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/client/src/stores/dataSource.js b/packages/client/src/stores/dataSource.js index c60039aa8..247ba1883 100644 --- a/packages/client/src/stores/dataSource.js +++ b/packages/client/src/stores/dataSource.js @@ -59,11 +59,10 @@ export const createDataSourceStore = () => { // Emit this as a window event, so parent screens which are iframing us in // can also invalidate the same datasource - window.dispatchEvent( - new CustomEvent("invalidate-datasource", { - detail: { dataSourceId }, - }) - ) + window.parent.postMessage({ + type: "close-screen-modal", + detail: { dataSourceId }, + }) let invalidations = [dataSourceId] diff --git a/packages/client/src/stores/notification.js b/packages/client/src/stores/notification.js index 97193b209..64178328c 100644 --- a/packages/client/src/stores/notification.js +++ b/packages/client/src/stores/notification.js @@ -34,11 +34,6 @@ const createNotificationStore = () => { icon, }, }) - // window.dispatchEvent( - // new CustomEvent("notification", { - // detail: { message, type, icon }, - // }) - // ) return } diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 11aa033c1..1fb228437 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -120,7 +120,7 @@ const changeFormStepHandler = async (action, context) => { const closeScreenModalHandler = () => { // Emit this as a window event, so parent screens which are iframing us in // can close the modal - window.dispatchEvent(new Event("close-screen-modal")) + window.parent.postMessage({ type: "close-screen-modal" }) } const updateStateHandler = action => { From 7db07ed081ec06fb9b10ed52bb441dc0555965e5 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Thu, 4 Nov 2021 16:30:06 +0000 Subject: [PATCH 063/148] v0.9.176-alpha.3 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index f7730dd4f..18f9328af 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 78c48af85..b5f27ca05 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 44f0ac437..0d1c5c15b 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 80d466cc8..56811c6d1 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.176-alpha.2", - "@budibase/client": "^0.9.176-alpha.2", + "@budibase/bbui": "^0.9.176-alpha.3", + "@budibase/client": "^0.9.176-alpha.3", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.176-alpha.2", + "@budibase/string-templates": "^0.9.176-alpha.3", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index dbb3ac8d1..f6f873edc 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 03bf4895f..dc487f6bf 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.176-alpha.2", + "@budibase/bbui": "^0.9.176-alpha.3", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.176-alpha.2", + "@budibase/string-templates": "^0.9.176-alpha.3", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index ecdebfb3c..cee6a2a2e 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.176-alpha.2", - "@budibase/client": "^0.9.176-alpha.2", - "@budibase/string-templates": "^0.9.176-alpha.2", + "@budibase/auth": "^0.9.176-alpha.3", + "@budibase/client": "^0.9.176-alpha.3", + "@budibase/string-templates": "^0.9.176-alpha.3", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index d024c4524..3a7268920 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 760200bb9..8d1c7141b 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.176-alpha.2", + "version": "0.9.176-alpha.3", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.176-alpha.2", - "@budibase/string-templates": "^0.9.176-alpha.2", + "@budibase/auth": "^0.9.176-alpha.3", + "@budibase/string-templates": "^0.9.176-alpha.3", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 6489d61fd1bd674f847f27a1bb21893f90cdedc9 Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Thu, 4 Nov 2021 16:37:06 +0000 Subject: [PATCH 064/148] v0.9.178 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index 217743355..df4c58df4 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.177", + "version": "0.9.178", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 5a6692c2a..0d5171458 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.177", + "version": "0.9.178", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index e4be1ddb3..4f7c369e1 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.177", + "version": "0.9.178", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index c86268f2b..d0376d611 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.177", + "version": "0.9.178", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.177", - "@budibase/client": "^0.9.177", + "@budibase/bbui": "^0.9.178", + "@budibase/client": "^0.9.178", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.177", + "@budibase/string-templates": "^0.9.178", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 2b87fc014..5cb584aa4 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.177", + "version": "0.9.178", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 21825fb7d..ddfd50264 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.177", + "version": "0.9.178", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.177", + "@budibase/bbui": "^0.9.178", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.177", + "@budibase/string-templates": "^0.9.178", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 08c5f7103..d55cdbdab 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.177", + "version": "0.9.178", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.177", - "@budibase/client": "^0.9.177", - "@budibase/string-templates": "^0.9.177", + "@budibase/auth": "^0.9.178", + "@budibase/client": "^0.9.178", + "@budibase/string-templates": "^0.9.178", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index e0b7c5558..196ec9a0c 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.177", + "version": "0.9.178", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 6e8b25bea..90da0e8cb 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.177", + "version": "0.9.178", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.177", - "@budibase/string-templates": "^0.9.177", + "@budibase/auth": "^0.9.178", + "@budibase/string-templates": "^0.9.178", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 6e76a7dd1af0056c2a885bc43be94e12c8e57106 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Thu, 4 Nov 2021 20:28:26 +0000 Subject: [PATCH 065/148] Adding a check to disable user sync in test when server not available. --- packages/worker/src/utilities/appService.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/worker/src/utilities/appService.js b/packages/worker/src/utilities/appService.js index a7be05b22..166a82f78 100644 --- a/packages/worker/src/utilities/appService.js +++ b/packages/worker/src/utilities/appService.js @@ -5,6 +5,9 @@ const { checkSlashesInUrl } = require("../utilities") const env = require("../environment") exports.syncUserInApps = async userId => { + if (env.isTest()) { + return + } const request = { headers: {} } request.headers[Headers.API_KEY] = env.INTERNAL_API_KEY if (isTenantIdSet()) { From 9c933b629f9d4f9beb91d9f5c02fec59c839e16e Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 5 Nov 2021 12:33:48 +0000 Subject: [PATCH 066/148] Linting and updating SQL Server schema generation to include auto column and primary key recognition. --- .../scripts/integrations/mssql/data/setup.sql | 28 ++++++-- .../api/controllers/row/ExternalRequest.ts | 7 +- packages/server/src/integrations/base/sql.ts | 4 +- .../server/src/integrations/base/sqlTable.ts | 44 +++++++++---- .../server/src/integrations/base/utils.ts | 5 +- .../src/integrations/microsoftSqlServer.ts | 66 ++++++++++++++++--- 6 files changed, 123 insertions(+), 31 deletions(-) diff --git a/packages/server/scripts/integrations/mssql/data/setup.sql b/packages/server/scripts/integrations/mssql/data/setup.sql index f6c94ee2c..766388f46 100644 --- a/packages/server/scripts/integrations/mssql/data/setup.sql +++ b/packages/server/scripts/integrations/mssql/data/setup.sql @@ -7,15 +7,30 @@ CREATE TABLE products ( id int IDENTITY(1,1), name varchar (20), - description varchar(30) + description varchar(30), + CONSTRAINT pk_products PRIMARY KEY NONCLUSTERED (id) ); + IF OBJECT_ID ('dbo.tasks', 'U') IS NOT NULL DROP TABLE tasks; GO CREATE TABLE tasks ( taskid int IDENTITY(1,1), - taskname varchar (20) + taskname varchar (20), + productid int, + CONSTRAINT pk_tasks PRIMARY KEY NONCLUSTERED (taskid), + CONSTRAINT fk_products FOREIGN KEY (productid) REFERENCES products (id), +); + +IF OBJECT_ID ('dbo.people', 'U') IS NOT NULL + DROP TABLE people; +GO +CREATE TABLE people +( + name varchar(30), + age varchar(20), + CONSTRAINT pk_people PRIMARY KEY NONCLUSTERED (name, age) ); INSERT products @@ -29,6 +44,11 @@ VALUES ('Meat', 'Animal thing'); INSERT tasks - (taskname) + (taskname, productid) +VALUES + ('Processing', 1); + +INSERT people + (name, age) VALUES - ('Processing'); + ('Bob', '30'); diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index f538e01f7..23d8deb25 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -226,7 +226,12 @@ module External { manyRelationships: ManyRelationship[] = [] for (let [key, field] of Object.entries(table.schema)) { // if set already, or not set just skip it - if (row[key] == null || newRow[key] || field.autocolumn || field.type === FieldTypes.FORMULA) { + if ( + row[key] == null || + newRow[key] || + field.autocolumn || + field.type === FieldTypes.FORMULA + ) { continue } // if its an empty string then it means return the column to null (if possible) diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 738b44afc..6c64d5c38 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -279,7 +279,9 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { case Operation.DELETE: query = buildDelete(client, json, opts) break - case Operation.CREATE_TABLE: case Operation.UPDATE_TABLE: case Operation.DELETE_TABLE: + case Operation.CREATE_TABLE: + case Operation.UPDATE_TABLE: + case Operation.DELETE_TABLE: return this._tableQuery(json) default: throw `Operation type is not supported by SQL query builder` diff --git a/packages/server/src/integrations/base/sqlTable.ts b/packages/server/src/integrations/base/sqlTable.ts index e5249dfe7..974f39506 100644 --- a/packages/server/src/integrations/base/sqlTable.ts +++ b/packages/server/src/integrations/base/sqlTable.ts @@ -6,7 +6,12 @@ import SchemaBuilder = Knex.SchemaBuilder import CreateTableBuilder = Knex.CreateTableBuilder const { FieldTypes, RelationshipTypes } = require("../../constants") -function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record, oldTable: null | Table = null) { +function generateSchema( + schema: CreateTableBuilder, + table: Table, + tables: Record, + oldTable: null | Table = null +) { let primaryKey = table && table.primary ? table.primary[0] : null const columns = Object.values(table.schema) // all columns in a junction table will be meta @@ -19,17 +24,21 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record schema.primary(metaCols.map(col => col.name)) } - // check if any columns need added const foreignKeys = Object.values(table.schema).map(col => col.foreignKey) for (let [key, column] of Object.entries(table.schema)) { // skip things that are already correct const oldColumn = oldTable ? oldTable.schema[key] : null - if ((oldColumn && oldColumn.type === column.type) || (primaryKey === key && !isJunction)) { + if ( + (oldColumn && oldColumn.type === column.type) || + (primaryKey === key && !isJunction) + ) { continue } switch (column.type) { - case FieldTypes.STRING: case FieldTypes.OPTIONS: case FieldTypes.LONGFORM: + case FieldTypes.STRING: + case FieldTypes.OPTIONS: + case FieldTypes.LONGFORM: schema.string(key) break case FieldTypes.NUMBER: @@ -67,7 +76,9 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record throw "Referenced table doesn't exist" } schema.integer(column.foreignKey).unsigned() - schema.foreign(column.foreignKey).references(`${tableName}.${relatedTable.primary[0]}`) + schema + .foreign(column.foreignKey) + .references(`${tableName}.${relatedTable.primary[0]}`) } break } @@ -76,7 +87,10 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record // need to check if any columns have been deleted if (oldTable) { const deletedColumns = Object.entries(oldTable.schema) - .filter(([key, schema]) => schema.type !== FieldTypes.LINK && table.schema[key] == null) + .filter( + ([key, schema]) => + schema.type !== FieldTypes.LINK && table.schema[key] == null + ) .map(([key]) => key) deletedColumns.forEach(key => { if (oldTable.constrained && oldTable.constrained.indexOf(key) !== -1) { @@ -92,7 +106,7 @@ function generateSchema(schema: CreateTableBuilder, table: Table, tables: Record function buildCreateTable( knex: Knex, table: Table, - tables: Record, + tables: Record ): SchemaBuilder { return knex.schema.createTable(table.name, schema => { generateSchema(schema, table, tables) @@ -103,17 +117,14 @@ function buildUpdateTable( knex: Knex, table: Table, tables: Record, - oldTable: Table, + oldTable: Table ): SchemaBuilder { return knex.schema.alterTable(table.name, schema => { generateSchema(schema, table, tables, oldTable) }) } -function buildDeleteTable( - knex: Knex, - table: Table, -): SchemaBuilder { +function buildDeleteTable(knex: Knex, table: Table): SchemaBuilder { return knex.schema.dropTable(table.name) } @@ -151,7 +162,12 @@ class SqlTableQueryBuilder { if (!json.meta || !json.meta.table) { throw "Must specify old table for update" } - query = buildUpdateTable(client, json.table, json.meta.tables, json.meta.table) + query = buildUpdateTable( + client, + json.table, + json.meta.tables, + json.meta.table + ) break case Operation.DELETE_TABLE: query = buildDeleteTable(client, json.table) @@ -164,4 +180,4 @@ class SqlTableQueryBuilder { } export default SqlTableQueryBuilder -module.exports = SqlTableQueryBuilder \ No newline at end of file +module.exports = SqlTableQueryBuilder diff --git a/packages/server/src/integrations/base/utils.ts b/packages/server/src/integrations/base/utils.ts index 5757232bc..086912b92 100644 --- a/packages/server/src/integrations/base/utils.ts +++ b/packages/server/src/integrations/base/utils.ts @@ -4,7 +4,10 @@ import { Datasource } from "../../definitions/common" module DatasourceUtils { const { integrations } = require("../index") - export async function makeExternalQuery(datasource: Datasource, json: QueryJson) { + export async function makeExternalQuery( + datasource: Datasource, + json: QueryJson + ) { const Integration = integrations[datasource.source] // query is the opinionated function if (Integration.prototype.query) { diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index d97c5f36b..f8fd63808 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -7,7 +7,7 @@ import { } from "../definitions/datasource" import { getSqlQuery } from "./utils" import { DatasourcePlus } from "./base/datasourcePlus" -import { Table, TableSchema } from "../definitions/common"; +import { Table, TableSchema } from "../definitions/common" module MSSQLModule { const sqlServer = require("mssql") @@ -129,9 +129,10 @@ module MSSQLModule { "spt_fallback_dev", "spt_fallback_usg", "spt_monitor", - "MSreplication_options" + "MSreplication_options", ] - TABLES_SQL = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" + TABLES_SQL = + "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='BASE TABLE'" getDefinitionSQL(tableName: string) { return `select * @@ -139,6 +140,28 @@ module MSSQLModule { where TABLE_NAME='${tableName}'` } + getConstraintsSQL(tableName: string) { + return `SELECT * FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS TC + INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KU + ON TC.CONSTRAINT_TYPE = 'PRIMARY KEY' + AND TC.CONSTRAINT_NAME = KU.CONSTRAINT_NAME + AND KU.table_name='${tableName}' + ORDER BY + KU.TABLE_NAME, + KU.ORDINAL_POSITION;` + } + + getAutoColumnsSQL(tableName: string) { + return `SELECT + COLUMNPROPERTY(OBJECT_ID(TABLE_SCHEMA+'.'+TABLE_NAME),COLUMN_NAME,'IsComputed') + AS IS_COMPUTED, + COLUMNPROPERTY(object_id(TABLE_SCHEMA+'.'+TABLE_NAME), COLUMN_NAME, 'IsIdentity') + AS IS_IDENTITY, + * + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME='${tableName}'` + } + constructor(config: MSSQLConfig) { super("mssql") this.config = config @@ -171,16 +194,39 @@ module MSSQLModule { * @param entities - the tables that are to be built */ async buildSchema(datasourceId: string, entities: Record) { - await this.connect() - let tableNames = await internalQuery(this.client, getSqlQuery(this.TABLES_SQL)) + let tableNames = await internalQuery( + this.client, + getSqlQuery(this.TABLES_SQL) + ) if (tableNames == null || !Array.isArray(tableNames.recordset)) { throw "Unable to get list of tables in database" } - tableNames = tableNames.recordset.map((record: any) => record.TABLE_NAME).filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1) + tableNames = tableNames.recordset + .map((record: any) => record.TABLE_NAME) + .filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1) const tables: Record = {} for (let tableName of tableNames) { - const definition = await internalQuery(this.client, getSqlQuery(this.getDefinitionSQL(tableName))) + const definition = await internalQuery( + this.client, + getSqlQuery(this.getDefinitionSQL(tableName)) + ) + const constraints = await internalQuery( + this.client, + getSqlQuery(this.getConstraintsSQL(tableName)) + ) + const columns = await internalQuery( + this.client, + getSqlQuery(this.getAutoColumnsSQL(tableName)) + ) + const autoColumns = columns.recordset + .filter((col: any) => col.IS_COMPUTED || col.IS_IDENTITY) + .map((col: any) => col.COLUMN_NAME) + const primaryKeys = constraints.recordset + .filter( + (constraint: any) => constraint.CONSTRAINT_TYPE === "PRIMARY KEY" + ) + .map((constraint: any) => constraint.COLUMN_NAME) let schema: TableSchema = {} for (let def of definition.recordset) { const name = def.COLUMN_NAME @@ -188,16 +234,16 @@ module MSSQLModule { continue } const type: string = convertType(def.DATA_TYPE, TYPE_MAP) - const identity = false + schema[name] = { - autocolumn: identity, + autocolumn: !!autoColumns.find((col: string) => col === name), name: name, type, } } tables[tableName] = { _id: buildExternalTableId(datasourceId, tableName), - primary: ["id"], + primary: primaryKeys, name: tableName, schema, } From 1f1786c2b342040e6fab00b9ed66f385224a1b24 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 5 Nov 2021 12:37:16 +0000 Subject: [PATCH 067/148] Fix issue saving a doc with a multi-options datatype that was not defined --- packages/server/src/api/controllers/row/utils.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/row/utils.js b/packages/server/src/api/controllers/row/utils.js index ca6c78271..6bbc6474e 100644 --- a/packages/server/src/api/controllers/row/utils.js +++ b/packages/server/src/api/controllers/row/utils.js @@ -68,7 +68,11 @@ exports.validate = async ({ appId, tableId, row, table }) => { let res // Validate.js doesn't seem to handle array - if (table.schema[fieldName].type === FieldTypes.ARRAY) { + if ( + table.schema[fieldName].type === FieldTypes.ARRAY && + row[fieldName] && + row[fieldName].length + ) { row[fieldName].map(val => { if (!constraints.inclusion.includes(val)) { errors[fieldName] = "Field not in list" From 117a7f7ce8849477d1dc9a7661f8e8607898074f Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 5 Nov 2021 12:37:42 +0000 Subject: [PATCH 068/148] Fix issue getting bindable properties when selecting a screen --- packages/builder/src/builderStore/dataBinding.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 9003b3e06..742c9052a 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -83,7 +83,7 @@ export const getActionProviderComponents = (asset, componentId, actionType) => { * Gets a datasource object for a certain data provider component */ export const getDatasourceForProvider = (asset, component) => { - const settings = getComponentSettings(component._component) + const settings = getComponentSettings(component?._component) // If this component has a dataProvider setting, go up the stack and use it const dataProviderSetting = settings.find(setting => { From 8c63b147fb07a8192204c2d09423c195bb6275cc Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 5 Nov 2021 12:38:15 +0000 Subject: [PATCH 069/148] Remove forced capitalisation of setting labels --- .../PropertiesPanel/PropertyControls/PropertyControl.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte index 91e67c168..ea0fdead7 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte @@ -122,7 +122,6 @@ } .label { - text-transform: capitalize; padding-bottom: var(--spectrum-global-dimension-size-65); } From d5002d3dda46039654e0b921d354f81252b24399 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 5 Nov 2021 12:38:33 +0000 Subject: [PATCH 070/148] Add ability to link rows in tables, and link rows in the table with search block --- packages/client/manifest.json | 65 +++++++++++++++++-- .../app/blocks/TableWithSearch.svelte | 8 +++ .../src/components/app/table/Table.svelte | 20 +++++- packages/client/src/stores/routes.js | 24 ++++++- packages/client/src/utils/buttonActions.js | 15 +---- 5 files changed, 109 insertions(+), 23 deletions(-) diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 46f87818f..982f96ef9 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2457,12 +2457,12 @@ "settings": [ { "type": "dataProvider", - "label": "Provider", + "label": "Data provider", "key": "dataProvider" }, { "type": "number", - "label": "Row Count", + "label": "Row count", "key": "rowCount", "defaultValue": 8 }, @@ -2496,9 +2496,36 @@ }, { "type": "boolean", - "label": "Auto Columns", + "label": "Show auto columns", "key": "showAutoColumns", "defaultValue": false + }, + { + "type": "boolean", + "label": "Link table rows", + "key": "linkRows" + }, + { + "type": "boolean", + "label": "Open link screens in modal", + "key": "linkPeek" + }, + { + "type": "url", + "label": "Link screen", + "key": "linkURL" + }, + { + "section": true, + "name": "Advanced", + "settings": [ + { + "type": "field", + "label": "ID column for linking (appended to URL)", + "key": "linkColumn", + "placeholder": "Default" + } + ] } ], "context": { @@ -2662,8 +2689,22 @@ { "type": "boolean", "label": "Show auto columns", - "key": "showAutoColumns", - "defaultValue": false + "key": "showAutoColumns" + }, + { + "type": "boolean", + "label": "Link table rows", + "key": "linkRows" + }, + { + "type": "boolean", + "label": "Open link in modal", + "key": "linkPeek" + }, + { + "type": "url", + "label": "Link screen", + "key": "linkURL" } ] }, @@ -2684,10 +2725,22 @@ }, { "type": "event", - "label": "Title Button Action", + "label": "Title button action", "key": "titleButtonOnClick" } ] + }, + { + "section": true, + "name": "Advanced", + "settings": [ + { + "type": "field", + "label": "ID column for linking (appended to URL)", + "key": "linkColumn", + "placeholder": "Default" + } + ] } ], "context": { diff --git a/packages/client/src/components/app/blocks/TableWithSearch.svelte b/packages/client/src/components/app/blocks/TableWithSearch.svelte index c4143df98..378a11157 100644 --- a/packages/client/src/components/app/blocks/TableWithSearch.svelte +++ b/packages/client/src/components/app/blocks/TableWithSearch.svelte @@ -16,6 +16,10 @@ export let rowCount export let quiet export let size + export let linkRows + export let linkURL + export let linkColumn + export let linkPeek export let showTitleButton export let titleButtonText export let titleButtonOnClick @@ -138,6 +142,10 @@ rowCount, quiet, size, + linkRows, + linkURL, + linkColumn, + linkPeek, }} /> diff --git a/packages/client/src/components/app/table/Table.svelte b/packages/client/src/components/app/table/Table.svelte index a6508c576..4178ca2bb 100644 --- a/packages/client/src/components/app/table/Table.svelte +++ b/packages/client/src/components/app/table/Table.svelte @@ -9,9 +9,13 @@ export let rowCount export let quiet export let size + export let linkRows + export let linkURL + export let linkColumn + export let linkPeek const component = getContext("component") - const { styleable, getAction, ActionTypes } = getContext("sdk") + const { styleable, getAction, ActionTypes, routeStore } = getContext("sdk") const setSorting = getAction( dataProvider?.id, ActionTypes.SetDataProviderSorting @@ -81,6 +85,19 @@ order: e.detail.order, }) } + + const onClick = e => { + if (!linkRows || !linkURL) { + return + } + const col = linkColumn || "_id" + const id = e.detail?.[col] + if (!id) { + return + } + const split = linkURL.split("/:") + routeStore.actions.navigate(`${split[0]}/${id}`, linkPeek) + }
@@ -97,6 +114,7 @@ showAutoColumns={true} disableSorting on:sort={onSort} + on:click={onClick} > diff --git a/packages/client/src/stores/routes.js b/packages/client/src/stores/routes.js index e6473fb40..1d5dca164 100644 --- a/packages/client/src/stores/routes.js +++ b/packages/client/src/stores/routes.js @@ -1,6 +1,8 @@ -import { writable } from "svelte/store" +import { get, writable } from "svelte/store" import { push } from "svelte-spa-router" import * as API from "../api" +import { peekStore } from "./peek" +import { builderStore } from "./builder" const createRouteStore = () => { const initialState = { @@ -59,7 +61,25 @@ const createRouteStore = () => { return state }) } - const navigate = push + const navigate = (url, peek) => { + if (get(builderStore).inBuilder) { + return + } + if (url) { + // If we're already peeking, don't peek again + const isPeeking = get(store).queryParams?.peek + if (peek && !isPeeking) { + peekStore.actions.showPeek(url) + } else { + const external = !url.startsWith("/") + if (external) { + window.location.href = url + } else { + push(url) + } + } + } + } const setRouterLoaded = () => { store.update(state => ({ ...state, routerLoaded: true })) } diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 655f2f32e..01b330d74 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -42,20 +42,7 @@ const triggerAutomationHandler = async action => { const navigationHandler = action => { const { url, peek } = action.parameters - if (url) { - // If we're already peeking, don't peek again - const isPeeking = get(routeStore).queryParams?.peek - if (peek && !isPeeking) { - peekStore.actions.showPeek(url) - } else { - const external = !url.startsWith("/") - if (external) { - window.location.href = url - } else { - routeStore.actions.navigate(action.parameters.url) - } - } - } + routeStore.actions.navigate(url, peek) } const queryExecutionHandler = async action => { From 5ec0d803afdaf6c7465fa0dfb731e574718fc3dc Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 5 Nov 2021 12:41:26 +0000 Subject: [PATCH 071/148] Cleaning up repeated work in sql server building of schema. --- .../src/integrations/microsoftSqlServer.ts | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index f8fd63808..7071ce6f7 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -188,6 +188,10 @@ module MSSQLModule { } } + async runSQL(sql: string) { + return (await internalQuery(this.client, getSqlQuery(sql))).recordset + } + /** * Fetches the tables from the sql server database and assigns them to the datasource. * @param {*} datasourceId - datasourceId to fetch @@ -195,40 +199,33 @@ module MSSQLModule { */ async buildSchema(datasourceId: string, entities: Record) { await this.connect() - let tableNames = await internalQuery( - this.client, - getSqlQuery(this.TABLES_SQL) - ) + let tableNames = await this.runSQL(this.TABLES_SQL) if (tableNames == null || !Array.isArray(tableNames.recordset)) { throw "Unable to get list of tables in database" } tableNames = tableNames.recordset .map((record: any) => record.TABLE_NAME) .filter((name: string) => this.MASTER_TABLES.indexOf(name) === -1) + const tables: Record = {} for (let tableName of tableNames) { - const definition = await internalQuery( - this.client, - getSqlQuery(this.getDefinitionSQL(tableName)) - ) - const constraints = await internalQuery( - this.client, - getSqlQuery(this.getConstraintsSQL(tableName)) - ) - const columns = await internalQuery( - this.client, - getSqlQuery(this.getAutoColumnsSQL(tableName)) - ) - const autoColumns = columns.recordset - .filter((col: any) => col.IS_COMPUTED || col.IS_IDENTITY) - .map((col: any) => col.COLUMN_NAME) - const primaryKeys = constraints.recordset + // get the column definition (type) + const definition = await this.runSQL(this.getDefinitionSQL(tableName)) + // find primary key constraints + const constraints = await this.runSQL(this.getConstraintsSQL(tableName)) + // find the computed and identity columns (auto columns) + const columns = await this.runSQL(this.getAutoColumnsSQL(tableName)) + const primaryKeys = constraints .filter( (constraint: any) => constraint.CONSTRAINT_TYPE === "PRIMARY KEY" ) .map((constraint: any) => constraint.COLUMN_NAME) + const autoColumns = columns + .filter((col: any) => col.IS_COMPUTED || col.IS_IDENTITY) + .map((col: any) => col.COLUMN_NAME) + let schema: TableSchema = {} - for (let def of definition.recordset) { + for (let def of definition) { const name = def.COLUMN_NAME if (typeof name !== "string") { continue From e2cbf054ce9fb522a950471ead2680494b02cb36 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Fri, 5 Nov 2021 12:43:26 +0000 Subject: [PATCH 072/148] Lint --- packages/client/src/utils/buttonActions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/client/src/utils/buttonActions.js b/packages/client/src/utils/buttonActions.js index 01b330d74..233a52606 100644 --- a/packages/client/src/utils/buttonActions.js +++ b/packages/client/src/utils/buttonActions.js @@ -4,7 +4,6 @@ import { builderStore, confirmationStore, authStore, - peekStore, stateStore, } from "stores" import { saveRow, deleteRow, executeQuery, triggerAutomation } from "api" From 3474f3ae8e45455022db504e600c8aaeda4f4100 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 5 Nov 2021 13:48:13 +0000 Subject: [PATCH 073/148] Updating underlying sql to not use ilike unless in postgres client. --- .../api/controllers/row/ExternalRequest.ts | 2 +- packages/server/src/integrations/base/sql.ts | 417 +++++++++--------- .../src/integrations/microsoftSqlServer.ts | 4 +- 3 files changed, 218 insertions(+), 205 deletions(-) diff --git a/packages/server/src/api/controllers/row/ExternalRequest.ts b/packages/server/src/api/controllers/row/ExternalRequest.ts index 23d8deb25..d4e8d475a 100644 --- a/packages/server/src/api/controllers/row/ExternalRequest.ts +++ b/packages/server/src/api/controllers/row/ExternalRequest.ts @@ -342,7 +342,7 @@ module External { table: Table, relationships: RelationshipsJson[] ) { - if (rows[0].read === true) { + if (!rows || rows.length === 0 || rows[0].read === true) { return [] } let finalRows: { [key: string]: Row } = {} diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 6c64d5c38..06a9d0aa1 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -29,222 +29,232 @@ function parseBody(body: any) { return body } -// right now we only do filters on the specific table being queried -function addFilters( - tableName: string, - query: KnexQuery, - filters: SearchFilters | undefined -): KnexQuery { - function iterate( - structure: { [key: string]: any }, - fn: (key: string, value: any) => void - ) { - for (let [key, value] of Object.entries(structure)) { - fn(`${tableName}.${key}`, value) - } - } - if (!filters) { - return query - } - // if all or specified in filters, then everything is an or - const allOr = filters.allOr - if (filters.oneOf) { - iterate(filters.oneOf, (key, array) => { - const fnc = allOr ? "orWhereIn" : "whereIn" - query = query[fnc](key, array) - }) - } - if (filters.string) { - iterate(filters.string, (key, value) => { - const fnc = allOr ? "orWhere" : "where" - query = query[fnc](key, "ilike", `${value}%`) - }) - } - if (filters.fuzzy) { - iterate(filters.fuzzy, (key, value) => { - const fnc = allOr ? "orWhere" : "where" - query = query[fnc](key, "ilike", `%${value}%`) - }) - } - if (filters.range) { - iterate(filters.range, (key, value) => { - if (!value.high || !value.low) { - return - } - const fnc = allOr ? "orWhereBetween" : "whereBetween" - query = query[fnc](key, [value.low, value.high]) - }) - } - if (filters.equal) { - iterate(filters.equal, (key, value) => { - const fnc = allOr ? "orWhere" : "where" - query = query[fnc]({ [key]: value }) - }) - } - if (filters.notEqual) { - iterate(filters.notEqual, (key, value) => { - const fnc = allOr ? "orWhereNot" : "whereNot" - query = query[fnc]({ [key]: value }) - }) - } - if (filters.empty) { - iterate(filters.empty, key => { - const fnc = allOr ? "orWhereNull" : "whereNull" - query = query[fnc](key) - }) - } - if (filters.notEmpty) { - iterate(filters.notEmpty, key => { - const fnc = allOr ? "orWhereNotNull" : "whereNotNull" - query = query[fnc](key) - }) +class InternalBuilder { + private readonly client: string + + constructor(client: string) { + this.client = client } - return query -} -function addRelationships( - knex: Knex, - query: KnexQuery, - fields: string | string[], - fromTable: string, - relationships: RelationshipsJson[] | undefined -): KnexQuery { - if (!relationships) { + // right now we only do filters on the specific table being queried + addFilters( + tableName: string, + query: KnexQuery, + filters: SearchFilters | undefined + ): KnexQuery { + function iterate( + structure: { [key: string]: any }, + fn: (key: string, value: any) => void + ) { + for (let [key, value] of Object.entries(structure)) { + fn(`${tableName}.${key}`, value) + } + } + if (!filters) { + return query + } + // if all or specified in filters, then everything is an or + const allOr = filters.allOr + if (filters.oneOf) { + iterate(filters.oneOf, (key, array) => { + const fnc = allOr ? "orWhereIn" : "whereIn" + query = query[fnc](key, array) + }) + } + if (filters.string) { + iterate(filters.string, (key, value) => { + const fnc = allOr ? "orWhere" : "where" + // postgres supports ilike, nothing else does + if (this.client === "pg") { + query = query[fnc](key, "ilike", `${value}%`) + } else { + const rawFnc = `${fnc}Raw` + // @ts-ignore + query = query[rawFnc](`LOWER(${key}) LIKE ?`, [`${value}%`]) + } + }) + } + if (filters.fuzzy) { + iterate(filters.fuzzy, (key, value) => { + const fnc = allOr ? "orWhere" : "where" + // postgres supports ilike, nothing else does + if (this.client === "pg") { + query = query[fnc](key, "ilike", `%${value}%`) + } else { + const rawFnc = `${fnc}Raw` + // @ts-ignore + query = query[rawFnc](`LOWER(${key}) LIKE ?`, [`%${value}%`]) + } + }) + } + if (filters.range) { + iterate(filters.range, (key, value) => { + if (!value.high || !value.low) { + return + } + const fnc = allOr ? "orWhereBetween" : "whereBetween" + query = query[fnc](key, [value.low, value.high]) + }) + } + if (filters.equal) { + iterate(filters.equal, (key, value) => { + const fnc = allOr ? "orWhere" : "where" + query = query[fnc]({ [key]: value }) + }) + } + if (filters.notEqual) { + iterate(filters.notEqual, (key, value) => { + const fnc = allOr ? "orWhereNot" : "whereNot" + query = query[fnc]({ [key]: value }) + }) + } + if (filters.empty) { + iterate(filters.empty, key => { + const fnc = allOr ? "orWhereNull" : "whereNull" + query = query[fnc](key) + }) + } + if (filters.notEmpty) { + iterate(filters.notEmpty, key => { + const fnc = allOr ? "orWhereNotNull" : "whereNotNull" + query = query[fnc](key) + }) + } return query } - for (let relationship of relationships) { - const from = relationship.from, - to = relationship.to, - toTable = relationship.tableName - if (!relationship.through) { - // @ts-ignore - query = query.leftJoin( - toTable, - `${fromTable}.${from}`, - `${toTable}.${to}` - ) - } else { - const throughTable = relationship.through - const fromPrimary = relationship.fromPrimary - const toPrimary = relationship.toPrimary - query = query + + addRelationships( + knex: Knex, + query: KnexQuery, + fields: string | string[], + fromTable: string, + relationships: RelationshipsJson[] | undefined + ): KnexQuery { + if (!relationships) { + return query + } + for (let relationship of relationships) { + const from = relationship.from, + to = relationship.to, + toTable = relationship.tableName + if (!relationship.through) { // @ts-ignore - .leftJoin( - throughTable, - `${fromTable}.${fromPrimary}`, - `${throughTable}.${from}` + query = query.leftJoin( + toTable, + `${fromTable}.${from}`, + `${toTable}.${to}` ) - .leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`) + } else { + const throughTable = relationship.through + const fromPrimary = relationship.fromPrimary + const toPrimary = relationship.toPrimary + query = query + // @ts-ignore + .leftJoin( + throughTable, + `${fromTable}.${fromPrimary}`, + `${throughTable}.${from}` + ) + .leftJoin(toTable, `${toTable}.${toPrimary}`, `${throughTable}.${to}`) + } } + return query.limit(BASE_LIMIT) } - return query.limit(BASE_LIMIT) -} -function buildCreate( - knex: Knex, - json: QueryJson, - opts: QueryOptions -): KnexQuery { - const { endpoint, body } = json - let query: KnexQuery = knex(endpoint.entityId) - const parsedBody = parseBody(body) - // make sure no null values in body for creation - for (let [key, value] of Object.entries(parsedBody)) { - if (value == null) { - delete parsedBody[key] + create(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { + const { endpoint, body } = json + let query: KnexQuery = knex(endpoint.entityId) + const parsedBody = parseBody(body) + // make sure no null values in body for creation + for (let [key, value] of Object.entries(parsedBody)) { + if (value == null) { + delete parsedBody[key] + } + } + // mysql can't use returning + if (opts.disableReturning) { + return query.insert(parsedBody) + } else { + return query.insert(parsedBody).returning("*") } } - // mysql can't use returning - if (opts.disableReturning) { - return query.insert(parsedBody) - } else { - return query.insert(parsedBody).returning("*") - } -} -function buildRead(knex: Knex, json: QueryJson, limit: number): KnexQuery { - let { endpoint, resource, filters, sort, paginate, relationships } = json - const tableName = endpoint.entityId - // select all if not specified - if (!resource) { - resource = { fields: [] } - } - let selectStatement: string | string[] = "*" - // handle select - if (resource.fields && resource.fields.length > 0) { - // select the resources as the format "table.columnName" - this is what is provided - // by the resource builder further up - selectStatement = resource.fields.map(field => `${field} as ${field}`) - } - let foundLimit = limit || BASE_LIMIT - // handle pagination - let foundOffset: number | null = null - if (paginate && paginate.page && paginate.limit) { - // @ts-ignore - const page = paginate.page <= 1 ? 0 : paginate.page - 1 - const offset = page * paginate.limit - foundLimit = paginate.limit - foundOffset = offset - } else if (paginate && paginate.limit) { - foundLimit = paginate.limit - } - // start building the query - let query: KnexQuery = knex(tableName).limit(foundLimit) - if (foundOffset) { - query = query.offset(foundOffset) - } - if (sort) { - for (let [key, value] of Object.entries(sort)) { - const direction = value === SortDirection.ASCENDING ? "asc" : "desc" - query = query.orderBy(key, direction) + read(knex: Knex, json: QueryJson, limit: number): KnexQuery { + let { endpoint, resource, filters, sort, paginate, relationships } = json + const tableName = endpoint.entityId + // select all if not specified + if (!resource) { + resource = { fields: [] } } - } - query = addFilters(tableName, query, filters) - // @ts-ignore - let preQuery: KnexQuery = knex({ + let selectStatement: string | string[] = "*" + // handle select + if (resource.fields && resource.fields.length > 0) { + // select the resources as the format "table.columnName" - this is what is provided + // by the resource builder further up + selectStatement = resource.fields.map(field => `${field} as ${field}`) + } + let foundLimit = limit || BASE_LIMIT + // handle pagination + let foundOffset: number | null = null + if (paginate && paginate.page && paginate.limit) { + // @ts-ignore + const page = paginate.page <= 1 ? 0 : paginate.page - 1 + const offset = page * paginate.limit + foundLimit = paginate.limit + foundOffset = offset + } else if (paginate && paginate.limit) { + foundLimit = paginate.limit + } + // start building the query + let query: KnexQuery = knex(tableName).limit(foundLimit) + if (foundOffset) { + query = query.offset(foundOffset) + } + if (sort) { + for (let [key, value] of Object.entries(sort)) { + const direction = value === SortDirection.ASCENDING ? "asc" : "desc" + query = query.orderBy(key, direction) + } + } + query = this.addFilters(tableName, query, filters) // @ts-ignore - [tableName]: query, - }).select(selectStatement) - // handle joins - return addRelationships( - knex, - preQuery, - selectStatement, - tableName, - relationships - ) -} + let preQuery: KnexQuery = knex({ + // @ts-ignore + [tableName]: query, + }).select(selectStatement) + // handle joins + return this.addRelationships( + knex, + preQuery, + selectStatement, + tableName, + relationships + ) + } -function buildUpdate( - knex: Knex, - json: QueryJson, - opts: QueryOptions -): KnexQuery { - const { endpoint, body, filters } = json - let query: KnexQuery = knex(endpoint.entityId) - const parsedBody = parseBody(body) - query = addFilters(endpoint.entityId, query, filters) - // mysql can't use returning - if (opts.disableReturning) { - return query.update(parsedBody) - } else { - return query.update(parsedBody).returning("*") + update(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { + const { endpoint, body, filters } = json + let query: KnexQuery = knex(endpoint.entityId) + const parsedBody = parseBody(body) + query = this.addFilters(endpoint.entityId, query, filters) + // mysql can't use returning + if (opts.disableReturning) { + return query.update(parsedBody) + } else { + return query.update(parsedBody).returning("*") + } } -} -function buildDelete( - knex: Knex, - json: QueryJson, - opts: QueryOptions -): KnexQuery { - const { endpoint, filters } = json - let query: KnexQuery = knex(endpoint.entityId) - query = addFilters(endpoint.entityId, query, filters) - // mysql can't use returning - if (opts.disableReturning) { - return query.delete() - } else { - return query.delete().returning("*") + delete(knex: Knex, json: QueryJson, opts: QueryOptions): KnexQuery { + const { endpoint, filters } = json + let query: KnexQuery = knex(endpoint.entityId) + query = this.addFilters(endpoint.entityId, query, filters) + // mysql can't use returning + if (opts.disableReturning) { + return query.delete() + } else { + return query.delete().returning("*") + } } } @@ -266,18 +276,19 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { const sqlClient = this.getSqlClient() const client = knex({ client: sqlClient }) let query + const builder = new InternalBuilder(sqlClient) switch (this._operation(json)) { case Operation.CREATE: - query = buildCreate(client, json, opts) + query = builder.create(client, json, opts) break case Operation.READ: - query = buildRead(client, json, this.limit) + query = builder.read(client, json, this.limit) break case Operation.UPDATE: - query = buildUpdate(client, json, opts) + query = builder.update(client, json, opts) break case Operation.DELETE: - query = buildDelete(client, json, opts) + query = builder.delete(client, json, opts) break case Operation.CREATE_TABLE: case Operation.UPDATE_TABLE: diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 7071ce6f7..bcb22f50a 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -245,7 +245,9 @@ module MSSQLModule { schema, } } - this.tables = tables + const final = finaliseExternalTables(tables) + this.tables = final.tables + this.schemaErrors = final.errors } async read(query: SqlQuery | string) { From 61a4a240f18e7299161793779de81023be0f27f7 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 5 Nov 2021 14:59:28 +0000 Subject: [PATCH 074/148] Updating usage quota middleware to fix issue presented in #3258 where anything with an _id and a _rev is considered to exist in CouchDB, which won't always be the case. Handle the scenario of an external database ID and don't error. --- packages/server/src/middleware/usageQuota.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/packages/server/src/middleware/usageQuota.js b/packages/server/src/middleware/usageQuota.js index c62f0078c..2b189b866 100644 --- a/packages/server/src/middleware/usageQuota.js +++ b/packages/server/src/middleware/usageQuota.js @@ -2,6 +2,10 @@ const CouchDB = require("../db") const usageQuota = require("../utilities/usageQuota") const env = require("../environment") const { getTenantId } = require("@budibase/auth/tenancy") +const { + isExternalTable, + isRowId: isExternalRowId, +} = require("../integrations/utils") // tenants without limits const EXCLUDED_TENANTS = ["bb", "default", "bbtest", "bbstaging"] @@ -46,14 +50,24 @@ module.exports = async (ctx, next) => { } // post request could be a save of a pre-existing entry if (ctx.request.body && ctx.request.body._id && ctx.request.body._rev) { + const usageId = ctx.request.body._id try { if (ctx.appId) { const db = new CouchDB(ctx.appId) - await db.get(ctx.request.body._id) + await db.get(usageId) } return next() } catch (err) { - ctx.throw(404, `${ctx.request.body._id} does not exist`) + if ( + isExternalTable(usageId) || + (ctx.request.body.tableId && + isExternalTable(ctx.request.body.tableId)) || + isExternalRowId(usageId) + ) { + return next() + } else { + ctx.throw(404, `${usageId} does not exist`) + } } } From b34cef26c304f67e2b8b3d0e3c76ea004db672bf Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Fri, 5 Nov 2021 18:55:36 +0000 Subject: [PATCH 075/148] Fixing an issue with relationship modal breaking when multiple data sources available to relate to, also fixing an pile of issues with creating and reading rows from SQL server plus. --- .../DataTable/modals/CreateEditColumn.svelte | 13 ++- packages/server/src/definitions/datasource.ts | 2 +- packages/server/src/integrations/base/sql.ts | 83 +++++++++++++++++++ .../src/integrations/microsoftSqlServer.ts | 35 +++++--- packages/server/src/integrations/mysql.ts | 61 +------------- packages/server/src/integrations/utils.ts | 2 +- 6 files changed, 121 insertions(+), 75 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index ebfea9cee..6ee0c48d2 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -59,9 +59,6 @@ let deletion $: checkConstraints(field) - $: tableOptions = $tables.list.filter( - opt => opt._id !== $tables.draft._id && opt.type === table.type - ) $: required = !!field?.constraints?.presence || primaryDisplay $: uneditable = $tables.selected?._id === TableNames.USERS && @@ -88,6 +85,14 @@ field.type !== LINK_TYPE && !uneditable && field.type !== AUTO_TYPE $: relationshipOptions = getRelationshipOptions(field) $: external = table.type === "external" + // in the case of internal tables the sourceId will just be undefined + $: tableOptions = $tables.list.filter( + opt => + opt._id !== $tables.draft._id && + opt.type === table.type && + table.sourceId === opt.sourceId + ) + $: console.log(tableOptions) async function saveColumn() { if (field.type === AUTO_TYPE) { @@ -174,7 +179,7 @@ if (!field || !field.tableId) { return null } - const linkTable = tableOptions.find(table => table._id === field.tableId) + const linkTable = tableOptions?.find(table => table._id === field.tableId) if (!linkTable) { return null } diff --git a/packages/server/src/definitions/datasource.ts b/packages/server/src/definitions/datasource.ts index a82e50b14..6e6cb02f4 100644 --- a/packages/server/src/definitions/datasource.ts +++ b/packages/server/src/definitions/datasource.ts @@ -119,7 +119,7 @@ export interface SortJson { export interface PaginationJson { limit: number - page: string | number + page?: string | number } export interface RelationshipsJson { diff --git a/packages/server/src/integrations/base/sql.ts b/packages/server/src/integrations/base/sql.ts index 06a9d0aa1..d72f87958 100644 --- a/packages/server/src/integrations/base/sql.ts +++ b/packages/server/src/integrations/base/sql.ts @@ -216,6 +216,10 @@ class InternalBuilder { query = query.orderBy(key, direction) } } + if (this.client === "mssql" && !sort && paginate?.limit) { + // @ts-ignore + query = query.orderBy(json.meta?.table?.primary[0]) + } query = this.addFilters(tableName, query, filters) // @ts-ignore let preQuery: KnexQuery = knex({ @@ -301,6 +305,85 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { // @ts-ignore return query.toSQL().toNative() } + + async getReturningRow(queryFn: Function, json: QueryJson) { + if (!json.extra || !json.extra.idFilter) { + return {} + } + const input = this._query({ + endpoint: { + ...json.endpoint, + operation: Operation.READ, + }, + resource: { + fields: [], + }, + filters: json.extra.idFilter, + paginate: { + limit: 1, + }, + meta: json.meta, + }) + return queryFn(input, Operation.READ) + } + + // when creating if an ID has been inserted need to make sure + // the id filter is enriched with it before trying to retrieve the row + checkLookupKeys(id: any, json: QueryJson) { + if (!id || !json.meta?.table || !json.meta.table.primary) { + return json + } + const primaryKey = json.meta.table.primary?.[0] + json.extra = { + idFilter: { + equal: { + [primaryKey]: id, + }, + }, + } + return json + } + + // this function recreates the returning functionality of postgres + async queryWithReturning( + json: QueryJson, + queryFn: Function, + processFn: Function = (result: any) => result + ) { + const sqlClient = this.getSqlClient() + const operation = this._operation(json) + const input = this._query(json, { disableReturning: true }) + if (Array.isArray(input)) { + const responses = [] + for (let query of input) { + responses.push(await queryFn(query, operation)) + } + return responses + } + let row + // need to manage returning, a feature mySQL can't do + if (operation === Operation.DELETE) { + row = processFn(await this.getReturningRow(queryFn, json)) + } + const response = await queryFn(input, operation) + const results = processFn(response) + // same as delete, manage returning + if (operation === Operation.CREATE || operation === Operation.UPDATE) { + let id + if (sqlClient === "mssql") { + id = results?.[0].id + } else if (sqlClient === "mysql") { + id = results?.insertId + } + row = processFn( + await this.getReturningRow(queryFn, this.checkLookupKeys(id, json)) + ) + } + if (operation !== Operation.READ) { + return row + } + return results.length ? results : [{ [operation.toLowerCase()]: true }] + } } module.exports = SqlQueryBuilder diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index bcb22f50a..1ee64759e 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -1,8 +1,9 @@ import { - Integration, DatasourceFieldTypes, - QueryTypes, + Integration, + Operation, QueryJson, + QueryTypes, SqlQuery, } from "../definitions/datasource" import { getSqlQuery } from "./utils" @@ -103,15 +104,26 @@ module MSSQLModule { json: DatasourceFieldTypes.JSON, } - async function internalQuery(client: any, query: SqlQuery) { + async function internalQuery( + client: any, + query: SqlQuery, + operation: string | undefined = undefined + ) { + const request = client.request() try { if (Array.isArray(query.bindings)) { let count = 0 for (let binding of query.bindings) { - client.input(`p${count++}`, binding) + request.input(`p${count++}`, binding) } } - return await client.query(query.sql) + // this is a hack to get the inserted ID back, + // no way to do this with Knex nicely + const sql = + operation === Operation.CREATE + ? `${query.sql}; SELECT SCOPE_IDENTITY() AS id;` + : query.sql + return await request.query(sql) } catch (err) { // @ts-ignore throw new Error(err) @@ -180,8 +192,7 @@ module MSSQLModule { async connect() { try { - const client = await this.pool.connect() - this.client = client.request() + this.client = await this.pool.connect() } catch (err) { // @ts-ignore throw new Error(err) @@ -276,10 +287,12 @@ module MSSQLModule { async query(json: QueryJson) { await this.connect() - const operation = this._operation(json).toLowerCase() - const input = this._query(json) - const response = await internalQuery(this.client, input) - return response.recordset ? response.recordset : [{ [operation]: true }] + const operation = this._operation(json) + const queryFn = (query: any, op: string) => + internalQuery(this.client, query, op) + const processFn = (result: any) => + result.recordset ? result.recordset : [{ [operation]: true }] + return this.queryWithReturning(json, queryFn, processFn) } } diff --git a/packages/server/src/integrations/mysql.ts b/packages/server/src/integrations/mysql.ts index 30cbd836b..ad313d930 100644 --- a/packages/server/src/integrations/mysql.ts +++ b/packages/server/src/integrations/mysql.ts @@ -223,67 +223,12 @@ module MySQLModule { return results.length ? results : [{ deleted: true }] } - async getReturningRow(json: QueryJson) { - if (!json.extra || !json.extra.idFilter) { - return {} - } - const input = this._query({ - endpoint: { - ...json.endpoint, - operation: Operation.READ, - }, - fields: [], - filters: json.extra.idFilter, - paginate: { - limit: 1, - }, - }) - return internalQuery(this.client, input, false) - } - - // when creating if an ID has been inserted need to make sure - // the id filter is enriched with it before trying to retrieve the row - checkLookupKeys(results: any, json: QueryJson) { - if (!results?.insertId || !json.meta?.table || !json.meta.table.primary) { - return json - } - const primaryKey = json.meta.table.primary?.[0] - json.extra = { - idFilter: { - equal: { - [primaryKey]: results.insertId, - }, - }, - } - return json - } - async query(json: QueryJson) { - const operation = this._operation(json) this.client.connect() - const input = this._query(json, { disableReturning: true }) - if (Array.isArray(input)) { - const responses = [] - for (let query of input) { - responses.push(await internalQuery(this.client, query, false)) - } - return responses - } - let row - // need to manage returning, a feature mySQL can't do - if (operation === operation.DELETE) { - row = this.getReturningRow(json) - } - const results = await internalQuery(this.client, input, false) - // same as delete, manage returning - if (operation === Operation.CREATE || operation === Operation.UPDATE) { - row = this.getReturningRow(this.checkLookupKeys(results, json)) - } + const queryFn = (query: any) => internalQuery(this.client, query, false) + const output = await this.queryWithReturning(json, queryFn) this.client.end() - if (operation !== Operation.READ) { - return row - } - return results.length ? results : [{ [operation.toLowerCase()]: true }] + return output } } diff --git a/packages/server/src/integrations/utils.ts b/packages/server/src/integrations/utils.ts index f91d25423..55ec086b7 100644 --- a/packages/server/src/integrations/utils.ts +++ b/packages/server/src/integrations/utils.ts @@ -1,4 +1,4 @@ -import { SqlQuery } from "../definitions/datasource" +import { Operation, SqlQuery } from "../definitions/datasource" import { Datasource, Table } from "../definitions/common" import { SourceNames } from "../definitions/datasource" const { DocumentTypes, SEPARATOR } = require("../db/utils") From 7c21645799da3b873b1ba1f0ca440c52b7a12345 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 8 Nov 2021 13:06:25 +0100 Subject: [PATCH 076/148] fix revert on unpublished app --- packages/server/src/api/controllers/dev.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/server/src/api/controllers/dev.js b/packages/server/src/api/controllers/dev.js index c43de7f55..ed58b8048 100644 --- a/packages/server/src/api/controllers/dev.js +++ b/packages/server/src/api/controllers/dev.js @@ -82,6 +82,13 @@ exports.revert = async ctx => { const db = new CouchDB(productionAppId, { skip_setup: true }) const info = await db.info() if (info.error) throw info.error + const deploymentDoc = await db.get(DocumentTypes.DEPLOYMENTS) + if ( + !deploymentDoc.history || + Object.keys(deploymentDoc.history).length === 0 + ) { + throw new Error("No deployments for app") + } } catch (err) { return ctx.throw(400, "App has not yet been deployed") } From 25965696fcca6f38b06f0c78a65bb31dfb3883f2 Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Mon, 8 Nov 2021 12:29:59 +0000 Subject: [PATCH 077/148] v0.9.179 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index df4c58df4..cea115bf1 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.178", + "version": "0.9.179", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 0d5171458..aeea64e2d 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.178", + "version": "0.9.179", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 4f7c369e1..00bd4051a 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.178", + "version": "0.9.179", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index d0376d611..2b88ce977 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.178", + "version": "0.9.179", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.178", - "@budibase/client": "^0.9.178", + "@budibase/bbui": "^0.9.179", + "@budibase/client": "^0.9.179", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.178", + "@budibase/string-templates": "^0.9.179", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 5cb584aa4..24c2c70b7 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.178", + "version": "0.9.179", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index ddfd50264..7f8a0a546 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.178", + "version": "0.9.179", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.178", + "@budibase/bbui": "^0.9.179", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.178", + "@budibase/string-templates": "^0.9.179", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index d55cdbdab..236e5175d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.178", + "version": "0.9.179", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.178", - "@budibase/client": "^0.9.178", - "@budibase/string-templates": "^0.9.178", + "@budibase/auth": "^0.9.179", + "@budibase/client": "^0.9.179", + "@budibase/string-templates": "^0.9.179", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 196ec9a0c..a3ed17a1a 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.178", + "version": "0.9.179", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 90da0e8cb..05a652e07 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.178", + "version": "0.9.179", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.178", - "@budibase/string-templates": "^0.9.178", + "@budibase/auth": "^0.9.179", + "@budibase/string-templates": "^0.9.179", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 7df3227432b4cc0ea6c0dad0526dcef7a514de07 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Mon, 8 Nov 2021 14:13:09 +0000 Subject: [PATCH 078/148] v0.9.180-alpha.0 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index cea115bf1..2b7b35e6f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.179", + "version": "0.9.180-alpha.0", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index aeea64e2d..91305f3cb 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 66b1f9ad9..ba325bcd0 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 2b88ce977..c362ce691 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.179", - "@budibase/client": "^0.9.179", + "@budibase/bbui": "^0.9.180-alpha.0", + "@budibase/client": "^0.9.180-alpha.0", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.179", + "@budibase/string-templates": "^0.9.180-alpha.0", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 24c2c70b7..02c0c8e08 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 7f8a0a546..c92508774 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.179", + "@budibase/bbui": "^0.9.180-alpha.0", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.179", + "@budibase/string-templates": "^0.9.180-alpha.0", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 236e5175d..27c274f2d 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.179", - "@budibase/client": "^0.9.179", - "@budibase/string-templates": "^0.9.179", + "@budibase/auth": "^0.9.180-alpha.0", + "@budibase/client": "^0.9.180-alpha.0", + "@budibase/string-templates": "^0.9.180-alpha.0", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index a3ed17a1a..187f72040 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 05a652e07..84650b771 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.179", + "version": "0.9.180-alpha.0", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.179", - "@budibase/string-templates": "^0.9.179", + "@budibase/auth": "^0.9.180-alpha.0", + "@budibase/string-templates": "^0.9.180-alpha.0", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 035879d5151d4fdfbe2dbaac1562e5b13265428d Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 8 Nov 2021 15:26:07 +0100 Subject: [PATCH 079/148] adding check to make sure production db isn't created on sync --- packages/server/src/api/controllers/application.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index e2e42c20f..ff4955f53 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -329,6 +329,19 @@ exports.sync = async ctx => { ctx.throw(400, "This action cannot be performed for production apps") } const prodAppId = getDeployedAppID(appId) + + try { + const prodDb = new CouchDB(prodAppId, { skip_setup: true }) + const info = await prodDb.info() + if (info.error) throw info.error + } catch (err) { + // the database doesn't exist. Don't replicate + ctx.body = { + message: "App sync completed successfully.", + } + return + } + const replication = new Replication({ source: prodAppId, target: appId, From 9fb811a8dae903f739e709b9077fef0ed11865a1 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Mon, 8 Nov 2021 15:26:44 +0100 Subject: [PATCH 080/148] change message when app not deployed --- packages/server/src/api/controllers/application.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/server/src/api/controllers/application.js b/packages/server/src/api/controllers/application.js index ff4955f53..f27efff29 100644 --- a/packages/server/src/api/controllers/application.js +++ b/packages/server/src/api/controllers/application.js @@ -337,7 +337,7 @@ exports.sync = async ctx => { } catch (err) { // the database doesn't exist. Don't replicate ctx.body = { - message: "App sync completed successfully.", + message: "App sync not required, app not deployed.", } return } From a7849eac7d354b04b3f353110c1f4f4c3a659642 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Nov 2021 14:35:58 +0000 Subject: [PATCH 081/148] Add card list with search block. Add concept of nested settings which can consume their own contexts and are not enriched at the top level --- .../builder/src/builderStore/dataBinding.js | 48 +++- .../design/AppPreview/componentStructure.json | 3 +- .../ComponentSettingsSection.svelte | 83 +++--- .../PropertiesPanel/PropertiesPanel.svelte | 10 +- .../PropertyControls/PropertyControl.svelte | 18 +- packages/client/manifest.json | 155 ++++++++++- .../src/components/BlockComponent.svelte | 3 +- .../client/src/components/Component.svelte | 135 +++++++--- .../src/components/app/SpectrumCard.svelte | 13 + .../app/blocks/CardListWithSearch.svelte | 240 ++++++++++++++++++ .../client/src/components/app/blocks/index.js | 1 + packages/client/src/stores/context.js | 3 +- 12 files changed, 616 insertions(+), 96 deletions(-) create mode 100644 packages/client/src/components/app/blocks/CardListWithSearch.svelte diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 742c9052a..165ed37fb 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -39,6 +39,25 @@ export const getBindableProperties = (asset, componentId) => { ] } +/** + * Gets the bindable properties exposed by a certain component. + */ +export const getComponentBindableProperties = (asset, componentId) => { + if (!asset || !componentId) { + return [] + } + + // Ensure that the component exists and exposes context + const component = findComponent(asset.props, componentId) + const def = store.actions.components.getDefinition(component?._component) + if (!def?.context) { + return [] + } + + // Get the bindings for the component + return getProviderContextBindings(asset, component) +} + /** * Gets all data provider components above a component. */ @@ -125,9 +144,26 @@ export const getDatasourceForProvider = (asset, component) => { const getContextBindings = (asset, componentId) => { // Extract any components which provide data contexts const dataProviders = getDataProviderComponents(asset, componentId) - let bindings = [] + + // Generate bindings for all matching components + return getProviderContextBindings(asset, dataProviders) +} + +/** + * Gets the context bindings exposed by a set of data provider components. + */ +const getProviderContextBindings = (asset, dataProviders) => { + if (!asset || !dataProviders) { + return [] + } + + // Ensure providers is an array + if (!Array.isArray(dataProviders)) { + dataProviders = [dataProviders] + } // Create bindings for each data provider + let bindings = [] dataProviders.forEach(component => { const def = store.actions.components.getDefinition(component._component) const contexts = Array.isArray(def.context) ? def.context : [def.context] @@ -140,6 +176,7 @@ const getContextBindings = (asset, componentId) => { let schema let readablePrefix + let runtimeSuffix = context.suffix if (context.type === "form") { // Forms do not need table schemas @@ -169,8 +206,14 @@ const getContextBindings = (asset, componentId) => { const keys = Object.keys(schema).sort() + // Generate safe unique runtime prefix + let runtimeId = component._id + if (runtimeSuffix) { + runtimeId += `-${runtimeSuffix}` + } + const safeComponentId = makePropSafe(runtimeId) + // Create bindable properties for each schema field - const safeComponentId = makePropSafe(component._id) keys.forEach(key => { const fieldSchema = schema[key] @@ -182,6 +225,7 @@ const getContextBindings = (asset, componentId) => { } else if (fieldSchema.type === "attachment") { runtimeBoundKey = `${key}_first` } + const runtimeBinding = `${safeComponentId}.${makePropSafe( runtimeBoundKey )}` diff --git a/packages/builder/src/components/design/AppPreview/componentStructure.json b/packages/builder/src/components/design/AppPreview/componentStructure.json index b6675c248..9a87bb576 100644 --- a/packages/builder/src/components/design/AppPreview/componentStructure.json +++ b/packages/builder/src/components/design/AppPreview/componentStructure.json @@ -3,7 +3,8 @@ "name": "Blocks", "icon": "Article", "children": [ - "tablewithsearch" + "tablewithsearch", + "cardlistwithsearch" ] }, "section", diff --git a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte index f7123eb9e..356e86b20 100644 --- a/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/ComponentSettingsSection.svelte @@ -12,6 +12,7 @@ export let componentInstance export let assetInstance export let bindings + export let componentBindings const layoutDefinition = [] const screenDefinition = [ @@ -21,12 +22,24 @@ { key: "layoutId", label: "Layout", control: LayoutSelect }, ] - $: settings = componentDefinition?.settings ?? [] - $: generalSettings = settings.filter(setting => !setting.section) - $: sections = settings.filter(setting => setting.section) + $: sections = getSections(componentDefinition) $: isLayout = assetInstance && assetInstance.favicon $: assetDefinition = isLayout ? layoutDefinition : screenDefinition + const getSections = definition => { + const settings = definition?.settings ?? [] + const generalSettings = settings.filter(setting => !setting.section) + const customSections = settings.filter(setting => setting.section) + return [ + { + name: "General", + info: componentDefinition?.info, + settings: generalSettings, + }, + ...(customSections || []), + ] + } + const updateProp = store.actions.components.updateProp const canRenderControl = setting => { @@ -61,53 +74,18 @@ } - - {#if !componentInstance._component.endsWith("/layout")} - updateProp("_instanceName", val)} - /> - {/if} - {#if generalSettings.length} - {#each generalSettings as setting (setting.key)} - {#if canRenderControl(setting)} - updateProp(setting.key, val)} - props={{ - options: setting.options || [], - placeholder: setting.placeholder || null, - min: setting.min || null, - max: setting.max || null, - }} - {bindings} - {componentDefinition} - /> - {/if} - {/each} - {/if} - {#if componentDefinition?.component?.endsWith("/fieldgroup")} - - {/if} - {#if componentDefinition?.info} -
- {@html componentDefinition.info} -
- {/if} -
- -{#each sections as section (section.name)} +{#each sections as section, idx (section.name)} + {#if idx === 0 && !componentInstance._component.endsWith("/layout")} + updateProp("_instanceName", val)} + /> + {/if} {#each section.settings as setting (setting.key)} {#if canRenderControl(setting)} updateProp(setting.key, val)} props={{ options: setting.options || [], @@ -126,10 +104,15 @@ max: setting.max || null, }} {bindings} + {componentBindings} + {componentInstance} {componentDefinition} /> {/if} {/each} + {#if idx === 0 && componentDefinition?.component?.endsWith("/fieldgroup")} + + {/if} {#if section?.info}
{@html section.info} diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte index 27f6650cd..df91a8745 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertiesPanel.svelte @@ -6,13 +6,20 @@ import DesignSection from "./DesignSection.svelte" import CustomStylesSection from "./CustomStylesSection.svelte" import ConditionalUISection from "./ConditionalUISection.svelte" - import { getBindableProperties } from "builderStore/dataBinding" + import { + getBindableProperties, + getComponentBindableProperties, + } from "builderStore/dataBinding" $: componentInstance = $selectedComponent $: componentDefinition = store.actions.components.getDefinition( $selectedComponent?._component ) $: bindings = getBindableProperties($currentAsset, $store.selectedComponentId) + $: componentBindings = getComponentBindableProperties( + $currentAsset, + $store.selectedComponentId + ) @@ -28,6 +35,7 @@ {componentInstance} {componentDefinition} {bindings} + {componentBindings} /> {} export let bindings = [] + export let componentBindings = [] + export let nested = false let bindingDrawer let anchor let valid - $: safeValue = getSafeValue(value, props.defaultValue, bindings) + $: allBindings = getAllBindings(bindings, componentBindings, nested) + $: safeValue = getSafeValue(value, props.defaultValue, allBindings) $: tempValue = safeValue - $: replaceBindings = val => readableToRuntimeBinding(bindings, val) + $: replaceBindings = val => readableToRuntimeBinding(allBindings, val) + + const getAllBindings = (bindings, componentBindings, nested) => { + if (!nested) { + return bindings + } + return [...(bindings || []), ...(componentBindings || [])] + } const handleClose = () => { handleChange(tempValue) @@ -78,7 +88,7 @@ updateOnChange={false} on:change={handleChange} onChange={handleChange} - {bindings} + bindings={allBindings} name={key} text={label} {type} @@ -104,7 +114,7 @@ bind:valid value={safeValue} on:change={e => (tempValue = e.detail)} - bindableProperties={bindings} + bindableProperties={allBindings} allowJS /> diff --git a/packages/client/manifest.json b/packages/client/manifest.json index 982f96ef9..f3ba71223 100644 --- a/packages/client/manifest.json +++ b/packages/client/manifest.json @@ -2599,6 +2599,21 @@ "type": "boolean", "key": "horizontal", "label": "Horizontal" + }, + { + "type": "boolean", + "label": "Show button", + "key": "showButton" + }, + { + "type": "text", + "key": "buttonText", + "label": "Button text" + }, + { + "type": "event", + "label": "Button action", + "key": "buttonOnClick" } ] }, @@ -2710,22 +2725,22 @@ }, { "section": true, - "name": "Button", + "name": "Title button", "settings": [ { "type": "boolean", "key": "showTitleButton", - "label": "Show title button", + "label": "Show button", "defaultValue": false }, { "type": "text", "key": "titleButtonText", - "label": "Title button text" + "label": "Button text" }, { "type": "event", - "label": "Title button action", + "label": "Button action", "key": "titleButtonOnClick" } ] @@ -2742,9 +2757,139 @@ } ] } + ] + }, + "cardlistwithsearch": { + "block": true, + "name": "Card list with search", + "icon": "Table", + "styles": ["size"], + "info": "Only the first 3 search columns will be used.", + "settings": [ + { + "type": "text", + "label": "Title", + "key": "title" + }, + { + "type": "dataSource", + "label": "Data", + "key": "dataSource" + }, + { + "type": "multifield", + "label": "Search Columns", + "key": "searchColumns", + "placeholder": "Choose search columns" + }, + { + "type": "filter", + "label": "Filtering", + "key": "filter" + }, + { + "type": "field", + "label": "Sort Column", + "key": "sortColumn" + }, + { + "type": "select", + "label": "Sort Order", + "key": "sortOrder", + "options": ["Ascending", "Descending"], + "defaultValue": "Descending" + }, + { + "type": "number", + "label": "Limit", + "key": "limit", + "defaultValue": 10 + }, + { + "type": "boolean", + "label": "Paginate", + "key": "paginate" + }, + { + "section": true, + "name": "Cards", + "settings": [ + { + "type": "text", + "key": "cardTitle", + "label": "Title", + "nested": true + }, + { + "type": "text", + "key": "cardSubtitle", + "label": "Subtitle", + "nested": true + }, + { + "type": "text", + "key": "cardDescription", + "label": "Description", + "nested": true + + }, + { + "type": "text", + "key": "cardImageURL", + "label": "Image URL", + "nested": true + + }, + { + "type": "boolean", + "key": "cardHorizontal", + "label": "Horizontal" + }, + { + "type": "boolean", + "label": "Show button", + "key": "showCardButton" + }, + { + "type": "text", + "key": "cardButtonText", + "label": "Button text", + "nested": true + + }, + { + "type": "event", + "label": "Button action", + "key": "cardButtonOnClick", + "nested": true + } + ] + }, + { + "section": true, + "name": "Title button", + "settings": [ + { + "type": "boolean", + "key": "showTitleButton", + "label": "Show button" + }, + { + "type": "text", + "key": "titleButtonText", + "label": "Button text" + }, + { + "type": "event", + "label": "Button action", + "key": "titleButtonOnClick" + } + ] + } ], "context": { - "type": "schema" + "type": "schema", + "suffix": "repeater" } } } diff --git a/packages/client/src/components/BlockComponent.svelte b/packages/client/src/components/BlockComponent.svelte index 02456322d..589998994 100644 --- a/packages/client/src/components/BlockComponent.svelte +++ b/packages/client/src/components/BlockComponent.svelte @@ -6,6 +6,7 @@ export let type export let props export let styles + export let context // ID is only exposed as a prop so that it can be bound to from parent // block components @@ -16,7 +17,7 @@ // Create a fake component instance so that we can use the core Component // to render this part of the block, taking advantage of binding enrichment - $: id = block.id + rand + $: id = `${block.id}-${context ?? rand}` $: instance = { _component: `@budibase/standard-components/${type}`, _id: id, diff --git a/packages/client/src/components/Component.svelte b/packages/client/src/components/Component.svelte index c13a50d52..346de98f2 100644 --- a/packages/client/src/components/Component.svelte +++ b/packages/client/src/components/Component.svelte @@ -1,3 +1,7 @@ + + {#key renderKey} - {#if constructor && componentSettings && (visible || inSelectedPath)} + {#if constructor && settings && (visible || inSelectedPath)}
- + {#if children.length} {#each children as child (child._id)} diff --git a/packages/client/src/components/app/SpectrumCard.svelte b/packages/client/src/components/app/SpectrumCard.svelte index bac0a81fb..ba3e919cd 100644 --- a/packages/client/src/components/app/SpectrumCard.svelte +++ b/packages/client/src/components/app/SpectrumCard.svelte @@ -1,6 +1,7 @@ + + +
+ + {#if title || enrichedSearchColumns?.length || showTitleButton} +
+
+ {title || ""} +
+
+ {#if enrichedSearchColumns?.length} + + {/if} + {#if showTitleButton} + + {/if} +
+
+ {/if} + + + + + + +
+
+ + diff --git a/packages/client/src/components/app/blocks/index.js b/packages/client/src/components/app/blocks/index.js index 16b123d17..7d0d15080 100644 --- a/packages/client/src/components/app/blocks/index.js +++ b/packages/client/src/components/app/blocks/index.js @@ -1 +1,2 @@ export { default as tablewithsearch } from "./TableWithSearch.svelte" +export { default as cardlistwithsearch } from "./CardListWithSearch.svelte" diff --git a/packages/client/src/stores/context.js b/packages/client/src/stores/context.js index e372b837b..fcbcf0f59 100644 --- a/packages/client/src/stores/context.js +++ b/packages/client/src/stores/context.js @@ -1,4 +1,5 @@ import { writable, derived } from "svelte/store" +import { hashString } from "../utils/helpers" export const createContextStore = oldContext => { const newContext = writable({}) @@ -9,7 +10,7 @@ export const createContextStore = oldContext => { for (let i = 0; i < $contexts.length - 1; i++) { key += $contexts[i].key } - key += JSON.stringify($contexts[$contexts.length - 1]) + key = hashString(key + JSON.stringify($contexts[$contexts.length - 1])) // Reduce global state const reducer = (total, context) => ({ ...total, ...context }) From 65837abcc049b80e551dc57564f26b6dbab99b95 Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Mon, 8 Nov 2021 14:36:40 +0000 Subject: [PATCH 082/148] v0.9.180 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index cea115bf1..afd137b06 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.179", + "version": "0.9.180", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index aeea64e2d..ec0270dd2 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.179", + "version": "0.9.180", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 00bd4051a..b70d9241b 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.179", + "version": "0.9.180", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 2b88ce977..d06f70285 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.179", + "version": "0.9.180", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.179", - "@budibase/client": "^0.9.179", + "@budibase/bbui": "^0.9.180", + "@budibase/client": "^0.9.180", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.179", + "@budibase/string-templates": "^0.9.180", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 24c2c70b7..ac2523ec3 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.179", + "version": "0.9.180", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 7f8a0a546..1ebe4dc1a 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.179", + "version": "0.9.180", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.179", + "@budibase/bbui": "^0.9.180", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.179", + "@budibase/string-templates": "^0.9.180", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 236e5175d..555ae6893 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.179", + "version": "0.9.180", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.179", - "@budibase/client": "^0.9.179", - "@budibase/string-templates": "^0.9.179", + "@budibase/auth": "^0.9.180", + "@budibase/client": "^0.9.180", + "@budibase/string-templates": "^0.9.180", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index a3ed17a1a..8b96ae250 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.179", + "version": "0.9.180", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 05a652e07..486482734 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.179", + "version": "0.9.180", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.179", - "@budibase/string-templates": "^0.9.179", + "@budibase/auth": "^0.9.180", + "@budibase/string-templates": "^0.9.180", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 37c2690a316544b19d835319aba01f50a5bd8c77 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Nov 2021 14:51:13 +0000 Subject: [PATCH 083/148] Fix card button text potentially showing as undefined --- packages/client/src/components/app/SpectrumCard.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/client/src/components/app/SpectrumCard.svelte b/packages/client/src/components/app/SpectrumCard.svelte index ba3e919cd..981ac98d9 100644 --- a/packages/client/src/components/app/SpectrumCard.svelte +++ b/packages/client/src/components/app/SpectrumCard.svelte @@ -66,7 +66,7 @@ {/if} {#if showButton} {/if}
From 9883fdb623140d24bd8d2276283949f1ea76d758 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Mon, 8 Nov 2021 16:40:45 +0000 Subject: [PATCH 084/148] Fix card list block empty state and update size --- .../client/src/components/app/Repeater.svelte | 1 + .../src/components/app/SpectrumCard.svelte | 16 ++++++++++++++-- .../app/blocks/CardListWithSearch.svelte | 9 +++------ 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/packages/client/src/components/app/Repeater.svelte b/packages/client/src/components/app/Repeater.svelte index 79f044f40..ff077f359 100644 --- a/packages/client/src/components/app/Repeater.svelte +++ b/packages/client/src/components/app/Repeater.svelte @@ -38,6 +38,7 @@ padding: var(--spacing-l); display: grid; place-items: center; + grid-column: 1 / -1; } .noRows i { margin-bottom: var(--spacing-m); diff --git a/packages/client/src/components/app/SpectrumCard.svelte b/packages/client/src/components/app/SpectrumCard.svelte index 981ac98d9..d8353eea7 100644 --- a/packages/client/src/components/app/SpectrumCard.svelte +++ b/packages/client/src/components/app/SpectrumCard.svelte @@ -74,7 +74,7 @@ diff --git a/packages/client/src/components/app/blocks/CardListWithSearch.svelte b/packages/client/src/components/app/blocks/CardListWithSearch.svelte index 3e320bfee..a750a3736 100644 --- a/packages/client/src/components/app/blocks/CardListWithSearch.svelte +++ b/packages/client/src/components/app/blocks/CardListWithSearch.svelte @@ -41,7 +41,7 @@ $: enrichedSearchColumns = enrichSearchColumns(searchColumns, schema) $: enrichedFilter = enrichFilter(filter, enrichedSearchColumns, formId) - $: cardWidth = cardHorizontal ? 420 : 240 + $: cardWidth = cardHorizontal ? 420 : 300 // Enrich the default filter with the specified search fields const enrichFilter = (filter, columns, formId) => { @@ -140,9 +140,10 @@ props={{ dataProvider: `{{ literal [${dataProviderId}] }}`, direction: "row", - hAlign: "left", + hAlign: "stretch", vAlign: "top", gap: "M", + noRowsMessage: "No rows found", }} styles={{ display: "grid", @@ -172,10 +173,6 @@ diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte index fb8b48b9e..dc2fa7ad8 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/URLSelect.svelte @@ -10,4 +10,10 @@ .filter(x => x != null) - + diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js index 69bb3f8b4..b9b227bef 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/componentSettings.js @@ -15,10 +15,10 @@ import URLSelect from "./URLSelect.svelte" import OptionsEditor from "./OptionsEditor/OptionsEditor.svelte" import FormFieldSelect from "./FormFieldSelect.svelte" import ValidationEditor from "./ValidationEditor/ValidationEditor.svelte" -import Input from "./Input.svelte" +import DrawerBindableCombobox from "components/common/bindings/DrawerBindableCombobox.svelte" const componentMap = { - text: Input, + text: DrawerBindableCombobox, select: Select, dataSource: DataSourceSelect, dataProvider: DataProviderSelect, diff --git a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte index efe51ebda..4a7c77746 100644 --- a/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/ScreenSettingsSection.svelte @@ -54,7 +54,6 @@ {#each screenSettings as def (`${componentInstance._id}-${def.key}`)} Date: Wed, 10 Nov 2021 11:48:02 +0000 Subject: [PATCH 114/148] Update block search so that string fields do a 'starts with' search rather than an exact match --- .../client/src/components/app/blocks/CardListWithSearch.svelte | 3 ++- .../client/src/components/app/blocks/TableWithSearch.svelte | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/client/src/components/app/blocks/CardListWithSearch.svelte b/packages/client/src/components/app/blocks/CardListWithSearch.svelte index a750a3736..7c9a067bd 100644 --- a/packages/client/src/components/app/blocks/CardListWithSearch.svelte +++ b/packages/client/src/components/app/blocks/CardListWithSearch.svelte @@ -49,7 +49,7 @@ columns?.forEach(column => { enrichedFilter.push({ field: column.name, - operator: "equal", + operator: column.type === "string" ? "string" : "equal", type: "string", valueType: "Binding", value: `{{ [${formId}].[${column.name}] }}`, @@ -68,6 +68,7 @@ enrichedColumns.push({ name: column, componentType, + type: schemaType, }) } }) diff --git a/packages/client/src/components/app/blocks/TableWithSearch.svelte b/packages/client/src/components/app/blocks/TableWithSearch.svelte index 378a11157..12a202268 100644 --- a/packages/client/src/components/app/blocks/TableWithSearch.svelte +++ b/packages/client/src/components/app/blocks/TableWithSearch.svelte @@ -48,7 +48,7 @@ columns?.forEach(column => { enrichedFilter.push({ field: column.name, - operator: "equal", + operator: column.type === "string" ? "string" : "equal", type: "string", valueType: "Binding", value: `{{ [${formId}].[${column.name}] }}`, @@ -67,6 +67,7 @@ enrichedColumns.push({ name: column, componentType, + type: schemaType, }) } }) From d6051e7067c2a676c6bade22316fa0915184abc9 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 10 Nov 2021 11:58:27 +0000 Subject: [PATCH 115/148] Add cypress data tag to binding icon in drawer bindable combo box --- .../common/bindings/DrawerBindableCombobox.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte b/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte index ba5a869e7..af0732eb8 100644 --- a/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte +++ b/packages/builder/src/components/common/bindings/DrawerBindableCombobox.svelte @@ -62,7 +62,11 @@ options={allOptions} /> {#if !disabled} -
+
{/if} From 47122f76fd1fb961cd929ed963acf51cbe7f9512 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 10 Nov 2021 12:00:29 +0000 Subject: [PATCH 116/148] Updating per review comments. --- packages/auth/src/db/utils.js | 18 ++++++++++++++++++ packages/server/src/api/controllers/user.js | 18 ++++++++---------- packages/server/src/api/routes/user.js | 2 +- packages/worker/src/utilities/appService.js | 21 ++++++++++++++------- 4 files changed, 41 insertions(+), 18 deletions(-) diff --git a/packages/auth/src/db/utils.js b/packages/auth/src/db/utils.js index 03bd77392..b95608966 100644 --- a/packages/auth/src/db/utils.js +++ b/packages/auth/src/db/utils.js @@ -259,6 +259,24 @@ exports.getAllApps = async (CouchDB, { dev, all, idsOnly } = {}) => { } } +/** + * Utility function for getAllApps but filters to production apps only. + */ +exports.getDeployedAppIDs = async CouchDB => { + return (await exports.getAllApps(CouchDB, { idsOnly: true })).filter( + id => !exports.isDevAppID(id) + ) +} + +/** + * Utility function for the inverse of above. + */ +exports.getDevAppIDs = async CouchDB => { + return (await exports.getAllApps(CouchDB, { idsOnly: true })).filter(id => + exports.isDevAppID(id) + ) +} + exports.dbExists = async (CouchDB, dbName) => { let exists = false try { diff --git a/packages/server/src/api/controllers/user.js b/packages/server/src/api/controllers/user.js index 5faf82134..908018fe5 100644 --- a/packages/server/src/api/controllers/user.js +++ b/packages/server/src/api/controllers/user.js @@ -8,11 +8,7 @@ const { getGlobalUsers, getRawGlobalUser } = require("../../utilities/global") const { getFullUser } = require("../../utilities/users") const { isEqual } = require("lodash") const { BUILTIN_ROLE_IDS } = require("@budibase/auth/roles") -const { - getDevelopmentAppID, - getAllApps, - isDevAppID, -} = require("@budibase/auth/db") +const { getDevelopmentAppID, getDeployedAppIDs } = require("@budibase/auth/db") const { doesDatabaseExist } = require("../../utilities") const { UserStatus } = require("@budibase/auth/constants") @@ -78,8 +74,12 @@ exports.syncUser = async function (ctx) { try { user = await getRawGlobalUser(userId) } catch (err) { - user = {} - deleting = true + if (err && err.status === 404) { + user = {} + deleting = true + } else { + throw err + } } const roles = user.roles // remove props which aren't useful to metadata @@ -90,9 +90,7 @@ exports.syncUser = async function (ctx) { let prodAppIds // if they are a builder then get all production app IDs if ((user.builder && user.builder.global) || deleting) { - prodAppIds = (await getAllApps(CouchDB, { idsOnly: true })).filter( - id => !isDevAppID(id) - ) + prodAppIds = await getDeployedAppIDs(CouchDB) } else { prodAppIds = Object.entries(roles) .filter(entry => entry[1] !== BUILTIN_ROLE_IDS.PUBLIC) diff --git a/packages/server/src/api/routes/user.js b/packages/server/src/api/routes/user.js index 43c08a7f3..a3043b5af 100644 --- a/packages/server/src/api/routes/user.js +++ b/packages/server/src/api/routes/user.js @@ -35,7 +35,7 @@ router controller.destroyMetadata ) .post( - "/api/users/sync/:id", + "/api/users/metadata/sync/:id", authorized(PermissionTypes.USER, PermissionLevels.WRITE), controller.syncUser ) diff --git a/packages/worker/src/utilities/appService.js b/packages/worker/src/utilities/appService.js index 166a82f78..92809c904 100644 --- a/packages/worker/src/utilities/appService.js +++ b/packages/worker/src/utilities/appService.js @@ -4,7 +4,7 @@ const { getTenantId, isTenantIdSet } = require("@budibase/auth/tenancy") const { checkSlashesInUrl } = require("../utilities") const env = require("../environment") -exports.syncUserInApps = async userId => { +async function makeAppRequest(url, method, body) { if (env.isTest()) { return } @@ -13,12 +13,19 @@ exports.syncUserInApps = async userId => { if (isTenantIdSet()) { request.headers[Headers.TENANT_ID] = getTenantId() } - request.headers["Content-Type"] = "application/json" - request.body = JSON.stringify({}) - request.method = "POST" - const response = await fetch( - checkSlashesInUrl(env.APPS_URL + `/api/users/sync/${userId}`), - request + if (body) { + request.headers["Content-Type"] = "application/json" + request.body = JSON.stringify(body) + } + request.method = method + return fetch(checkSlashesInUrl(env.APPS_URL + url), request) +} + +exports.syncUserInApps = async userId => { + const response = await makeAppRequest( + `/api/users/metadata/sync/${userId}`, + "POST", + {} ) if (response.status !== 200) { throw "Unable to sync user." From f5406cecf2a68b06ef715f15a1b6335b2e79351e Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 10 Nov 2021 13:04:59 +0100 Subject: [PATCH 117/148] fix cypress tests --- packages/builder/cypress/support/commands.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index ff1d13d6c..5682dcb2e 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -43,16 +43,14 @@ Cypress.Commands.add("createApp", name => { }) }) -Cypress.Commands.add("deleteApp", appName => { +Cypress.Commands.add("deleteApp", () => { cy.visit(`localhost:${Cypress.env("PORT")}/builder`) cy.wait(1000) cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`) .its("body") .then(val => { - console.log(val) if (val.length > 0) { cy.get(".title > :nth-child(3) > .spectrum-Icon").click() - cy.get("input").type(appName) cy.contains("Delete").click() cy.get(".spectrum-Button--warning").click() } From c62741a31103885a53a54a5184838097bb47daf8 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 10 Nov 2021 12:17:43 +0000 Subject: [PATCH 118/148] v0.9.180-alpha.4 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index 3410e9fd8..a99572473 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 1552bece1..8187b8791 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index bdc524a39..8cdaafcdf 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 6f68915cb..3cc2758d9 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.3", - "@budibase/client": "^0.9.180-alpha.3", + "@budibase/bbui": "^0.9.180-alpha.4", + "@budibase/client": "^0.9.180-alpha.4", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.180-alpha.3", + "@budibase/string-templates": "^0.9.180-alpha.4", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index f78889201..922e60e28 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index f0ccea1ec..c93e5e80f 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.3", + "@budibase/bbui": "^0.9.180-alpha.4", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.180-alpha.3", + "@budibase/string-templates": "^0.9.180-alpha.4", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 36a3efd91..5c790e803 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.3", - "@budibase/client": "^0.9.180-alpha.3", - "@budibase/string-templates": "^0.9.180-alpha.3", + "@budibase/auth": "^0.9.180-alpha.4", + "@budibase/client": "^0.9.180-alpha.4", + "@budibase/string-templates": "^0.9.180-alpha.4", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index eae4595d9..9cab05b62 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 07b8644ab..261107db7 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.180-alpha.3", + "version": "0.9.180-alpha.4", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.3", - "@budibase/string-templates": "^0.9.180-alpha.3", + "@budibase/auth": "^0.9.180-alpha.4", + "@budibase/string-templates": "^0.9.180-alpha.4", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From a20d21ebf58bc7ed0daa07f77dea8d58efd17fa7 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 10 Nov 2021 12:29:11 +0000 Subject: [PATCH 119/148] v0.9.180-alpha.5 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index a99572473..f32daef8b 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 8187b8791..45957402d 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 8cdaafcdf..1a80c23ca 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 3cc2758d9..279bb0ec3 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.4", - "@budibase/client": "^0.9.180-alpha.4", + "@budibase/bbui": "^0.9.180-alpha.5", + "@budibase/client": "^0.9.180-alpha.5", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.180-alpha.4", + "@budibase/string-templates": "^0.9.180-alpha.5", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 922e60e28..1b7487b0e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index c93e5e80f..6b6c3d172 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.4", + "@budibase/bbui": "^0.9.180-alpha.5", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.180-alpha.4", + "@budibase/string-templates": "^0.9.180-alpha.5", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 5c790e803..1e7351b8c 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.4", - "@budibase/client": "^0.9.180-alpha.4", - "@budibase/string-templates": "^0.9.180-alpha.4", + "@budibase/auth": "^0.9.180-alpha.5", + "@budibase/client": "^0.9.180-alpha.5", + "@budibase/string-templates": "^0.9.180-alpha.5", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index 9cab05b62..d56cc3466 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 261107db7..6dccc5e52 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.180-alpha.4", + "version": "0.9.180-alpha.5", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.4", - "@budibase/string-templates": "^0.9.180-alpha.4", + "@budibase/auth": "^0.9.180-alpha.5", + "@budibase/string-templates": "^0.9.180-alpha.5", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 18b98a158a034f059b01009bc47720865a687ab4 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 10 Nov 2021 12:52:23 +0000 Subject: [PATCH 120/148] Fixing issue found by test case. --- packages/worker/src/utilities/appService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/worker/src/utilities/appService.js b/packages/worker/src/utilities/appService.js index 92809c904..23c558151 100644 --- a/packages/worker/src/utilities/appService.js +++ b/packages/worker/src/utilities/appService.js @@ -27,7 +27,7 @@ exports.syncUserInApps = async userId => { "POST", {} ) - if (response.status !== 200) { + if (response && response.status !== 200) { throw "Unable to sync user." } } From 8f7b57837e74a301bc097759c95163457ccd3e94 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 10 Nov 2021 14:08:34 +0100 Subject: [PATCH 121/148] adding cypress tag to input --- packages/builder/cypress/support/commands.js | 4 ++-- packages/builder/src/pages/builder/portal/apps/index.svelte | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index 5682dcb2e..af60272d4 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -43,7 +43,7 @@ Cypress.Commands.add("createApp", name => { }) }) -Cypress.Commands.add("deleteApp", () => { +Cypress.Commands.add("deleteApp", appName => { cy.visit(`localhost:${Cypress.env("PORT")}/builder`) cy.wait(1000) cy.request(`localhost:${Cypress.env("PORT")}/api/applications?status=all`) @@ -51,7 +51,7 @@ Cypress.Commands.add("deleteApp", () => { .then(val => { if (val.length > 0) { cy.get(".title > :nth-child(3) > .spectrum-Icon").click() - cy.contains("Delete").click() + cy.get(`[data-cy="delete-app-confirmation"]`).type(appName) cy.get(".spectrum-Button--warning").click() } }) diff --git a/packages/builder/src/pages/builder/portal/apps/index.svelte b/packages/builder/src/pages/builder/portal/apps/index.svelte index d465f7b97..53ad661f7 100644 --- a/packages/builder/src/pages/builder/portal/apps/index.svelte +++ b/packages/builder/src/pages/builder/portal/apps/index.svelte @@ -303,7 +303,7 @@ Are you sure you want to delete the app {selectedApp?.name}?

Please enter the app name below to confirm.

- + Date: Wed, 10 Nov 2021 13:50:18 +0000 Subject: [PATCH 122/148] v0.9.180-alpha.6 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index f32daef8b..6c39265db 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 45957402d..2cbb76f44 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 1a80c23ca..6a407d285 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 279bb0ec3..4b1951762 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.5", - "@budibase/client": "^0.9.180-alpha.5", + "@budibase/bbui": "^0.9.180-alpha.6", + "@budibase/client": "^0.9.180-alpha.6", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.180-alpha.5", + "@budibase/string-templates": "^0.9.180-alpha.6", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 1b7487b0e..70f800e85 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 6b6c3d172..83240ea6c 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.5", + "@budibase/bbui": "^0.9.180-alpha.6", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.180-alpha.5", + "@budibase/string-templates": "^0.9.180-alpha.6", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 1e7351b8c..5df56f7be 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.5", - "@budibase/client": "^0.9.180-alpha.5", - "@budibase/string-templates": "^0.9.180-alpha.5", + "@budibase/auth": "^0.9.180-alpha.6", + "@budibase/client": "^0.9.180-alpha.6", + "@budibase/string-templates": "^0.9.180-alpha.6", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index d56cc3466..f9d280e7a 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 6dccc5e52..606337b78 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.180-alpha.5", + "version": "0.9.180-alpha.6", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.5", - "@budibase/string-templates": "^0.9.180-alpha.5", + "@budibase/auth": "^0.9.180-alpha.6", + "@budibase/string-templates": "^0.9.180-alpha.6", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 91a9e78e928c5a625b8f146c248cd26cc53bf0f3 Mon Sep 17 00:00:00 2001 From: Martin McKeaveney Date: Wed, 10 Nov 2021 14:57:46 +0100 Subject: [PATCH 123/148] fix renaming an app --- .../cypress/integration/renameAnApplication.spec.js | 3 ++- packages/builder/cypress/support/commands.js | 7 +++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/builder/cypress/integration/renameAnApplication.spec.js b/packages/builder/cypress/integration/renameAnApplication.spec.js index b9da64989..95a152c01 100644 --- a/packages/builder/cypress/integration/renameAnApplication.spec.js +++ b/packages/builder/cypress/integration/renameAnApplication.spec.js @@ -11,7 +11,8 @@ it("should rename an unpublished application", () => { renameApp(appRename) cy.searchForApplication(appRename) cy.get(".appGrid").find(".wrapper").should("have.length", 1) - }) + cy.deleteApp(appRename) +}) xit("Should rename a published application", () => { // It is not possible to rename a published application diff --git a/packages/builder/cypress/support/commands.js b/packages/builder/cypress/support/commands.js index af60272d4..ca758e46d 100644 --- a/packages/builder/cypress/support/commands.js +++ b/packages/builder/cypress/support/commands.js @@ -51,8 +51,11 @@ Cypress.Commands.add("deleteApp", appName => { .then(val => { if (val.length > 0) { cy.get(".title > :nth-child(3) > .spectrum-Icon").click() - cy.get(`[data-cy="delete-app-confirmation"]`).type(appName) - cy.get(".spectrum-Button--warning").click() + cy.contains("Delete").click() + cy.get(".spectrum-Modal").within(() => { + cy.get("input").type(appName) + cy.get(".spectrum-Button--warning").click() + }) } }) }) From 34e04e3837ca251e015269461f117d6bf419ebe7 Mon Sep 17 00:00:00 2001 From: Budibase Release Bot <> Date: Wed, 10 Nov 2021 14:28:28 +0000 Subject: [PATCH 124/148] v0.9.183 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index a81b847a0..b197f911f 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.182", + "version": "0.9.183", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 5d8ecd7ee..426616b64 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.182", + "version": "0.9.183", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 971780b06..ce8e0268d 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.182", + "version": "0.9.183", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index af055551b..5006ba1a4 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.182", + "version": "0.9.183", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.182", - "@budibase/client": "^0.9.182", + "@budibase/bbui": "^0.9.183", + "@budibase/client": "^0.9.183", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.182", + "@budibase/string-templates": "^0.9.183", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 3343ceeec..d39bf5ea5 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.182", + "version": "0.9.183", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index c7e955e13..b3d43fe9b 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.182", + "version": "0.9.183", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.182", + "@budibase/bbui": "^0.9.183", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.182", + "@budibase/string-templates": "^0.9.183", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 3deac54a0..927ae42e2 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.182", + "version": "0.9.183", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.182", - "@budibase/client": "^0.9.182", - "@budibase/string-templates": "^0.9.182", + "@budibase/auth": "^0.9.183", + "@budibase/client": "^0.9.183", + "@budibase/string-templates": "^0.9.183", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index d7ae7c8c8..be90f4402 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.182", + "version": "0.9.183", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 80409b0d8..1b63d5f08 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.182", + "version": "0.9.183", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.182", - "@budibase/string-templates": "^0.9.182", + "@budibase/auth": "^0.9.183", + "@budibase/string-templates": "^0.9.183", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 4e6a9c81548ae00b4d968d09e8e16473f995a259 Mon Sep 17 00:00:00 2001 From: Peter Clement Date: Wed, 10 Nov 2021 14:43:07 +0000 Subject: [PATCH 125/148] fix width of automation blocks --- .../automation/AutomationBuilder/FlowChart/FlowItem.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte index 74e82a2da..7ddc5c3e4 100644 --- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte +++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte @@ -202,7 +202,7 @@ display: inline-block; } .block { - width: 360px; + width: 480px; font-size: 16px; background-color: var(--background); border: 1px solid var(--spectrum-global-color-gray-300); From 611337c140e79d2297b324f531fbf5a5dcffb843 Mon Sep 17 00:00:00 2001 From: Budibase Staging Release Bot <> Date: Wed, 10 Nov 2021 14:56:30 +0000 Subject: [PATCH 126/148] v0.9.180-alpha.7 --- lerna.json | 2 +- packages/auth/package.json | 2 +- packages/bbui/package.json | 2 +- packages/builder/package.json | 8 ++++---- packages/cli/package.json | 2 +- packages/client/package.json | 6 +++--- packages/server/package.json | 8 ++++---- packages/string-templates/package.json | 2 +- packages/worker/package.json | 6 +++--- 9 files changed, 19 insertions(+), 19 deletions(-) diff --git a/lerna.json b/lerna.json index 6c39265db..ad87b1bdb 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/auth/package.json b/packages/auth/package.json index 2cbb76f44..f643988c4 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/auth", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "description": "Authentication middlewares for budibase builder and apps", "main": "src/index.js", "author": "Budibase", diff --git a/packages/bbui/package.json b/packages/bbui/package.json index 6a407d285..7dbedb8ec 100644 --- a/packages/bbui/package.json +++ b/packages/bbui/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/bbui", "description": "A UI solution used in the different Budibase projects.", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "license": "AGPL-3.0", "svelte": "src/index.js", "module": "dist/bbui.es.js", diff --git a/packages/builder/package.json b/packages/builder/package.json index 4b1951762..481ac940a 100644 --- a/packages/builder/package.json +++ b/packages/builder/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/builder", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "license": "AGPL-3.0", "private": true, "scripts": { @@ -65,10 +65,10 @@ } }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.6", - "@budibase/client": "^0.9.180-alpha.6", + "@budibase/bbui": "^0.9.180-alpha.7", + "@budibase/client": "^0.9.180-alpha.7", "@budibase/colorpicker": "1.1.2", - "@budibase/string-templates": "^0.9.180-alpha.6", + "@budibase/string-templates": "^0.9.180-alpha.7", "@sentry/browser": "5.19.1", "@spectrum-css/page": "^3.0.1", "@spectrum-css/vars": "^3.0.1", diff --git a/packages/cli/package.json b/packages/cli/package.json index 70f800e85..3a6ab5278 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/cli", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "description": "Budibase CLI, for developers, self hosting and migrations.", "main": "src/index.js", "bin": { diff --git a/packages/client/package.json b/packages/client/package.json index 83240ea6c..e2824c0e0 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/client", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "license": "MPL-2.0", "module": "dist/budibase-client.js", "main": "dist/budibase-client.js", @@ -19,9 +19,9 @@ "dev:builder": "rollup -cw" }, "dependencies": { - "@budibase/bbui": "^0.9.180-alpha.6", + "@budibase/bbui": "^0.9.180-alpha.7", "@budibase/standard-components": "^0.9.139", - "@budibase/string-templates": "^0.9.180-alpha.6", + "@budibase/string-templates": "^0.9.180-alpha.7", "regexparam": "^1.3.0", "shortid": "^2.2.15", "svelte-spa-router": "^3.0.5" diff --git a/packages/server/package.json b/packages/server/package.json index 5df56f7be..6a1c403ed 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/server", "email": "hi@budibase.com", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "description": "Budibase Web Server", "main": "src/index.js", "repository": { @@ -68,9 +68,9 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.6", - "@budibase/client": "^0.9.180-alpha.6", - "@budibase/string-templates": "^0.9.180-alpha.6", + "@budibase/auth": "^0.9.180-alpha.7", + "@budibase/client": "^0.9.180-alpha.7", + "@budibase/string-templates": "^0.9.180-alpha.7", "@elastic/elasticsearch": "7.10.0", "@koa/router": "8.0.0", "@sendgrid/mail": "7.1.1", diff --git a/packages/string-templates/package.json b/packages/string-templates/package.json index f9d280e7a..e870f8706 100644 --- a/packages/string-templates/package.json +++ b/packages/string-templates/package.json @@ -1,6 +1,6 @@ { "name": "@budibase/string-templates", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "description": "Handlebars wrapper for Budibase templating.", "main": "src/index.cjs", "module": "dist/bundle.mjs", diff --git a/packages/worker/package.json b/packages/worker/package.json index 606337b78..0122e0202 100644 --- a/packages/worker/package.json +++ b/packages/worker/package.json @@ -1,7 +1,7 @@ { "name": "@budibase/worker", "email": "hi@budibase.com", - "version": "0.9.180-alpha.6", + "version": "0.9.180-alpha.7", "description": "Budibase background service", "main": "src/index.js", "repository": { @@ -29,8 +29,8 @@ "author": "Budibase", "license": "AGPL-3.0-or-later", "dependencies": { - "@budibase/auth": "^0.9.180-alpha.6", - "@budibase/string-templates": "^0.9.180-alpha.6", + "@budibase/auth": "^0.9.180-alpha.7", + "@budibase/string-templates": "^0.9.180-alpha.7", "@koa/router": "^8.0.0", "@sentry/node": "^6.0.0", "@techpass/passport-openidconnect": "^0.3.0", From 2b59d44e06762b3ed05e264726fb40a65e909407 Mon Sep 17 00:00:00 2001 From: Andrew Kingston Date: Wed, 10 Nov 2021 14:57:46 +0000 Subject: [PATCH 127/148] Change bindable properties order --- packages/builder/src/builderStore/dataBinding.js | 6 +++--- .../PropertiesPanel/PropertyControls/PropertyControl.svelte | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/builder/src/builderStore/dataBinding.js b/packages/builder/src/builderStore/dataBinding.js index 165ed37fb..0551997b7 100644 --- a/packages/builder/src/builderStore/dataBinding.js +++ b/packages/builder/src/builderStore/dataBinding.js @@ -31,11 +31,11 @@ export const getBindableProperties = (asset, componentId) => { const deviceBindings = getDeviceBindings() const stateBindings = getStateBindings() return [ - ...stateBindings, - ...deviceBindings, - ...urlBindings, ...contextBindings, + ...urlBindings, + ...stateBindings, ...userBindings, + ...deviceBindings, ] } diff --git a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte index a6086bbbc..72b54f3b9 100644 --- a/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte +++ b/packages/builder/src/components/design/PropertiesPanel/PropertyControls/PropertyControl.svelte @@ -27,7 +27,7 @@ if (!nested) { return bindings } - return [...(bindings || []), ...(componentBindings || [])] + return [...(componentBindings || []), ...(bindings || [])] } // Handle a value change of any type From 7f055ed8dcb897162e52a35c342bfaf04e0cd152 Mon Sep 17 00:00:00 2001 From: mike12345567 Date: Wed, 10 Nov 2021 15:01:44 +0000 Subject: [PATCH 128/148] Adding a way to switch between string and options, as well as number and boolean types, this is very useful for SQL tables. --- .../DataTable/modals/CreateEditColumn.svelte | 19 +++++++++++++++++-- .../builder/src/constants/backend/index.js | 16 ++++++++++++++++ packages/builder/src/stores/backend/tables.js | 7 ++++++- .../src/api/controllers/table/external.js | 5 +++++ .../src/api/controllers/table/internal.js | 6 +++++- .../server/src/api/controllers/table/utils.js | 19 ++++++++++++++++++- packages/server/src/constants/index.js | 7 +++++++ .../server/src/integrations/base/sqlTable.ts | 2 +- 8 files changed, 75 insertions(+), 6 deletions(-) diff --git a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte index aa21799ca..83ed741b7 100644 --- a/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte +++ b/packages/builder/src/components/backend/DataTable/modals/CreateEditColumn.svelte @@ -18,6 +18,11 @@ FIELDS, AUTO_COLUMN_SUB_TYPES, RelationshipTypes, + ALLOWABLE_STRING_OPTIONS, + ALLOWABLE_NUMBER_OPTIONS, + ALLOWABLE_STRING_TYPES, + ALLOWABLE_NUMBER_TYPES, + SWITCHABLE_TYPES, } from "constants/backend" import { getAutoColumnInformation, buildAutoColumn } from "builderStore/utils" import { notifications } from "@budibase/bbui" @@ -92,6 +97,9 @@ opt.type === table.type && table.sourceId === opt.sourceId ) + $: typeEnabled = + !originalName || + (originalName && SWITCHABLE_TYPES.indexOf(field.type) !== -1) async function saveColumn() { if (field.type === AUTO_TYPE) { @@ -204,7 +212,14 @@ } function getAllowedTypes() { - if (!external) { + if (originalName && ALLOWABLE_STRING_TYPES.indexOf(field.type) !== -1) { + return ALLOWABLE_STRING_OPTIONS + } else if ( + originalName && + ALLOWABLE_NUMBER_TYPES.indexOf(field.type) !== -1 + ) { + return ALLOWABLE_NUMBER_OPTIONS + } else if (!external) { return [ ...Object.values(fieldDefinitions), { name: "Auto Column", type: AUTO_TYPE }, @@ -259,7 +274,7 @@ /> +